From 718585062bf3d5bf5067003da9a6b70bfb407940 Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Tue, 30 Apr 2024 22:06:54 -0400 Subject: [PATCH 01/72] Add togglable stat change display --- index.css | 4 + index.html | 3 + public/images/pbinfo_stat_numbers.json | 293 ++++++++++++++++++ .../ui/legacy/pbinfo_enemy_boss_stats.png | Bin 0 -> 435 bytes .../ui/legacy/pbinfo_enemy_mini_stats.png | Bin 0 -> 666 bytes .../ui/legacy/pbinfo_player_mini_stats.png | Bin 0 -> 674 bytes .../images/ui/legacy/pbinfo_player_stats.png | Bin 0 -> 285 bytes public/images/ui/legacy/pbinfo_stat.json | 188 +++++++++++ public/images/ui/legacy/pbinfo_stat.png | Bin 0 -> 263 bytes .../images/ui/legacy/pbinfo_stat_numbers.json | 293 ++++++++++++++++++ .../images/ui/legacy/pbinfo_stat_numbers.png | Bin 0 -> 392 bytes public/images/ui/pbinfo_enemy_boss.png | Bin 554 -> 526 bytes public/images/ui/pbinfo_enemy_boss_stats.png | Bin 0 -> 257 bytes public/images/ui/pbinfo_enemy_mini.png | Bin 888 -> 851 bytes public/images/ui/pbinfo_enemy_mini_stats.png | Bin 0 -> 642 bytes public/images/ui/pbinfo_enemy_type.png | Bin 1502 -> 3599 bytes public/images/ui/pbinfo_enemy_type1.png | Bin 1360 -> 3305 bytes public/images/ui/pbinfo_enemy_type2.png | Bin 1340 -> 3197 bytes public/images/ui/pbinfo_player.png | Bin 654 -> 619 bytes public/images/ui/pbinfo_player_mini.png | Bin 898 -> 860 bytes public/images/ui/pbinfo_player_mini_stats.png | Bin 0 -> 648 bytes public/images/ui/pbinfo_player_stats.png | Bin 0 -> 312 bytes public/images/ui/pbinfo_player_type1.png | Bin 1340 -> 3197 bytes public/images/ui/pbinfo_player_type2.png | Bin 1360 -> 3305 bytes public/images/ui/pbinfo_stat.json | 188 +++++++++++ public/images/ui/pbinfo_stat.png | Bin 0 -> 278 bytes public/images/ui/pbinfo_stat_numbers.json | 293 ++++++++++++++++++ public/images/ui/pbinfo_stat_numbers.png | Bin 0 -> 430 bytes src/battle-scene.ts | 72 +++-- src/data/splash-messages.ts | 3 +- src/field/pokemon.ts | 4 + src/loading-scene.ts | 6 + src/locales/de/tutorial.ts | 4 + src/locales/en/tutorial.ts | 4 + src/locales/es/tutorial.ts | 4 + src/locales/fr/tutorial.ts | 4 + src/locales/it/tutorial.ts | 4 + src/phases.ts | 10 +- src/tutorial.ts | 6 + src/ui/battle-info.ts | 100 +++++- 40 files changed, 1440 insertions(+), 43 deletions(-) create mode 100644 public/images/pbinfo_stat_numbers.json create mode 100644 public/images/ui/legacy/pbinfo_enemy_boss_stats.png create mode 100644 public/images/ui/legacy/pbinfo_enemy_mini_stats.png create mode 100644 public/images/ui/legacy/pbinfo_player_mini_stats.png create mode 100644 public/images/ui/legacy/pbinfo_player_stats.png create mode 100644 public/images/ui/legacy/pbinfo_stat.json create mode 100644 public/images/ui/legacy/pbinfo_stat.png create mode 100644 public/images/ui/legacy/pbinfo_stat_numbers.json create mode 100644 public/images/ui/legacy/pbinfo_stat_numbers.png create mode 100644 public/images/ui/pbinfo_enemy_boss_stats.png create mode 100644 public/images/ui/pbinfo_enemy_mini_stats.png create mode 100644 public/images/ui/pbinfo_player_mini_stats.png create mode 100644 public/images/ui/pbinfo_player_stats.png create mode 100644 public/images/ui/pbinfo_stat.json create mode 100644 public/images/ui/pbinfo_stat.png create mode 100644 public/images/ui/pbinfo_stat_numbers.json create mode 100644 public/images/ui/pbinfo_stat_numbers.png diff --git a/index.css b/index.css index 9a507ad6766..dd47387adee 100644 --- a/index.css +++ b/index.css @@ -150,6 +150,10 @@ body { display: none; } +#touchControls:not([data-ui-mode='COMMAND']):not([data-ui-mode='FIGHT']):not([data-ui-mode='BALL']):not([data-ui-mode='TARGET_SELECT']) #apad #apadStats { + display: none; +} + #apad .apadRectBtnContainer + .apadSqBtnContainer { top: calc(var(--controls-size) * -1.9); left: calc(var(--controls-size) * -0.9); diff --git a/index.html b/index.html index bd316330a99..506fa4f1efa 100644 --- a/index.html +++ b/index.html @@ -74,6 +74,9 @@
V
+
+ Shift +
Menu
diff --git a/public/images/pbinfo_stat_numbers.json b/public/images/pbinfo_stat_numbers.json new file mode 100644 index 00000000000..32170690aa0 --- /dev/null +++ b/public/images/pbinfo_stat_numbers.json @@ -0,0 +1,293 @@ +{ + "textures": [ + { + "image": "pbinfo_stat_numbers.png", + "format": "RGBA8888", + "size": { + "w": 117, + "h": 8 + }, + "scale": 1, + "frames": [ + { + "filename": "+1", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "+2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 9, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "+3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 18, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "+4", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 27, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "+5", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 36, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "+6", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 45, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-1", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 54, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 63, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 72, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-4", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 81, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-5", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 90, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-6", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 99, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "0", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 108, + "y": 0, + "w": 9, + "h": 8 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:794aa4af3291db5abd8a2667626c1998:1a6706ad557b92f9bf099c23e02af4a6:6537c634087637bb27e8a1edb1ee2e35$" + } +} diff --git a/public/images/ui/legacy/pbinfo_enemy_boss_stats.png b/public/images/ui/legacy/pbinfo_enemy_boss_stats.png new file mode 100644 index 0000000000000000000000000000000000000000..94c9f2a181736d88c6752f2c97ed0bbbee23ebcc GIT binary patch literal 435 zcmeAS@N?(olHy`uVBq!ia0vp^n}ArJgAGVJb4-r_QjEnx?oJHr&dIz4vU5FM978JR zyuG8?cgR7a?csXf_7^8kc|Ex$m-yBz<$7q-n^RU*Eb9Vy3q^L$xwlCBgn&~-ln2-0 zC$%D(Zao#Zd6NElh+n&%^Pj+>91Q?jM7YZ*~R6rK6tBHXtJ>3o}%+B70Tit?}|9LLp3388Oyx(ny$dZ`X4n6UD>PshjO%e?;W3et7Lx@QEIV2LHO-ZhLc6eY9Ry zIQ|Mdb1{9R)SaoXcSRIE<`z6H%nuWjbE9V$ zXGWbr(B0xb=lC1f6GDcM4fWFUoyzXm2QNAn5;^S^|FUJBo0|`=UT>R$XHs^CNV z##av>ty$f?T7lzV!;W1Rn!7wYzpJ*28OBxY>HqxBa!BncE&SaXRbV6dDO(__3L?7E8i*EoZkKZ{HwqsHRc+nk205eyDOS2sxDu$ zd@tM{5g62QzVkTGE`^WE*Hfq8w-A>Rt4KTHq5izn`AE{j-lt}1uFk6Sl=!q)x&3rH zmfHGREPZQC>e=c~;%vpYyt-a*X%jpw^vJ`ZrANz4IZ?ukeBYJTaNN^-KBA z)J%%Y&U~o6pj>*#j=aoIas@k?dF)+-(V{Q3XI{exr|Grpv%NI5;(qK@ xp0+UKM9$<@NoVioZhp6Q^O64&v*v`HV4ZIk%FUH_dOOew44$rjF6*2UngE&&E5rZ* literal 0 HcmV?d00001 diff --git a/public/images/ui/legacy/pbinfo_player_mini_stats.png b/public/images/ui/legacy/pbinfo_player_mini_stats.png new file mode 100644 index 0000000000000000000000000000000000000000..dd2b7e65ba3522986e78d6844a6be8823c3382ae GIT binary patch literal 674 zcmV;T0$u%yP)EX>4Tx04R}tkv&MmKpe$iQ%gl!9Lyl%kfA!+MMWJ;6^me@v=v%)FuC*#nzSS- zE{=k0!NHHks)LKOt`4q(Aou~|>f)s6A|?JWDYS_3;J6>}?mh0_0Ya# zo%24i$jY)xd`>)J&;^MfxvseU#<}FMz%xZ7o1P~YiKS8xD?QB0hDJP198oo$@`aqs zD(5ZETD8GC_v9}O74(%1*J+L-fh8o7qK*_aP(c+IqO|Iym`Kxp+`~WO_*3Lk$W;L& z#{z25AUl5WKlt6PS)7`5lR|MI@M7B^V?b~hXg6*9``EVICxHJMxYE1+S__!_B)!?y zB1gdBHgIv>)s#Kpat9cGs>_D#NPe0^u?W1M(KqFRp<7^J&F!tTkJASrOIK2l+uOfqI{p0s^F(smE#4Fv0000mP)t-s0001cl!Q`iV>wbnAvplXy>s5y zwg3O#*3P|BYg+%cd;kCcN$J_5c5S*Us$?%8vTKwfg`6|6Wc}-=`Gc19G2( z)VthFjRI1_B|(0{3_xi#U}t|v7bsoq>Eaj?(fam=p-_VZhjU<>!iIbQ4@G5d*>KA2 zr+S66yVASV%+m`tUAT0h%_Vu-2F6#OE9N=hF1aYEASTnz@k_ZzU>c{|jD#j+;!l_T zYhIRn;@{452VTh2;XbSE{bIVBSPWaCe#7lsobz5x%h_{T;XlZgp00i_>zopr0I}G2 ADF6Tf literal 0 HcmV?d00001 diff --git a/public/images/ui/legacy/pbinfo_stat.json b/public/images/ui/legacy/pbinfo_stat.json new file mode 100644 index 00000000000..b7da47fc192 --- /dev/null +++ b/public/images/ui/legacy/pbinfo_stat.json @@ -0,0 +1,188 @@ +{ + "textures": [ + { + "image": "pbinfo_stat.png", + "format": "RGBA8888", + "size": { + "w": 112, + "h": 6 + }, + "scale": 1, + "frames": [ + { + "filename": "SPATK", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 19, + "h": 8 + }, + "spriteSourceSize": { + "x": 1, + "y": 2, + "w": 18, + "h": 6 + }, + "frame": { + "x": 0, + "y": 0, + "w": 18, + "h": 6 + } + }, + { + "filename": "SPDEF", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 19, + "h": 8 + }, + "spriteSourceSize": { + "x": 1, + "y": 2, + "w": 18, + "h": 6 + }, + "frame": { + "x": 18, + "y": 0, + "w": 18, + "h": 6 + } + }, + { + "filename": "CRIT", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 17, + "h": 8 + }, + "spriteSourceSize": { + "x": 1, + "y": 2, + "w": 16, + "h": 6 + }, + "frame": { + "x": 36, + "y": 0, + "w": 16, + "h": 6 + } + }, + { + "filename": "ACC", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 13, + "h": 8 + }, + "spriteSourceSize": { + "x": 1, + "y": 2, + "w": 12, + "h": 6 + }, + "frame": { + "x": 52, + "y": 0, + "w": 12, + "h": 6 + } + }, + { + "filename": "ATK", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 13, + "h": 8 + }, + "spriteSourceSize": { + "x": 1, + "y": 2, + "w": 12, + "h": 6 + }, + "frame": { + "x": 64, + "y": 0, + "w": 12, + "h": 6 + } + }, + { + "filename": "DEF", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 13, + "h": 8 + }, + "spriteSourceSize": { + "x": 1, + "y": 2, + "w": 12, + "h": 6 + }, + "frame": { + "x": 76, + "y": 0, + "w": 12, + "h": 6 + } + }, + { + "filename": "EVA", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 13, + "h": 8 + }, + "spriteSourceSize": { + "x": 1, + "y": 2, + "w": 12, + "h": 6 + }, + "frame": { + "x": 88, + "y": 0, + "w": 12, + "h": 6 + } + }, + { + "filename": "SPD", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 13, + "h": 8 + }, + "spriteSourceSize": { + "x": 1, + "y": 2, + "w": 12, + "h": 6 + }, + "frame": { + "x": 100, + "y": 0, + "w": 12, + "h": 6 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:40d30205ce8efd40dfa86cd11b0491d6:7076db6ed74199dcfb38fc8cd4d4a0e8:05882267d3999884e0491134e98b1b53$" + } +} diff --git a/public/images/ui/legacy/pbinfo_stat.png b/public/images/ui/legacy/pbinfo_stat.png new file mode 100644 index 0000000000000000000000000000000000000000..62ec3758772daea6013a4de5532575a66caf8116 GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0vp^1whQk!3-pITwg5(Qk(%kA+A8$!NK9)wXI7Q-Kzj{ z7)yfuf*Bm1-ADteDDa3ZW?Ec4QuN(io6fN32b;e=)XJ@8wjxa57 z6;5`pyz#?~2;;a-r4XYn{3?!Y<6HKbItN$2xk}gw>0y zUzy)p<5e-!w)Vy<(87aih3;8-LtI=7KLTHk<}Jk-^i|&t;uc GLK6T7%VuW) literal 0 HcmV?d00001 diff --git a/public/images/ui/legacy/pbinfo_stat_numbers.json b/public/images/ui/legacy/pbinfo_stat_numbers.json new file mode 100644 index 00000000000..9c74ee86dbc --- /dev/null +++ b/public/images/ui/legacy/pbinfo_stat_numbers.json @@ -0,0 +1,293 @@ +{ + "textures": [ + { + "image": "pbinfo_stat_numbers.png", + "format": "RGBA8888", + "size": { + "w": 117, + "h": 8 + }, + "scale": 1, + "frames": [ + { + "filename": "+1", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "+2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 9, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "+3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 18, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "+4", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 27, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "+5", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 36, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "+6", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 45, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-1", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 54, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 63, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 72, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-4", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 81, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-5", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 90, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-6", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 99, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "0", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 108, + "y": 0, + "w": 9, + "h": 8 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:1f22b7cb085faf9e9764273fa5e70c28:afc5587ebacca78d178ac7e0c434591b:6537c634087637bb27e8a1edb1ee2e35$" + } +} diff --git a/public/images/ui/legacy/pbinfo_stat_numbers.png b/public/images/ui/legacy/pbinfo_stat_numbers.png new file mode 100644 index 0000000000000000000000000000000000000000..ee1453b21070f8de40a299a2d0c82c49093799cc GIT binary patch literal 392 zcmV;30eAk1P)NeVolC?^B79yfh4NP^lrY9U!*DY-V@3rV{hYdQ>YK;=1YJaz3T;`<^$DGJL<5 z0VRW87@CHmA>NuYKzH1TLC5xSzn%dVgI*Y#hCzM2e@<+(--30)Oref_gmu$R&9E*Q zKCPUg&65~>rQzm$c=)wGxON}pkE{!ZPit-h_?q;dhMV)@;n(^|U!-Qgl_%A@VDM** z28vT)T`)O@Pln{f8%r6yr(x9i(DP6xH!0n5bN5`F;gccxJgbFgqhZwe(DRg7RCba7 mA?H5)Du%PaS?j+(7uOe-FYwO$9P0Z30000Ik&UmVKT0GxPa8d!07jZZ!ddIBQBbh_PFZe&65JuT|9nKq=MA`2Ra01f-NW z91f+QE2Xg6Y_!guHF6k+mXtE_eP3^s9ZQpWyFcUJ3~9SRW4V~*j$cQ1WnC#{?2Y{H zp1HO|plBRLh_0>&dpk(u@=|B3Ul!cn-d9Bu|Irn<2(MATii<NL1q8595j002ovPDHLkV1ifd@6!MP delta 515 zcmV+e0{s1s1gZp(F@NMqL_t(|obB6BYQjJm1@M;=C_;s9>aGx7IS8(W?BZR#K+fR> zdKYIGa4pEV(m;21BcvdOLb@oX#w6N||Hk-!EB%ba5WYMoi2;a+$P89q(Q(?bWqnK1js?_P5*2T3V0acimCcp71_vhnu(jb5jIunqv- zU|m?J^YT3J;D0uwQBe98btaL0--i&Q%orEbYPFKro2Hw%bs$(LP1z0Bn7Fmy_dE4% zMRfpBN}Xl?_f7}_DJACfdG6;*DGY~0t+A6v4#Sx>8X@+5UvHKdwn^skG{U|W(s&x7 z*QuwrAFS-cx>Cy61NqkdXW#0iF_3fBLidQcv~I9QcYG^xiwstFvMunJ#6@+wo@071 z6=j=LzJ;IG-9*kySisI*Q}3$_A-J?SlT8{I?O!P+!f>JWs8i-krl0glDKjDTt88$>!uSb_l5uf002ovPDHLk FV1lYA{=)zO diff --git a/public/images/ui/pbinfo_enemy_boss_stats.png b/public/images/ui/pbinfo_enemy_boss_stats.png new file mode 100644 index 0000000000000000000000000000000000000000..7148a7af4759141abb5e2b39c02a17b45af905e5 GIT binary patch literal 257 zcmeAS@N?(olHy`uVBq!ia0vp^n}ArJgAGVJb4-r_QjEnx?oJHr&dIz4a&~*VIEGZr zd3$>`-ysJ9)(e`BNfSH%{_kJqko58BL=U^z3cqSH|eR)57 zW1&p?=O4X~e>-L8TFuvct=1%`yX>BUe4QLNkl8GRYx|2)P*70tlomTy+AL)kaKVi zE&#J{fxIOH3ldw!o(@eA9|jTwfke-5G6qF2@~g-B0uhl?&o>!GQQmYRa=R?cyz5!T z`|(5+MftElx~(F4j)*+88Q$()i?q{0_b3h8Z?jzmZ4pWY0rr0qL21w(A*rB55THl| zr9t=9O$8-_0MJt!bXT2JP$CGRMv#IUK>#&^6m9ha8#1%t_N<261?l{K=~*1pAjk_btXV2r7AjK;-r zyc-`ce5q`T&+mUP){_|k&bdbFdlX{~)>_gu^?vW1V>+D%9edXZS(f#zwRw^xVO733 z=iJLT_%&7jLr5Bc=c*yJqh3v!6wCSI$(1zcmbE+B8p>2?Q-u1?3(9$bLGjrb(}}GC z&Tny{X#k#=SKD&ZXsreQPoB<=eZOzJOKWr2MgYCV+*TmByu~acA|fIpa@iluDW|ek SO(V4c0000wNkl)q|N~u!nI~O4Yq?Ab0 z)cUDa4A$g)|GB+zjjyH$DNlu{Sp;D;RZA6(J^uv|5`cGRUYNim(gR9s1U zPC0iQQ-etbpCZ(@E->2xpqYObLeyev0QOIDQc7gm-04MCwVfaNvS^f20{C4#?Hk+n z_uXHMMb~Ko*z*>1x7*b&2cv4u=Wc00L_|bHM0D5>)LE${MNRhx00000NkvXXu0mjf DZ|lEX>4Tx04R}tkv&MmP!xqvQ>7vm5sQd8WT;LSL`4J_sbUc+7C6sqP{?%e(K->QQng1AHR!9McVpc!PL) z)6zNb6Ngw)Qi#uq#|*k4@gvt|m)|%S92R(H$VeyWi9^IW<^6Ko+1t_sz&)j z#$|=`7H73wWzBo?7Y1|MN{Z{Wh7rRO;z&S*j4Dbf!$O31jT93}I*)qzha7)`Tr#;z zVB}ap1u7)R5B>+gXKUssC)}i96zF`h?T-;4unRP5w*7r<+l>>z{|sDdEq|pB%zTnw zYiZ#lpm!U%xNd3k9&ot>3_j_SAvuztmXOZ_?`QN)S)l(G=w5T@);!1Q1CXX!E#CkK zhrnoove!M{-PJy~e|wtq`vH(aagbUB zzo-t5uI_cI;7<`vL}@r@>=fw7Q_>^>xEhuomQto)FNAjEI4-`=cWfUYlv1Ys?$EX( z{-b279fr-f*TOp8O^+I^-|2j;`a~!KNp6au2K}h1f+CP)E`l2L=hG@E0!flV4f^#- z6%>Ia27#GDAc;X>X8YJF+efPS#oQskn5pI%x-*WUY4S8Vs<2+QHAobJnOn>qX}QG= c008jX1y1rsg=?D3Y5)KL07*qoM6N<$f~t=qVE_OC literal 0 HcmV?d00001 diff --git a/public/images/ui/pbinfo_enemy_type.png b/public/images/ui/pbinfo_enemy_type.png index 021a120070c1872b54405196e4bcb2cec9920d06..9bac63e5e72ba305c0c7769d72bc39d72aa8202e 100644 GIT binary patch literal 3599 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 diff --git a/public/images/ui/pbinfo_enemy_type1.png b/public/images/ui/pbinfo_enemy_type1.png index 89b84d7f6305169db2e227aa33a9e2202cdeebfa..6d94871e8da1dfd56a0271a6a8ef1ae8e9d6c3c4 100644 GIT binary patch literal 3305 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 delta 1332 zcmV-41K;roK6x|8rVOt-T?ULCa%fweLZBshW_&&HC;* zO0vk;&DMDOm4U9|mAs4J&B(p@`1tjx^{$}s^^2`iam|Lp|9@hcy`Z4dqs6<(m4=$( z@Ycwh|J;Giu7~bbDWAdC&0W2FNPBZod$Y)zgQZ%P*Yx1fkon7G_No9%p+S^Ti}|f> zm8jtMc@R>*?(~L`sg$n0l(@~ZN?llm^Z)<=0d!JMQvg8b*k%9#010qNS#tmY4#WTe z4#WYKD-Ig~0DlAzNkl(^Y-#Wr6(Oj4xVAPdRD7!nD#iAB*BzHNIOCF7+K!2!Mo?4Ma{y?`n4?k5THGfPb znjaf?PygBd=;)}=AC3b1KsV?cB*s@ciU)rw57cPk>(CnArfu-@+b7_eU=Lj1OnvNcwffW0-uP_mXO_l4S!y5_eP^JhH)c@!3IEp%o=Epqlf^Q zdl4vm%oVI6jAf-z5$|I$U2Dmtnyz&NU|gM1Tovo?z9%sl038k@0T?JGHsIL@QDnrd zDzX{HYQ?=uvO=g-#FB$Nsuv5}+iLfdlS^uKdBRa(`I~AmiC0_`**#%3i+m|xZDaqP znSbbOs;KIv6AN{%B`!mDz1^R4OyqbTAb6NW0}$>+AUJ_2A{5z+2=NU>5xD9kiW7b_ ziQ3*&JDtuMz*$E^ zq5Oy)WOl}~7tbVB4ihDjPFJx4ljiYZ^SDMTc5Eak+VETLetdjNB~Onz3M4|@U_y^2 zIZTv9KC>90ws`^*7o%$YR54G)Z&akbQ~r1nO{!**|rqpNJ<0!EF`8Alxn}7E5 z(}~lmd`(2y!z<9KqCiv?B4ap}nkwRT+RHPkNNQz9jwytB>h0bPVUU_P&kYuaaOFk$ z8LiIGod{VZ7{z9D<;CVoyik#-*^P(`O#DR2_+sU8C^NhOn2+~R33uoA15d^47ggKu*i{Slh@`p?1>g%h%6Cw5J!=T0U*R1MnDJ6|U#*Z*JkoesN4y6h&V9 zS^IL#rHNpS$$z3KVzb$F)3Ol+L9lnip}Z&_gDU{iG###yJqW`PfbDi$yYFhX!dhEB z4IRgEH!YixG)-SW$f;^_3~?M|t<_*LPlNlL+mTx`uF6D6l4LfiP&6*cw*!3q`#KE6 z*>nv)$B`rn;PGFB@1WyQS!;op!Bg3K(f(8CKUlOl=YJNph0sZ>!pgJLse-2Lyi&dt}*K+!0R$E0vTWLUzE`_5mXrc zsQaRf);@*cL$jCTsXOrp#Tb)a{=Cd~yPcLDF5CP8>Nk1daueF@H!&L_t(|obBAdPTNo%hT%6=r7mDtOmVaZ|#D^=AwA$T>{|y z{`MMK0n4%gn9t{_=Z;1rTz8s03~k$XIW5~GzVAQ(BKK9E&tTg&t~=GuVw47V*Ecn{ zq+W@M;5bfWQX%fXAUY0k`1iGCS&iu$vV0E5aexf}HGd3;XC*YPKAz_Re{P;O?Z=(J z@3P-4P6>ipC$SJTFR}T;@LhT#Kr@~tNIX4Rlr7F3ih1JlvSD0}h;CUMrfz+?^FUrW92r7(fqb;z7>41Gsv{dh>cWt0R&T-FUZ9s?$T_$M z7l7HfK;Dvp1&OUH5K*IY>CJ^)^|N88NNC4pVs+=4}QGTmJ(3~vGe$D%9 z=$A!Nln?u(Y8Bx=BIU(qc)3?Ccq~Cn18LBHo9*gki69XmDIk9lNQ3S;P6ZMHlCDey z(x7{MDv$_}bVVYN2HmyUuGk}Bhem)T8UcGW0wi(y`1JhcWAML^ZL!&|BuT^msC0bn znVUT57V~&KuA`Qlv)1Y@{gNcD<5}t0Th136Ouiehu`ZX)k+t@4i#a$Ek|dEaCiL`1 z#BqEW7bo8HP4R#J`Jwe>CP{M6HBw()j4`s-DoxYU_nmW^PNyfwu5N@Z%X-$@JV}zU zDj%G4?%^B!KbQQ5<1~;eTs0Iss;zudEa!_mSJIraxeHnvd@8glLd*6A{^x002ovPDHLkV1g-F&x8N~ delta 473 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 delta 1332 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 Wt8RFN+!3I289ZJ6T-G@yGywokWokPB literal 0 HcmV?d00001 diff --git a/public/images/ui/pbinfo_stat_numbers.json b/public/images/ui/pbinfo_stat_numbers.json new file mode 100644 index 00000000000..ec4f7117bb7 --- /dev/null +++ b/public/images/ui/pbinfo_stat_numbers.json @@ -0,0 +1,293 @@ +{ + "textures": [ + { + "image": "pbinfo_stat_numbers.png", + "format": "RGBA8888", + "size": { + "w": 117, + "h": 8 + }, + "scale": 1, + "frames": [ + { + "filename": "1", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 9, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 18, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "4", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 27, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "5", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 36, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "6", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 45, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-1", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 54, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 63, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 72, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-4", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 81, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-5", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 90, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-6", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 99, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "0", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 108, + "y": 0, + "w": 9, + "h": 8 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:b0719fae0d9b670a727148cdc7202249:afc5587ebacca78d178ac7e0c434591b:4825a9f02f72f1fe28a724c6c5dffb37$" + } +} diff --git a/public/images/ui/pbinfo_stat_numbers.png b/public/images/ui/pbinfo_stat_numbers.png new file mode 100644 index 0000000000000000000000000000000000000000..c778ba992734421a718b2c49db1db0ae77a28e09 GIT binary patch literal 430 zcmV;f0a5;mP)X}UpFSFJe%YMSjb zvz=}Te=dw_+OM;>zwNiTz<(WGW!%j?&)@0VTARh5OWbc`j(J{Tok%Zt#$YoH;sBj7 z0D#IlJRc6p%*|?r>-8D{#_^;+F^22I1yqy`_PebZNKrNbfWEEq_WF{{oLyYu^!yS4 z#PO(4jM4P@WGYS8UqlLVGYqiSvW&F&OBuS>FtHC$Vz?0ZyX|CN5<3@SjG<>5X2}?8 zQ)v+?7z&xQg%~oUa!zD?QzeEgj_Hh<7_VVM6DZ`EEo4UD)*|DZy2Lt;DavMIyoRBA zxP2Ty%KN9gENZI8IE_78Q^T$GD~(@jhsGYQsdI~*V!X;!+J?fg{Gd2S+NQZaWGcsm zi<{b~a&9zLI&@IbQb7LyuD?x7eaKXf@hzMCJ+VH0TaTtDpMHPh p)) + p.toggleStats(pressed); + if (pressed) + this.setLastProcessedMovementTime(Button.STATS); + } else + return; + } if (inputSuccess && this.enableVibration && typeof navigator.vibrate !== 'undefined') navigator.vibrate(vibrationLength || 10); } @@ -1443,7 +1454,7 @@ export default class BattleScene extends SceneBase { * or not. It will only return true once, until the key is released and pressed down * again. */ - gamepadButtonJustDown(button: Phaser.Input.Gamepad.Button) : boolean { + gamepadButtonJustDown(button: Phaser.Input.Gamepad.Button): boolean { if (!button || !this.gamepadSupport) return false; @@ -1463,6 +1474,23 @@ export default class BattleScene extends SceneBase { return this.buttonKeys[button].some(k => Phaser.Input.Keyboard.JustDown(k)) || this.gamepadButtonJustDown(gamepad?.buttons[this.gamepadKeyConfig[button]]); } + /** + * gamepadButtonJustUp returns true if @param button has just been released + * or not. It will only return true once, until the key is released and pressed down + * again. + */ + gamepadButtonJustUp(button: Phaser.Input.Gamepad.Button): boolean { + if (!button || !this.gamepadSupport) + return false; + + return !this.gamepadButtonStates[button.index]; + } + + buttonJustReleased(button: Button): boolean { + const gamepad = this.input.gamepad?.gamepads[0]; + return this.buttonKeys[button].some(k => Phaser.Input.Keyboard.JustUp(k)) || this.gamepadButtonJustUp(gamepad?.buttons[this.gamepadKeyConfig[button]]); + } + /** * repeatInputDurationJustPassed returns true if @param button has been held down long * enough to fire a repeated input. A button must claim the movementButtonLock before diff --git a/src/data/splash-messages.ts b/src/data/splash-messages.ts index 11629cf05d7..198ff07cec9 100644 --- a/src/data/splash-messages.ts +++ b/src/data/splash-messages.ts @@ -33,6 +33,5 @@ splashMessages.push(...[ 'Also Try Emerald Rogue!', 'Also Try Radical Red!', 'Eevee Expo!', - 'YNOproject!', - 'Shh, don\'t tell Sam!' + 'YNOproject!' ]); \ No newline at end of file diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 9a7bfb48621..7072875d3ce 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -1179,6 +1179,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return this.battleInfo.updateInfo(this, instant); } + toggleStats(visible: boolean): void { + this.battleInfo.toggleStats(visible); + } + addExp(exp: integer) { const maxExpLevel = this.scene.getMaxExpLevel(); const initialExp = this.exp; diff --git a/src/loading-scene.ts b/src/loading-scene.ts index 2f37b900ab5..875d618ec0f 100644 --- a/src/loading-scene.ts +++ b/src/loading-scene.ts @@ -39,15 +39,21 @@ export class LoadingScene extends SceneBase { } this.loadAtlas('namebox', 'ui'); this.loadImage('pbinfo_player', 'ui'); + this.loadImage('pbinfo_player_stats', 'ui'); this.loadImage('pbinfo_player_mini', 'ui'); + this.loadImage('pbinfo_player_mini_stats', 'ui'); this.loadAtlas('pbinfo_player_type', 'ui'); this.loadAtlas('pbinfo_player_type1', 'ui'); this.loadAtlas('pbinfo_player_type2', 'ui'); this.loadImage('pbinfo_enemy_mini', 'ui'); + this.loadImage('pbinfo_enemy_mini_stats', 'ui'); this.loadImage('pbinfo_enemy_boss', 'ui'); + this.loadImage('pbinfo_enemy_boss_stats', 'ui'); this.loadAtlas('pbinfo_enemy_type', 'ui'); this.loadAtlas('pbinfo_enemy_type1', 'ui'); this.loadAtlas('pbinfo_enemy_type2', 'ui'); + this.loadAtlas('pbinfo_stat', 'ui'); + this.loadAtlas('pbinfo_stat_numbers', 'ui'); this.loadImage('overlay_lv', 'ui'); this.loadAtlas('numbers', 'ui'); this.loadAtlas('numbers_red', 'ui'); diff --git a/src/locales/de/tutorial.ts b/src/locales/de/tutorial.ts index 2722c02ad45..f37afcae92d 100644 --- a/src/locales/de/tutorial.ts +++ b/src/locales/de/tutorial.ts @@ -20,6 +20,10 @@ export const tutorial: SimpleTranslationEntries = { "pokerus": `A daily random 3 selectable starters have a purple border. $If you see a starter you own with one of these,\ntry adding it to your party. Be sure to check its summary!`, + "statChange": `Stat changes persist across battles as long as your Pokémon aren't recalled. + $Your Pokémon are recalled before a trainer battle and before entering a new biome. + $You can also view the stat changes for the Pokémon on the field by holding shift.`, + "selectItem": `After every battle, you are given a choice of 3 random items.\nYou may only pick one. $These range from consumables, to Pokémon held items, to passive permanent items. $Most non-consumable item effects will stack in various ways. diff --git a/src/locales/en/tutorial.ts b/src/locales/en/tutorial.ts index 2722c02ad45..f37afcae92d 100644 --- a/src/locales/en/tutorial.ts +++ b/src/locales/en/tutorial.ts @@ -20,6 +20,10 @@ export const tutorial: SimpleTranslationEntries = { "pokerus": `A daily random 3 selectable starters have a purple border. $If you see a starter you own with one of these,\ntry adding it to your party. Be sure to check its summary!`, + "statChange": `Stat changes persist across battles as long as your Pokémon aren't recalled. + $Your Pokémon are recalled before a trainer battle and before entering a new biome. + $You can also view the stat changes for the Pokémon on the field by holding shift.`, + "selectItem": `After every battle, you are given a choice of 3 random items.\nYou may only pick one. $These range from consumables, to Pokémon held items, to passive permanent items. $Most non-consumable item effects will stack in various ways. diff --git a/src/locales/es/tutorial.ts b/src/locales/es/tutorial.ts index 2722c02ad45..f37afcae92d 100644 --- a/src/locales/es/tutorial.ts +++ b/src/locales/es/tutorial.ts @@ -20,6 +20,10 @@ export const tutorial: SimpleTranslationEntries = { "pokerus": `A daily random 3 selectable starters have a purple border. $If you see a starter you own with one of these,\ntry adding it to your party. Be sure to check its summary!`, + "statChange": `Stat changes persist across battles as long as your Pokémon aren't recalled. + $Your Pokémon are recalled before a trainer battle and before entering a new biome. + $You can also view the stat changes for the Pokémon on the field by holding shift.`, + "selectItem": `After every battle, you are given a choice of 3 random items.\nYou may only pick one. $These range from consumables, to Pokémon held items, to passive permanent items. $Most non-consumable item effects will stack in various ways. diff --git a/src/locales/fr/tutorial.ts b/src/locales/fr/tutorial.ts index c9f8a392e1e..55262b195ca 100644 --- a/src/locales/fr/tutorial.ts +++ b/src/locales/fr/tutorial.ts @@ -25,6 +25,10 @@ export const tutorial: SimpleTranslationEntries = { $violet. Si un starter que vous possédez l’a, essayez de $ l’ajouter à votre équipe. Vérifiez bien son résumé !`, + "statChange": `Stat changes persist across battles as long as your Pokémon aren't recalled. + $Your Pokémon are recalled before a trainer battle and before entering a new biome. + $You can also view the stat changes for the Pokémon on the field by holding shift.`, + "selectItem": `Après chaque combat, vous avez le choix entre 3 objets\ntirés au sort. Vous ne pouvez en prendre qu’un. $Cela peut être des objets consommables, des objets à\nfaire tenir, ou des objets passifs aux effets permanents. $La plupart des effets des objets non-consommables se cumuleront de diverses manières. diff --git a/src/locales/it/tutorial.ts b/src/locales/it/tutorial.ts index 2722c02ad45..f37afcae92d 100644 --- a/src/locales/it/tutorial.ts +++ b/src/locales/it/tutorial.ts @@ -20,6 +20,10 @@ export const tutorial: SimpleTranslationEntries = { "pokerus": `A daily random 3 selectable starters have a purple border. $If you see a starter you own with one of these,\ntry adding it to your party. Be sure to check its summary!`, + "statChange": `Stat changes persist across battles as long as your Pokémon aren't recalled. + $Your Pokémon are recalled before a trainer battle and before entering a new biome. + $You can also view the stat changes for the Pokémon on the field by holding shift.`, + "selectItem": `After every battle, you are given a choice of 3 random items.\nYou may only pick one. $These range from consumables, to Pokémon held items, to passive permanent items. $Most non-consumable item effects will stack in various ways. diff --git a/src/phases.ts b/src/phases.ts index 8eda33de20e..ceba555f2ce 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -2671,7 +2671,6 @@ export class StatChangePhase extends PokemonPhase { let random = false; - const allStats = Utils.getEnumValues(BattleStat); if (this.stats.length === 1 && this.stats[0] === BattleStat.RAND) { this.stats[0] = this.getRandomStat(); random = true; @@ -2712,8 +2711,11 @@ export class StatChangePhase extends PokemonPhase { for (let stat of filteredStats) pokemon.summonData.battleStats[stat] = Math.max(Math.min(pokemon.summonData.battleStats[stat] + levels.value, 6), -6); - applyPostStatChangeAbAttrs(PostStatChangeAbAttr, pokemon, filteredStats, this.levels, this.selfTarget) - this.end(); + applyPostStatChangeAbAttrs(PostStatChangeAbAttr, pokemon, filteredStats, this.levels, this.selfTarget); + + pokemon.updateInfo(); + + handleTutorial(this.scene, Tutorial.Stat_Change).then(() => super.end()); }; if (relLevels.filter(l => l).length && this.scene.moveAnimations) { @@ -3337,7 +3339,7 @@ export class TrainerVictoryPhase extends BattlePhase { const trainerType = this.scene.currentBattle.trainer.config.trainerType; if (vouchers.hasOwnProperty(TrainerType[trainerType])) { if (!this.scene.validateVoucher(vouchers[TrainerType[trainerType]]) && this.scene.currentBattle.trainer.config.isBoss) - this.scene.pushPhase(new ModifierRewardPhase(this.scene, modifierTypes.VOUCHER)); + this.scene.unshiftPhase(new ModifierRewardPhase(this.scene, [ modifierTypes.VOUCHER, modifierTypes.VOUCHER, modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PREMIUM ][vouchers[TrainerType[trainerType]].voucherType])); } this.scene.ui.showText(i18next.t('menu:trainerDefeated', { trainerName: this.scene.currentBattle.trainer.getName(TrainerSlot.NONE, true) }), null, () => { diff --git a/src/tutorial.ts b/src/tutorial.ts index 918c68b9bb4..88e88fa809c 100644 --- a/src/tutorial.ts +++ b/src/tutorial.ts @@ -9,6 +9,7 @@ export enum Tutorial { Menu = "MENU", Starter_Select = "STARTER_SELECT", Pokerus = "POKERUS", + Stat_Change = "STAT_CHANGE", Select_Item = "SELECT_ITEM", Egg_Gacha = "EGG_GACHA" } @@ -42,6 +43,11 @@ const tutorialHandlers = { scene.ui.showText(i18next.t("tutorial:pokerus"), null, () => scene.ui.showText('', null, () => resolve()), null, true); }); }, + [Tutorial.Stat_Change]: (scene: BattleScene) => { + return new Promise(resolve => { + scene.showFieldOverlay(1000).then(() => scene.ui.showText(i18next.t("tutorial:statChange"), null, () => scene.ui.showText('', null, () => scene.hideFieldOverlay(1000).then(() => resolve())), null, true)); + }); + }, [Tutorial.Select_Item]: (scene: BattleScene) => { return new Promise(resolve => { scene.ui.setModeWithoutClear(Mode.MESSAGE).then(() => { diff --git a/src/ui/battle-info.ts b/src/ui/battle-info.ts index ae794a256fa..3c2b541c618 100644 --- a/src/ui/battle-info.ts +++ b/src/ui/battle-info.ts @@ -7,6 +7,9 @@ import { StatusEffect } from '../data/status-effect'; import BattleScene from '../battle-scene'; import { Type, getTypeRgb } from '../data/type'; import { getVariantTint } from '#app/data/variant'; +import { BattleStat } from '#app/data/battle-stat'; + +const battleStatOrder = [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.ACC, BattleStat.EVA, BattleStat.SPD ]; export default class BattleInfo extends Phaser.GameObjects.Container { private player: boolean; @@ -24,6 +27,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { private lastLevelExp: integer; private lastLevel: integer; private lastLevelCapped: boolean; + private lastBattleStats: string; private box: Phaser.GameObjects.Sprite; private nameText: Phaser.GameObjects.Text; @@ -46,6 +50,11 @@ export default class BattleInfo extends Phaser.GameObjects.Container { public expMaskRect: Phaser.GameObjects.Graphics; + private statsContainer: Phaser.GameObjects.Container; + private statsBox: Phaser.GameObjects.Sprite; + private statValuesContainer: Phaser.GameObjects.Container; + private statNumbers: Phaser.GameObjects.Sprite[]; + constructor(scene: Phaser.Scene, x: number, y: number, player: boolean) { super(scene, x, y); this.player = player; @@ -138,18 +147,6 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.levelNumbersContainer = this.scene.add.container(9.5, (this.scene as BattleScene).uiTheme ? 0 : -0.5); this.levelContainer.add(this.levelNumbersContainer); - this.type1Icon = this.scene.add.sprite(player ? -139 : -15, player ? -17 : -15.5, `pbinfo_${player ? 'player' : 'enemy'}_type1`); - this.type1Icon.setOrigin(0, 0); - this.add(this.type1Icon); - - this.type2Icon = this.scene.add.sprite(player ? -139 : -15, player ? -1 : -2.5, `pbinfo_${player ? 'player' : 'enemy'}_type2`); - this.type2Icon.setOrigin(0, 0); - this.add(this.type2Icon); - - this.type3Icon = this.scene.add.sprite(player ? -154 : 0, player ? -17 : -15.5, `pbinfo_${player ? 'player' : 'enemy'}_type`); - this.type3Icon.setOrigin(0, 0); - this.add(this.type3Icon); - if (this.player) { this.hpNumbersContainer = this.scene.add.container(-15, 10); this.add(this.hpNumbersContainer); @@ -171,6 +168,46 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.expBar = expBar; this.expMaskRect = expMaskRect; } + + this.statsContainer = this.scene.add.container(0, 0); + this.statsContainer.setAlpha(0); + this.add(this.statsContainer); + + this.statsBox = this.scene.add.sprite(0, 0, `${this.getTextureName()}_stats`); + this.statsBox.setOrigin(1, 0.5); + this.statsContainer.add(this.statsBox); + + const statLabels: Phaser.GameObjects.Sprite[] = []; + this.statNumbers = []; + + this.statValuesContainer = this.scene.add.container(0, 0); + this.statsContainer.add(this.statValuesContainer); + + battleStatOrder.map((s, i) => { + const statX = i > 1 ? this.statNumbers[i - 2].x + this.statNumbers[i - 2].width + 4 : -this.statsBox.width + 8; + const statY = -this.statsBox.height / 2 + 4 + (i < battleStatOrder.length - 1 ? (i % 2 ? 10 : 0) : 5); + const statLabel = this.scene.add.sprite(statX, statY, 'pbinfo_stat', BattleStat[s]); + statLabel.setOrigin(0, 0); + statLabels.push(statLabel); + this.statValuesContainer.add(statLabel); + + const statNumber = this.scene.add.sprite(statX + statLabel.width, statY, 'pbinfo_stat_numbers', '3'); + statNumber.setOrigin(0, 0); + this.statNumbers.push(statNumber); + this.statValuesContainer.add(statNumber); + }); + + this.type1Icon = this.scene.add.sprite(player ? -139 : -15, player ? -17 : -15.5, `pbinfo_${player ? 'player' : 'enemy'}_type1`); + this.type1Icon.setOrigin(0, 0); + this.add(this.type1Icon); + + this.type2Icon = this.scene.add.sprite(player ? -139 : -15, player ? -1 : -2.5, `pbinfo_${player ? 'player' : 'enemy'}_type2`); + this.type2Icon.setOrigin(0, 0); + this.add(this.type2Icon); + + this.type3Icon = this.scene.add.sprite(player ? -154 : 0, player ? -17 : -15.5, `pbinfo_${player ? 'player' : 'enemy'}_type`); + this.type3Icon.setOrigin(0, 0); + this.add(this.type3Icon); } initInfo(pokemon: Pokemon) { @@ -258,7 +295,14 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.expMaskRect.x = (pokemon.levelExp / getLevelTotalExp(pokemon.level, pokemon.species.growthRate)) * 510; this.lastExp = pokemon.exp; this.lastLevelExp = pokemon.levelExp; + + this.statValuesContainer.setPosition(8, 7) } + + const battleStats = battleStatOrder.map(() => 0); + + this.lastBattleStats = battleStats.join(''); + this.updateBattleStats(battleStats); } getTextureName(): string { @@ -272,6 +316,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.mini = mini; this.box.setTexture(this.getTextureName()); + this.statsBox.setTexture(`${this.getTextureName()}_stats`); if (this.player) this.y -= 12 * (mini ? 1 : -1); @@ -284,21 +329,34 @@ export default class BattleInfo extends Phaser.GameObjects.Container { el.y += -8 * (mini ? 1 : -1); }); + this.statValuesContainer.x += 2 * (mini ? 1 : -1); + this.statValuesContainer.y += -7 * (mini ? 1 : -1); + const toggledElements = [ this.hpNumbersContainer, this.expBar ]; toggledElements.forEach(el => el.setVisible(!mini)); } + toggleStats(visible: boolean): void { + this.scene.tweens.add({ + targets: this.statsContainer, + duration: Utils.fixedInt(125), + ease: 'Sine.easeInOut', + alpha: visible ? 1 : 0 + }); + } + updateBossSegments(pokemon: EnemyPokemon): void { const boss = !!pokemon.bossSegments; if (boss !== this.boss) { this.boss = boss; - [ this.nameText, this.genderText, this.teraIcon, this.splicedIcon, this.shinyIcon, this.ownedIcon, this.statusIndicator, this.levelContainer ].map(e => e.x += 48 * (boss ? -1 : 1)); + [ this.nameText, this.genderText, this.teraIcon, this.splicedIcon, this.shinyIcon, this.ownedIcon, this.statusIndicator, this.levelContainer, this.statValuesContainer ].map(e => e.x += 48 * (boss ? -1 : 1)); this.hpBar.x += 38 * (boss ? -1 : 1); this.hpBar.y += 2 * (this.boss ? -1 : 1); this.hpBar.setTexture(`overlay_hp${boss ? '_boss' : ''}`); this.box.setTexture(this.getTextureName()); + this.statsBox.setTexture(`${this.getTextureName()}_stats`); } this.bossSegments = boss ? pokemon.bossSegments : 0; @@ -317,6 +375,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { const divider = this.scene.add.rectangle(0, 0, 1, this.hpBar.height - (uiTheme ? 0 : 1), pokemon.bossSegmentIndex >= s ? 0xFFFFFF : 0x404040) divider.setOrigin(0.5, 0); this.add(divider); + this.moveBelow(divider as Phaser.GameObjects.GameObject, this.statsContainer); divider.setPositionRelative(this.hpBar, dividerX, uiTheme ? 0 : 1); this.hpBarSegmentDividers.push(divider); @@ -439,6 +498,11 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.lastLevel = pokemon.level; } + const battleStats = pokemon.summonData.battleStats.join(''); + + if (this.lastBattleStats !== battleStats) + this.updateBattleStats(pokemon.summonData.battleStats); + this.shinyIcon.setVisible(pokemon.isShiny()); resolve(); @@ -513,7 +577,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { }); } - setLevel(level: integer) { + setLevel(level: integer): void { const isCapped = level >= (this.scene as BattleScene).getMaxExpLevel(); this.levelNumbersContainer.removeAll(true); const levelStr = level.toString(); @@ -522,7 +586,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.levelContainer.setX((this.player ? -41 : -50) - 8 * Math.max(levelStr.length - 3, 0)); } - setHpNumbers(hp: integer, maxHp: integer) { + setHpNumbers(hp: integer, maxHp: integer): void { if (!this.player || !this.scene) return; this.hpNumbersContainer.removeAll(true); @@ -535,6 +599,12 @@ export default class BattleInfo extends Phaser.GameObjects.Container { for (let i = hpStr.length - 1; i >= 0; i--) this.hpNumbersContainer.add(this.scene.add.image(offset++ * -8, 0, 'numbers', hpStr[i])); } + + updateBattleStats(battleStats: integer[]): void { + battleStatOrder.map((s, i) => { + this.statNumbers[i].setFrame(battleStats[s].toString()); + }); + } } export class PlayerBattleInfo extends BattleInfo { From 8a54e862fc0d165f1f6ca8967ca6f5940d624f01 Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Tue, 30 Apr 2024 22:14:24 -0400 Subject: [PATCH 02/72] Revert "Add togglable stat change display" This reverts commit 718585062bf3d5bf5067003da9a6b70bfb407940. --- index.css | 4 - index.html | 3 - public/images/pbinfo_stat_numbers.json | 293 ------------------ .../ui/legacy/pbinfo_enemy_boss_stats.png | Bin 435 -> 0 bytes .../ui/legacy/pbinfo_enemy_mini_stats.png | Bin 666 -> 0 bytes .../ui/legacy/pbinfo_player_mini_stats.png | Bin 674 -> 0 bytes .../images/ui/legacy/pbinfo_player_stats.png | Bin 285 -> 0 bytes public/images/ui/legacy/pbinfo_stat.json | 188 ----------- public/images/ui/legacy/pbinfo_stat.png | Bin 263 -> 0 bytes .../images/ui/legacy/pbinfo_stat_numbers.json | 293 ------------------ .../images/ui/legacy/pbinfo_stat_numbers.png | Bin 392 -> 0 bytes public/images/ui/pbinfo_enemy_boss.png | Bin 526 -> 554 bytes public/images/ui/pbinfo_enemy_boss_stats.png | Bin 257 -> 0 bytes public/images/ui/pbinfo_enemy_mini.png | Bin 851 -> 888 bytes public/images/ui/pbinfo_enemy_mini_stats.png | Bin 642 -> 0 bytes public/images/ui/pbinfo_enemy_type.png | Bin 3599 -> 1502 bytes public/images/ui/pbinfo_enemy_type1.png | Bin 3305 -> 1360 bytes public/images/ui/pbinfo_enemy_type2.png | Bin 3197 -> 1340 bytes public/images/ui/pbinfo_player.png | Bin 619 -> 654 bytes public/images/ui/pbinfo_player_mini.png | Bin 860 -> 898 bytes public/images/ui/pbinfo_player_mini_stats.png | Bin 648 -> 0 bytes public/images/ui/pbinfo_player_stats.png | Bin 312 -> 0 bytes public/images/ui/pbinfo_player_type1.png | Bin 3197 -> 1340 bytes public/images/ui/pbinfo_player_type2.png | Bin 3305 -> 1360 bytes public/images/ui/pbinfo_stat.json | 188 ----------- public/images/ui/pbinfo_stat.png | Bin 278 -> 0 bytes public/images/ui/pbinfo_stat_numbers.json | 293 ------------------ public/images/ui/pbinfo_stat_numbers.png | Bin 430 -> 0 bytes src/battle-scene.ts | 72 ++--- src/data/splash-messages.ts | 3 +- src/field/pokemon.ts | 4 - src/loading-scene.ts | 6 - src/locales/de/tutorial.ts | 4 - src/locales/en/tutorial.ts | 4 - src/locales/es/tutorial.ts | 4 - src/locales/fr/tutorial.ts | 4 - src/locales/it/tutorial.ts | 4 - src/phases.ts | 10 +- src/tutorial.ts | 6 - src/ui/battle-info.ts | 100 +----- 40 files changed, 43 insertions(+), 1440 deletions(-) delete mode 100644 public/images/pbinfo_stat_numbers.json delete mode 100644 public/images/ui/legacy/pbinfo_enemy_boss_stats.png delete mode 100644 public/images/ui/legacy/pbinfo_enemy_mini_stats.png delete mode 100644 public/images/ui/legacy/pbinfo_player_mini_stats.png delete mode 100644 public/images/ui/legacy/pbinfo_player_stats.png delete mode 100644 public/images/ui/legacy/pbinfo_stat.json delete mode 100644 public/images/ui/legacy/pbinfo_stat.png delete mode 100644 public/images/ui/legacy/pbinfo_stat_numbers.json delete mode 100644 public/images/ui/legacy/pbinfo_stat_numbers.png delete mode 100644 public/images/ui/pbinfo_enemy_boss_stats.png delete mode 100644 public/images/ui/pbinfo_enemy_mini_stats.png delete mode 100644 public/images/ui/pbinfo_player_mini_stats.png delete mode 100644 public/images/ui/pbinfo_player_stats.png delete mode 100644 public/images/ui/pbinfo_stat.json delete mode 100644 public/images/ui/pbinfo_stat.png delete mode 100644 public/images/ui/pbinfo_stat_numbers.json delete mode 100644 public/images/ui/pbinfo_stat_numbers.png diff --git a/index.css b/index.css index dd47387adee..9a507ad6766 100644 --- a/index.css +++ b/index.css @@ -150,10 +150,6 @@ body { display: none; } -#touchControls:not([data-ui-mode='COMMAND']):not([data-ui-mode='FIGHT']):not([data-ui-mode='BALL']):not([data-ui-mode='TARGET_SELECT']) #apad #apadStats { - display: none; -} - #apad .apadRectBtnContainer + .apadSqBtnContainer { top: calc(var(--controls-size) * -1.9); left: calc(var(--controls-size) * -0.9); diff --git a/index.html b/index.html index 506fa4f1efa..bd316330a99 100644 --- a/index.html +++ b/index.html @@ -74,9 +74,6 @@
V
-
- Shift -
Menu
diff --git a/public/images/pbinfo_stat_numbers.json b/public/images/pbinfo_stat_numbers.json deleted file mode 100644 index 32170690aa0..00000000000 --- a/public/images/pbinfo_stat_numbers.json +++ /dev/null @@ -1,293 +0,0 @@ -{ - "textures": [ - { - "image": "pbinfo_stat_numbers.png", - "format": "RGBA8888", - "size": { - "w": 117, - "h": 8 - }, - "scale": 1, - "frames": [ - { - "filename": "+1", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "+2", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 9, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "+3", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 18, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "+4", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 27, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "+5", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 36, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "+6", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 45, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "-1", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 54, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "-2", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 63, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "-3", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 72, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "-4", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 81, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "-5", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 90, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "-6", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 99, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "0", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 108, - "y": 0, - "w": 9, - "h": 8 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:794aa4af3291db5abd8a2667626c1998:1a6706ad557b92f9bf099c23e02af4a6:6537c634087637bb27e8a1edb1ee2e35$" - } -} diff --git a/public/images/ui/legacy/pbinfo_enemy_boss_stats.png b/public/images/ui/legacy/pbinfo_enemy_boss_stats.png deleted file mode 100644 index 94c9f2a181736d88c6752f2c97ed0bbbee23ebcc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 435 zcmeAS@N?(olHy`uVBq!ia0vp^n}ArJgAGVJb4-r_QjEnx?oJHr&dIz4vU5FM978JR zyuG8?cgR7a?csXf_7^8kc|Ex$m-yBz<$7q-n^RU*Eb9Vy3q^L$xwlCBgn&~-ln2-0 zC$%D(Zao#Zd6NElh+n&%^Pj+>91Q?jM7YZ*~R6rK6tBHXtJ>3o}%+B70Tit?}|9LLp3388Oyx(ny$dZ`X4n6UD>PshjO%e?;W3et7Lx@QEIV2LHO-ZhLc6eY9Ry zIQ|Mdb1{9R)SaoXcSRIE<`z6H%nuWjbE9V$ zXGWbr(B0xb=lC1f6GDcM4fWFUoyzXm2QNAn5;^S^|FUJBo0|`=UT>R$XHs^CNV z##av>ty$f?T7lzV!;W1Rn!7wYzpJ*28OBxY>HqxBa!BncE&SaXRbV6dDO(__3L?7E8i*EoZkKZ{HwqsHRc+nk205eyDOS2sxDu$ zd@tM{5g62QzVkTGE`^WE*Hfq8w-A>Rt4KTHq5izn`AE{j-lt}1uFk6Sl=!q)x&3rH zmfHGREPZQC>e=c~;%vpYyt-a*X%jpw^vJ`ZrANz4IZ?ukeBYJTaNN^-KBA z)J%%Y&U~o6pj>*#j=aoIas@k?dF)+-(V{Q3XI{exr|Grpv%NI5;(qK@ xp0+UKM9$<@NoVioZhp6Q^O64&v*v`HV4ZIk%FUH_dOOew44$rjF6*2UngE&&E5rZ* diff --git a/public/images/ui/legacy/pbinfo_player_mini_stats.png b/public/images/ui/legacy/pbinfo_player_mini_stats.png deleted file mode 100644 index dd2b7e65ba3522986e78d6844a6be8823c3382ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 674 zcmV;T0$u%yP)EX>4Tx04R}tkv&MmKpe$iQ%gl!9Lyl%kfA!+MMWJ;6^me@v=v%)FuC*#nzSS- zE{=k0!NHHks)LKOt`4q(Aou~|>f)s6A|?JWDYS_3;J6>}?mh0_0Ya# zo%24i$jY)xd`>)J&;^MfxvseU#<}FMz%xZ7o1P~YiKS8xD?QB0hDJP198oo$@`aqs zD(5ZETD8GC_v9}O74(%1*J+L-fh8o7qK*_aP(c+IqO|Iym`Kxp+`~WO_*3Lk$W;L& z#{z25AUl5WKlt6PS)7`5lR|MI@M7B^V?b~hXg6*9``EVICxHJMxYE1+S__!_B)!?y zB1gdBHgIv>)s#Kpat9cGs>_D#NPe0^u?W1M(KqFRp<7^J&F!tTkJASrOIK2l+uOfqI{p0s^F(smE#4Fv0000mP)t-s0001cl!Q`iV>wbnAvplXy>s5y zwg3O#*3P|BYg+%cd;kCcN$J_5c5S*Us$?%8vTKwfg`6|6Wc}-=`Gc19G2( z)VthFjRI1_B|(0{3_xi#U}t|v7bsoq>Eaj?(fam=p-_VZhjU<>!iIbQ4@G5d*>KA2 zr+S66yVASV%+m`tUAT0h%_Vu-2F6#OE9N=hF1aYEASTnz@k_ZzU>c{|jD#j+;!l_T zYhIRn;@{452VTh2;XbSE{bIVBSPWaCe#7lsobz5x%h_{T;XlZgp00i_>zopr0I}G2 ADF6Tf diff --git a/public/images/ui/legacy/pbinfo_stat.json b/public/images/ui/legacy/pbinfo_stat.json deleted file mode 100644 index b7da47fc192..00000000000 --- a/public/images/ui/legacy/pbinfo_stat.json +++ /dev/null @@ -1,188 +0,0 @@ -{ - "textures": [ - { - "image": "pbinfo_stat.png", - "format": "RGBA8888", - "size": { - "w": 112, - "h": 6 - }, - "scale": 1, - "frames": [ - { - "filename": "SPATK", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 19, - "h": 8 - }, - "spriteSourceSize": { - "x": 1, - "y": 2, - "w": 18, - "h": 6 - }, - "frame": { - "x": 0, - "y": 0, - "w": 18, - "h": 6 - } - }, - { - "filename": "SPDEF", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 19, - "h": 8 - }, - "spriteSourceSize": { - "x": 1, - "y": 2, - "w": 18, - "h": 6 - }, - "frame": { - "x": 18, - "y": 0, - "w": 18, - "h": 6 - } - }, - { - "filename": "CRIT", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 17, - "h": 8 - }, - "spriteSourceSize": { - "x": 1, - "y": 2, - "w": 16, - "h": 6 - }, - "frame": { - "x": 36, - "y": 0, - "w": 16, - "h": 6 - } - }, - { - "filename": "ACC", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 13, - "h": 8 - }, - "spriteSourceSize": { - "x": 1, - "y": 2, - "w": 12, - "h": 6 - }, - "frame": { - "x": 52, - "y": 0, - "w": 12, - "h": 6 - } - }, - { - "filename": "ATK", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 13, - "h": 8 - }, - "spriteSourceSize": { - "x": 1, - "y": 2, - "w": 12, - "h": 6 - }, - "frame": { - "x": 64, - "y": 0, - "w": 12, - "h": 6 - } - }, - { - "filename": "DEF", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 13, - "h": 8 - }, - "spriteSourceSize": { - "x": 1, - "y": 2, - "w": 12, - "h": 6 - }, - "frame": { - "x": 76, - "y": 0, - "w": 12, - "h": 6 - } - }, - { - "filename": "EVA", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 13, - "h": 8 - }, - "spriteSourceSize": { - "x": 1, - "y": 2, - "w": 12, - "h": 6 - }, - "frame": { - "x": 88, - "y": 0, - "w": 12, - "h": 6 - } - }, - { - "filename": "SPD", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 13, - "h": 8 - }, - "spriteSourceSize": { - "x": 1, - "y": 2, - "w": 12, - "h": 6 - }, - "frame": { - "x": 100, - "y": 0, - "w": 12, - "h": 6 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:40d30205ce8efd40dfa86cd11b0491d6:7076db6ed74199dcfb38fc8cd4d4a0e8:05882267d3999884e0491134e98b1b53$" - } -} diff --git a/public/images/ui/legacy/pbinfo_stat.png b/public/images/ui/legacy/pbinfo_stat.png deleted file mode 100644 index 62ec3758772daea6013a4de5532575a66caf8116..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 263 zcmeAS@N?(olHy`uVBq!ia0vp^1whQk!3-pITwg5(Qk(%kA+A8$!NK9)wXI7Q-Kzj{ z7)yfuf*Bm1-ADteDDa3ZW?Ec4QuN(io6fN32b;e=)XJ@8wjxa57 z6;5`pyz#?~2;;a-r4XYn{3?!Y<6HKbItN$2xk}gw>0y zUzy)p<5e-!w)Vy<(87aih3;8-LtI=7KLTHk<}Jk-^i|&t;uc GLK6T7%VuW) diff --git a/public/images/ui/legacy/pbinfo_stat_numbers.json b/public/images/ui/legacy/pbinfo_stat_numbers.json deleted file mode 100644 index 9c74ee86dbc..00000000000 --- a/public/images/ui/legacy/pbinfo_stat_numbers.json +++ /dev/null @@ -1,293 +0,0 @@ -{ - "textures": [ - { - "image": "pbinfo_stat_numbers.png", - "format": "RGBA8888", - "size": { - "w": 117, - "h": 8 - }, - "scale": 1, - "frames": [ - { - "filename": "+1", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "+2", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 9, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "+3", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 18, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "+4", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 27, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "+5", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 36, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "+6", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 45, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "-1", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 54, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "-2", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 63, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "-3", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 72, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "-4", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 81, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "-5", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 90, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "-6", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 99, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "0", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 108, - "y": 0, - "w": 9, - "h": 8 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:1f22b7cb085faf9e9764273fa5e70c28:afc5587ebacca78d178ac7e0c434591b:6537c634087637bb27e8a1edb1ee2e35$" - } -} diff --git a/public/images/ui/legacy/pbinfo_stat_numbers.png b/public/images/ui/legacy/pbinfo_stat_numbers.png deleted file mode 100644 index ee1453b21070f8de40a299a2d0c82c49093799cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 392 zcmV;30eAk1P)NeVolC?^B79yfh4NP^lrY9U!*DY-V@3rV{hYdQ>YK;=1YJaz3T;`<^$DGJL<5 z0VRW87@CHmA>NuYKzH1TLC5xSzn%dVgI*Y#hCzM2e@<+(--30)Oref_gmu$R&9E*Q zKCPUg&65~>rQzm$c=)wGxON}pkE{!ZPit-h_?q;dhMV)@;n(^|U!-Qgl_%A@VDM** z28vT)T`)O@Pln{f8%r6yr(x9i(DP6xH!0n5bN5`F;gccxJgbFgqhZwe(DRg7RCba7 mA?H5)Du%PaS?j+(7uOe-FYwO$9P0Z30000aGx7IS8(W?BZR#K+fR> zdKYIGa4pEV(m;21BcvdOLb@oX#w6N||Hk-!EB%ba5WYMoi2;a+$P89q(Q(?bWqnK1js?_P5*2T3V0acimCcp71_vhnu(jb5jIunqv- zU|m?J^YT3J;D0uwQBe98btaL0--i&Q%orEbYPFKro2Hw%bs$(LP1z0Bn7Fmy_dE4% zMRfpBN}Xl?_f7}_DJACfdG6;*DGY~0t+A6v4#Sx>8X@+5UvHKdwn^skG{U|W(s&x7 z*QuwrAFS-cx>Cy61NqkdXW#0iF_3fBLidQcv~I9QcYG^xiwstFvMunJ#6@+wo@071 z6=j=LzJ;IG-9*kySisI*Q}3$_A-J?SlT8{I?O!P+!f>JWs8i-krl0glDKjDTt88$>!uSb_l5uf002ovPDHLk FV1lYA{=)zO delta 487 zcmVIk&UmVKT0GxPa8d!07jZZ!ddIBQBbh_PFZe&65JuT|9nKq=MA`2Ra01f-NW z91f+QE2Xg6Y_!guHF6k+mXtE_eP3^s9ZQpWyFcUJ3~9SRW4V~*j$cQ1WnC#{?2Y{H zp1HO|plBRLh_0>&dpk(u@=|B3Ul!cn-d9Bu|Irn<2(MATii<NL1q8595j002ovPDHLkV1ifd@6!MP diff --git a/public/images/ui/pbinfo_enemy_boss_stats.png b/public/images/ui/pbinfo_enemy_boss_stats.png deleted file mode 100644 index 7148a7af4759141abb5e2b39c02a17b45af905e5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 257 zcmeAS@N?(olHy`uVBq!ia0vp^n}ArJgAGVJb4-r_QjEnx?oJHr&dIz4a&~*VIEGZr zd3$>`-ysJ9)(e`BNfSH%{_kJqko58BL=U^z3cqSH|eR)57 zW1&p?=O4X~e>-L8TFuvct=1%`yX>BUe4QwNkl)q|N~u!nI~O4Yq?Ab0 z)cUDa4A$g)|GB+zjjyH$DNlu{Sp;D;RZA6(J^uv|5`cGRUYNim(gR9s1U zPC0iQQ-etbpCZ(@E->2xpqYObLeyev0QOIDQc7gm-04MCwVfaNvS^f20{C4#?Hk+n z_uXHMMb~Ko*z*>1x7*b&2cv4u=Wc00L_|bHM0D5>)LE${MNRhx00000NkvXXu0mjf DZ|lLNkl8GRYx|2)P*70tlomTy+AL)kaKVi zE&#J{fxIOH3ldw!o(@eA9|jTwfke-5G6qF2@~g-B0uhl?&o>!GQQmYRa=R?cyz5!T z`|(5+MftElx~(F4j)*+88Q$()i?q{0_b3h8Z?jzmZ4pWY0rr0qL21w(A*rB55THl| zr9t=9O$8-_0MJt!bXT2JP$CGRMv#IUK>#&^6m9ha8#1%t_N<261?l{K=~*1pAjk_btXV2r7AjK;-r zyc-`ce5q`T&+mUP){_|k&bdbFdlX{~)>_gu^?vW1V>+D%9edXZS(f#zwRw^xVO733 z=iJLT_%&7jLr5Bc=c*yJqh3v!6wCSI$(1zcmbE+B8p>2?Q-u1?3(9$bLGjrb(}}GC z&Tny{X#k#=SKD&ZXsreQPoB<=eZOzJOKWr2MgYCV+*TmByu~acA|fIpa@iluDW|ek SO(V4c0000EX>4Tx04R}tkv&MmP!xqvQ>7vm5sQd8WT;LSL`4J_sbUc+7C6sqP{?%e(K->QQng1AHR!9McVpc!PL) z)6zNb6Ngw)Qi#uq#|*k4@gvt|m)|%S92R(H$VeyWi9^IW<^6Ko+1t_sz&)j z#$|=`7H73wWzBo?7Y1|MN{Z{Wh7rRO;z&S*j4Dbf!$O31jT93}I*)qzha7)`Tr#;z zVB}ap1u7)R5B>+gXKUssC)}i96zF`h?T-;4unRP5w*7r<+l>>z{|sDdEq|pB%zTnw zYiZ#lpm!U%xNd3k9&ot>3_j_SAvuztmXOZ_?`QN)S)l(G=w5T@);!1Q1CXX!E#CkK zhrnoove!M{-PJy~e|wtq`vH(aagbUB zzo-t5uI_cI;7<`vL}@r@>=fw7Q_>^>xEhuomQto)FNAjEI4-`=cWfUYlv1Ys?$EX( z{-b279fr-f*TOp8O^+I^-|2j;`a~!KNp6au2K}h1f+CP)E`l2L=hG@E0!flV4f^#- z6%>Ia27#GDAc;X>X8YJF+efPS#oQskn5pI%x-*WUY4S8Vs<2+QHAobJnOn>qX}QG= c008jX1y1rsg=?D3Y5)KL07*qoM6N<$f~t=qVE_OC diff --git a/public/images/ui/pbinfo_enemy_type.png b/public/images/ui/pbinfo_enemy_type.png index 9bac63e5e72ba305c0c7769d72bc39d72aa8202e..021a120070c1872b54405196e4bcb2cec9920d06 100644 GIT binary patch literal 1502 zcmXw3e>l^59RD&u=ccklkrpRr5<fnh6k_S2{W7L7M z-u$_fs5z|3JThfIZhj>vf2A;Ol~}!6vHB@x@25&&4P&{!zP?c%v(a_#GdV;0!csb% zA(cw)w?mv{dgKx@KK_97)X;g^K{d`JFaZG6pgT(rpiuV%fC9_Y1sM=E+Hi-6({=yG zxoCXs&Z*1^4UcG#nDE;8NB&feT+%pQDt-9g(#mvpj&!dCxj4~1iTcj#WUk(Yh+O{m zxmHG){;FeW(-VZ1x9ZY?^zZ;D@MFk&A_&BKeql53NRSK2!S_KE=XJ9PmmDj*ZIYx~ zTg9pyr*I9=_cN%IW))RtSLGltUlzv+_dpo1cVx9E_YL;E)(~hH+7v8>_uNQ7A?d3n z*^lR<-JJn9yxt;uln$25#AKM%>8vasJgBHuQ+Vg-@<^UVWu7?2V6u&>38Tba{J}$S zV(f(tS-AhEz1Ga$$KYO!W|{d#Nf^fyNsDe77C;Id)&1~GVO*Hi@$iS&N!kgxts2$B zoJg@T<&}T%q;UIkzxjl4ihwuOxg8^Qdc*I%T7TpsOW(<1mzVUoj29K0r1|{pdgna4 z&8kKv9m6CE%W?Vx;(Wv35O8L*OA^$tu8BJYzo)r85@ExX)EQwyx&s$$jDFNM?6E_dii|3k`+mD)0Rjpr!9)ox>gN7O_05b$7 zh-Cmw;T1baQQ6?w$OJ8Uauw2!Me)&j+nD%Fv4R-V8kMt5p#B zRX0wvKmR%XS;e0{gV-bjt2gvFYW~diB zxSs22nK2yIv0XE_6Y1Uh@j;mitpMW~gtb^0y+bJzYJoU}Jg2zmLC;7ujHm0vjKSPE zg<^<;G5AV}M~dZzHrN@Cby}FF@n8VN@W!-aYc_h{(yu;zS6zWXk)NFb+gdy6jJ+Mo z-RyzY@62$Nspw+%(#I`y5qTW8TLpF~I=ekdrM>;Ixen@t3;az~zkui1`J#0Hqb`?D zqMfOe)lOehL2>?PC)Fab1F?7AR^2eNqTNouQZ82b*?Ul1^-N=cO^x6f)MUrqYFX&n zViWJ!OIQOzgMFmuD7_PG3~z9tE{XiFK3mpPg~H9eH^R83^8Kv3ui9VkXvf%E_uRtr zVO;!3?U5RE+iSNHR2%4!Bmqi)drkKzt5!(KDPMU8!`o}EcntfsWNDGD3<`*Q6At0BKS`47C$X9aYeb!_U0x*TY~<5hSE8n8iUmue1aT_L@j9XO;i@vXJOa= zM!DY1da9gR_TgAx-U6pN%Y0^L29=$c?$kOmqRmkk&xRY|vZGU#hT1`nxk{fTg@1Z+ znzkPF5qP7j)Q?j2LVj7U0RES|Vh$hWlH9jho!K42`>;mfZ)as?!3|Ci&Ckvg-UnVo resupsym6>#pP=$lydvQr&2;62s?XefC_i8JmjRxxJ}&H2p_%^y$!^{i literal 3599 zcmYjUXH-+&5)GmPN(~@L6(hYVRZtK@fY1p|Fa!aq(n~J zrM#d}fhNFA7YryL;9I2zb?ZSiEgoer230FO(9`2T^WB)!5cn`ZHQjXbz5ir-r_<;(Oerg4nw)R^B3;hY4TQikq*ONS6xpfD+&3Pk z+0%Bbs}fsRF@7Wus12I*m^J-|yb(WLgoF1Z44EadiG0>8^izP=PV!MkQg zpVeI=kYM42I}3Uc76-FBF%ft3p5&7FtYdX;fPUCPE7-@swCjpO8hZ_gl0tIEM?(Wo z2a=rxnI0!Ay83wEi16ek7#>dnaE%mu^=zmAt?tMx9C~c$gtk}U>0h~+=m&m{=<*BN z#=?SvwmI%KCCI;}rX@YX0YBC42w6;QbqqcI8PYxU)F;0&vM336i&q#scJL#yJCGk- za)8f3CH3|VH`pP685?x`bGrj?VXDAwwdOR;8|Zr)?9W$q8u47wV=E0av;c{QufD5! zTI5Up4wpb}($poFHKJpz{fYleX6U@az4bc}%KU=eT4LP;nXxh?n5ftr$;0VkV)1NH zY*oaoJvkk8`3i$J)`-6$n_fku()%7%{9u6^04_+zOVW=U@zR+Chp~lEG9b=#_=EB4 z+~RdPYHLu{{xi~UYabM69So94pf8Y{!kSk#Vl!j33vq9CoFUn$cz@Gq9??S@t#!AD8oU4(Po=k$*ff~$`>O_zE?kfdwtIyp&U`bLa{a*)3jHtbZ6^)46u5O zRsyRQRpO;L3{c6Am3(=jtM%b3dUS<8Jn^>+tSvc~!{)y^^5oDG|BS8&ORrY3DhddI zO&qB=4Gf*JIdZ*GvH$x6i0zj)V$egNBkaq2N_Hk6K*QK5L5O23CSY_{8eK7 z;MnAde$*_QFj>xBlSiuE&>Bv^#Fk-}bjXD_-@JR_eb|=|CEX4@LxEIQp(2szw_aEz zDUj%%aH~OGxP0A5`DSaaJ@3ZNi0DMaDcwS3NteJx>t<0I{_JNtp;n%3QhyG{YL-qG zW`DvJaw+hj2{wZzjQo3y-?rd2ZVH)fe9p3o z`OYP%F;*F7Q@pXv-;aqtJF)ju<(SYj@a>_psLv>!esoNgG=qZOV{|5 zTHW{eu7%&o!d-7Fsci3lWr~JYEOFch3E<;OvVqi)f4QN@B zC`Yk3D$dT4BA~0l6d*>de~t%ZOAEkT2fTZT90$!6#*;W>BL(rU6Xp__A`h@uj#B?!L)ablmHlNKo@F!E~5Y9|X) zd!?)t{F=(iW0hdi5@_3+T}V5u96x?|Y3kuDVre;;a44=j_p?2g7AwwPj<6!l4u&gF zBNR(HU)i=kl`Pwo*57P`fyXRHd$Cz{Dw>yxFM4K?;1Xd4<=a73h)~u9Q>SG#DD6C! zmcTJOlHBMsow$YkCM|}}@bgiCU{f{m*NzFd!BEl{UOOq{qE2QwX5H}I?WPf)B&xLV|+ZQ!2XZw&Z&{DcOOyud2b)m4aWPWFKec*&H1;==#su2{_U9QjFvuqiW9#HsudcousTkb9cscJZTWiRBQaDhJC(- z>Li0`%w;w}+;P_L06rqt*XYCxoH=M5?rK^g-WCs98eUmX8Doqo_9%=aMaZ1GJ#-~l z^{Z*h(Npu7qRuePzihvXbW35ruqnFhs-FL$ZFWkGUkQQ|VSC1s#K=oz(R&auna%>v z`hQDF{zv5=jfE?zxxNj0*FfSE~#9gBB6hPLBT)$p%IVcOne!tKm&B)nDw%djpElLQrB8?~V#!2Zj8 z6fNNW^Ly=83s18r(WUPuO_A0TB#vwzK?O(*cZ-P&?(KOfBZSHT?S@WT|NeSiQN8%u zBE8Q>N$>;NziyM~sqR#^GeaRarR#jtSaswNFb8vpeJI+azH}8CKSH#EppW=+% zZu?I^8iPqN9QjOjG!Ji4o)10w@Y&e6Rkn&6sJ10#=eQAt&VUQcjSs9kmX$l?17a{6Hlf$!;-uWQ7_^EZzIR z--iZD$7!vNNB=qM9&Eyn{2N8Zq}g+)a*szY?==mrE}wBAVp6{xb@(3{6&^MXsS&>% zU1hf$B}Ry^FNe18=XuMRvSS*HW{Nm0kS658mn?Aft5N-QVnEApSzwe#L79aA_l(B< z$Ke!O(@?I;xwJ>8z0P`7IHAw62HoUq^{FV-Llbd>F*)q4EBRSgsFl}$tvat@V5K+e z(xL?CK)QgTT;?OdVrH=PZS$j!qw(DFn|rCpwTmRGZ~LV;b`-rC`bwjVsc{gX#j_x> z=jSHua#^8q;|uoO3xX+mYpDhI!VH+lH2Kbi$>axG3V^*t zX#jX~idguzfbC6eJyLP^Y*<~n>GhybPbWiIN^=vhh{`62Mj>9r9!cqHIkTo!bS^~w zaEKeUg}|L9b$fH-FL^}{P9DC(EPUL08LV(uO;B?y?`5K+cbTW+C&A-FwKsXZZNFdz zvAQz};_EluM-91}ZtXy62Ge3hLplb+J}07CwHc@6^^(7z29}M8NxR6fgs{t`F9^0X zXeE(SV!GoK;roK6x|8rVOt-T?ULCa%fweLZBshW_&&HA#) z*Ui>=uHluui{JW{fz8OhuAuPssP*{x`1OmehQj}QNPD25(tm@cTBF6g$d!hg;qd?5 zfl8r4*2tQaP>WJ=&CRZdVwt_}I7)L+d!ND9&0W3jRVlN`nw8h|;Lwoy%VhSd0F|iV z`K@jCc@WLAO7w=1sg$n0l(JYVN?hu22&L|x<$1xtHZ=fSB1)Trhy?v zoa3n3UrWrX;+*zippZEd6gn4+-m@z3Iz>?lBFaT&Gu~8G0(^~DNvbr&_PnBMxTl-6$7${0tvjq z8{UgbXK9_@DJo}*X;tK!C{;z0C&Nb2)Kns?;ACA*RXRszdZlWyMp0|ce(E9^i1>AC z)eNo5V6|GEI+X!`PEO^sgG}kXI%pvNf*4421%Km)KMzoI_Lmwn%y ztZ7sgQD}&wGNY#Crd6|N)KMlzb*y>R?0tz_zUsE$4+f_HsePl~CU|R9Qp9sA9r6>Z6O;EJ|jp?<^(Di!Uj&>*>2owya16-_YeAtY+jotiG{xT@Mxr{f#Y5=N~xdrxA@ zC8xb!FpvrJo>8YP=~h%yVuDc(Eb1X7I+dGsE$URqltB7vY+xP}HF}G#aR?K~-*Opgn&3-PS zot~cu122I~e$K7RlCDL)Bqwe~Re!Of9zvof{Xo^#sIjGUuWIvFtu_1KF#ukJgG*qU zVWNCbRn^UGyYWh2JDoHq~D#xXTM7g2Zlu?)I9;4Qp{qFAW*Dv79x39p@pRwMW z=p7aOM$e~DNnI0u67$Ey!$VTnYdk%D!Pg)EAi+j>Pl;#J?YIZf>@=DnB0#4gWz*>~@TwpZ$Le*Q*bmNc=P)Px>qe(QJbv@}9BwInvjmRN~AA~$EW}N5&-bgs~suPG)r}LnHc~)Q}Q^r-oHsn?E(O=*P9Y4|J<z$QrZ&QnTawD4a0DK^lFFJ_{HuHso4{+>;+A~ zJDd>G0639lV(LcR&iJEOJDkNZ6IloW;OC^HYe{msJ)&;p$*YCG@CX1PHhB>7nLhJe zbEDUJE(1U?Fm0LvfWPnvf`Mr*b(UcmuI5Jh$=KvUZCQK78gD6~C$H8d8Hna{KSb`y ztJRXi>-DDkhtfZy#xK2`8o%_irJU-sl#b?Me5Q{Z496l$kxurSC1fe3gyLYZ@l(|y zafUSFZ1>_beFz4o5e!UQ%30BfD`UtKiG(68t7VeQ!Qw(?qb+6IaAEkY zl#p$plB!M?kPhy^=%lm}+dU#@6)Y~~W`*rtuV&X?N5mYVj?#%(N@)ybgWMX-BT)oi}3z>{){QOOX8fVRm)dfbJ-IuAG ztQjjUA&?HPNJ$DuauJT?n$)61O56J~(Ns0ur8Tw~$|%`^A#*ZTQA!EPfHf6~Rix52 zc3oh^VkDC|IK9yl^*jtU&RQlmNt{kvLZY&dAcXZT6^7gpx`iHHq{FJ`+f5; zzdn;SHq+3QcmavB48w5c*C*s>r&_IL>$aOOr+ado$)b#33Z)U|!rQmIrb zb>qYh^R=jJ`>v&KoVa1Wc9hGv{&5Qckl3F zGG?F4Y`ln0ciuwCQYQP7aM!xIMl9W`M_0jJ>*g-PQd$V9vAfo78O@y6bKtIZTQ0&% zn#-{#W1LxHf5LJslm7$1`o5glpD?>eO7O>uX>>mp4u**4T`0cea|uq)WaG*4WgLezT;ksf7?o2Unz|F0x%EBeqPW)Mg4x zlHIRgP;rEIl(#!uF<0$3<0y)yRK}2PO!1@NDq}!#U#59U-IUEinKn+?tg)$^E1M1@ zyFZ5P{+M=zrG!Lji=#4Jl3Z?SzvS5D0nZ8mK&gKv^7HeZ?|rFENatg>rFG5kmt~X> zcvf&Gtl2m5p8x=D%^SI{YY9a&q9QXTp^Q>RClZR3%6aJ2Oi3tG?hIygCV;-HMCoX4 zqoTDXB+BmhzDB8krET|Qlv2XQm?;T~GGiw)T#{T41m2W3C@sAg4Gj-+W!>Fh;QaaT z007bGOV01hkw}Hb3;-G$9z-Nkp`^|-48s+TzGNY@Q)%hF2n61Ac3&p4#>PR*IVzLU zn}#w<(Li+pky86^BgRS>JC0DK?C$=;wjo=GrIf~yriIQ-RY#i3G%sacl*N%0jlQJ6 zFE=(0TDl*JRA{HwGRft-exDTtuYQ5{h)=SBJE8oS{f*M@PpZrIJu= z=!DKAhveJ*{MJX6Q!ki0BBeA_*f`M-E7@RK2t`VE%CJW4IaWlej3G5Qg^jNUYqQ3AlN!HaM=2TekEbI^<*Nu+d~%S6bA zLrJKkBom6E7!HwAN=TK-h(?w*6T425KlkN%ni~XFV^RM23C(j~fkWoRc0#5kBuYm} zGQ%awUy~2Xm35XR=KEDIMo>w6`7rF#XxP0HBPa<@@DGxEOf_WhgA# z#hGobe#bPNnHshjHHJpj-!IQh4P$bw%VI|7bdu(>I4|=G%8>u?bINYAl#cdbXQqa2 z$&`dd>8Q2La7l9c`L?&E4Se}|s4UuGDQ`V~4ghehWoKr&Tv@aMt;f&d@Q%k!6FZq} zY?1Qtj>jxiRCapoD@;t!5T*SZ+n1lGBxpT;P8tTz&@c?wv6h`?p{@Z@(nX(dd)xW< z%WT)^m@ZaXw1GQEvgEQDOLnB$IMOkRVyPrlO&J-vl2AseB9iG?%TD|E!`9>HaC+=3 zyJ~7eqIB#a8ZJpL=eFqo9l*%^6fF@`zRmjFmu(CyACSLR$;@RH<;YI{Sfre7%Xhwy zEt;vySedyz+s6MXyRLiex!jg%XZPiUrD{XnIc|+DQUbt{^XkSVmeTgFclw+350LJv zjt)@da&F5s*O(~TW4Z{d*|vN&AvHKy%2TP#l!Qd7Zlc%H8Ex5m1h6| zmp|{ox^MPjg|`u_Hm4U*HxJzn0N8Xw@jUkEj|=a3&Rdheb9slR4LjFH`JUf&ce|E_E z{}svpterdVy{%tx0+Rc(Z~J@b|C1k`eV5_ROCq^$J(@P$iDMs6B01y6+V5ki*K;roK6x|8rVOt-T?ULCa%fweLZBshW_&&HC;* zO0vk;&DMDOm4U9|mAs4J&B(p@`1tjx^{$}s^^2`iam|Lp|9@hcy`Z4dqs6<(m4=$( z@Ycwh|J;Giu7~bbDWAdC&0W2FNPBZod$Y)zgQZ%P*Yx1fkon7G_No9%p+S^Ti}|f> zm8jtMc@R>*?(~L`sg$n0l(@~ZN?llm^Z)<=0d!JMQvg8b*k%9#010qNS#tmY4#WTe z4#WYKD-Ig~0DlAzNkl(^Y-#Wr6(Oj4xVAPdRD7!nD#iAB*BzHNIOCF7+K!2!Mo?4Ma{y?`n4?k5THGfPb znjaf?PygBd=;)}=AC3b1KsV?cB*s@ciU)rw57cPk>(CnArfu-@+b7_eU=Lj1OnvNcwffW0-uP_mXO_l4S!y5_eP^JhH)c@!3IEp%o=Epqlf^Q zdl4vm%oVI6jAf-z5$|I$U2Dmtnyz&NU|gM1Tovo?z9%sl038k@0T?JGHsIL@QDnrd zDzX{HYQ?=uvO=g-#FB$Nsuv5}+iLfdlS^uKdBRa(`I~AmiC0_`**#%3i+m|xZDaqP znSbbOs;KIv6AN{%B`!mDz1^R4OyqbTAb6NW0}$>+AUJ_2A{5z+2=NU>5xD9kiW7b_ ziQ3*&JDtuMz*$E^ zq5Oy)WOl}~7tbVB4ihDjPFJx4ljiYZ^SDMTc5Eak+VETLetdjNB~Onz3M4|@U_y^2 zIZTv9KC>90ws`^*7o%$YR54G)Z&akbQ~r1nO{!**|rqpNJ<0!EF`8Alxn}7E5 z(}~lmd`(2y!z<9KqCiv?B4ap}nkwRT+RHPkNNQz9jwytB>h0bPVUU_P&kYuaaOFk$ z8LiIGod{VZ7{z9D<;CVoyik#-*^P(`O#DR2_Px>H%UZ6RCt`#oNr8&M;^z&TPxA+i*8TPNYg3{X%8gk%EC#-+bb@O&5TC>_Jn;4b^hL{-u z_%fPM5*RWP3WhRWWMGq}fodPoX>&Oxxtx)7g;RwWk*6e=8%g2ydM7$ViI=SY6E9En zpLp4_pX&3I=x7~AM>>p?VWg7@c`}(&rqdG2f#>6=tHTWCnWZ7}pGyKmCK)L>a7q3OG`H^)432akKy&*( zEXiM?HJzcNTav#5W!3Akd;2zg8yyrH#4emeS@n9vE}Rp}x_Srnxm;Flf56h!VTN+- zs1ZLrB9}#UfPyPDXlR|!!l4t(Wji`DCu0?zmXHj1Q<+#t>awFVDK$0Kc`nygjan8q$uvRJ zG?$0kJ;1z`K-yNZaIhZu?oV2?)YUP=I#e~3J5b1STpnuoOzjvy1N`7IvBmfqVC)Me zo&ELlO;8HCEYK~D=v&QODRf43fGL-IeR@L!rAtZ2iziid!qb@vRVMRR+E#ZN>39(- z*MUsujF8mpODt^DWMSIoa^y*ISe`dLh;5A7n)yEPsblDQV``F;9!(P7<#MCE-o$m@ z*sigOiyJOlu0AIwCMGU!xHvJkYm9xS7llblIR4jh06=VG4DpUQ03hBGXTzp)m4tI_ zId*(wlZo#GpE;NLcoChcoYxGQ?)s(caF@Gr{nB+@`{o(|uy-I(4EWW zhAjK@8kOpfjq3j%R&*XVzUyQ;$G#OhNB6NweJxE$D=0!=OOvsla37neODia1p9e#G zEkg~K=2_?f!#d2ZnYwc{7}{$;gh{dc*rwQ}6%+|Xym&ezA+Ow;O#-pb9GJXbR?)@J ze}@Nt;urSywKU=5*M6;~GZGGl_TEtJNYgZzPh?H~?VC}s5;JSI;%ZAhu7&jH*8s5S znCTpQQe-l-#{T>oP~PjrAyrtl=Q zI?d;W0--K;L~^yI9#=|zERH%lW~dV1nBqt8Dr1t%G_y2J-5QkXjD!H#FlW|m#jMT< zW_3o4Gt3B$H4M6QxxA(Mgto!MDTxbMzi%eq?YbhAHP$Y2_7|HsA@xMA+7rrj52wr! zOn9@C(QCrK#@a;~9v*fX31u^)lFfJt*UK`UsRQ1W=m5hyR1K9VZ3*pW)-+U}&PeEl zR!OL$qxjhkPo~on`h7EP&2*Zkxf}?*1px5-A4Fy4VxhdP?KAZBe62JKhhNaoa%*d$ z#S8!{D;J}+wNOiFIW7kRZ^7?>P}_hc*9nJT&>xqHtg33irHuBe=mkPPb}9p12Rt2M zb6l2VWs03ZDATpIeP-K`>hN^TP?m04@MgL?E?w*Z^$__u%5+*nzOg*~*49GfvYMv3 zT+x}Oteick0R87fTC-s3u^W5drg%Y(Z5`|Xq$IlRIRyZKhOACuzq}nRJ?89sSw%&i z7zs^uq&=rwl${WrVCaOd|9r?u#|&?Vj<$I^Bca^T2^}!`tcV?*+zE9c(`gBBbY^)? z(_DUi)%`bR_R`LOI6KD%fa1na*ylZ4eyXi!$>m$2Gv;z}<0p)2Va_jvGI?7`Xrl8K zziiwlI>FE>ft^?`^K?WI+4Gv#oc8l{T0+vPqaRv^CwFQgyd5*k?^CWrew~@toJ!L) zmzOGTEw^XQ$LeGH2POcZw=~b$ak+i+hGn~hThf;6WtmQ8q9W}rH9RYFD-v>96+0af zFQO9+?X>;$CHqR?a##M@w8pRw=Hz~=dsf=EM@=@9UMTUFD%rNCFC;E z5rryVw2u!3(FumPODvc9nKccI4~I;rCFF<2oAQ&QTRtwCj+btU&;?d27S2UMZHiDHYL4Rb{pXZsZ$``X>+r>J4l@fiM-gg{0ssnX zQ}ALqM@wk=p45hv-N-DQtEBmS|2amTSvXfHdox<5&t)Q04UP86p&$vlOtHIB5uIRo zyTqOq;px6VJC4*m4{|H-$MWilOLh#@tWmyO(stZACdk(8$a07->8aMzXy0{^# zziKf90C#N(JmFWhgqB>6q&$tJ!l~rviFo3q!W@Cr7u}`LWoi^}?qak=Mf+6rfc)Io zWb8=e`;Wq1TY^|%Gh%_waMzY7<41IYp`D134~I(Ze^N3XucX2p!~&az7}C&rIxQhp zCL@|z-b}Z2Tsk^_5=`sP`Ey^~5S@?-gvJ^M-ML(DZCH9!W>s~)_V>O5745=yIJg?i zO5ekw&gYf&E%&~7I@yd@a$3HH&Un47Gb5waN1ink@^m`0aB#KKi0A}EJB5R*0RTgv z{s92AF=WSOK6Y2)7x2RevIVncrSDUgMri~1C+mZ={j%q4&=W_YE#&-b#S*gh=%1yU4s^57~X|`j_ zT5}AGa??@2^B}gaTCO#bW%+Ie(QRF|902gxVlM#TFMo?->#F5=Y_S*rjQ<;>7r(dA zX>&O%HCangzw@9n3?w0!iO$r3$oWo*4zO8=d;7k?v7r%Rn>s7XO&7{Y?6^#HG%ON7 z)2iX}bVfqml2MWKa>;bEC}uLbiVkq__ppBFLG10beg#LTX`0LPw}?LvaCmLvJx?EM z0KjNts(lQL9#(&LL};QT=_p4VQ|<3#%VxTLyo6ll=}g0u%ZN@el(osPD>0X`dtY+w zNKHNZ#xfn?;HbCvWa0%RhH9b%CZESv(S0`t_!k0eeTmOMnlokA)B~J6Z>2L564fTZ zNY&IcRi@H3&E@yEWx!Xo4*+oL_%_TtxdAi0RY=N7oIqXPd>;Vd%HNZLuf42o_8HA@ z5$ylh)PuGQf1LOZJ(-b_Y(}!2V?RH6Cidav>D;N~iF3j6qt%J`t``$Vl3Df{&2JI( z{$~Vrlc&UFI{T>!W_I<f-$`F6iB@fY-i_heQ4=81$S~B@p%hSlYS3&d^~{oh#Pay zMNqb`7e?U zySrpMPkIcV^cXX%NxugG*mhvu699lKvw+~2L3J*B(x-ZgJtRJe((=U^0AR<*1I%>T jJ9$Usc+f(4+jIH9YsahgIi)MH00000NkvXXu0mjfPm>$C diff --git a/public/images/ui/pbinfo_player.png b/public/images/ui/pbinfo_player.png index fee08f71044ee488bd172bf9b02db706a9cf4082..9d3e03bd66d86cdf8ab3cfd59be4ef9d6410ccd5 100644 GIT binary patch delta 616 zcmV-u0+;>k1daueF@H!&L_t(|obBAdPTNo%hT%6=r7mDtOmVaZ|#D^=AwA$T>{|y z{`MMK0n4%gn9t{_=Z;1rTz8s03~k$XIW5~GzVAQ(BKK9E&tTg&t~=GuVw47V*Ecn{ zq+W@M;5bfWQX%fXAUY0k`1iGCS&iu$vV0E5aexf}HGd3;XC*YPKAz_Re{P;O?Z=(J z@3P-4P6>ipC$SJTFR}T;@LhT#Kr@~tNIX4Rlr7F3ih1JlvSD0}h;CUMrfz+?^FUrW92r7(fq+sU8C^NhOn2+~R33uoA15d^47ggK
u*i{Slh@`p?1>g%h%6Cw5J!=T0U*R1MnDJ6|U#*Z*JkoesN4y6h&V9 zS^IL#rHNpS$$z3KVzb$F)3Ol+L9lnip}Z&_gDU{iG###yJqW`PfbDi$yYFhX!dhEB z4IRgEH!YixG)-SW$f;^_3~?M|t<_*LPlNlL+mTx`uF6D6l4LfiP&6*cw*!3q`#KE6 z*>nv)$B`rn;PGFB@1WyQS!;op!Bg3K(f(8CKUlOl=YJNph0sZ>!pgJLse-2Lyi&dt}*K+!0R$E0vTWLUzE`_5mXrc zsQaRf);@*cL$jCTsXOrp#Tb)a{=Cd~yPcLDF5CP8>N7zOZ`s!|s^Ay5~jkO`|t=mu+hfnI_k z=inM#0M>Zx5s;aZNL^66l`fsq0gNCG1sw9X?>Cu1(1-l#*$DxNh%_t9$+kU+E$jPQ zwNL@#_zq#X{59{lreA2=gSdO&%~lna!$zEJhMTf#p=vQ&8km0u^%t$9gC&BAKmZI9 zfoaej`>DW0AOII80@I**bSf|r2*3r2z%*#CXdQ8nKpSiX0>DO~Ej9uH;N|1Lr!OCk z|9z~BkFR$CK&RD99q;S3dWF_jB}TWHN28}aYPmWoB_8}&0Km$brjE76Y>xK$v+x@8 zG8_(1e#Z0OcDH|+jT6CjT?ipePcMYyIJb;z7>41Gsv{dh>cWt0R&T-FUZ9s?$T_$M z7l7HfK;Dvp1&OUH5K*IY>CJ^)^|N88NNC4pVs+=4}QGTmJ(3~vGe$D%9 z=$A!Nln?u(Y8Bx=BIU(qc)3?Ccq~Cn18LBHo9*gki69XmDIk9lNQ3S;P6ZMHlCDey z(x7{MDv$_}bVVYN2HmyUuGk}Bhem)T8UcGW0wi(y`1JhcWAML^ZL!&|BuT^msC0bn znVUT57V~&KuA`Qlv)1Y@{gNcD<5}t0Th136Ouiehu`ZX)k+t@4i#a$Ek|dEaCiL`1 z#BqEW7bo8HP4R#J`Jwe>CP{M6HBw()j4`s-DoxYU_nmW^PNyfwu5N@Z%X-$@JV}zU zDj%G4?%^B!KbQQ5<1~;eTs0Iss;zudEa!_mSJIraxeHnvd@8glLd*6A{^x002ovPDHLkV1g-F&x8N~ diff --git a/public/images/ui/pbinfo_player_mini_stats.png b/public/images/ui/pbinfo_player_mini_stats.png deleted file mode 100644 index 7ce3bd1af1e541826337cedf9f284a5d14d9661d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 648 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 diff --git a/public/images/ui/pbinfo_player_type2.png b/public/images/ui/pbinfo_player_type2.png index 6d94871e8da1dfd56a0271a6a8ef1ae8e9d6c3c4..89b84d7f6305169db2e227aa33a9e2202cdeebfa 100644 GIT binary patch delta 1352 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 Wt8RFN+!3I289ZJ6T-G@yGywokWokPB diff --git a/public/images/ui/pbinfo_stat_numbers.json b/public/images/ui/pbinfo_stat_numbers.json deleted file mode 100644 index ec4f7117bb7..00000000000 --- a/public/images/ui/pbinfo_stat_numbers.json +++ /dev/null @@ -1,293 +0,0 @@ -{ - "textures": [ - { - "image": "pbinfo_stat_numbers.png", - "format": "RGBA8888", - "size": { - "w": 117, - "h": 8 - }, - "scale": 1, - "frames": [ - { - "filename": "1", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "2", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 9, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "3", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 18, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "4", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 27, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "5", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 36, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "6", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 45, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "-1", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 54, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "-2", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 63, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "-3", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 72, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "-4", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 81, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "-5", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 90, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "-6", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 99, - "y": 0, - "w": 9, - "h": 8 - } - }, - { - "filename": "0", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 9, - "h": 8 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 9, - "h": 8 - }, - "frame": { - "x": 108, - "y": 0, - "w": 9, - "h": 8 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:b0719fae0d9b670a727148cdc7202249:afc5587ebacca78d178ac7e0c434591b:4825a9f02f72f1fe28a724c6c5dffb37$" - } -} diff --git a/public/images/ui/pbinfo_stat_numbers.png b/public/images/ui/pbinfo_stat_numbers.png deleted file mode 100644 index c778ba992734421a718b2c49db1db0ae77a28e09..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 430 zcmV;f0a5;mP)X}UpFSFJe%YMSjb zvz=}Te=dw_+OM;>zwNiTz<(WGW!%j?&)@0VTARh5OWbc`j(J{Tok%Zt#$YoH;sBj7 z0D#IlJRc6p%*|?r>-8D{#_^;+F^22I1yqy`_PebZNKrNbfWEEq_WF{{oLyYu^!yS4 z#PO(4jM4P@WGYS8UqlLVGYqiSvW&F&OBuS>FtHC$Vz?0ZyX|CN5<3@SjG<>5X2}?8 zQ)v+?7z&xQg%~oUa!zD?QzeEgj_Hh<7_VVM6DZ`EEo4UD)*|DZy2Lt;DavMIyoRBA zxP2Ty%KN9gENZI8IE_78Q^T$GD~(@jhsGYQsdI~*V!X;!+J?fg{Gd2S+NQZaWGcsm zi<{b~a&9zLI&@IbQb7LyuD?x7eaKXf@hzMCJ+VH0TaTtDpMHPh p)) - p.toggleStats(pressed); - if (pressed) - this.setLastProcessedMovementTime(Button.STATS); - } else - return; - } + } else + return; if (inputSuccess && this.enableVibration && typeof navigator.vibrate !== 'undefined') navigator.vibrate(vibrationLength || 10); } @@ -1454,7 +1443,7 @@ export default class BattleScene extends SceneBase { * or not. It will only return true once, until the key is released and pressed down * again. */ - gamepadButtonJustDown(button: Phaser.Input.Gamepad.Button): boolean { + gamepadButtonJustDown(button: Phaser.Input.Gamepad.Button) : boolean { if (!button || !this.gamepadSupport) return false; @@ -1474,23 +1463,6 @@ export default class BattleScene extends SceneBase { return this.buttonKeys[button].some(k => Phaser.Input.Keyboard.JustDown(k)) || this.gamepadButtonJustDown(gamepad?.buttons[this.gamepadKeyConfig[button]]); } - /** - * gamepadButtonJustUp returns true if @param button has just been released - * or not. It will only return true once, until the key is released and pressed down - * again. - */ - gamepadButtonJustUp(button: Phaser.Input.Gamepad.Button): boolean { - if (!button || !this.gamepadSupport) - return false; - - return !this.gamepadButtonStates[button.index]; - } - - buttonJustReleased(button: Button): boolean { - const gamepad = this.input.gamepad?.gamepads[0]; - return this.buttonKeys[button].some(k => Phaser.Input.Keyboard.JustUp(k)) || this.gamepadButtonJustUp(gamepad?.buttons[this.gamepadKeyConfig[button]]); - } - /** * repeatInputDurationJustPassed returns true if @param button has been held down long * enough to fire a repeated input. A button must claim the movementButtonLock before diff --git a/src/data/splash-messages.ts b/src/data/splash-messages.ts index 198ff07cec9..11629cf05d7 100644 --- a/src/data/splash-messages.ts +++ b/src/data/splash-messages.ts @@ -33,5 +33,6 @@ splashMessages.push(...[ 'Also Try Emerald Rogue!', 'Also Try Radical Red!', 'Eevee Expo!', - 'YNOproject!' + 'YNOproject!', + 'Shh, don\'t tell Sam!' ]); \ No newline at end of file diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 7072875d3ce..9a7bfb48621 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -1179,10 +1179,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return this.battleInfo.updateInfo(this, instant); } - toggleStats(visible: boolean): void { - this.battleInfo.toggleStats(visible); - } - addExp(exp: integer) { const maxExpLevel = this.scene.getMaxExpLevel(); const initialExp = this.exp; diff --git a/src/loading-scene.ts b/src/loading-scene.ts index 875d618ec0f..2f37b900ab5 100644 --- a/src/loading-scene.ts +++ b/src/loading-scene.ts @@ -39,21 +39,15 @@ export class LoadingScene extends SceneBase { } this.loadAtlas('namebox', 'ui'); this.loadImage('pbinfo_player', 'ui'); - this.loadImage('pbinfo_player_stats', 'ui'); this.loadImage('pbinfo_player_mini', 'ui'); - this.loadImage('pbinfo_player_mini_stats', 'ui'); this.loadAtlas('pbinfo_player_type', 'ui'); this.loadAtlas('pbinfo_player_type1', 'ui'); this.loadAtlas('pbinfo_player_type2', 'ui'); this.loadImage('pbinfo_enemy_mini', 'ui'); - this.loadImage('pbinfo_enemy_mini_stats', 'ui'); this.loadImage('pbinfo_enemy_boss', 'ui'); - this.loadImage('pbinfo_enemy_boss_stats', 'ui'); this.loadAtlas('pbinfo_enemy_type', 'ui'); this.loadAtlas('pbinfo_enemy_type1', 'ui'); this.loadAtlas('pbinfo_enemy_type2', 'ui'); - this.loadAtlas('pbinfo_stat', 'ui'); - this.loadAtlas('pbinfo_stat_numbers', 'ui'); this.loadImage('overlay_lv', 'ui'); this.loadAtlas('numbers', 'ui'); this.loadAtlas('numbers_red', 'ui'); diff --git a/src/locales/de/tutorial.ts b/src/locales/de/tutorial.ts index f37afcae92d..2722c02ad45 100644 --- a/src/locales/de/tutorial.ts +++ b/src/locales/de/tutorial.ts @@ -20,10 +20,6 @@ export const tutorial: SimpleTranslationEntries = { "pokerus": `A daily random 3 selectable starters have a purple border. $If you see a starter you own with one of these,\ntry adding it to your party. Be sure to check its summary!`, - "statChange": `Stat changes persist across battles as long as your Pokémon aren't recalled. - $Your Pokémon are recalled before a trainer battle and before entering a new biome. - $You can also view the stat changes for the Pokémon on the field by holding shift.`, - "selectItem": `After every battle, you are given a choice of 3 random items.\nYou may only pick one. $These range from consumables, to Pokémon held items, to passive permanent items. $Most non-consumable item effects will stack in various ways. diff --git a/src/locales/en/tutorial.ts b/src/locales/en/tutorial.ts index f37afcae92d..2722c02ad45 100644 --- a/src/locales/en/tutorial.ts +++ b/src/locales/en/tutorial.ts @@ -20,10 +20,6 @@ export const tutorial: SimpleTranslationEntries = { "pokerus": `A daily random 3 selectable starters have a purple border. $If you see a starter you own with one of these,\ntry adding it to your party. Be sure to check its summary!`, - "statChange": `Stat changes persist across battles as long as your Pokémon aren't recalled. - $Your Pokémon are recalled before a trainer battle and before entering a new biome. - $You can also view the stat changes for the Pokémon on the field by holding shift.`, - "selectItem": `After every battle, you are given a choice of 3 random items.\nYou may only pick one. $These range from consumables, to Pokémon held items, to passive permanent items. $Most non-consumable item effects will stack in various ways. diff --git a/src/locales/es/tutorial.ts b/src/locales/es/tutorial.ts index f37afcae92d..2722c02ad45 100644 --- a/src/locales/es/tutorial.ts +++ b/src/locales/es/tutorial.ts @@ -20,10 +20,6 @@ export const tutorial: SimpleTranslationEntries = { "pokerus": `A daily random 3 selectable starters have a purple border. $If you see a starter you own with one of these,\ntry adding it to your party. Be sure to check its summary!`, - "statChange": `Stat changes persist across battles as long as your Pokémon aren't recalled. - $Your Pokémon are recalled before a trainer battle and before entering a new biome. - $You can also view the stat changes for the Pokémon on the field by holding shift.`, - "selectItem": `After every battle, you are given a choice of 3 random items.\nYou may only pick one. $These range from consumables, to Pokémon held items, to passive permanent items. $Most non-consumable item effects will stack in various ways. diff --git a/src/locales/fr/tutorial.ts b/src/locales/fr/tutorial.ts index 55262b195ca..c9f8a392e1e 100644 --- a/src/locales/fr/tutorial.ts +++ b/src/locales/fr/tutorial.ts @@ -25,10 +25,6 @@ export const tutorial: SimpleTranslationEntries = { $violet. Si un starter que vous possédez l’a, essayez de $ l’ajouter à votre équipe. Vérifiez bien son résumé !`, - "statChange": `Stat changes persist across battles as long as your Pokémon aren't recalled. - $Your Pokémon are recalled before a trainer battle and before entering a new biome. - $You can also view the stat changes for the Pokémon on the field by holding shift.`, - "selectItem": `Après chaque combat, vous avez le choix entre 3 objets\ntirés au sort. Vous ne pouvez en prendre qu’un. $Cela peut être des objets consommables, des objets à\nfaire tenir, ou des objets passifs aux effets permanents. $La plupart des effets des objets non-consommables se cumuleront de diverses manières. diff --git a/src/locales/it/tutorial.ts b/src/locales/it/tutorial.ts index f37afcae92d..2722c02ad45 100644 --- a/src/locales/it/tutorial.ts +++ b/src/locales/it/tutorial.ts @@ -20,10 +20,6 @@ export const tutorial: SimpleTranslationEntries = { "pokerus": `A daily random 3 selectable starters have a purple border. $If you see a starter you own with one of these,\ntry adding it to your party. Be sure to check its summary!`, - "statChange": `Stat changes persist across battles as long as your Pokémon aren't recalled. - $Your Pokémon are recalled before a trainer battle and before entering a new biome. - $You can also view the stat changes for the Pokémon on the field by holding shift.`, - "selectItem": `After every battle, you are given a choice of 3 random items.\nYou may only pick one. $These range from consumables, to Pokémon held items, to passive permanent items. $Most non-consumable item effects will stack in various ways. diff --git a/src/phases.ts b/src/phases.ts index ceba555f2ce..8eda33de20e 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -2671,6 +2671,7 @@ export class StatChangePhase extends PokemonPhase { let random = false; + const allStats = Utils.getEnumValues(BattleStat); if (this.stats.length === 1 && this.stats[0] === BattleStat.RAND) { this.stats[0] = this.getRandomStat(); random = true; @@ -2711,11 +2712,8 @@ export class StatChangePhase extends PokemonPhase { for (let stat of filteredStats) pokemon.summonData.battleStats[stat] = Math.max(Math.min(pokemon.summonData.battleStats[stat] + levels.value, 6), -6); - applyPostStatChangeAbAttrs(PostStatChangeAbAttr, pokemon, filteredStats, this.levels, this.selfTarget); - - pokemon.updateInfo(); - - handleTutorial(this.scene, Tutorial.Stat_Change).then(() => super.end()); + applyPostStatChangeAbAttrs(PostStatChangeAbAttr, pokemon, filteredStats, this.levels, this.selfTarget) + this.end(); }; if (relLevels.filter(l => l).length && this.scene.moveAnimations) { @@ -3339,7 +3337,7 @@ export class TrainerVictoryPhase extends BattlePhase { const trainerType = this.scene.currentBattle.trainer.config.trainerType; if (vouchers.hasOwnProperty(TrainerType[trainerType])) { if (!this.scene.validateVoucher(vouchers[TrainerType[trainerType]]) && this.scene.currentBattle.trainer.config.isBoss) - this.scene.unshiftPhase(new ModifierRewardPhase(this.scene, [ modifierTypes.VOUCHER, modifierTypes.VOUCHER, modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PREMIUM ][vouchers[TrainerType[trainerType]].voucherType])); + this.scene.pushPhase(new ModifierRewardPhase(this.scene, modifierTypes.VOUCHER)); } this.scene.ui.showText(i18next.t('menu:trainerDefeated', { trainerName: this.scene.currentBattle.trainer.getName(TrainerSlot.NONE, true) }), null, () => { diff --git a/src/tutorial.ts b/src/tutorial.ts index 88e88fa809c..918c68b9bb4 100644 --- a/src/tutorial.ts +++ b/src/tutorial.ts @@ -9,7 +9,6 @@ export enum Tutorial { Menu = "MENU", Starter_Select = "STARTER_SELECT", Pokerus = "POKERUS", - Stat_Change = "STAT_CHANGE", Select_Item = "SELECT_ITEM", Egg_Gacha = "EGG_GACHA" } @@ -43,11 +42,6 @@ const tutorialHandlers = { scene.ui.showText(i18next.t("tutorial:pokerus"), null, () => scene.ui.showText('', null, () => resolve()), null, true); }); }, - [Tutorial.Stat_Change]: (scene: BattleScene) => { - return new Promise(resolve => { - scene.showFieldOverlay(1000).then(() => scene.ui.showText(i18next.t("tutorial:statChange"), null, () => scene.ui.showText('', null, () => scene.hideFieldOverlay(1000).then(() => resolve())), null, true)); - }); - }, [Tutorial.Select_Item]: (scene: BattleScene) => { return new Promise(resolve => { scene.ui.setModeWithoutClear(Mode.MESSAGE).then(() => { diff --git a/src/ui/battle-info.ts b/src/ui/battle-info.ts index 3c2b541c618..ae794a256fa 100644 --- a/src/ui/battle-info.ts +++ b/src/ui/battle-info.ts @@ -7,9 +7,6 @@ import { StatusEffect } from '../data/status-effect'; import BattleScene from '../battle-scene'; import { Type, getTypeRgb } from '../data/type'; import { getVariantTint } from '#app/data/variant'; -import { BattleStat } from '#app/data/battle-stat'; - -const battleStatOrder = [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.ACC, BattleStat.EVA, BattleStat.SPD ]; export default class BattleInfo extends Phaser.GameObjects.Container { private player: boolean; @@ -27,7 +24,6 @@ export default class BattleInfo extends Phaser.GameObjects.Container { private lastLevelExp: integer; private lastLevel: integer; private lastLevelCapped: boolean; - private lastBattleStats: string; private box: Phaser.GameObjects.Sprite; private nameText: Phaser.GameObjects.Text; @@ -50,11 +46,6 @@ export default class BattleInfo extends Phaser.GameObjects.Container { public expMaskRect: Phaser.GameObjects.Graphics; - private statsContainer: Phaser.GameObjects.Container; - private statsBox: Phaser.GameObjects.Sprite; - private statValuesContainer: Phaser.GameObjects.Container; - private statNumbers: Phaser.GameObjects.Sprite[]; - constructor(scene: Phaser.Scene, x: number, y: number, player: boolean) { super(scene, x, y); this.player = player; @@ -147,6 +138,18 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.levelNumbersContainer = this.scene.add.container(9.5, (this.scene as BattleScene).uiTheme ? 0 : -0.5); this.levelContainer.add(this.levelNumbersContainer); + this.type1Icon = this.scene.add.sprite(player ? -139 : -15, player ? -17 : -15.5, `pbinfo_${player ? 'player' : 'enemy'}_type1`); + this.type1Icon.setOrigin(0, 0); + this.add(this.type1Icon); + + this.type2Icon = this.scene.add.sprite(player ? -139 : -15, player ? -1 : -2.5, `pbinfo_${player ? 'player' : 'enemy'}_type2`); + this.type2Icon.setOrigin(0, 0); + this.add(this.type2Icon); + + this.type3Icon = this.scene.add.sprite(player ? -154 : 0, player ? -17 : -15.5, `pbinfo_${player ? 'player' : 'enemy'}_type`); + this.type3Icon.setOrigin(0, 0); + this.add(this.type3Icon); + if (this.player) { this.hpNumbersContainer = this.scene.add.container(-15, 10); this.add(this.hpNumbersContainer); @@ -168,46 +171,6 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.expBar = expBar; this.expMaskRect = expMaskRect; } - - this.statsContainer = this.scene.add.container(0, 0); - this.statsContainer.setAlpha(0); - this.add(this.statsContainer); - - this.statsBox = this.scene.add.sprite(0, 0, `${this.getTextureName()}_stats`); - this.statsBox.setOrigin(1, 0.5); - this.statsContainer.add(this.statsBox); - - const statLabels: Phaser.GameObjects.Sprite[] = []; - this.statNumbers = []; - - this.statValuesContainer = this.scene.add.container(0, 0); - this.statsContainer.add(this.statValuesContainer); - - battleStatOrder.map((s, i) => { - const statX = i > 1 ? this.statNumbers[i - 2].x + this.statNumbers[i - 2].width + 4 : -this.statsBox.width + 8; - const statY = -this.statsBox.height / 2 + 4 + (i < battleStatOrder.length - 1 ? (i % 2 ? 10 : 0) : 5); - const statLabel = this.scene.add.sprite(statX, statY, 'pbinfo_stat', BattleStat[s]); - statLabel.setOrigin(0, 0); - statLabels.push(statLabel); - this.statValuesContainer.add(statLabel); - - const statNumber = this.scene.add.sprite(statX + statLabel.width, statY, 'pbinfo_stat_numbers', '3'); - statNumber.setOrigin(0, 0); - this.statNumbers.push(statNumber); - this.statValuesContainer.add(statNumber); - }); - - this.type1Icon = this.scene.add.sprite(player ? -139 : -15, player ? -17 : -15.5, `pbinfo_${player ? 'player' : 'enemy'}_type1`); - this.type1Icon.setOrigin(0, 0); - this.add(this.type1Icon); - - this.type2Icon = this.scene.add.sprite(player ? -139 : -15, player ? -1 : -2.5, `pbinfo_${player ? 'player' : 'enemy'}_type2`); - this.type2Icon.setOrigin(0, 0); - this.add(this.type2Icon); - - this.type3Icon = this.scene.add.sprite(player ? -154 : 0, player ? -17 : -15.5, `pbinfo_${player ? 'player' : 'enemy'}_type`); - this.type3Icon.setOrigin(0, 0); - this.add(this.type3Icon); } initInfo(pokemon: Pokemon) { @@ -295,14 +258,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.expMaskRect.x = (pokemon.levelExp / getLevelTotalExp(pokemon.level, pokemon.species.growthRate)) * 510; this.lastExp = pokemon.exp; this.lastLevelExp = pokemon.levelExp; - - this.statValuesContainer.setPosition(8, 7) } - - const battleStats = battleStatOrder.map(() => 0); - - this.lastBattleStats = battleStats.join(''); - this.updateBattleStats(battleStats); } getTextureName(): string { @@ -316,7 +272,6 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.mini = mini; this.box.setTexture(this.getTextureName()); - this.statsBox.setTexture(`${this.getTextureName()}_stats`); if (this.player) this.y -= 12 * (mini ? 1 : -1); @@ -329,34 +284,21 @@ export default class BattleInfo extends Phaser.GameObjects.Container { el.y += -8 * (mini ? 1 : -1); }); - this.statValuesContainer.x += 2 * (mini ? 1 : -1); - this.statValuesContainer.y += -7 * (mini ? 1 : -1); - const toggledElements = [ this.hpNumbersContainer, this.expBar ]; toggledElements.forEach(el => el.setVisible(!mini)); } - toggleStats(visible: boolean): void { - this.scene.tweens.add({ - targets: this.statsContainer, - duration: Utils.fixedInt(125), - ease: 'Sine.easeInOut', - alpha: visible ? 1 : 0 - }); - } - updateBossSegments(pokemon: EnemyPokemon): void { const boss = !!pokemon.bossSegments; if (boss !== this.boss) { this.boss = boss; - [ this.nameText, this.genderText, this.teraIcon, this.splicedIcon, this.shinyIcon, this.ownedIcon, this.statusIndicator, this.levelContainer, this.statValuesContainer ].map(e => e.x += 48 * (boss ? -1 : 1)); + [ this.nameText, this.genderText, this.teraIcon, this.splicedIcon, this.shinyIcon, this.ownedIcon, this.statusIndicator, this.levelContainer ].map(e => e.x += 48 * (boss ? -1 : 1)); this.hpBar.x += 38 * (boss ? -1 : 1); this.hpBar.y += 2 * (this.boss ? -1 : 1); this.hpBar.setTexture(`overlay_hp${boss ? '_boss' : ''}`); this.box.setTexture(this.getTextureName()); - this.statsBox.setTexture(`${this.getTextureName()}_stats`); } this.bossSegments = boss ? pokemon.bossSegments : 0; @@ -375,7 +317,6 @@ export default class BattleInfo extends Phaser.GameObjects.Container { const divider = this.scene.add.rectangle(0, 0, 1, this.hpBar.height - (uiTheme ? 0 : 1), pokemon.bossSegmentIndex >= s ? 0xFFFFFF : 0x404040) divider.setOrigin(0.5, 0); this.add(divider); - this.moveBelow(divider as Phaser.GameObjects.GameObject, this.statsContainer); divider.setPositionRelative(this.hpBar, dividerX, uiTheme ? 0 : 1); this.hpBarSegmentDividers.push(divider); @@ -498,11 +439,6 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.lastLevel = pokemon.level; } - const battleStats = pokemon.summonData.battleStats.join(''); - - if (this.lastBattleStats !== battleStats) - this.updateBattleStats(pokemon.summonData.battleStats); - this.shinyIcon.setVisible(pokemon.isShiny()); resolve(); @@ -577,7 +513,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { }); } - setLevel(level: integer): void { + setLevel(level: integer) { const isCapped = level >= (this.scene as BattleScene).getMaxExpLevel(); this.levelNumbersContainer.removeAll(true); const levelStr = level.toString(); @@ -586,7 +522,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.levelContainer.setX((this.player ? -41 : -50) - 8 * Math.max(levelStr.length - 3, 0)); } - setHpNumbers(hp: integer, maxHp: integer): void { + setHpNumbers(hp: integer, maxHp: integer) { if (!this.player || !this.scene) return; this.hpNumbersContainer.removeAll(true); @@ -599,12 +535,6 @@ export default class BattleInfo extends Phaser.GameObjects.Container { for (let i = hpStr.length - 1; i >= 0; i--) this.hpNumbersContainer.add(this.scene.add.image(offset++ * -8, 0, 'numbers', hpStr[i])); } - - updateBattleStats(battleStats: integer[]): void { - battleStatOrder.map((s, i) => { - this.statNumbers[i].setFrame(battleStats[s].toString()); - }); - } } export class PlayerBattleInfo extends BattleInfo { From 6fd5709b13adfc71f6bf7b402df82af3f983477a Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Tue, 30 Apr 2024 23:02:16 -0400 Subject: [PATCH 03/72] Reapply stat change feature with fixes --- index.css | 4 + index.html | 3 + public/images/pbinfo_stat_numbers.json | 293 ++++++++++++++++++ .../ui/legacy/pbinfo_enemy_boss_stats.png | Bin 0 -> 435 bytes .../ui/legacy/pbinfo_enemy_mini_stats.png | Bin 0 -> 666 bytes .../ui/legacy/pbinfo_player_mini_stats.png | Bin 0 -> 674 bytes .../images/ui/legacy/pbinfo_player_stats.png | Bin 0 -> 285 bytes public/images/ui/legacy/pbinfo_stat.json | 188 +++++++++++ public/images/ui/legacy/pbinfo_stat.png | Bin 0 -> 263 bytes .../images/ui/legacy/pbinfo_stat_numbers.json | 293 ++++++++++++++++++ .../images/ui/legacy/pbinfo_stat_numbers.png | Bin 0 -> 392 bytes public/images/ui/pbinfo_enemy_boss.png | Bin 554 -> 526 bytes public/images/ui/pbinfo_enemy_boss_stats.png | Bin 0 -> 257 bytes public/images/ui/pbinfo_enemy_mini.png | Bin 888 -> 851 bytes public/images/ui/pbinfo_enemy_mini_stats.png | Bin 0 -> 642 bytes public/images/ui/pbinfo_enemy_type.png | Bin 1502 -> 3599 bytes public/images/ui/pbinfo_enemy_type1.png | Bin 1360 -> 3305 bytes public/images/ui/pbinfo_enemy_type2.png | Bin 1340 -> 3197 bytes public/images/ui/pbinfo_player.png | Bin 654 -> 619 bytes public/images/ui/pbinfo_player_mini.png | Bin 898 -> 860 bytes public/images/ui/pbinfo_player_mini_stats.png | Bin 0 -> 648 bytes public/images/ui/pbinfo_player_stats.png | Bin 0 -> 312 bytes public/images/ui/pbinfo_player_type1.png | Bin 1340 -> 3197 bytes public/images/ui/pbinfo_player_type2.png | Bin 1360 -> 3305 bytes public/images/ui/pbinfo_stat.json | 188 +++++++++++ public/images/ui/pbinfo_stat.png | Bin 0 -> 278 bytes public/images/ui/pbinfo_stat_numbers.json | 293 ++++++++++++++++++ public/images/ui/pbinfo_stat_numbers.png | Bin 0 -> 430 bytes src/battle-scene.ts | 72 +++-- src/data/splash-messages.ts | 3 +- src/field/pokemon.ts | 4 + src/loading-scene.ts | 6 + src/locales/de/tutorial.ts | 4 + src/locales/en/tutorial.ts | 4 + src/locales/es/tutorial.ts | 4 + src/locales/fr/tutorial.ts | 4 + src/locales/it/tutorial.ts | 4 + src/phases.ts | 10 +- src/tutorial.ts | 6 + src/ui/battle-info.ts | 102 +++++- 40 files changed, 1442 insertions(+), 43 deletions(-) create mode 100644 public/images/pbinfo_stat_numbers.json create mode 100644 public/images/ui/legacy/pbinfo_enemy_boss_stats.png create mode 100644 public/images/ui/legacy/pbinfo_enemy_mini_stats.png create mode 100644 public/images/ui/legacy/pbinfo_player_mini_stats.png create mode 100644 public/images/ui/legacy/pbinfo_player_stats.png create mode 100644 public/images/ui/legacy/pbinfo_stat.json create mode 100644 public/images/ui/legacy/pbinfo_stat.png create mode 100644 public/images/ui/legacy/pbinfo_stat_numbers.json create mode 100644 public/images/ui/legacy/pbinfo_stat_numbers.png create mode 100644 public/images/ui/pbinfo_enemy_boss_stats.png create mode 100644 public/images/ui/pbinfo_enemy_mini_stats.png create mode 100644 public/images/ui/pbinfo_player_mini_stats.png create mode 100644 public/images/ui/pbinfo_player_stats.png create mode 100644 public/images/ui/pbinfo_stat.json create mode 100644 public/images/ui/pbinfo_stat.png create mode 100644 public/images/ui/pbinfo_stat_numbers.json create mode 100644 public/images/ui/pbinfo_stat_numbers.png diff --git a/index.css b/index.css index 9a507ad6766..dd47387adee 100644 --- a/index.css +++ b/index.css @@ -150,6 +150,10 @@ body { display: none; } +#touchControls:not([data-ui-mode='COMMAND']):not([data-ui-mode='FIGHT']):not([data-ui-mode='BALL']):not([data-ui-mode='TARGET_SELECT']) #apad #apadStats { + display: none; +} + #apad .apadRectBtnContainer + .apadSqBtnContainer { top: calc(var(--controls-size) * -1.9); left: calc(var(--controls-size) * -0.9); diff --git a/index.html b/index.html index bd316330a99..177a92efce6 100644 --- a/index.html +++ b/index.html @@ -74,6 +74,9 @@
V
+
+ C +
Menu
diff --git a/public/images/pbinfo_stat_numbers.json b/public/images/pbinfo_stat_numbers.json new file mode 100644 index 00000000000..32170690aa0 --- /dev/null +++ b/public/images/pbinfo_stat_numbers.json @@ -0,0 +1,293 @@ +{ + "textures": [ + { + "image": "pbinfo_stat_numbers.png", + "format": "RGBA8888", + "size": { + "w": 117, + "h": 8 + }, + "scale": 1, + "frames": [ + { + "filename": "+1", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "+2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 9, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "+3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 18, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "+4", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 27, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "+5", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 36, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "+6", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 45, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-1", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 54, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 63, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 72, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-4", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 81, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-5", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 90, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-6", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 99, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "0", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 108, + "y": 0, + "w": 9, + "h": 8 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:794aa4af3291db5abd8a2667626c1998:1a6706ad557b92f9bf099c23e02af4a6:6537c634087637bb27e8a1edb1ee2e35$" + } +} diff --git a/public/images/ui/legacy/pbinfo_enemy_boss_stats.png b/public/images/ui/legacy/pbinfo_enemy_boss_stats.png new file mode 100644 index 0000000000000000000000000000000000000000..94c9f2a181736d88c6752f2c97ed0bbbee23ebcc GIT binary patch literal 435 zcmeAS@N?(olHy`uVBq!ia0vp^n}ArJgAGVJb4-r_QjEnx?oJHr&dIz4vU5FM978JR zyuG8?cgR7a?csXf_7^8kc|Ex$m-yBz<$7q-n^RU*Eb9Vy3q^L$xwlCBgn&~-ln2-0 zC$%D(Zao#Zd6NElh+n&%^Pj+>91Q?jM7YZ*~R6rK6tBHXtJ>3o}%+B70Tit?}|9LLp3388Oyx(ny$dZ`X4n6UD>PshjO%e?;W3et7Lx@QEIV2LHO-ZhLc6eY9Ry zIQ|Mdb1{9R)SaoXcSRIE<`z6H%nuWjbE9V$ zXGWbr(B0xb=lC1f6GDcM4fWFUoyzXm2QNAn5;^S^|FUJBo0|`=UT>R$XHs^CNV z##av>ty$f?T7lzV!;W1Rn!7wYzpJ*28OBxY>HqxBa!BncE&SaXRbV6dDO(__3L?7E8i*EoZkKZ{HwqsHRc+nk205eyDOS2sxDu$ zd@tM{5g62QzVkTGE`^WE*Hfq8w-A>Rt4KTHq5izn`AE{j-lt}1uFk6Sl=!q)x&3rH zmfHGREPZQC>e=c~;%vpYyt-a*X%jpw^vJ`ZrANz4IZ?ukeBYJTaNN^-KBA z)J%%Y&U~o6pj>*#j=aoIas@k?dF)+-(V{Q3XI{exr|Grpv%NI5;(qK@ xp0+UKM9$<@NoVioZhp6Q^O64&v*v`HV4ZIk%FUH_dOOew44$rjF6*2UngE&&E5rZ* literal 0 HcmV?d00001 diff --git a/public/images/ui/legacy/pbinfo_player_mini_stats.png b/public/images/ui/legacy/pbinfo_player_mini_stats.png new file mode 100644 index 0000000000000000000000000000000000000000..dd2b7e65ba3522986e78d6844a6be8823c3382ae GIT binary patch literal 674 zcmV;T0$u%yP)EX>4Tx04R}tkv&MmKpe$iQ%gl!9Lyl%kfA!+MMWJ;6^me@v=v%)FuC*#nzSS- zE{=k0!NHHks)LKOt`4q(Aou~|>f)s6A|?JWDYS_3;J6>}?mh0_0Ya# zo%24i$jY)xd`>)J&;^MfxvseU#<}FMz%xZ7o1P~YiKS8xD?QB0hDJP198oo$@`aqs zD(5ZETD8GC_v9}O74(%1*J+L-fh8o7qK*_aP(c+IqO|Iym`Kxp+`~WO_*3Lk$W;L& z#{z25AUl5WKlt6PS)7`5lR|MI@M7B^V?b~hXg6*9``EVICxHJMxYE1+S__!_B)!?y zB1gdBHgIv>)s#Kpat9cGs>_D#NPe0^u?W1M(KqFRp<7^J&F!tTkJASrOIK2l+uOfqI{p0s^F(smE#4Fv0000mP)t-s0001cl!Q`iV>wbnAvplXy>s5y zwg3O#*3P|BYg+%cd;kCcN$J_5c5S*Us$?%8vTKwfg`6|6Wc}-=`Gc19G2( z)VthFjRI1_B|(0{3_xi#U}t|v7bsoq>Eaj?(fam=p-_VZhjU<>!iIbQ4@G5d*>KA2 zr+S66yVASV%+m`tUAT0h%_Vu-2F6#OE9N=hF1aYEASTnz@k_ZzU>c{|jD#j+;!l_T zYhIRn;@{452VTh2;XbSE{bIVBSPWaCe#7lsobz5x%h_{T;XlZgp00i_>zopr0I}G2 ADF6Tf literal 0 HcmV?d00001 diff --git a/public/images/ui/legacy/pbinfo_stat.json b/public/images/ui/legacy/pbinfo_stat.json new file mode 100644 index 00000000000..b7da47fc192 --- /dev/null +++ b/public/images/ui/legacy/pbinfo_stat.json @@ -0,0 +1,188 @@ +{ + "textures": [ + { + "image": "pbinfo_stat.png", + "format": "RGBA8888", + "size": { + "w": 112, + "h": 6 + }, + "scale": 1, + "frames": [ + { + "filename": "SPATK", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 19, + "h": 8 + }, + "spriteSourceSize": { + "x": 1, + "y": 2, + "w": 18, + "h": 6 + }, + "frame": { + "x": 0, + "y": 0, + "w": 18, + "h": 6 + } + }, + { + "filename": "SPDEF", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 19, + "h": 8 + }, + "spriteSourceSize": { + "x": 1, + "y": 2, + "w": 18, + "h": 6 + }, + "frame": { + "x": 18, + "y": 0, + "w": 18, + "h": 6 + } + }, + { + "filename": "CRIT", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 17, + "h": 8 + }, + "spriteSourceSize": { + "x": 1, + "y": 2, + "w": 16, + "h": 6 + }, + "frame": { + "x": 36, + "y": 0, + "w": 16, + "h": 6 + } + }, + { + "filename": "ACC", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 13, + "h": 8 + }, + "spriteSourceSize": { + "x": 1, + "y": 2, + "w": 12, + "h": 6 + }, + "frame": { + "x": 52, + "y": 0, + "w": 12, + "h": 6 + } + }, + { + "filename": "ATK", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 13, + "h": 8 + }, + "spriteSourceSize": { + "x": 1, + "y": 2, + "w": 12, + "h": 6 + }, + "frame": { + "x": 64, + "y": 0, + "w": 12, + "h": 6 + } + }, + { + "filename": "DEF", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 13, + "h": 8 + }, + "spriteSourceSize": { + "x": 1, + "y": 2, + "w": 12, + "h": 6 + }, + "frame": { + "x": 76, + "y": 0, + "w": 12, + "h": 6 + } + }, + { + "filename": "EVA", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 13, + "h": 8 + }, + "spriteSourceSize": { + "x": 1, + "y": 2, + "w": 12, + "h": 6 + }, + "frame": { + "x": 88, + "y": 0, + "w": 12, + "h": 6 + } + }, + { + "filename": "SPD", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 13, + "h": 8 + }, + "spriteSourceSize": { + "x": 1, + "y": 2, + "w": 12, + "h": 6 + }, + "frame": { + "x": 100, + "y": 0, + "w": 12, + "h": 6 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:40d30205ce8efd40dfa86cd11b0491d6:7076db6ed74199dcfb38fc8cd4d4a0e8:05882267d3999884e0491134e98b1b53$" + } +} diff --git a/public/images/ui/legacy/pbinfo_stat.png b/public/images/ui/legacy/pbinfo_stat.png new file mode 100644 index 0000000000000000000000000000000000000000..62ec3758772daea6013a4de5532575a66caf8116 GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0vp^1whQk!3-pITwg5(Qk(%kA+A8$!NK9)wXI7Q-Kzj{ z7)yfuf*Bm1-ADteDDa3ZW?Ec4QuN(io6fN32b;e=)XJ@8wjxa57 z6;5`pyz#?~2;;a-r4XYn{3?!Y<6HKbItN$2xk}gw>0y zUzy)p<5e-!w)Vy<(87aih3;8-LtI=7KLTHk<}Jk-^i|&t;uc GLK6T7%VuW) literal 0 HcmV?d00001 diff --git a/public/images/ui/legacy/pbinfo_stat_numbers.json b/public/images/ui/legacy/pbinfo_stat_numbers.json new file mode 100644 index 00000000000..9c74ee86dbc --- /dev/null +++ b/public/images/ui/legacy/pbinfo_stat_numbers.json @@ -0,0 +1,293 @@ +{ + "textures": [ + { + "image": "pbinfo_stat_numbers.png", + "format": "RGBA8888", + "size": { + "w": 117, + "h": 8 + }, + "scale": 1, + "frames": [ + { + "filename": "+1", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "+2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 9, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "+3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 18, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "+4", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 27, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "+5", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 36, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "+6", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 45, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-1", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 54, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 63, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 72, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-4", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 81, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-5", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 90, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-6", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 99, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "0", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 108, + "y": 0, + "w": 9, + "h": 8 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:1f22b7cb085faf9e9764273fa5e70c28:afc5587ebacca78d178ac7e0c434591b:6537c634087637bb27e8a1edb1ee2e35$" + } +} diff --git a/public/images/ui/legacy/pbinfo_stat_numbers.png b/public/images/ui/legacy/pbinfo_stat_numbers.png new file mode 100644 index 0000000000000000000000000000000000000000..ee1453b21070f8de40a299a2d0c82c49093799cc GIT binary patch literal 392 zcmV;30eAk1P)NeVolC?^B79yfh4NP^lrY9U!*DY-V@3rV{hYdQ>YK;=1YJaz3T;`<^$DGJL<5 z0VRW87@CHmA>NuYKzH1TLC5xSzn%dVgI*Y#hCzM2e@<+(--30)Oref_gmu$R&9E*Q zKCPUg&65~>rQzm$c=)wGxON}pkE{!ZPit-h_?q;dhMV)@;n(^|U!-Qgl_%A@VDM** z28vT)T`)O@Pln{f8%r6yr(x9i(DP6xH!0n5bN5`F;gccxJgbFgqhZwe(DRg7RCba7 mA?H5)Du%PaS?j+(7uOe-FYwO$9P0Z30000Ik&UmVKT0GxPa8d!07jZZ!ddIBQBbh_PFZe&65JuT|9nKq=MA`2Ra01f-NW z91f+QE2Xg6Y_!guHF6k+mXtE_eP3^s9ZQpWyFcUJ3~9SRW4V~*j$cQ1WnC#{?2Y{H zp1HO|plBRLh_0>&dpk(u@=|B3Ul!cn-d9Bu|Irn<2(MATii<NL1q8595j002ovPDHLkV1ifd@6!MP delta 515 zcmV+e0{s1s1gZp(F@NMqL_t(|obB6BYQjJm1@M;=C_;s9>aGx7IS8(W?BZR#K+fR> zdKYIGa4pEV(m;21BcvdOLb@oX#w6N||Hk-!EB%ba5WYMoi2;a+$P89q(Q(?bWqnK1js?_P5*2T3V0acimCcp71_vhnu(jb5jIunqv- zU|m?J^YT3J;D0uwQBe98btaL0--i&Q%orEbYPFKro2Hw%bs$(LP1z0Bn7Fmy_dE4% zMRfpBN}Xl?_f7}_DJACfdG6;*DGY~0t+A6v4#Sx>8X@+5UvHKdwn^skG{U|W(s&x7 z*QuwrAFS-cx>Cy61NqkdXW#0iF_3fBLidQcv~I9QcYG^xiwstFvMunJ#6@+wo@071 z6=j=LzJ;IG-9*kySisI*Q}3$_A-J?SlT8{I?O!P+!f>JWs8i-krl0glDKjDTt88$>!uSb_l5uf002ovPDHLk FV1lYA{=)zO diff --git a/public/images/ui/pbinfo_enemy_boss_stats.png b/public/images/ui/pbinfo_enemy_boss_stats.png new file mode 100644 index 0000000000000000000000000000000000000000..7148a7af4759141abb5e2b39c02a17b45af905e5 GIT binary patch literal 257 zcmeAS@N?(olHy`uVBq!ia0vp^n}ArJgAGVJb4-r_QjEnx?oJHr&dIz4a&~*VIEGZr zd3$>`-ysJ9)(e`BNfSH%{_kJqko58BL=U^z3cqSH|eR)57 zW1&p?=O4X~e>-L8TFuvct=1%`yX>BUe4QLNkl8GRYx|2)P*70tlomTy+AL)kaKVi zE&#J{fxIOH3ldw!o(@eA9|jTwfke-5G6qF2@~g-B0uhl?&o>!GQQmYRa=R?cyz5!T z`|(5+MftElx~(F4j)*+88Q$()i?q{0_b3h8Z?jzmZ4pWY0rr0qL21w(A*rB55THl| zr9t=9O$8-_0MJt!bXT2JP$CGRMv#IUK>#&^6m9ha8#1%t_N<261?l{K=~*1pAjk_btXV2r7AjK;-r zyc-`ce5q`T&+mUP){_|k&bdbFdlX{~)>_gu^?vW1V>+D%9edXZS(f#zwRw^xVO733 z=iJLT_%&7jLr5Bc=c*yJqh3v!6wCSI$(1zcmbE+B8p>2?Q-u1?3(9$bLGjrb(}}GC z&Tny{X#k#=SKD&ZXsreQPoB<=eZOzJOKWr2MgYCV+*TmByu~acA|fIpa@iluDW|ek SO(V4c0000wNkl)q|N~u!nI~O4Yq?Ab0 z)cUDa4A$g)|GB+zjjyH$DNlu{Sp;D;RZA6(J^uv|5`cGRUYNim(gR9s1U zPC0iQQ-etbpCZ(@E->2xpqYObLeyev0QOIDQc7gm-04MCwVfaNvS^f20{C4#?Hk+n z_uXHMMb~Ko*z*>1x7*b&2cv4u=Wc00L_|bHM0D5>)LE${MNRhx00000NkvXXu0mjf DZ|lEX>4Tx04R}tkv&MmP!xqvQ>7vm5sQd8WT;LSL`4J_sbUc+7C6sqP{?%e(K->QQng1AHR!9McVpc!PL) z)6zNb6Ngw)Qi#uq#|*k4@gvt|m)|%S92R(H$VeyWi9^IW<^6Ko+1t_sz&)j z#$|=`7H73wWzBo?7Y1|MN{Z{Wh7rRO;z&S*j4Dbf!$O31jT93}I*)qzha7)`Tr#;z zVB}ap1u7)R5B>+gXKUssC)}i96zF`h?T-;4unRP5w*7r<+l>>z{|sDdEq|pB%zTnw zYiZ#lpm!U%xNd3k9&ot>3_j_SAvuztmXOZ_?`QN)S)l(G=w5T@);!1Q1CXX!E#CkK zhrnoove!M{-PJy~e|wtq`vH(aagbUB zzo-t5uI_cI;7<`vL}@r@>=fw7Q_>^>xEhuomQto)FNAjEI4-`=cWfUYlv1Ys?$EX( z{-b279fr-f*TOp8O^+I^-|2j;`a~!KNp6au2K}h1f+CP)E`l2L=hG@E0!flV4f^#- z6%>Ia27#GDAc;X>X8YJF+efPS#oQskn5pI%x-*WUY4S8Vs<2+QHAobJnOn>qX}QG= c008jX1y1rsg=?D3Y5)KL07*qoM6N<$f~t=qVE_OC literal 0 HcmV?d00001 diff --git a/public/images/ui/pbinfo_enemy_type.png b/public/images/ui/pbinfo_enemy_type.png index 021a120070c1872b54405196e4bcb2cec9920d06..9bac63e5e72ba305c0c7769d72bc39d72aa8202e 100644 GIT binary patch literal 3599 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 diff --git a/public/images/ui/pbinfo_enemy_type1.png b/public/images/ui/pbinfo_enemy_type1.png index 89b84d7f6305169db2e227aa33a9e2202cdeebfa..6d94871e8da1dfd56a0271a6a8ef1ae8e9d6c3c4 100644 GIT binary patch literal 3305 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 delta 1332 zcmV-41K;roK6x|8rVOt-T?ULCa%fweLZBshW_&&HC;* zO0vk;&DMDOm4U9|mAs4J&B(p@`1tjx^{$}s^^2`iam|Lp|9@hcy`Z4dqs6<(m4=$( z@Ycwh|J;Giu7~bbDWAdC&0W2FNPBZod$Y)zgQZ%P*Yx1fkon7G_No9%p+S^Ti}|f> zm8jtMc@R>*?(~L`sg$n0l(@~ZN?llm^Z)<=0d!JMQvg8b*k%9#010qNS#tmY4#WTe z4#WYKD-Ig~0DlAzNkl(^Y-#Wr6(Oj4xVAPdRD7!nD#iAB*BzHNIOCF7+K!2!Mo?4Ma{y?`n4?k5THGfPb znjaf?PygBd=;)}=AC3b1KsV?cB*s@ciU)rw57cPk>(CnArfu-@+b7_eU=Lj1OnvNcwffW0-uP_mXO_l4S!y5_eP^JhH)c@!3IEp%o=Epqlf^Q zdl4vm%oVI6jAf-z5$|I$U2Dmtnyz&NU|gM1Tovo?z9%sl038k@0T?JGHsIL@QDnrd zDzX{HYQ?=uvO=g-#FB$Nsuv5}+iLfdlS^uKdBRa(`I~AmiC0_`**#%3i+m|xZDaqP znSbbOs;KIv6AN{%B`!mDz1^R4OyqbTAb6NW0}$>+AUJ_2A{5z+2=NU>5xD9kiW7b_ ziQ3*&JDtuMz*$E^ zq5Oy)WOl}~7tbVB4ihDjPFJx4ljiYZ^SDMTc5Eak+VETLetdjNB~Onz3M4|@U_y^2 zIZTv9KC>90ws`^*7o%$YR54G)Z&akbQ~r1nO{!**|rqpNJ<0!EF`8Alxn}7E5 z(}~lmd`(2y!z<9KqCiv?B4ap}nkwRT+RHPkNNQz9jwytB>h0bPVUU_P&kYuaaOFk$ z8LiIGod{VZ7{z9D<;CVoyik#-*^P(`O#DR2_+sU8C^NhOn2+~R33uoA15d^47ggK
u*i{Slh@`p?1>g%h%6Cw5J!=T0U*R1MnDJ6|U#*Z*JkoesN4y6h&V9 zS^IL#rHNpS$$z3KVzb$F)3Ol+L9lnip}Z&_gDU{iG###yJqW`PfbDi$yYFhX!dhEB z4IRgEH!YixG)-SW$f;^_3~?M|t<_*LPlNlL+mTx`uF6D6l4LfiP&6*cw*!3q`#KE6 z*>nv)$B`rn;PGFB@1WyQS!;op!Bg3K(f(8CKUlOl=YJNph0sZ>!pgJLse-2Lyi&dt}*K+!0R$E0vTWLUzE`_5mXrc zsQaRf);@*cL$jCTsXOrp#Tb)a{=Cd~yPcLDF5CP8>Nk1daueF@H!&L_t(|obBAdPTNo%hT%6=r7mDtOmVaZ|#D^=AwA$T>{|y z{`MMK0n4%gn9t{_=Z;1rTz8s03~k$XIW5~GzVAQ(BKK9E&tTg&t~=GuVw47V*Ecn{ zq+W@M;5bfWQX%fXAUY0k`1iGCS&iu$vV0E5aexf}HGd3;XC*YPKAz_Re{P;O?Z=(J z@3P-4P6>ipC$SJTFR}T;@LhT#Kr@~tNIX4Rlr7F3ih1JlvSD0}h;CUMrfz+?^FUrW92r7(fqb;z7>41Gsv{dh>cWt0R&T-FUZ9s?$T_$M z7l7HfK;Dvp1&OUH5K*IY>CJ^)^|N88NNC4pVs+=4}QGTmJ(3~vGe$D%9 z=$A!Nln?u(Y8Bx=BIU(qc)3?Ccq~Cn18LBHo9*gki69XmDIk9lNQ3S;P6ZMHlCDey z(x7{MDv$_}bVVYN2HmyUuGk}Bhem)T8UcGW0wi(y`1JhcWAML^ZL!&|BuT^msC0bn znVUT57V~&KuA`Qlv)1Y@{gNcD<5}t0Th136Ouiehu`ZX)k+t@4i#a$Ek|dEaCiL`1 z#BqEW7bo8HP4R#J`Jwe>CP{M6HBw()j4`s-DoxYU_nmW^PNyfwu5N@Z%X-$@JV}zU zDj%G4?%^B!KbQQ5<1~;eTs0Iss;zudEa!_mSJIraxeHnvd@8glLd*6A{^x002ovPDHLkV1g-F&x8N~ delta 473 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 delta 1332 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 Wt8RFN+!3I289ZJ6T-G@yGywokWokPB literal 0 HcmV?d00001 diff --git a/public/images/ui/pbinfo_stat_numbers.json b/public/images/ui/pbinfo_stat_numbers.json new file mode 100644 index 00000000000..ec4f7117bb7 --- /dev/null +++ b/public/images/ui/pbinfo_stat_numbers.json @@ -0,0 +1,293 @@ +{ + "textures": [ + { + "image": "pbinfo_stat_numbers.png", + "format": "RGBA8888", + "size": { + "w": 117, + "h": 8 + }, + "scale": 1, + "frames": [ + { + "filename": "1", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 9, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 18, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "4", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 27, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "5", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 36, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "6", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 45, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-1", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 54, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-2", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 63, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-3", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 72, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-4", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 81, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-5", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 90, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "-6", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 99, + "y": 0, + "w": 9, + "h": 8 + } + }, + { + "filename": "0", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 9, + "h": 8 + }, + "frame": { + "x": 108, + "y": 0, + "w": 9, + "h": 8 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:b0719fae0d9b670a727148cdc7202249:afc5587ebacca78d178ac7e0c434591b:4825a9f02f72f1fe28a724c6c5dffb37$" + } +} diff --git a/public/images/ui/pbinfo_stat_numbers.png b/public/images/ui/pbinfo_stat_numbers.png new file mode 100644 index 0000000000000000000000000000000000000000..c778ba992734421a718b2c49db1db0ae77a28e09 GIT binary patch literal 430 zcmV;f0a5;mP)X}UpFSFJe%YMSjb zvz=}Te=dw_+OM;>zwNiTz<(WGW!%j?&)@0VTARh5OWbc`j(J{Tok%Zt#$YoH;sBj7 z0D#IlJRc6p%*|?r>-8D{#_^;+F^22I1yqy`_PebZNKrNbfWEEq_WF{{oLyYu^!yS4 z#PO(4jM4P@WGYS8UqlLVGYqiSvW&F&OBuS>FtHC$Vz?0ZyX|CN5<3@SjG<>5X2}?8 zQ)v+?7z&xQg%~oUa!zD?QzeEgj_Hh<7_VVM6DZ`EEo4UD)*|DZy2Lt;DavMIyoRBA zxP2Ty%KN9gENZI8IE_78Q^T$GD~(@jhsGYQsdI~*V!X;!+J?fg{Gd2S+NQZaWGcsm zi<{b~a&9zLI&@IbQb7LyuD?x7eaKXf@hzMCJ+VH0TaTtDpMHPh p)) + p.toggleStats(pressed); + if (pressed) + this.setLastProcessedMovementTime(Button.STATS); + } else + return; + } if (inputSuccess && this.enableVibration && typeof navigator.vibrate !== 'undefined') navigator.vibrate(vibrationLength || 10); } @@ -1443,7 +1454,7 @@ export default class BattleScene extends SceneBase { * or not. It will only return true once, until the key is released and pressed down * again. */ - gamepadButtonJustDown(button: Phaser.Input.Gamepad.Button) : boolean { + gamepadButtonJustDown(button: Phaser.Input.Gamepad.Button): boolean { if (!button || !this.gamepadSupport) return false; @@ -1463,6 +1474,23 @@ export default class BattleScene extends SceneBase { return this.buttonKeys[button].some(k => Phaser.Input.Keyboard.JustDown(k)) || this.gamepadButtonJustDown(gamepad?.buttons[this.gamepadKeyConfig[button]]); } + /** + * gamepadButtonJustUp returns true if @param button has just been released + * or not. It will only return true once, until the key is released and pressed down + * again. + */ + gamepadButtonJustUp(button: Phaser.Input.Gamepad.Button): boolean { + if (!button || !this.gamepadSupport) + return false; + + return !this.gamepadButtonStates[button.index]; + } + + buttonJustReleased(button: Button): boolean { + const gamepad = this.input.gamepad?.gamepads[0]; + return this.buttonKeys[button].some(k => Phaser.Input.Keyboard.JustUp(k)) || this.gamepadButtonJustUp(gamepad?.buttons[this.gamepadKeyConfig[button]]); + } + /** * repeatInputDurationJustPassed returns true if @param button has been held down long * enough to fire a repeated input. A button must claim the movementButtonLock before diff --git a/src/data/splash-messages.ts b/src/data/splash-messages.ts index 11629cf05d7..198ff07cec9 100644 --- a/src/data/splash-messages.ts +++ b/src/data/splash-messages.ts @@ -33,6 +33,5 @@ splashMessages.push(...[ 'Also Try Emerald Rogue!', 'Also Try Radical Red!', 'Eevee Expo!', - 'YNOproject!', - 'Shh, don\'t tell Sam!' + 'YNOproject!' ]); \ No newline at end of file diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 9a7bfb48621..7072875d3ce 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -1179,6 +1179,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return this.battleInfo.updateInfo(this, instant); } + toggleStats(visible: boolean): void { + this.battleInfo.toggleStats(visible); + } + addExp(exp: integer) { const maxExpLevel = this.scene.getMaxExpLevel(); const initialExp = this.exp; diff --git a/src/loading-scene.ts b/src/loading-scene.ts index 2f37b900ab5..875d618ec0f 100644 --- a/src/loading-scene.ts +++ b/src/loading-scene.ts @@ -39,15 +39,21 @@ export class LoadingScene extends SceneBase { } this.loadAtlas('namebox', 'ui'); this.loadImage('pbinfo_player', 'ui'); + this.loadImage('pbinfo_player_stats', 'ui'); this.loadImage('pbinfo_player_mini', 'ui'); + this.loadImage('pbinfo_player_mini_stats', 'ui'); this.loadAtlas('pbinfo_player_type', 'ui'); this.loadAtlas('pbinfo_player_type1', 'ui'); this.loadAtlas('pbinfo_player_type2', 'ui'); this.loadImage('pbinfo_enemy_mini', 'ui'); + this.loadImage('pbinfo_enemy_mini_stats', 'ui'); this.loadImage('pbinfo_enemy_boss', 'ui'); + this.loadImage('pbinfo_enemy_boss_stats', 'ui'); this.loadAtlas('pbinfo_enemy_type', 'ui'); this.loadAtlas('pbinfo_enemy_type1', 'ui'); this.loadAtlas('pbinfo_enemy_type2', 'ui'); + this.loadAtlas('pbinfo_stat', 'ui'); + this.loadAtlas('pbinfo_stat_numbers', 'ui'); this.loadImage('overlay_lv', 'ui'); this.loadAtlas('numbers', 'ui'); this.loadAtlas('numbers_red', 'ui'); diff --git a/src/locales/de/tutorial.ts b/src/locales/de/tutorial.ts index 2722c02ad45..7a27f2077e6 100644 --- a/src/locales/de/tutorial.ts +++ b/src/locales/de/tutorial.ts @@ -20,6 +20,10 @@ export const tutorial: SimpleTranslationEntries = { "pokerus": `A daily random 3 selectable starters have a purple border. $If you see a starter you own with one of these,\ntry adding it to your party. Be sure to check its summary!`, + "statChange": `Stat changes persist across battles as long as your Pokémon aren't recalled. + $Your Pokémon are recalled before a trainer battle and before entering a new biome. + $You can also view the stat changes for the Pokémon on the field by holding C.`, + "selectItem": `After every battle, you are given a choice of 3 random items.\nYou may only pick one. $These range from consumables, to Pokémon held items, to passive permanent items. $Most non-consumable item effects will stack in various ways. diff --git a/src/locales/en/tutorial.ts b/src/locales/en/tutorial.ts index 2722c02ad45..7a27f2077e6 100644 --- a/src/locales/en/tutorial.ts +++ b/src/locales/en/tutorial.ts @@ -20,6 +20,10 @@ export const tutorial: SimpleTranslationEntries = { "pokerus": `A daily random 3 selectable starters have a purple border. $If you see a starter you own with one of these,\ntry adding it to your party. Be sure to check its summary!`, + "statChange": `Stat changes persist across battles as long as your Pokémon aren't recalled. + $Your Pokémon are recalled before a trainer battle and before entering a new biome. + $You can also view the stat changes for the Pokémon on the field by holding C.`, + "selectItem": `After every battle, you are given a choice of 3 random items.\nYou may only pick one. $These range from consumables, to Pokémon held items, to passive permanent items. $Most non-consumable item effects will stack in various ways. diff --git a/src/locales/es/tutorial.ts b/src/locales/es/tutorial.ts index 2722c02ad45..7a27f2077e6 100644 --- a/src/locales/es/tutorial.ts +++ b/src/locales/es/tutorial.ts @@ -20,6 +20,10 @@ export const tutorial: SimpleTranslationEntries = { "pokerus": `A daily random 3 selectable starters have a purple border. $If you see a starter you own with one of these,\ntry adding it to your party. Be sure to check its summary!`, + "statChange": `Stat changes persist across battles as long as your Pokémon aren't recalled. + $Your Pokémon are recalled before a trainer battle and before entering a new biome. + $You can also view the stat changes for the Pokémon on the field by holding C.`, + "selectItem": `After every battle, you are given a choice of 3 random items.\nYou may only pick one. $These range from consumables, to Pokémon held items, to passive permanent items. $Most non-consumable item effects will stack in various ways. diff --git a/src/locales/fr/tutorial.ts b/src/locales/fr/tutorial.ts index c9f8a392e1e..e280ee2d5dc 100644 --- a/src/locales/fr/tutorial.ts +++ b/src/locales/fr/tutorial.ts @@ -25,6 +25,10 @@ export const tutorial: SimpleTranslationEntries = { $violet. Si un starter que vous possédez l’a, essayez de $ l’ajouter à votre équipe. Vérifiez bien son résumé !`, + "statChange": `Stat changes persist across battles as long as your Pokémon aren't recalled. + $Your Pokémon are recalled before a trainer battle and before entering a new biome. + $You can also view the stat changes for the Pokémon on the field by holding C.`, + "selectItem": `Après chaque combat, vous avez le choix entre 3 objets\ntirés au sort. Vous ne pouvez en prendre qu’un. $Cela peut être des objets consommables, des objets à\nfaire tenir, ou des objets passifs aux effets permanents. $La plupart des effets des objets non-consommables se cumuleront de diverses manières. diff --git a/src/locales/it/tutorial.ts b/src/locales/it/tutorial.ts index 2722c02ad45..7a27f2077e6 100644 --- a/src/locales/it/tutorial.ts +++ b/src/locales/it/tutorial.ts @@ -20,6 +20,10 @@ export const tutorial: SimpleTranslationEntries = { "pokerus": `A daily random 3 selectable starters have a purple border. $If you see a starter you own with one of these,\ntry adding it to your party. Be sure to check its summary!`, + "statChange": `Stat changes persist across battles as long as your Pokémon aren't recalled. + $Your Pokémon are recalled before a trainer battle and before entering a new biome. + $You can also view the stat changes for the Pokémon on the field by holding C.`, + "selectItem": `After every battle, you are given a choice of 3 random items.\nYou may only pick one. $These range from consumables, to Pokémon held items, to passive permanent items. $Most non-consumable item effects will stack in various ways. diff --git a/src/phases.ts b/src/phases.ts index 8eda33de20e..ceba555f2ce 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -2671,7 +2671,6 @@ export class StatChangePhase extends PokemonPhase { let random = false; - const allStats = Utils.getEnumValues(BattleStat); if (this.stats.length === 1 && this.stats[0] === BattleStat.RAND) { this.stats[0] = this.getRandomStat(); random = true; @@ -2712,8 +2711,11 @@ export class StatChangePhase extends PokemonPhase { for (let stat of filteredStats) pokemon.summonData.battleStats[stat] = Math.max(Math.min(pokemon.summonData.battleStats[stat] + levels.value, 6), -6); - applyPostStatChangeAbAttrs(PostStatChangeAbAttr, pokemon, filteredStats, this.levels, this.selfTarget) - this.end(); + applyPostStatChangeAbAttrs(PostStatChangeAbAttr, pokemon, filteredStats, this.levels, this.selfTarget); + + pokemon.updateInfo(); + + handleTutorial(this.scene, Tutorial.Stat_Change).then(() => super.end()); }; if (relLevels.filter(l => l).length && this.scene.moveAnimations) { @@ -3337,7 +3339,7 @@ export class TrainerVictoryPhase extends BattlePhase { const trainerType = this.scene.currentBattle.trainer.config.trainerType; if (vouchers.hasOwnProperty(TrainerType[trainerType])) { if (!this.scene.validateVoucher(vouchers[TrainerType[trainerType]]) && this.scene.currentBattle.trainer.config.isBoss) - this.scene.pushPhase(new ModifierRewardPhase(this.scene, modifierTypes.VOUCHER)); + this.scene.unshiftPhase(new ModifierRewardPhase(this.scene, [ modifierTypes.VOUCHER, modifierTypes.VOUCHER, modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PREMIUM ][vouchers[TrainerType[trainerType]].voucherType])); } this.scene.ui.showText(i18next.t('menu:trainerDefeated', { trainerName: this.scene.currentBattle.trainer.getName(TrainerSlot.NONE, true) }), null, () => { diff --git a/src/tutorial.ts b/src/tutorial.ts index 918c68b9bb4..88e88fa809c 100644 --- a/src/tutorial.ts +++ b/src/tutorial.ts @@ -9,6 +9,7 @@ export enum Tutorial { Menu = "MENU", Starter_Select = "STARTER_SELECT", Pokerus = "POKERUS", + Stat_Change = "STAT_CHANGE", Select_Item = "SELECT_ITEM", Egg_Gacha = "EGG_GACHA" } @@ -42,6 +43,11 @@ const tutorialHandlers = { scene.ui.showText(i18next.t("tutorial:pokerus"), null, () => scene.ui.showText('', null, () => resolve()), null, true); }); }, + [Tutorial.Stat_Change]: (scene: BattleScene) => { + return new Promise(resolve => { + scene.showFieldOverlay(1000).then(() => scene.ui.showText(i18next.t("tutorial:statChange"), null, () => scene.ui.showText('', null, () => scene.hideFieldOverlay(1000).then(() => resolve())), null, true)); + }); + }, [Tutorial.Select_Item]: (scene: BattleScene) => { return new Promise(resolve => { scene.ui.setModeWithoutClear(Mode.MESSAGE).then(() => { diff --git a/src/ui/battle-info.ts b/src/ui/battle-info.ts index ae794a256fa..ae8f518e727 100644 --- a/src/ui/battle-info.ts +++ b/src/ui/battle-info.ts @@ -7,6 +7,9 @@ import { StatusEffect } from '../data/status-effect'; import BattleScene from '../battle-scene'; import { Type, getTypeRgb } from '../data/type'; import { getVariantTint } from '#app/data/variant'; +import { BattleStat } from '#app/data/battle-stat'; + +const battleStatOrder = [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.ACC, BattleStat.EVA, BattleStat.SPD ]; export default class BattleInfo extends Phaser.GameObjects.Container { private player: boolean; @@ -24,6 +27,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { private lastLevelExp: integer; private lastLevel: integer; private lastLevelCapped: boolean; + private lastBattleStats: string; private box: Phaser.GameObjects.Sprite; private nameText: Phaser.GameObjects.Text; @@ -46,6 +50,11 @@ export default class BattleInfo extends Phaser.GameObjects.Container { public expMaskRect: Phaser.GameObjects.Graphics; + private statsContainer: Phaser.GameObjects.Container; + private statsBox: Phaser.GameObjects.Sprite; + private statValuesContainer: Phaser.GameObjects.Container; + private statNumbers: Phaser.GameObjects.Sprite[]; + constructor(scene: Phaser.Scene, x: number, y: number, player: boolean) { super(scene, x, y); this.player = player; @@ -138,18 +147,6 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.levelNumbersContainer = this.scene.add.container(9.5, (this.scene as BattleScene).uiTheme ? 0 : -0.5); this.levelContainer.add(this.levelNumbersContainer); - this.type1Icon = this.scene.add.sprite(player ? -139 : -15, player ? -17 : -15.5, `pbinfo_${player ? 'player' : 'enemy'}_type1`); - this.type1Icon.setOrigin(0, 0); - this.add(this.type1Icon); - - this.type2Icon = this.scene.add.sprite(player ? -139 : -15, player ? -1 : -2.5, `pbinfo_${player ? 'player' : 'enemy'}_type2`); - this.type2Icon.setOrigin(0, 0); - this.add(this.type2Icon); - - this.type3Icon = this.scene.add.sprite(player ? -154 : 0, player ? -17 : -15.5, `pbinfo_${player ? 'player' : 'enemy'}_type`); - this.type3Icon.setOrigin(0, 0); - this.add(this.type3Icon); - if (this.player) { this.hpNumbersContainer = this.scene.add.container(-15, 10); this.add(this.hpNumbersContainer); @@ -171,6 +168,46 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.expBar = expBar; this.expMaskRect = expMaskRect; } + + this.statsContainer = this.scene.add.container(0, 0); + this.statsContainer.setAlpha(0); + this.add(this.statsContainer); + + this.statsBox = this.scene.add.sprite(0, 0, `${this.getTextureName()}_stats`); + this.statsBox.setOrigin(1, 0.5); + this.statsContainer.add(this.statsBox); + + const statLabels: Phaser.GameObjects.Sprite[] = []; + this.statNumbers = []; + + this.statValuesContainer = this.scene.add.container(0, 0); + this.statsContainer.add(this.statValuesContainer); + + battleStatOrder.map((s, i) => { + const statX = i > 1 ? this.statNumbers[i - 2].x + this.statNumbers[i - 2].width + 4 : -this.statsBox.width + 8; + const statY = -this.statsBox.height / 2 + 4 + (i < battleStatOrder.length - 1 ? (i % 2 ? 10 : 0) : 5); + const statLabel = this.scene.add.sprite(statX, statY, 'pbinfo_stat', BattleStat[s]); + statLabel.setOrigin(0, 0); + statLabels.push(statLabel); + this.statValuesContainer.add(statLabel); + + const statNumber = this.scene.add.sprite(statX + statLabel.width, statY, 'pbinfo_stat_numbers', '3'); + statNumber.setOrigin(0, 0); + this.statNumbers.push(statNumber); + this.statValuesContainer.add(statNumber); + }); + + this.type1Icon = this.scene.add.sprite(player ? -139 : -15, player ? -17 : -15.5, `pbinfo_${player ? 'player' : 'enemy'}_type1`); + this.type1Icon.setOrigin(0, 0); + this.add(this.type1Icon); + + this.type2Icon = this.scene.add.sprite(player ? -139 : -15, player ? -1 : -2.5, `pbinfo_${player ? 'player' : 'enemy'}_type2`); + this.type2Icon.setOrigin(0, 0); + this.add(this.type2Icon); + + this.type3Icon = this.scene.add.sprite(player ? -154 : 0, player ? -17 : -15.5, `pbinfo_${player ? 'player' : 'enemy'}_type`); + this.type3Icon.setOrigin(0, 0); + this.add(this.type3Icon); } initInfo(pokemon: Pokemon) { @@ -258,7 +295,14 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.expMaskRect.x = (pokemon.levelExp / getLevelTotalExp(pokemon.level, pokemon.species.growthRate)) * 510; this.lastExp = pokemon.exp; this.lastLevelExp = pokemon.levelExp; + + this.statValuesContainer.setPosition(8, 7) } + + const battleStats = battleStatOrder.map(() => 0); + + this.lastBattleStats = battleStats.join(''); + this.updateBattleStats(battleStats); } getTextureName(): string { @@ -272,6 +316,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.mini = mini; this.box.setTexture(this.getTextureName()); + this.statsBox.setTexture(`${this.getTextureName()}_stats`); if (this.player) this.y -= 12 * (mini ? 1 : -1); @@ -284,21 +329,34 @@ export default class BattleInfo extends Phaser.GameObjects.Container { el.y += -8 * (mini ? 1 : -1); }); + this.statValuesContainer.x += 2 * (mini ? 1 : -1); + this.statValuesContainer.y += -7 * (mini ? 1 : -1); + const toggledElements = [ this.hpNumbersContainer, this.expBar ]; toggledElements.forEach(el => el.setVisible(!mini)); } + toggleStats(visible: boolean): void { + this.scene.tweens.add({ + targets: this.statsContainer, + duration: Utils.fixedInt(125), + ease: 'Sine.easeInOut', + alpha: visible ? 1 : 0 + }); + } + updateBossSegments(pokemon: EnemyPokemon): void { const boss = !!pokemon.bossSegments; if (boss !== this.boss) { this.boss = boss; - [ this.nameText, this.genderText, this.teraIcon, this.splicedIcon, this.shinyIcon, this.ownedIcon, this.statusIndicator, this.levelContainer ].map(e => e.x += 48 * (boss ? -1 : 1)); + [ this.nameText, this.genderText, this.teraIcon, this.splicedIcon, this.shinyIcon, this.ownedIcon, this.statusIndicator, this.levelContainer, this.statValuesContainer ].map(e => e.x += 48 * (boss ? -1 : 1)); this.hpBar.x += 38 * (boss ? -1 : 1); this.hpBar.y += 2 * (this.boss ? -1 : 1); this.hpBar.setTexture(`overlay_hp${boss ? '_boss' : ''}`); this.box.setTexture(this.getTextureName()); + this.statsBox.setTexture(`${this.getTextureName()}_stats`); } this.bossSegments = boss ? pokemon.bossSegments : 0; @@ -317,6 +375,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { const divider = this.scene.add.rectangle(0, 0, 1, this.hpBar.height - (uiTheme ? 0 : 1), pokemon.bossSegmentIndex >= s ? 0xFFFFFF : 0x404040) divider.setOrigin(0.5, 0); this.add(divider); + this.moveBelow(divider as Phaser.GameObjects.GameObject, this.statsContainer); divider.setPositionRelative(this.hpBar, dividerX, uiTheme ? 0 : 1); this.hpBarSegmentDividers.push(divider); @@ -439,6 +498,13 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.lastLevel = pokemon.level; } + if (pokemon.summonData) { + const battleStats = pokemon.summonData.battleStats.join(''); + + if (this.lastBattleStats !== battleStats) + this.updateBattleStats(pokemon.summonData.battleStats); + } + this.shinyIcon.setVisible(pokemon.isShiny()); resolve(); @@ -513,7 +579,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { }); } - setLevel(level: integer) { + setLevel(level: integer): void { const isCapped = level >= (this.scene as BattleScene).getMaxExpLevel(); this.levelNumbersContainer.removeAll(true); const levelStr = level.toString(); @@ -522,7 +588,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.levelContainer.setX((this.player ? -41 : -50) - 8 * Math.max(levelStr.length - 3, 0)); } - setHpNumbers(hp: integer, maxHp: integer) { + setHpNumbers(hp: integer, maxHp: integer): void { if (!this.player || !this.scene) return; this.hpNumbersContainer.removeAll(true); @@ -535,6 +601,12 @@ export default class BattleInfo extends Phaser.GameObjects.Container { for (let i = hpStr.length - 1; i >= 0; i--) this.hpNumbersContainer.add(this.scene.add.image(offset++ * -8, 0, 'numbers', hpStr[i])); } + + updateBattleStats(battleStats: integer[]): void { + battleStatOrder.map((s, i) => { + this.statNumbers[i].setFrame(battleStats[s].toString()); + }); + } } export class PlayerBattleInfo extends BattleInfo { From 93765d41215fc006b790695f5af16ad3523d33b9 Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Tue, 30 Apr 2024 23:23:32 -0400 Subject: [PATCH 04/72] Update battle info on stat change --- src/data/move.ts | 6 ++++++ src/field/pokemon.ts | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/data/move.ts b/src/data/move.ts index 5d5fec95729..ccf3872b473 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -1552,6 +1552,8 @@ export class CopyStatsAttr extends MoveEffectAttr { else user.removeTag(BattlerTagType.CRIT_BOOST); + user.updateInfo(); + target.scene.queueMessage(getPokemonMessage(user, 'copied\n') + getPokemonMessage(target, `'s stat changes!`)); return true; @@ -1566,6 +1568,8 @@ export class InvertStatsAttr extends MoveEffectAttr { for (let s = 0; s < target.summonData.battleStats.length; s++) target.summonData.battleStats[s] *= -1; + user.updateInfo(); + target.scene.queueMessage(getPokemonMessage(target, `'s stat changes\nwere all reversed!`)); return true; @@ -1580,6 +1584,8 @@ export class ResetStatsAttr extends MoveEffectAttr { for (let s = 0; s < target.summonData.battleStats.length; s++) target.summonData.battleStats[s] = 0; + user.updateInfo(); + target.scene.queueMessage(getPokemonMessage(target, `'s stat changes\nwere eliminated!`)); return true; diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 7072875d3ce..55036e1906d 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -1624,6 +1624,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.summonData.tags.push(tag); if (this instanceof PlayerPokemon && source.summonData.battleStats.find(bs => bs === 6)) this.scene.validateAchv(achvs.TRANSFER_MAX_BATTLE_STAT); + this.updateInfo(); } getMoveHistory(): TurnMove[] { @@ -1924,6 +1925,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } this.summonDataPrimer = null; } + this.updateInfo(); } resetBattleData(): void { From 7ad9c67673d348651e26f499c7e6dd5d7390953b Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Tue, 30 Apr 2024 23:27:22 -0400 Subject: [PATCH 05/72] Fix crash on catch --- src/battle-scene.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 39eb912ef87..8f07256e327 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -1438,7 +1438,7 @@ export default class BattleScene extends SceneBase { } else { let pressed = false; if (this.buttonJustReleased(Button.STATS) || (pressed = this.buttonJustPressed(Button.STATS))) { - for (let p of this.getField().filter(p => p)) + for (let p of this.getField().filter(p => p?.isActive(true))) p.toggleStats(pressed); if (pressed) this.setLastProcessedMovementTime(Button.STATS); From e06561044010f88e59f53b96d5d7b308f9a29207 Mon Sep 17 00:00:00 2001 From: lucfd <83493765+lucfd@users.noreply.github.com> Date: Tue, 30 Apr 2024 23:30:10 -0400 Subject: [PATCH 06/72] Fixed Dire Claw & Tri-Attack status chances (#367) * created MultiStatusEffectAttr * removed testing stuff * switched to randSeedItem --- src/data/move.ts | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/data/move.ts b/src/data/move.ts index ccf3872b473..60e07b8f513 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -1009,6 +1009,25 @@ export class StatusEffectAttr extends MoveEffectAttr { } } +export class MultiStatusEffectAttr extends StatusEffectAttr { + public effects: StatusEffect[]; + + constructor(effects: StatusEffect[], selfTarget?: boolean, cureTurn?: integer, overrideStatus?: boolean) { + super(effects[0], selfTarget, cureTurn, overrideStatus); + this.effects = effects; + } + + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + this.effect = Utils.randSeedItem(this.effects); + const result = super.apply(user, target, move, args); + return result; + } + + getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number { + return !(this.selfTarget ? user : target).status && (this.selfTarget ? user : target).canSetStatus(this.effect, true) ? Math.floor(move.chance * -0.1) : 0; + } +} + export class PsychoShiftEffectAttr extends MoveEffectAttr { constructor() { super(false, MoveEffectTrigger.HIT); @@ -4170,9 +4189,7 @@ export function initMoves() { new SelfStatusMove(Moves.CONVERSION, Type.NORMAL, -1, 30, -1, 0, 1) .attr(FirstMoveTypeAttr), new AttackMove(Moves.TRI_ATTACK, Type.NORMAL, MoveCategory.SPECIAL, 80, 100, 10, 20, 0, 1) - .attr(StatusEffectAttr, StatusEffect.PARALYSIS) - .attr(StatusEffectAttr, StatusEffect.BURN) - .attr(StatusEffectAttr, StatusEffect.FREEZE), + .attr(MultiStatusEffectAttr, [StatusEffect.BURN, StatusEffect.FREEZE, StatusEffect.PARALYSIS]), new AttackMove(Moves.SUPER_FANG, Type.NORMAL, MoveCategory.PHYSICAL, -1, 90, 10, -1, 0, 1) .attr(TargetHalfHpDamageAttr), new AttackMove(Moves.SLASH, Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 20, -1, 0, 1) @@ -5986,9 +6003,7 @@ export function initMoves() { .soundBased() .partial(), new AttackMove(Moves.DIRE_CLAW, Type.POISON, MoveCategory.PHYSICAL, 80, 100, 15, 50, 0, 8) - .attr(StatusEffectAttr, StatusEffect.POISON) - .attr(StatusEffectAttr, StatusEffect.PARALYSIS) - .attr(StatusEffectAttr, StatusEffect.SLEEP), + .attr(MultiStatusEffectAttr, [StatusEffect.POISON, StatusEffect.PARALYSIS, StatusEffect.SLEEP]), new AttackMove(Moves.PSYSHIELD_BASH, Type.PSYCHIC, MoveCategory.PHYSICAL, 70, 90, 10, 100, 0, 8) .attr(StatChangeAttr, BattleStat.DEF, 1, true), new SelfStatusMove(Moves.POWER_SHIFT, Type.NORMAL, -1, 10, 100, 0, 8) From 17ec6b3ccc4b286bca017d23e9935d98de8b9db6 Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Wed, 1 May 2024 00:12:04 -0400 Subject: [PATCH 07/72] Fix start button mapping --- src/battle-scene.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 8f07256e327..0f2f712a501 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -205,8 +205,8 @@ export default class BattleScene extends SceneBase { [Button.SUBMIT]: 17, // touchpad [Button.ACTION]: 0, // X [Button.CANCEL]: 1, // O - [Button.MENU]: 8, // share - [Button.STATS]: 9, // options + [Button.MENU]: 9, // options + [Button.STATS]: 8, // share [Button.CYCLE_SHINY]: 5, // RB [Button.CYCLE_FORM]: 4, // LB [Button.CYCLE_GENDER]: 6, // LT From 77caa8ece5e3ce7f06e3bf694fc1d6628f5fa4c0 Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Wed, 1 May 2024 00:27:11 -0400 Subject: [PATCH 08/72] Add back shift for toggling stats --- src/battle-scene.ts | 4 ++-- src/locales/de/tutorial.ts | 2 +- src/locales/en/tutorial.ts | 2 +- src/locales/es/tutorial.ts | 2 +- src/locales/fr/tutorial.ts | 2 +- src/locales/it/tutorial.ts | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 0f2f712a501..cbf363f689a 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -617,7 +617,7 @@ export default class BattleScene extends SceneBase { [Button.ACTION]: [keyCodes.SPACE, keyCodes.ENTER, keyCodes.Z], [Button.CANCEL]: [keyCodes.BACKSPACE, keyCodes.X], [Button.MENU]: [keyCodes.ESC, keyCodes.M], - [Button.STATS]: [keyCodes.C], + [Button.STATS]: [keyCodes.SHIFT, keyCodes.C], [Button.CYCLE_SHINY]: [keyCodes.R], [Button.CYCLE_FORM]: [keyCodes.F], [Button.CYCLE_GENDER]: [keyCodes.G], @@ -1437,7 +1437,7 @@ export default class BattleScene extends SceneBase { } } else { let pressed = false; - if (this.buttonJustReleased(Button.STATS) || (pressed = this.buttonJustPressed(Button.STATS))) { + if (this.ui && (this.buttonJustReleased(Button.STATS) || (pressed = this.buttonJustPressed(Button.STATS)))) { for (let p of this.getField().filter(p => p?.isActive(true))) p.toggleStats(pressed); if (pressed) diff --git a/src/locales/de/tutorial.ts b/src/locales/de/tutorial.ts index 7a27f2077e6..2773b6710ba 100644 --- a/src/locales/de/tutorial.ts +++ b/src/locales/de/tutorial.ts @@ -22,7 +22,7 @@ export const tutorial: SimpleTranslationEntries = { "statChange": `Stat changes persist across battles as long as your Pokémon aren't recalled. $Your Pokémon are recalled before a trainer battle and before entering a new biome. - $You can also view the stat changes for the Pokémon on the field by holding C.`, + $You can also view the stat changes for the Pokémon on the field by holding C or Shift.`, "selectItem": `After every battle, you are given a choice of 3 random items.\nYou may only pick one. $These range from consumables, to Pokémon held items, to passive permanent items. diff --git a/src/locales/en/tutorial.ts b/src/locales/en/tutorial.ts index 7a27f2077e6..2773b6710ba 100644 --- a/src/locales/en/tutorial.ts +++ b/src/locales/en/tutorial.ts @@ -22,7 +22,7 @@ export const tutorial: SimpleTranslationEntries = { "statChange": `Stat changes persist across battles as long as your Pokémon aren't recalled. $Your Pokémon are recalled before a trainer battle and before entering a new biome. - $You can also view the stat changes for the Pokémon on the field by holding C.`, + $You can also view the stat changes for the Pokémon on the field by holding C or Shift.`, "selectItem": `After every battle, you are given a choice of 3 random items.\nYou may only pick one. $These range from consumables, to Pokémon held items, to passive permanent items. diff --git a/src/locales/es/tutorial.ts b/src/locales/es/tutorial.ts index 7a27f2077e6..2773b6710ba 100644 --- a/src/locales/es/tutorial.ts +++ b/src/locales/es/tutorial.ts @@ -22,7 +22,7 @@ export const tutorial: SimpleTranslationEntries = { "statChange": `Stat changes persist across battles as long as your Pokémon aren't recalled. $Your Pokémon are recalled before a trainer battle and before entering a new biome. - $You can also view the stat changes for the Pokémon on the field by holding C.`, + $You can also view the stat changes for the Pokémon on the field by holding C or Shift.`, "selectItem": `After every battle, you are given a choice of 3 random items.\nYou may only pick one. $These range from consumables, to Pokémon held items, to passive permanent items. diff --git a/src/locales/fr/tutorial.ts b/src/locales/fr/tutorial.ts index e280ee2d5dc..b60ccc03b5d 100644 --- a/src/locales/fr/tutorial.ts +++ b/src/locales/fr/tutorial.ts @@ -27,7 +27,7 @@ export const tutorial: SimpleTranslationEntries = { "statChange": `Stat changes persist across battles as long as your Pokémon aren't recalled. $Your Pokémon are recalled before a trainer battle and before entering a new biome. - $You can also view the stat changes for the Pokémon on the field by holding C.`, + $You can also view the stat changes for the Pokémon on the field by holding C or Shift.`, "selectItem": `Après chaque combat, vous avez le choix entre 3 objets\ntirés au sort. Vous ne pouvez en prendre qu’un. $Cela peut être des objets consommables, des objets à\nfaire tenir, ou des objets passifs aux effets permanents. diff --git a/src/locales/it/tutorial.ts b/src/locales/it/tutorial.ts index 7a27f2077e6..2773b6710ba 100644 --- a/src/locales/it/tutorial.ts +++ b/src/locales/it/tutorial.ts @@ -22,7 +22,7 @@ export const tutorial: SimpleTranslationEntries = { "statChange": `Stat changes persist across battles as long as your Pokémon aren't recalled. $Your Pokémon are recalled before a trainer battle and before entering a new biome. - $You can also view the stat changes for the Pokémon on the field by holding C.`, + $You can also view the stat changes for the Pokémon on the field by holding C or Shift.`, "selectItem": `After every battle, you are given a choice of 3 random items.\nYou may only pick one. $These range from consumables, to Pokémon held items, to passive permanent items. From eac9b4d385a137e24601953ae1dd237ef6cdcd14 Mon Sep 17 00:00:00 2001 From: TeKrop Date: Wed, 1 May 2024 00:11:05 +0200 Subject: [PATCH 09/72] fix: reworked daily and weekly rankings translations workflow --- src/locales/de/menu.ts | 2 +- src/locales/en/menu.ts | 2 +- src/locales/es/menu.ts | 2 +- src/locales/fr/menu.ts | 2 +- src/locales/it/menu.ts | 2 +- src/ui/daily-run-scoreboard.ts | 5 +++-- 6 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/locales/de/menu.ts b/src/locales/de/menu.ts index 4876fa3432a..442cfae218f 100644 --- a/src/locales/de/menu.ts +++ b/src/locales/de/menu.ts @@ -59,8 +59,8 @@ export const menu: SimpleTranslationEntries = { "escapeVerbSwitch": "auswechseln", "escapeVerbFlee": "flucht", "notDisabled": "{{moveName}} ist\nnicht mehr deaktiviert!", - "rankings": "Rankings", "dailyRankings": "Daily Rankings", + "weeklyRankings": "Weekly Rankings", "noRankings": "No Rankings", "loading": "Loading…", "playersOnline": "Players Online" diff --git a/src/locales/en/menu.ts b/src/locales/en/menu.ts index 1d840a3eb03..82a09e49d4f 100644 --- a/src/locales/en/menu.ts +++ b/src/locales/en/menu.ts @@ -78,8 +78,8 @@ export const menu: SimpleTranslationEntries = { "skipItemQuestion": "Are you sure you want to skip taking an item?", "eggHatching": "Oh?", "ivScannerUseQuestion": "Use IV Scanner on {{pokemonName}}?", - "rankings": "Rankings", "dailyRankings": "Daily Rankings", + "weeklyRankings": "Weekly Rankings", "noRankings": "No Rankings", "loading": "Loading…", "playersOnline": "Players Online" diff --git a/src/locales/es/menu.ts b/src/locales/es/menu.ts index e72710cee37..5dccc2e4eb3 100644 --- a/src/locales/es/menu.ts +++ b/src/locales/es/menu.ts @@ -62,8 +62,8 @@ export const menu: SimpleTranslationEntries = { "skipItemQuestion": "¿Estás seguro de que no quieres coger un objeto?", "eggHatching": "¿Y esto?", "ivScannerUseQuestion": "¿Quieres usar el Escáner de IVs en {{pokemonName}}?", - "rankings": "Rankings", "dailyRankings": "Daily Rankings", + "weeklyRankings": "Weekly Rankings", "noRankings": "No Rankings", "loading": "Loading…", "playersOnline": "Players Online" diff --git a/src/locales/fr/menu.ts b/src/locales/fr/menu.ts index 037f0f3b5e2..d5478c67a26 100644 --- a/src/locales/fr/menu.ts +++ b/src/locales/fr/menu.ts @@ -73,8 +73,8 @@ export const menu: SimpleTranslationEntries = { "skipItemQuestion": "Êtes-vous sûr·e de ne pas vouloir prendre d’objet ?", "eggHatching": "Oh ?", "ivScannerUseQuestion": "Utiliser le Scanner d’IV sur {{pokemonName}} ?", - "rankings": "Classement", "dailyRankings": "Classement du Jour", + "weeklyRankings": "Classement de la Semaine", "noRankings": "Pas de Classement", "loading": "Chargement…", "playersOnline": "Joueurs Connectés" diff --git a/src/locales/it/menu.ts b/src/locales/it/menu.ts index b9e288c26ce..c37a37b5169 100644 --- a/src/locales/it/menu.ts +++ b/src/locales/it/menu.ts @@ -7,8 +7,8 @@ export const menu: SimpleTranslationEntries = { "loadGame": "Carica Partita", "dailyRun": "Corsa Giornaliera (Beta)", "selectGameMode": "Seleziona una modalità di gioco.", - "rankings": "Rankings", "dailyRankings": "Daily Rankings", + "weeklyRankings": "Weekly Rankings", "noRankings": "No Rankings", "loading": "Loading…", "playersOnline": "Players Online" diff --git a/src/ui/daily-run-scoreboard.ts b/src/ui/daily-run-scoreboard.ts index 1379ec6a8ef..8f7ca0bf110 100644 --- a/src/ui/daily-run-scoreboard.ts +++ b/src/ui/daily-run-scoreboard.ts @@ -11,6 +11,7 @@ interface RankingEntry { wave: integer } +// Don't forget to update translations when adding a new category enum ScoreboardCategory { DAILY, WEEKLY @@ -40,7 +41,7 @@ export class DailyRunScoreboard extends Phaser.GameObjects.Container { const titleWindow = addWindow(this.scene, 0, 0, 114, 18, false, false, null, null, WindowVariant.THIN); this.add(titleWindow); - this.titleLabel = addTextObject(this.scene, titleWindow.displayWidth / 2, titleWindow.displayHeight / 2, i18next.t('menu:dailyRankings'), TextStyle.WINDOW, { fontSize: '64px' }); + this.titleLabel = addTextObject(this.scene, titleWindow.displayWidth / 2, titleWindow.displayHeight / 2, i18next.t('menu:loading'), TextStyle.WINDOW, { fontSize: '64px' }); this.titleLabel.setOrigin(0.5, 0.5); this.add(this.titleLabel); @@ -156,7 +157,7 @@ export class DailyRunScoreboard extends Phaser.GameObjects.Container { .then(jsonResponse => { this.page = page; this.category = category; - this.titleLabel.setText(`${Utils.toReadableString(ScoreboardCategory[category])} ${i18next.t("menu:rankings")}`); + this.titleLabel.setText(`${i18next.t(`menu:${ScoreboardCategory[category].toLowerCase()}Rankings`)}`); this.prevPageButton.setAlpha(page > 1 ? 1 : 0.5); this.nextPageButton.setAlpha(page < this.pageCount ? 1 : 0.5); this.pageNumberLabel.setText(page.toString()); From 3b09e176a29922ef8a20d028eb345eb72bc3df66 Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Wed, 1 May 2024 09:44:57 -0400 Subject: [PATCH 10/72] Fix IV text not comparing against starter species --- src/data/pokemon-species.ts | 4 ++-- src/ui/battle-message-ui-handler.ts | 6 ++++-- src/ui/pokemon-info-container.ts | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index 4136be5b70f..2f8edefa403 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -138,9 +138,9 @@ export abstract class PokemonSpeciesForm { this.genderDiffs = genderDiffs; } - getRootSpeciesId(): Species { + getRootSpeciesId(forStarter: boolean = false): Species { let ret = this.speciesId; - while (pokemonPrevolutions.hasOwnProperty(ret)) + while (pokemonPrevolutions.hasOwnProperty(ret) && (!forStarter || !speciesStarters.hasOwnProperty(ret))) ret = pokemonPrevolutions[ret]; return ret; } diff --git a/src/ui/battle-message-ui-handler.ts b/src/ui/battle-message-ui-handler.ts index 77144d6bbc0..7819017d896 100644 --- a/src/ui/battle-message-ui-handler.ts +++ b/src/ui/battle-message-ui-handler.ts @@ -5,6 +5,7 @@ import * as Utils from "../utils"; import MessageUiHandler from "./message-ui-handler"; import { getStatName, Stat } from "../data/pokemon-stat"; import { addWindow } from "./ui-theme"; +import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext"; export default class BattleMessageUiHandler extends MessageUiHandler { private levelUpStatsContainer: Phaser.GameObjects.Container; @@ -223,8 +224,9 @@ export default class BattleMessageUiHandler extends MessageUiHandler { } getIvDescriptor(value: integer, typeIv: integer): string { - let starterIvs: number[] = this.scene.gameData.dexData[this.scene.getEnemyPokemon().species.speciesId].ivs; - let uiTheme = (this.scene as BattleScene).uiTheme; // Assuming uiTheme is accessible + const starterSpecies = this.scene.getEnemyPokemon().species.getRootSpeciesId(true); + const starterIvs: number[] = this.scene.gameData.dexData[starterSpecies].ivs; + const uiTheme = (this.scene as BattleScene).uiTheme; // Assuming uiTheme is accessible // Function to wrap text in color based on comparison const coloredText = (text: string, isBetter: boolean) => { diff --git a/src/ui/pokemon-info-container.ts b/src/ui/pokemon-info-container.ts index 4d8ecfe0b03..572a28f10c8 100644 --- a/src/ui/pokemon-info-container.ts +++ b/src/ui/pokemon-info-container.ts @@ -161,8 +161,9 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { if (isFusion) this.pokemonFusionShinyIcon.setTint(getVariantTint(pokemon.fusionVariant)); - const originalIvs: integer[] = this.scene.gameData.dexData[pokemon.species.speciesId].caughtAttr - ? this.scene.gameData.dexData[pokemon.species.speciesId].ivs + const starterSpeciesId = pokemon.species.getRootSpeciesId(true); + const originalIvs: integer[] = this.scene.gameData.dexData[starterSpeciesId].caughtAttr + ? this.scene.gameData.dexData[starterSpeciesId].ivs : null; this.statsContainer.updateIvs(pokemon.ivs, originalIvs); From fc1a9f02837af4ebd5aee428e80d886a7b158e17 Mon Sep 17 00:00:00 2001 From: thicco-catto <67873211+thicco-catto@users.noreply.github.com> Date: Wed, 1 May 2024 16:16:58 +0200 Subject: [PATCH 11/72] Select Move UI Shows PP (#372) * Select move UI shows PP * Removed testing forced max pp * PP only shows when using PP restoring items * Removed testing max pp again * Update src/phases.ts * Update src/ui/party-ui-handler.ts --------- Co-authored-by: Samuel H --- src/phases.ts | 5 +++-- src/ui/party-ui-handler.ts | 11 ++++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/phases.ts b/src/phases.ts index ceba555f2ce..ad2a7537de7 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -19,7 +19,7 @@ import { BattleStat, getBattleStatLevelChangeDescription, getBattleStatName } fr import { biomeLinks, getBiomeName } from "./data/biomes"; import { Biome } from "./data/enums/biome"; import { ModifierTier } from "./modifier/modifier-tier"; -import { FusePokemonModifierType, ModifierPoolType, ModifierType, ModifierTypeFunc, ModifierTypeOption, PokemonModifierType, PokemonMoveModifierType, RememberMoveModifierType, TmModifierType, getDailyRunStarterModifiers, getEnemyBuffModifierForWave, getModifierType, getPlayerModifierTypeOptions, getPlayerShopModifierTypeOptionsForWave, modifierTypes, regenerateModifierPoolThresholds } from "./modifier/modifier-type"; +import { FusePokemonModifierType, ModifierPoolType, ModifierType, ModifierTypeFunc, ModifierTypeOption, PokemonModifierType, PokemonMoveModifierType, PokemonPpRestoreModifierType, PokemonPpUpModifierType, RememberMoveModifierType, TmModifierType, getDailyRunStarterModifiers, getEnemyBuffModifierForWave, getModifierType, getPlayerModifierTypeOptions, getPlayerShopModifierTypeOptionsForWave, modifierTypes, regenerateModifierPoolThresholds } from "./modifier/modifier-type"; import SoundFade from "phaser3-rex-plugins/plugins/soundfade"; import { BattlerTagLapseType, EncoreTag, HideSpriteTag as HiddenTag, ProtectedTag, TrappedTag } from "./data/battler-tags"; import { BattlerTagType } from "./data/enums/battler-tag-type"; @@ -4340,6 +4340,7 @@ export class SelectModifierPhase extends BattlePhase { const isMoveModifier = modifierType instanceof PokemonMoveModifierType; const isTmModifier = modifierType instanceof TmModifierType; const isRememberMoveModifier = modifierType instanceof RememberMoveModifierType; + const isPpRestoreModifier = modifierType instanceof PokemonPpRestoreModifierType; const partyUiMode = isMoveModifier ? PartyUiMode.MOVE_MODIFIER : isTmModifier ? PartyUiMode.TM_MODIFIER : isRememberMoveModifier ? PartyUiMode.REMEMBER_MOVE_MODIFIER @@ -4359,7 +4360,7 @@ export class SelectModifierPhase extends BattlePhase { }); } else this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers)); - }, pokemonModifierType.selectFilter, modifierType instanceof PokemonMoveModifierType ? (modifierType as PokemonMoveModifierType).moveSelectFilter : undefined, tmMoveId); + }, pokemonModifierType.selectFilter, modifierType instanceof PokemonMoveModifierType ? (modifierType as PokemonMoveModifierType).moveSelectFilter : undefined, tmMoveId, isPpRestoreModifier); } } else applyModifier(modifierType.newModifier()); diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts index 29a4037f12f..35014fa7027 100644 --- a/src/ui/party-ui-handler.ts +++ b/src/ui/party-ui-handler.ts @@ -90,6 +90,7 @@ export default class PartyUiHandler extends MessageUiHandler { private selectFilter: PokemonSelectFilter | PokemonModifierTransferSelectFilter; private moveSelectFilter: PokemonMoveSelectFilter; private tmMoveId: Moves; + private showMovePp: boolean; private iconAnimHandler: PokemonIconAnimHandler; @@ -185,6 +186,7 @@ export default class PartyUiHandler extends MessageUiHandler { ? args[4] as PokemonMoveSelectFilter : PartyUiHandler.FilterAllMoves; this.tmMoveId = args.length > 5 && args[5] ? args[5] : Moves.NONE; + this.showMovePp = args.length > 6 && args[6]; this.partyContainer.setVisible(true); this.partyBg.setTexture(`party_bg${this.scene.currentBattle.double ? '_double' : ''}`); @@ -663,7 +665,14 @@ export default class PartyUiHandler extends MessageUiHandler { case PartyOption.MOVE_2: case PartyOption.MOVE_3: case PartyOption.MOVE_4: - optionName = pokemon.moveset[option - PartyOption.MOVE_1].getName(); + const move = pokemon.moveset[option - PartyOption.MOVE_1]; + if(this.showMovePp) { + const maxPP = move.getMovePp(); + const currPP = maxPP - move.ppUsed; + optionName = `${move.getName()} ${currPP}/${maxPP}`; + } else { + optionName = move.getName(); + } break; default: if (formChangeItemModifiers && option >= PartyOption.FORM_CHANGE_ITEM) { From 56b24c70b6c7b5ddc1c51b6bdaa20c01d7fa2810 Mon Sep 17 00:00:00 2001 From: Mistmemo <114654503+LeoDoby@users.noreply.github.com> Date: Wed, 1 May 2024 16:50:13 +0200 Subject: [PATCH 12/72] fix double battle iv scanner color (#379) * Add color for the IV scanner add a new color SUMMARY_GREEN in text.js, add the green color if the iv of the pokemon is better than the iv on the starter of that pokemon Co-authored-by: EmoUsedHM01 <131687820+emousedhm01@users.noreply.github.com> * fix battle-message-ui-handler.ts formatting * fix missing similicon battle-message-ui-handler.ts * modified so it take a boolean instead of doing lot of else if battle-message-ui-handler.ts * Fix iv scanner only doing color for the right pokemon in double fight --------- Co-authored-by: EmoUsedHM01 <131687820+emousedhm01@users.noreply.github.com> --- src/ui/battle-message-ui-handler.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ui/battle-message-ui-handler.ts b/src/ui/battle-message-ui-handler.ts index 7819017d896..5e2cb56518f 100644 --- a/src/ui/battle-message-ui-handler.ts +++ b/src/ui/battle-message-ui-handler.ts @@ -210,7 +210,7 @@ export default class BattleMessageUiHandler extends MessageUiHandler { } else shownStats = stats; for (let s of stats) - levelUpStatsValuesText += `${shownStats.indexOf(s) > -1 ? this.getIvDescriptor(ivs[s], s) : '???'}\n`; + levelUpStatsValuesText += `${shownStats.indexOf(s) > -1 ? this.getIvDescriptor(ivs[s], s, pokemonId) : '???'}\n`; this.levelUpStatsValuesContent.text = levelUpStatsValuesText; this.levelUpStatsIncrContent.setVisible(false); this.levelUpStatsContainer.setVisible(true); @@ -223,8 +223,8 @@ export default class BattleMessageUiHandler extends MessageUiHandler { }); } - getIvDescriptor(value: integer, typeIv: integer): string { - const starterSpecies = this.scene.getEnemyPokemon().species.getRootSpeciesId(true); + getIvDescriptor(value: integer, typeIv: integer, pokemonId: integer): string { + const starterSpecies = this.scene.getPokemonById(pokemonId).species.getRootSpeciesId(true); const starterIvs: number[] = this.scene.gameData.dexData[starterSpecies].ivs; const uiTheme = (this.scene as BattleScene).uiTheme; // Assuming uiTheme is accessible From c8583d6c69efdb45a0bc9c80646e5d0fdcb8919f Mon Sep 17 00:00:00 2001 From: Thomas David <66013753+Kiriox94@users.noreply.github.com> Date: Sat, 27 Apr 2024 11:30:23 +0200 Subject: [PATCH 13/72] Update manifest.webmanifest --- public/manifest.webmanifest | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/manifest.webmanifest b/public/manifest.webmanifest index e6eedd27e2f..c75c70a8d45 100644 --- a/public/manifest.webmanifest +++ b/public/manifest.webmanifest @@ -4,7 +4,8 @@ "description": "A Pokémon fangame heavily inspired by the roguelite genre. Battle endlessly while gathering stacking items, exploring many different biomes, and reaching Pokémon stats you never thought possible.", "scope": "/", "start_url": "/", - "display": "standalone", + "display": "fullscreen", + "orientation": "landscape", "background_color": "#8c8c8c", "theme_color": "#8c8c8c", "icons": [ From 68f33266070893aa42138868cea1d903a926bc09 Mon Sep 17 00:00:00 2001 From: Madmadness65 Date: Wed, 1 May 2024 12:21:22 -0500 Subject: [PATCH 14/72] Add Heal Block back to level up learnsets The move itself is still not functional yet, but will be valuable for Endless when it is. Also made Curse's flavor text accurate to the canon games. --- src/data/move.ts | 2 +- src/data/pokemon-level-moves.ts | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/data/move.ts b/src/data/move.ts index 60e07b8f513..6ece04c70c4 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -2615,7 +2615,7 @@ export class CurseAttr extends MoveEffectAttr { } let curseRecoilDamage = Math.floor(user.getMaxHp() / 2); user.damageAndUpdate(curseRecoilDamage, HitResult.OTHER, false, true, true); - user.scene.queueMessage(getPokemonMessage(user, ' cut its own HP!')); + user.scene.queueMessage(getPokemonMessage(user, ` cut its own HP\nand laid a curse on the ${target.name}!`)); target.addTag(BattlerTagType.CURSED, 0, move.id, user.id); return true; } else { diff --git a/src/data/pokemon-level-moves.ts b/src/data/pokemon-level-moves.ts index 07691b01eff..0b545d1bd63 100644 --- a/src/data/pokemon-level-moves.ts +++ b/src/data/pokemon-level-moves.ts @@ -4278,6 +4278,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 30, Moves.ANCIENT_POWER ], [ 40, Moves.LIFE_DEW ], [ 50, Moves.LEECH_SEED ], + [ 55, Moves.HEAL_BLOCK ], [ 60, Moves.RECOVER ], [ 70, Moves.FUTURE_SIGHT ], [ 80, Moves.HEALING_WISH ], @@ -4976,6 +4977,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 23, Moves.ABSORB ], [ 29, Moves.SHADOW_SNEAK ], [ 36, Moves.FURY_SWIPES ], + [ 41, Moves.HEAL_BLOCK ], [ 43, Moves.MIND_READER ], [ 50, Moves.SHADOW_BALL ], [ 57, Moves.SPITE ], @@ -5796,6 +5798,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 20, Moves.PSYSHOCK ], [ 25, Moves.COSMIC_POWER ], [ 30, Moves.PSYCHIC ], + [ 33, Moves.HEAL_BLOCK ], [ 35, Moves.STONE_EDGE ], [ 40, Moves.FUTURE_SIGHT ], [ 45, Moves.MAGIC_ROOM ], @@ -5814,6 +5817,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 20, Moves.ZEN_HEADBUTT ], [ 25, Moves.COSMIC_POWER ], [ 30, Moves.PSYCHIC ], + [ 33, Moves.HEAL_BLOCK ], [ 35, Moves.STONE_EDGE ], [ 40, Moves.SOLAR_BEAM ], [ 45, Moves.WONDER_ROOM ], @@ -5890,6 +5894,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 3, Moves.RAPID_SPIN ], [ 6, Moves.CONFUSION ], [ 9, Moves.ROCK_TOMB ], + [ 10, Moves.HEAL_BLOCK ], [ 12, Moves.POWER_TRICK ], [ 15, Moves.PSYBEAM ], [ 18, Moves.ANCIENT_POWER ], @@ -5911,6 +5916,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 1, Moves.MUD_SLAP ], [ 1, Moves.RAPID_SPIN ], [ 9, Moves.ROCK_TOMB ], + [ 10, Moves.HEAL_BLOCK ], [ 12, Moves.POWER_TRICK ], [ 15, Moves.PSYBEAM ], [ 18, Moves.ANCIENT_POWER ], @@ -6506,6 +6512,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [Species.LATIOS]: [ [ 1, Moves.DRAGON_DANCE ], [ 1, Moves.STORED_POWER ], + [ 1, Moves.HEAL_BLOCK ], [ 5, Moves.HELPING_HAND ], [ 10, Moves.RECOVER ], [ 15, Moves.CONFUSION ], @@ -7364,6 +7371,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 36, Moves.IRON_DEFENSE ], [ 40, Moves.METAL_SOUND ], [ 44, Moves.FUTURE_SIGHT ], + [ 45, Moves.HEAL_BLOCK ], ], [Species.BRONZONG]: [ [ 0, Moves.BLOCK ], @@ -7382,6 +7390,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 38, Moves.IRON_DEFENSE ], [ 44, Moves.METAL_SOUND ], [ 50, Moves.FUTURE_SIGHT ], + [ 52, Moves.HEAL_BLOCK ], [ 56, Moves.RAIN_DANCE ], ], [Species.BONSLY]: [ @@ -9491,6 +9500,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [Species.YAMASK]: [ [ 1, Moves.PROTECT ], [ 1, Moves.ASTONISH ], + [ 1, Moves.HEAL_BLOCK ], [ 4, Moves.HAZE ], [ 8, Moves.NIGHT_SHADE ], [ 12, Moves.DISABLE ], @@ -9513,6 +9523,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 1, Moves.PROTECT ], [ 1, Moves.SCARY_FACE ], [ 1, Moves.ASTONISH ], + [ 1, Moves.HEAL_BLOCK ], [ 12, Moves.DISABLE ], [ 16, Moves.WILL_O_WISP ], [ 20, Moves.CRAFTY_SHIELD ], @@ -9720,6 +9731,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 24, Moves.HYPNOSIS ], [ 28, Moves.FAKE_TEARS ], [ 33, Moves.PSYCH_UP ], + [ 34, Moves.HEAL_BLOCK ], [ 36, Moves.PSYCHIC ], [ 40, Moves.FLATTER ], [ 44, Moves.FUTURE_SIGHT ], @@ -9735,6 +9747,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 20, Moves.PSYSHOCK ], [ 24, Moves.HYPNOSIS ], [ 28, Moves.FAKE_TEARS ], + [ 34, Moves.HEAL_BLOCK ], [ 35, Moves.PSYCH_UP ], [ 46, Moves.FLATTER ], [ 52, Moves.FUTURE_SIGHT ], @@ -9750,6 +9763,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 20, Moves.PSYSHOCK ], [ 24, Moves.HYPNOSIS ], [ 28, Moves.FAKE_TEARS ], + [ 34, Moves.HEAL_BLOCK ], [ 35, Moves.PSYCH_UP ], [ 40, Moves.PSYCHIC ], [ 48, Moves.FLATTER ], @@ -9771,6 +9785,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 36, Moves.PSYCHIC ], [ 40, Moves.SKILL_SWAP ], [ 44, Moves.FUTURE_SIGHT ], + [ 46, Moves.HEAL_BLOCK ], [ 48, Moves.WONDER_ROOM ], ], [Species.DUOSION]: [ @@ -9787,6 +9802,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 35, Moves.PAIN_SPLIT ], [ 40, Moves.PSYCHIC ], [ 46, Moves.SKILL_SWAP ], + [ 50, Moves.HEAL_BLOCK ], [ 52, Moves.FUTURE_SIGHT ], [ 58, Moves.WONDER_ROOM ], ], @@ -9805,6 +9821,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 35, Moves.PAIN_SPLIT ], [ 40, Moves.PSYCHIC ], [ 48, Moves.SKILL_SWAP ], + [ 54, Moves.HEAL_BLOCK ], [ 56, Moves.FUTURE_SIGHT ], [ 64, Moves.WONDER_ROOM ], ], @@ -10209,6 +10226,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 1, Moves.GROWL ], [ 1, Moves.CONFUSION ], [ 6, Moves.IMPRISON ], + [ 8, Moves.HEAL_BLOCK ], [ 12, Moves.TELEPORT ], [ 18, Moves.PSYBEAM ], [ 24, Moves.GUARD_SPLIT ], @@ -10226,6 +10244,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 1, Moves.TELEPORT ], [ 1, Moves.IMPRISON ], [ 1, Moves.PSYCHIC_TERRAIN ], + [ 8, Moves.HEAL_BLOCK ], [ 18, Moves.PSYBEAM ], [ 24, Moves.GUARD_SPLIT ], [ 24, Moves.POWER_SPLIT ], @@ -10884,6 +10903,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 20, Moves.SHOCK_WAVE ], [ 25, Moves.AGILITY ], [ 30, Moves.CHARGE ], + [ 31, Moves.HEAL_BLOCK ], [ 35, Moves.VOLT_SWITCH ], [ 40, Moves.CRUNCH ], [ 45, Moves.DISCHARGE ], @@ -11972,6 +11992,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 40, Moves.PLAY_ROUGH ], [ 44, Moves.MAGIC_ROOM ], [ 48, Moves.FOUL_PLAY ], + [ 50, Moves.HEAL_BLOCK ], [ 52, Moves.LAST_RESORT ], ], [Species.PHANTUMP]: [ @@ -13045,6 +13066,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 45, Moves.IRON_HEAD ], [ 50, Moves.TAKE_DOWN ], [ 55, Moves.DOUBLE_EDGE ], + [ 60, Moves.HEAL_BLOCK ], ], [Species.SILVALLY]: [ [ 0, Moves.MULTI_ATTACK ], @@ -13059,6 +13081,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 1, Moves.ICE_FANG ], [ 1, Moves.FIRE_FANG ], [ 1, Moves.IRON_HEAD ], + [ 1, Moves.HEAL_BLOCK ], [ 15, Moves.DOUBLE_HIT ], [ 20, Moves.METAL_SOUND ], [ 25, Moves.CRUSH_CLAW ], From e6c31966d79e71746f0893f4354d6890ebb88b3c Mon Sep 17 00:00:00 2001 From: dielle000 <168655502+dielle000@users.noreply.github.com> Date: Wed, 1 May 2024 21:10:31 +0200 Subject: [PATCH 15/72] Change pokemon stats chart Stats are arranged like in the mainline games --- src/ui/stats-container.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ui/stats-container.ts b/src/ui/stats-container.ts index 0144658051f..b8d9c59a4d7 100644 --- a/src/ui/stats-container.ts +++ b/src/ui/stats-container.ts @@ -4,7 +4,8 @@ import { Stat, getStatName } from "../data/pokemon-stat"; import { TextStyle, addBBCodeTextObject, addTextObject, getTextColor } from "./text"; const ivChartSize = 24; -const ivChartStatCoordMultipliers = [ [ 0, 1 ], [ 0.825, 0.5 ], [ 0.825, -0.5 ], [ 0, -1 ], [ -0.825, -0.5 ], [ -0.825, 0.5 ] ]; +const ivChartStatCoordMultipliers = [ [ 0, -1 ], [ 0.825, -0.5 ], [ 0.825, 0.5 ], [ -0.825, -0.5 ], [ -0.825, 0.5 ], [ 0, 1 ] ]; +const ivChartStatIndexes = [0,1,2,5,4,3] // swap special attack and speed const defaultIvChartData = new Array(12).fill(null).map(() => 0); export class StatsContainer extends Phaser.GameObjects.Container { @@ -22,7 +23,7 @@ export class StatsContainer extends Phaser.GameObjects.Container { } setup() { - const ivChartBgData = new Array(6).fill(null).map((_, i: integer) => [ ivChartSize * ivChartStatCoordMultipliers[i][0], ivChartSize * ivChartStatCoordMultipliers[i][1] ] ).flat(); + const ivChartBgData = new Array(6).fill(null).map((_, i: integer) => [ ivChartSize * ivChartStatCoordMultipliers[ivChartStatIndexes[i]][0], ivChartSize * ivChartStatCoordMultipliers[ivChartStatIndexes[i]][1] ] ).flat(); const ivChartBg = this.scene.add.polygon(48, 44, ivChartBgData, 0xd8e0f0, 0.625); ivChartBg.setOrigin(0, 0); @@ -62,7 +63,7 @@ export class StatsContainer extends Phaser.GameObjects.Container { updateIvs(ivs: integer[], originalIvs?: integer[]): void { if (ivs) { - const ivChartData = new Array(6).fill(null).map((_, i) => [ (ivs[i] / 31) * ivChartSize * ivChartStatCoordMultipliers[i][0], (ivs[i] / 31) * ivChartSize * ivChartStatCoordMultipliers[i][1] ] ).flat(); + const ivChartData = new Array(6).fill(null).map((_, i) => [ (ivs[ivChartStatIndexes[i]] / 31) * ivChartSize * ivChartStatCoordMultipliers[ivChartStatIndexes[i]][0], (ivs[ivChartStatIndexes[i]] / 31) * ivChartSize * ivChartStatCoordMultipliers[ivChartStatIndexes[i]][1] ] ).flat(); const lastIvChartData = this.statsIvsCache || defaultIvChartData; this.statsIvsCache = ivChartData.slice(0); From 10169382d95b8249dbb8023d1051646d890debd1 Mon Sep 17 00:00:00 2001 From: InfernoVulpix <66154242+InfernoVulpix@users.noreply.github.com> Date: Wed, 1 May 2024 16:14:19 -0400 Subject: [PATCH 16/72] Implemented Synchronoise's effect (#221) * Implemented Synchronoise's effect Tested with Soak, Forest's Curse, and a variety of attacker and defender types. * Fixed Synchronoise double battle functionality It now does zero damage only to targets who do not share any types with it, while correctly damaging any who do. It also fails entirely if the user is UNKNOWN type. --- src/data/move.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/data/move.ts b/src/data/move.ts index 6ece04c70c4..78c47e1ea66 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -3706,6 +3706,19 @@ export class FirstMoveCondition extends MoveCondition { } } +export class hitsSameTypeAttr extends VariableMoveTypeMultiplierAttr { + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + const multiplier = args[0] as Utils.NumberHolder; + if (!user.getTypes().some(type => target.getTypes().includes(type))){ + multiplier.value = 0; + return true; + } + return false; + } +} + +const unknownTypeCondition: MoveConditionFunc = (user, target, move) => !user.getTypes().includes(Type.UNKNOWN); + export type MoveTargetSet = { targets: BattlerIndex[]; multiple: boolean; @@ -5087,7 +5100,8 @@ export function initMoves() { .condition(failOnMaxCondition), new AttackMove(Moves.SYNCHRONOISE, Type.PSYCHIC, MoveCategory.SPECIAL, 120, 100, 10, -1, 0, 5) .target(MoveTarget.ALL_NEAR_OTHERS) - .partial(), + .condition(unknownTypeCondition) + .attr(hitsSameTypeAttr), new AttackMove(Moves.ELECTRO_BALL, Type.ELECTRIC, MoveCategory.SPECIAL, -1, 100, 10, -1, 0, 5) .attr(BattleStatRatioPowerAttr, Stat.SPD) .ballBombMove(), From d6ca09e4317fa60b15abcd4b7ede5a71d3c9ebea Mon Sep 17 00:00:00 2001 From: Xavion3 Date: Thu, 2 May 2024 06:36:47 +1000 Subject: [PATCH 17/72] Implement Belch --- src/data/berry.ts | 12 ++++++++++++ src/data/move.ts | 2 +- src/field/pokemon.ts | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/data/berry.ts b/src/data/berry.ts index b28772373b1..1228bb54904 100644 --- a/src/data/berry.ts +++ b/src/data/berry.ts @@ -99,6 +99,8 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc { case BerryType.SITRUS: case BerryType.ENIGMA: return (pokemon: Pokemon) => { + if (pokemon.battleData) + pokemon.battleData.berriesEaten.push(berryType); const hpHealed = new Utils.NumberHolder(Math.floor(pokemon.getMaxHp() / 4)); applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, hpHealed); pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(), @@ -106,6 +108,8 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc { }; case BerryType.LUM: return (pokemon: Pokemon) => { + if (pokemon.battleData) + pokemon.battleData.berriesEaten.push(berryType); if (pokemon.status) { pokemon.scene.queueMessage(getPokemonMessage(pokemon, getStatusEffectHealText(pokemon.status.effect))); pokemon.resetStatus(); @@ -119,6 +123,8 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc { case BerryType.APICOT: case BerryType.SALAC: return (pokemon: Pokemon) => { + if (pokemon.battleData) + pokemon.battleData.berriesEaten.push(berryType); const battleStat = (berryType - BerryType.LIECHI) as BattleStat; const statLevels = new Utils.NumberHolder(1); applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, statLevels); @@ -126,16 +132,22 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc { }; case BerryType.LANSAT: return (pokemon: Pokemon) => { + if (pokemon.battleData) + pokemon.battleData.berriesEaten.push(berryType); pokemon.addTag(BattlerTagType.CRIT_BOOST); }; case BerryType.STARF: return (pokemon: Pokemon) => { + if (pokemon.battleData) + pokemon.battleData.berriesEaten.push(berryType); const statLevels = new Utils.NumberHolder(2); applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, statLevels); pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ BattleStat.RAND ], statLevels.value)); }; case BerryType.LEPPA: return (pokemon: Pokemon) => { + if (pokemon.battleData) + pokemon.battleData.berriesEaten.push(berryType); const ppRestoreMove = pokemon.getMoveset().find(m => !m.getPpRatio()); ppRestoreMove.ppUsed = Math.max(ppRestoreMove.ppUsed - 10, 0); pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` restored PP to its move ${ppRestoreMove.getName()}\nusing its ${getBerryName(berryType)}!`)); diff --git a/src/data/move.ts b/src/data/move.ts index 78c47e1ea66..8b94756d04b 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -5301,7 +5301,7 @@ export function initMoves() { new StatusMove(Moves.MAT_BLOCK, Type.FIGHTING, -1, 10, -1, 0, 6) .unimplemented(), new AttackMove(Moves.BELCH, Type.POISON, MoveCategory.SPECIAL, 120, 90, 10, -1, 0, 6) - .partial(), + .condition((user, target, move) => user.battleData.berriesEaten.length > 0), new StatusMove(Moves.ROTOTILLER, Type.GROUND, -1, 10, 100, 0, 6) .target(MoveTarget.ALL) .unimplemented(), diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 55036e1906d..ed248f7cc80 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -43,6 +43,7 @@ import { Nature, getNatureStatMultiplier } from '../data/nature'; import { SpeciesFormChange, SpeciesFormChangeActiveTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangeStatusEffectTrigger } from '../data/pokemon-forms'; import { TerrainType } from '../data/terrain'; import { TrainerSlot } from '../data/trainer-config'; +import { BerryType } from '../data/berry'; import { ABILITY_OVERRIDE, MOVE_OVERRIDE, OPP_ABILITY_OVERRIDE, OPP_MOVE_OVERRIDE, OPP_SHINY_OVERRIDE, OPP_VARIANT_OVERRIDE } from '../overrides'; export enum FieldPosition { @@ -2993,6 +2994,7 @@ export class PokemonSummonData { export class PokemonBattleData { public hitCount: integer = 0; public endured: boolean = false; + public berriesEaten: BerryType[] = []; } export class PokemonBattleSummonData { From 5a6ea40dae30a0fe5364acd4054389d34c479095 Mon Sep 17 00:00:00 2001 From: Xavion3 Date: Thu, 2 May 2024 07:09:54 +1000 Subject: [PATCH 18/72] Implement Acrobatics Currently scales from 0-5 items --- src/data/move.ts | 2 +- src/field/pokemon.ts | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/data/move.ts b/src/data/move.ts index 8b94756d04b..a13c1ac8861 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -5171,7 +5171,7 @@ export function initMoves() { new StatusMove(Moves.QUASH, Type.DARK, 100, 15, -1, 0, 5) .unimplemented(), new AttackMove(Moves.ACROBATICS, Type.FLYING, MoveCategory.PHYSICAL, 55, 100, 15, -1, 0, 5) - .partial(), + .attr(MovePowerMultiplierAttr, (user, target, move) => Math.max(1, 2 - 0.2 * user.getHeldItems().reduce((v, m) => v + m.stackCount, 0))), new StatusMove(Moves.REFLECT_TYPE, Type.NORMAL, -1, 15, -1, 0, 5) .attr(CopyTypeAttr), new AttackMove(Moves.RETALIATE, Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 5, -1, 0, 5) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index ed248f7cc80..82915ce41bc 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -456,6 +456,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return 1; } + getHeldItems(): PokemonHeldItemModifier[] { + if (!this.scene) + return []; + return this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier && (m as PokemonHeldItemModifier).pokemonId === this.id, this.isPlayer()) as PokemonHeldItemModifier[]; + } + updateScale(): void { this.setScale(this.getSpriteScale()); } From 0f153d39b1131de54805822be32c790c1363b013 Mon Sep 17 00:00:00 2001 From: Tempoanon <163687446+TempsRay@users.noreply.github.com> Date: Wed, 1 May 2024 17:47:32 -0400 Subject: [PATCH 19/72] Fix effect spore immunities, tera blast TM distribution, and IVs shown on catch (#388) * Fix effect spore, tera blast distribution, and IVs shown on catch * Forgot to add tms * Unown does not learn any TMs * Fix some tera blast learns * delelele whooooop --- src/data/ability.ts | 15 +- src/data/tms.ts | 435 ++++++++++++++++++++++++++++++++++++++++++-- src/phases.ts | 2 +- 3 files changed, 433 insertions(+), 19 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index 2ac7d6be1ac..35f6da685eb 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -679,6 +679,19 @@ export class PostDefendContactApplyStatusEffectAbAttr extends PostDefendAbAttr { } } +export class EffectSporeAbAttr extends PostDefendContactApplyStatusEffectAbAttr { + constructor() { + super(10, StatusEffect.POISON, StatusEffect.PARALYSIS, StatusEffect.SLEEP); + } + + applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { + if (attacker.hasAbility(Abilities.OVERCOAT) || attacker.isOfType(Type.GRASS)) { + return false; + } + return super.applyPostDefend(pokemon, passive, attacker, move, hitResult, args); + } +} + export class PostDefendContactApplyTagChanceAbAttr extends PostDefendAbAttr { private chance: integer; private tagType: BattlerTagType; @@ -2572,7 +2585,7 @@ export function initAbilities() { .attr(TypeImmunityAbAttr, Type.GROUND, (pokemon: Pokemon) => !pokemon.getTag(BattlerTagType.IGNORE_FLYING) && !pokemon.scene.arena.getTag(ArenaTagType.GRAVITY) && !pokemon.getTag(BattlerTagType.GROUNDED)) .ignorable(), new Ability(Abilities.EFFECT_SPORE, 3) - .attr(PostDefendContactApplyStatusEffectAbAttr, 10, StatusEffect.POISON, StatusEffect.PARALYSIS, StatusEffect.SLEEP), + .attr(EffectSporeAbAttr), new Ability(Abilities.SYNCHRONIZE, 3) .attr(SyncEncounterNatureAbAttr) .unimplemented(), diff --git a/src/data/tms.ts b/src/data/tms.ts index 71264d16c62..332eb2234b1 100644 --- a/src/data/tms.ts +++ b/src/data/tms.ts @@ -29550,7 +29550,6 @@ export const tmSpecies: TmSpecies = { Species.MURKROW, Species.SLOWKING, Species.MISDREAVUS, - Species.UNOWN, Species.GIRAFARIG, Species.PINECO, Species.FORRETRESS, @@ -62012,21 +62011,49 @@ export const tmSpecies: TmSpecies = { Species.ALOLA_MAROWAK, ], [Moves.TERA_BLAST]: [ + Species.BULBASAUR, + Species.IVYSAUR, + Species.VENUSAUR, Species.CHARMANDER, Species.CHARMELEON, Species.CHARIZARD, + Species.SQUIRTLE, + Species.WARTORTLE, + Species.BLASTOISE, + Species.BUTTERFREE, + Species.BEEDRILL, + Species.PIDGEY, + Species.PIDGEOTTO, + Species.PIDGEOT, + Species.RATTATA, + Species.RATICATE, + Species.SPEAROW, + Species.FEAROW, Species.EKANS, Species.ARBOK, Species.PIKACHU, Species.RAICHU, Species.SANDSHREW, Species.SANDSLASH, + Species.NIDORAN_F, + Species.NIDORINA, + Species.NIDOQUEEN, + Species.NIDORAN_M, + Species.NIDORINO, + Species.NIDOKING, Species.CLEFAIRY, Species.CLEFABLE, Species.VULPIX, Species.NINETALES, Species.JIGGLYPUFF, Species.WIGGLYTUFF, + Species.ZUBAT, + Species.GOLBAT, + Species.ODDISH, + Species.GLOOM, + Species.VILEPLUME, + Species.PARAS, + Species.PARASECT, Species.VENONAT, Species.VENOMOTH, Species.DIGLETT, @@ -62042,16 +62069,31 @@ export const tmSpecies: TmSpecies = { Species.POLIWAG, Species.POLIWHIRL, Species.POLIWRATH, + Species.ABRA, + Species.KADABRA, + Species.ALAKAZAM, + Species.MACHOP, + Species.MACHOKE, + Species.MACHAMP, Species.BELLSPROUT, Species.WEEPINBELL, Species.VICTREEBEL, + Species.TENTACOOL, + Species.TENTACRUEL, Species.GEODUDE, Species.GRAVELER, Species.GOLEM, + Species.PONYTA, + Species.RAPIDASH, Species.SLOWPOKE, Species.SLOWBRO, Species.MAGNEMITE, Species.MAGNETON, + Species.FARFETCHD, + Species.DODUO, + Species.DODRIO, + Species.SEEL, + Species.DEWGONG, Species.GRIMER, Species.MUK, Species.SHELLDER, @@ -62059,20 +62101,52 @@ export const tmSpecies: TmSpecies = { Species.GASTLY, Species.HAUNTER, Species.GENGAR, + Species.ONIX, Species.DROWZEE, Species.HYPNO, + Species.KRABBY, + Species.KINGLER, Species.VOLTORB, Species.ELECTRODE, + Species.EXEGGCUTE, + Species.EXEGGUTOR, + Species.CUBONE, + Species.MAROWAK, + Species.HITMONLEE, + Species.HITMONCHAN, + Species.LICKITUNG, Species.KOFFING, Species.WEEZING, + Species.RHYHORN, + Species.RHYDON, Species.CHANSEY, + Species.TANGELA, + Species.KANGASKHAN, + Species.HORSEA, + Species.SEADRA, + Species.GOLDEEN, + Species.SEAKING, + Species.STARYU, + Species.STARMIE, + Species.MR_MIME, Species.SCYTHER, + Species.JYNX, + Species.ELECTABUZZ, + Species.MAGMAR, + Species.PINSIR, Species.TAUROS, Species.GYARADOS, + Species.LAPRAS, Species.EEVEE, Species.VAPOREON, Species.JOLTEON, Species.FLAREON, + Species.PORYGON, + Species.OMANYTE, + Species.OMASTAR, + Species.KABUTO, + Species.KABUTOPS, + Species.AERODACTYL, Species.SNORLAX, Species.ARTICUNO, Species.ZAPDOS, @@ -62082,21 +62156,37 @@ export const tmSpecies: TmSpecies = { Species.DRAGONITE, Species.MEWTWO, Species.MEW, + Species.CHIKORITA, + Species.BAYLEEF, + Species.MEGANIUM, Species.CYNDAQUIL, Species.QUILAVA, Species.TYPHLOSION, + Species.TOTODILE, + Species.CROCONAW, + Species.FERALIGATR, Species.SENTRET, Species.FURRET, Species.HOOTHOOT, Species.NOCTOWL, + Species.LEDYBA, + Species.LEDIAN, Species.SPINARAK, Species.ARIADOS, + Species.CROBAT, + Species.CHINCHOU, + Species.LANTURN, Species.PICHU, Species.CLEFFA, Species.IGGLYBUFF, + Species.TOGEPI, + Species.TOGETIC, + Species.NATU, + Species.XATU, Species.MAREEP, Species.FLAAFFY, Species.AMPHAROS, + Species.BELLOSSOM, Species.MARILL, Species.AZUMARILL, Species.SUDOWOODO, @@ -62120,8 +62210,12 @@ export const tmSpecies: TmSpecies = { Species.FORRETRESS, Species.DUNSPARCE, Species.GLIGAR, + Species.STEELIX, + Species.SNUBBULL, + Species.GRANBULL, Species.QWILFISH, Species.SCIZOR, + Species.SHUCKLE, Species.HERACROSS, Species.SNEASEL, Species.TEDDIURSA, @@ -62130,24 +62224,58 @@ export const tmSpecies: TmSpecies = { Species.MAGCARGO, Species.SWINUB, Species.PILOSWINE, + Species.CORSOLA, + Species.REMORAID, + Species.OCTILLERY, Species.DELIBIRD, + Species.MANTINE, + Species.SKARMORY, Species.HOUNDOUR, Species.HOUNDOOM, + Species.KINGDRA, Species.PHANPY, Species.DONPHAN, + Species.PORYGON2, Species.STANTLER, + Species.TYROGUE, + Species.HITMONTOP, + Species.SMOOCHUM, + Species.ELEKID, + Species.MAGBY, + Species.MILTANK, Species.BLISSEY, + Species.RAIKOU, + Species.ENTEI, + Species.SUICUNE, Species.LARVITAR, Species.PUPITAR, Species.TYRANITAR, + Species.LUGIA, + Species.HO_OH, + Species.CELEBI, + Species.TREECKO, + Species.GROVYLE, + Species.SCEPTILE, + Species.TORCHIC, + Species.COMBUSKEN, + Species.BLAZIKEN, + Species.MUDKIP, + Species.MARSHTOMP, + Species.SWAMPERT, Species.POOCHYENA, Species.MIGHTYENA, + Species.ZIGZAGOON, + Species.LINOONE, + Species.BEAUTIFLY, + Species.DUSTOX, Species.LOTAD, Species.LOMBRE, Species.LUDICOLO, Species.SEEDOT, Species.NUZLEAF, Species.SHIFTRY, + Species.TAILLOW, + Species.SWELLOW, Species.WINGULL, Species.PELIPPER, Species.RALTS, @@ -62160,49 +62288,101 @@ export const tmSpecies: TmSpecies = { Species.SLAKOTH, Species.VIGOROTH, Species.SLAKING, + Species.NINCADA, + Species.NINJASK, + Species.SHEDINJA, + Species.WHISMUR, + Species.LOUDRED, + Species.EXPLOUD, Species.MAKUHITA, Species.HARIYAMA, Species.AZURILL, Species.NOSEPASS, + Species.SKITTY, + Species.DELCATTY, Species.SABLEYE, + Species.MAWILE, + Species.ARON, + Species.LAIRON, + Species.AGGRON, Species.MEDITITE, Species.MEDICHAM, + Species.ELECTRIKE, + Species.MANECTRIC, + Species.PLUSLE, + Species.MINUN, Species.VOLBEAT, Species.ILLUMISE, + Species.ROSELIA, Species.GULPIN, Species.SWALOT, + Species.CARVANHA, + Species.SHARPEDO, + Species.WAILMER, + Species.WAILORD, Species.NUMEL, Species.CAMERUPT, Species.TORKOAL, Species.SPOINK, Species.GRUMPIG, + Species.SPINDA, + Species.TRAPINCH, + Species.VIBRAVA, + Species.FLYGON, Species.CACNEA, Species.CACTURNE, Species.SWABLU, Species.ALTARIA, Species.ZANGOOSE, Species.SEVIPER, + Species.LUNATONE, + Species.SOLROCK, Species.BARBOACH, Species.WHISCASH, Species.CORPHISH, Species.CRAWDAUNT, + Species.BALTOY, + Species.CLAYDOL, + Species.LILEEP, + Species.CRADILY, + Species.ANORITH, + Species.ARMALDO, Species.FEEBAS, Species.MILOTIC, + Species.CASTFORM, + Species.KECLEON, Species.SHUPPET, Species.BANETTE, Species.DUSKULL, Species.DUSCLOPS, Species.TROPIUS, Species.CHIMECHO, + Species.ABSOL, Species.SNORUNT, Species.GLALIE, + Species.SPHEAL, + Species.SEALEO, + Species.WALREIN, + Species.CLAMPERL, + Species.HUNTAIL, + Species.GOREBYSS, + Species.RELICANTH, Species.LUVDISC, Species.BAGON, Species.SHELGON, Species.SALAMENCE, + Species.METANG, + Species.METAGROSS, + Species.REGIROCK, + Species.REGICE, + Species.REGISTEEL, + Species.LATIAS, + Species.LATIOS, Species.KYOGRE, Species.GROUDON, Species.RAYQUAZA, + Species.JIRACHI, + Species.DEOXYS, Species.TURTWIG, Species.GROTLE, Species.TORTERRA, @@ -62215,30 +62395,49 @@ export const tmSpecies: TmSpecies = { Species.STARLY, Species.STARAVIA, Species.STARAPTOR, + Species.BIDOOF, + Species.BIBAREL, Species.KRICKETOT, Species.KRICKETUNE, Species.SHINX, Species.LUXIO, Species.LUXRAY, + Species.BUDEW, + Species.ROSERADE, + Species.CRANIDOS, + Species.RAMPARDOS, + Species.SHIELDON, + Species.BASTIODON, + Species.BURMY, + Species.WORMADAM, + Species.MOTHIM, Species.COMBEE, Species.VESPIQUEN, Species.PACHIRISU, Species.BUIZEL, Species.FLOATZEL, + Species.CHERUBI, + Species.CHERRIM, Species.SHELLOS, Species.GASTRODON, Species.AMBIPOM, Species.DRIFLOON, Species.DRIFBLIM, + Species.BUNEARY, + Species.LOPUNNY, Species.MISMAGIUS, Species.HONCHKROW, + Species.GLAMEOW, + Species.PURUGLY, Species.CHINGLING, Species.STUNKY, Species.SKUNTANK, Species.BRONZOR, Species.BRONZONG, Species.BONSLY, + Species.MIME_JR, Species.HAPPINY, + Species.CHATOT, Species.SPIRITOMB, Species.GIBLE, Species.GABITE, @@ -62248,19 +62447,30 @@ export const tmSpecies: TmSpecies = { Species.LUCARIO, Species.HIPPOPOTAS, Species.HIPPOWDON, + Species.SKORUPI, + Species.DRAPION, Species.CROAGUNK, Species.TOXICROAK, + Species.CARNIVINE, Species.FINNEON, Species.LUMINEON, + Species.MANTYKE, Species.SNOVER, Species.ABOMASNOW, Species.WEAVILE, Species.MAGNEZONE, + Species.LICKILICKY, + Species.RHYPERIOR, + Species.TANGROWTH, + Species.ELECTIVIRE, + Species.MAGMORTAR, + Species.TOGEKISS, Species.YANMEGA, Species.LEAFEON, Species.GLACEON, Species.GLISCOR, Species.MAMOSWINE, + Species.PORYGON_Z, Species.GALLADE, Species.PROBOPASS, Species.DUSKNOIR, @@ -62272,39 +62482,127 @@ export const tmSpecies: TmSpecies = { Species.DIALGA, Species.PALKIA, Species.HEATRAN, + Species.REGIGIGAS, Species.GIRATINA, Species.CRESSELIA, + Species.PHIONE, + Species.MANAPHY, + Species.DARKRAI, + Species.SHAYMIN, Species.ARCEUS, + Species.VICTINI, + Species.SNIVY, + Species.SERVINE, + Species.SERPERIOR, + Species.TEPIG, + Species.PIGNITE, + Species.EMBOAR, Species.OSHAWOTT, Species.DEWOTT, Species.SAMUROTT, + Species.PATRAT, + Species.WATCHOG, + Species.LILLIPUP, + Species.HERDIER, + Species.STOUTLAND, + Species.PURRLOIN, + Species.LIEPARD, + Species.PANSAGE, + Species.SIMISAGE, + Species.PANSEAR, + Species.SIMISEAR, + Species.PANPOUR, + Species.SIMIPOUR, + Species.MUNNA, + Species.MUSHARNA, + Species.PIDOVE, + Species.TRANQUILL, + Species.UNFEZANT, + Species.BLITZLE, + Species.ZEBSTRIKA, + Species.ROGGENROLA, + Species.BOLDORE, + Species.GIGALITH, + Species.WOOBAT, + Species.SWOOBAT, + Species.DRILBUR, + Species.EXCADRILL, + Species.AUDINO, Species.TIMBURR, Species.GURDURR, Species.CONKELDURR, + Species.TYMPOLE, + Species.PALPITOAD, + Species.SEISMITOAD, + Species.THROH, + Species.SAWK, Species.SEWADDLE, Species.SWADLOON, Species.LEAVANNY, + Species.VENIPEDE, + Species.WHIRLIPEDE, + Species.SCOLIPEDE, + Species.COTTONEE, + Species.WHIMSICOTT, Species.PETILIL, Species.LILLIGANT, Species.BASCULIN, Species.SANDILE, Species.KROKOROK, Species.KROOKODILE, + Species.DARUMAKA, + Species.DARMANITAN, + Species.MARACTUS, + Species.DWEBBLE, + Species.CRUSTLE, + Species.SCRAGGY, + Species.SCRAFTY, + Species.SIGILYPH, + Species.YAMASK, + Species.COFAGRIGUS, + Species.TIRTOUGA, + Species.CARRACOSTA, + Species.ARCHEN, + Species.ARCHEOPS, + Species.TRUBBISH, + Species.GARBODOR, Species.ZORUA, Species.ZOROARK, + Species.MINCCINO, + Species.CINCCINO, Species.GOTHITA, Species.GOTHORITA, Species.GOTHITELLE, + Species.SOLOSIS, + Species.DUOSION, + Species.REUNICLUS, Species.DUCKLETT, Species.SWANNA, + Species.VANILLITE, + Species.VANILLISH, + Species.VANILLUXE, Species.DEERLING, Species.SAWSBUCK, + Species.EMOLGA, + Species.KARRABLAST, + Species.ESCAVALIER, Species.FOONGUS, Species.AMOONGUSS, + Species.FRILLISH, + Species.JELLICENT, Species.ALOMOMOLA, + Species.JOLTIK, + Species.GALVANTULA, + Species.FERROSEED, + Species.FERROTHORN, + Species.KLINK, + Species.KLANG, + Species.KLINKLANG, Species.TYNAMO, Species.EELEKTRIK, Species.EELEKTROSS, + Species.ELGYEM, + Species.BEHEEYEM, Species.LITWICK, Species.LAMPENT, Species.CHANDELURE, @@ -62314,23 +62612,40 @@ export const tmSpecies: TmSpecies = { Species.CUBCHOO, Species.BEARTIC, Species.CRYOGONAL, + Species.SHELMET, + Species.ACCELGOR, + Species.STUNFISK, Species.MIENFOO, Species.MIENSHAO, + Species.DRUDDIGON, + Species.GOLETT, + Species.GOLURK, Species.PAWNIARD, Species.BISHARP, + Species.BOUFFALANT, Species.RUFFLET, Species.BRAVIARY, Species.VULLABY, Species.MANDIBUZZ, + Species.HEATMOR, + Species.DURANT, Species.DEINO, Species.ZWEILOUS, Species.HYDREIGON, Species.LARVESTA, Species.VOLCARONA, + Species.COBALION, + Species.TERRAKION, + Species.VIRIZION, Species.TORNADUS, Species.THUNDURUS, + Species.RESHIRAM, + Species.ZEKROM, Species.LANDORUS, + Species.KYUREM, + Species.KELDEO, Species.MELOETTA, + Species.GENESECT, Species.CHESPIN, Species.QUILLADIN, Species.CHESNAUGHT, @@ -62345,6 +62660,8 @@ export const tmSpecies: TmSpecies = { 'battle-bond', 'ash', ], + Species.BUNNELBY, + Species.DIGGERSBY, Species.FLETCHLING, Species.FLETCHINDER, Species.TALONFLAME, @@ -62354,14 +62671,43 @@ export const tmSpecies: TmSpecies = { Species.LITLEO, Species.PYROAR, Species.FLABEBE, - Species.FLOETTE, + [ + Species.FLOETTE, + 'red', + 'yellow', + 'orange', + 'blue', + 'white', + ], Species.FLORGES, Species.SKIDDO, Species.GOGOAT, + Species.PANCHAM, + Species.PANGORO, + Species.FURFROU, + Species.ESPURR, + Species.MEOWSTIC, + Species.HONEDGE, + Species.DOUBLADE, + Species.AEGISLASH, + Species.SPRITZEE, + Species.AROMATISSE, + Species.SWIRLIX, + Species.SLURPUFF, + Species.INKAY, + Species.MALAMAR, + Species.BINACLE, + Species.BARBARACLE, Species.SKRELP, Species.DRAGALGE, Species.CLAUNCHER, Species.CLAWITZER, + Species.HELIOPTILE, + Species.HELIOLISK, + Species.TYRUNT, + Species.TYRANTRUM, + Species.AMAURA, + Species.AURORUS, Species.SYLVEON, Species.HAWLUCHA, Species.DEDENNE, @@ -62372,16 +62718,30 @@ export const tmSpecies: TmSpecies = { Species.KLEFKI, Species.PHANTUMP, Species.TREVENANT, + Species.PUMPKABOO, + Species.GOURGEIST, Species.BERGMITE, Species.AVALUGG, Species.NOIBAT, Species.NOIVERN, + Species.XERNEAS, + Species.YVELTAL, + Species.ZYGARDE, Species.DIANCIE, Species.HOOPA, Species.VOLCANION, Species.ROWLET, Species.DARTRIX, Species.DECIDUEYE, + Species.LITTEN, + Species.TORRACAT, + Species.INCINEROAR, + Species.POPPLIO, + Species.BRIONNE, + Species.PRIMARINA, + Species.PIKIPEK, + Species.TRUMBEAK, + Species.TOUCANNON, Species.YUNGOOS, Species.GUMSHOOS, Species.GRUBBIN, @@ -62394,28 +62754,84 @@ export const tmSpecies: TmSpecies = { Species.RIBOMBEE, Species.ROCKRUFF, Species.LYCANROC, + Species.WISHIWASHI, Species.MAREANIE, Species.TOXAPEX, Species.MUDBRAY, Species.MUDSDALE, + Species.DEWPIDER, + Species.ARAQUANID, Species.FOMANTIS, Species.LURANTIS, + Species.MORELULL, + Species.SHIINOTIC, Species.SALANDIT, Species.SALAZZLE, + Species.STUFFUL, + Species.BEWEAR, Species.BOUNSWEET, Species.STEENEE, Species.TSAREENA, + Species.COMFEY, Species.ORANGURU, Species.PASSIMIAN, + Species.WIMPOD, + Species.GOLISOPOD, Species.SANDYGAST, Species.PALOSSAND, + Species.TYPE_NULL, + Species.SILVALLY, + Species.MINIOR, Species.KOMALA, + Species.TURTONATOR, + Species.TOGEDEMARU, Species.MIMIKYU, Species.BRUXISH, + Species.DRAMPA, + Species.DHELMISE, Species.JANGMO_O, Species.HAKAMO_O, Species.KOMMO_O, + Species.TAPU_KOKO, + Species.TAPU_LELE, + Species.TAPU_BULU, + Species.TAPU_FINI, + Species.SOLGALEO, + Species.LUNALA, + Species.NIHILEGO, + Species.BUZZWOLE, + Species.PHEROMOSA, + Species.XURKITREE, + Species.CELESTEELA, + Species.KARTANA, + Species.GUZZLORD, + Species.NECROZMA, Species.MAGEARNA, + Species.MARSHADOW, + Species.POIPOLE, + Species.NAGANADEL, + Species.STAKATAKA, + Species.BLACEPHALON, + Species.ZERAORA, + Species.ALOLA_RATTATA, + Species.ALOLA_RATICATE, + Species.ALOLA_RAICHU, + Species.ALOLA_SANDSHREW, + Species.ALOLA_SANDSLASH, + Species.ALOLA_VULPIX, + Species.ALOLA_NINETALES, + Species.ALOLA_DIGLETT, + Species.ALOLA_DUGTRIO, + Species.ALOLA_MEOWTH, + Species.ALOLA_PERSIAN, + Species.ALOLA_GEODUDE, + Species.ALOLA_GRAVELER, + Species.ALOLA_GOLEM, + Species.ALOLA_GRIMER, + Species.ALOLA_MUK, + Species.ALOLA_EXEGGUTOR, + Species.ALOLA_MAROWAK, + Species.ETERNAL_FLOETTE, Species.GROOKEY, Species.THWACKEY, Species.RILLABOOM, @@ -62596,21 +63012,6 @@ export const tmSpecies: TmSpecies = { Species.MUNKIDORI, Species.FEZANDIPITI, Species.OGERPON, - Species.ALOLA_RAICHU, - Species.ALOLA_SANDSHREW, - Species.ALOLA_SANDSLASH, - Species.ALOLA_VULPIX, - Species.ALOLA_NINETALES, - Species.ALOLA_DIGLETT, - Species.ALOLA_DUGTRIO, - Species.ALOLA_MEOWTH, - Species.ALOLA_PERSIAN, - Species.ALOLA_GEODUDE, - Species.ALOLA_GRAVELER, - Species.ALOLA_GOLEM, - Species.ALOLA_GRIMER, - Species.ALOLA_MUK, - Species.ETERNAL_FLOETTE, Species.GALAR_MEOWTH, Species.GALAR_SLOWPOKE, Species.GALAR_SLOWBRO, diff --git a/src/phases.ts b/src/phases.ts index ad2a7537de7..2e0b8425567 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -4095,7 +4095,7 @@ export class AttemptCapturePhase extends PokemonPhase { this.scene.pokemonInfoContainer.show(pokemon, true); - this.scene.gameData.updateSpeciesDexIvs(pokemon.species.speciesId, pokemon.ivs); + this.scene.gameData.updateSpeciesDexIvs(pokemon.species.getRootSpeciesId(true), pokemon.ivs); this.scene.ui.showText(i18next.t('menu:pokemonCaught', { pokemonName: pokemon.name }), null, () => { const end = () => { From 7a418109c3063d45cd0f334ff1ef61dc87f339c6 Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Wed, 1 May 2024 18:17:12 -0400 Subject: [PATCH 20/72] Fix not checking move conditions for AI --- src/data/ability.ts | 6 +++--- src/data/move.ts | 24 +++++++++++++++--------- src/field/pokemon.ts | 2 +- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index 35f6da685eb..7c350f025be 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -919,8 +919,8 @@ export class MovePowerBoostAbAttr extends VariableMovePowerAbAttr { private condition: PokemonAttackCondition; private powerMultiplier: number; - constructor(condition: PokemonAttackCondition, powerMultiplier: number) { - super(true); + constructor(condition: PokemonAttackCondition, powerMultiplier: number, showAbility: boolean = true) { + super(showAbility); this.condition = condition; this.powerMultiplier = powerMultiplier; } @@ -2725,7 +2725,7 @@ export function initAbilities() { .attr(TypeImmunityStatChangeAbAttr, Type.ELECTRIC, BattleStat.SPD, 1) .ignorable(), new Ability(Abilities.RIVALRY, 4) - .attr(MovePowerBoostAbAttr, (user, target, move) => user.gender !== Gender.GENDERLESS && target.gender !== Gender.GENDERLESS && user.gender === target.gender, 1.25) + .attr(MovePowerBoostAbAttr, (user, target, move) => user.gender !== Gender.GENDERLESS && target.gender !== Gender.GENDERLESS && user.gender === target.gender, 1.25, true) .attr(MovePowerBoostAbAttr, (user, target, move) => user.gender !== Gender.GENDERLESS && target.gender !== Gender.GENDERLESS && user.gender !== target.gender, 0.75), new Ability(Abilities.STEADFAST, 4) .attr(FlinchStatChangeAbAttr, BattleStat.SPD, 1), diff --git a/src/data/move.ts b/src/data/move.ts index a13c1ac8861..d6367794a35 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -3645,6 +3645,20 @@ export class MoneyAttr extends MoveEffectAttr { } } +export class LastResortAttr extends MoveAttr { + getCondition(): MoveConditionFunc { + return (user: Pokemon, target: Pokemon, move: Move) => { + const uniqueUsedMoveIds = new Set(); + const movesetMoveIds = user.getMoveset().map(m => m.moveId); + user.getMoveHistory().map(m => { + if (m.move !== move.id && movesetMoveIds.find(mm => mm === m.move)) + uniqueUsedMoveIds.add(m.move); + }); + return uniqueUsedMoveIds.size >= movesetMoveIds.length - 1; + }; + } +} + const failOnGravityCondition: MoveConditionFunc = (user, target, move) => !user.scene.arena.getTag(ArenaTagType.GRAVITY); const failOnBossCondition: MoveConditionFunc = (user, target, move) => !target.isBossImmune(); @@ -4836,15 +4850,7 @@ export function initMoves() { new AttackMove(Moves.PUNISHMENT, Type.DARK, MoveCategory.PHYSICAL, -1, 100, 5, -1, 0, 4) .unimplemented(), new AttackMove(Moves.LAST_RESORT, Type.NORMAL, MoveCategory.PHYSICAL, 140, 100, 5, -1, 0, 4) - .condition((user, target, move) => { - const uniqueUsedMoveIds = new Set(); - const movesetMoveIds = user.getMoveset().map(m => m.moveId); - user.getMoveHistory().map(m => { - if (m.move !== move.id && movesetMoveIds.find(mm => mm === m.move)) - uniqueUsedMoveIds.add(m.move); - }); - return uniqueUsedMoveIds.size >= movesetMoveIds.length - 1; - }), + .attr(LastResortAttr), new StatusMove(Moves.WORRY_SEED, Type.GRASS, 100, 10, -1, 0, 4) .attr(AbilityChangeAttr, Abilities.INSOMNIA), new AttackMove(Moves.SUCKER_PUNCH, Type.DARK, MoveCategory.PHYSICAL, 70, 100, 5, -1, 1, 4) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 82915ce41bc..ce2d8dfffe6 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -2680,7 +2680,7 @@ export class EnemyPokemon extends Pokemon { for (let mt of moveTargets[move.id]) { const target = this.scene.getField()[mt]; let targetScore = move.getUserBenefitScore(this, target, move) + move.getTargetBenefitScore(this, target, move) * (mt < BattlerIndex.ENEMY === this.isPlayer() ? 1 : -1); - if (move.name.endsWith(' (N)')) + if (move.name.endsWith(' (N)') || !move.applyConditions(this, target, move)) targetScore = -20; else if (move instanceof AttackMove) { const effectiveness = target.getAttackMoveEffectiveness(this, pokemonMove); From 89e2642d91e419d2ec61574f98d1e9286f213ce9 Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Wed, 1 May 2024 18:24:21 -0400 Subject: [PATCH 21/72] Fix update issue for battle stats display --- src/ui/battle-info.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/ui/battle-info.ts b/src/ui/battle-info.ts index ae8f518e727..2ca0457c801 100644 --- a/src/ui/battle-info.ts +++ b/src/ui/battle-info.ts @@ -498,11 +498,14 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.lastLevel = pokemon.level; } - if (pokemon.summonData) { - const battleStats = pokemon.summonData.battleStats.join(''); - - if (this.lastBattleStats !== battleStats) - this.updateBattleStats(pokemon.summonData.battleStats); + const battleStats = pokemon.summonData + ? pokemon.summonData.battleStats + : battleStatOrder.map(() => 0); + const battleStatsStr = battleStats.join(''); + + if (this.lastBattleStats !== battleStatsStr) { + this.updateBattleStats(battleStats); + this.lastBattleStats = battleStatsStr; } this.shinyIcon.setVisible(pokemon.isShiny()); From e34b20466426a9944a71306b993c6d149eeabd20 Mon Sep 17 00:00:00 2001 From: TeKrop Date: Wed, 1 May 2024 22:48:58 +0200 Subject: [PATCH 22/72] feat: added support for localisation on battle scene sentences --- src/field/pokemon.ts | 13 +++++++------ src/locales/de/menu.ts | 7 ++++++- src/locales/en/menu.ts | 7 ++++++- src/locales/es/menu.ts | 7 ++++++- src/locales/fr/menu.ts | 7 ++++++- src/locales/it/menu.ts | 7 ++++++- 6 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index ce2d8dfffe6..8c9224f5e1f 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -45,6 +45,7 @@ import { TerrainType } from '../data/terrain'; import { TrainerSlot } from '../data/trainer-config'; import { BerryType } from '../data/berry'; import { ABILITY_OVERRIDE, MOVE_OVERRIDE, OPP_ABILITY_OVERRIDE, OPP_MOVE_OVERRIDE, OPP_SHINY_OVERRIDE, OPP_VARIANT_OVERRIDE } from '../overrides'; +import i18next from '../plugins/i18n'; export enum FieldPosition { CENTER, @@ -1417,7 +1418,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { damage.value = this.damageAndUpdate(damage.value, result as DamageResult, isCritical, oneHitKo, oneHitKo); this.turnData.damageTaken += damage.value; if (isCritical) - this.scene.queueMessage('A critical hit!'); + this.scene.queueMessage(i18next.t('menu:hitResultCriticalHit')); this.scene.setPhaseQueueSplice(); if (source.isPlayer()) { this.scene.validateAchvs(DamageAchv, damage); @@ -1435,16 +1436,16 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (source.turnData.hitsLeft === 1) { switch (result) { case HitResult.SUPER_EFFECTIVE: - this.scene.queueMessage('It\'s super effective!'); + this.scene.queueMessage(i18next.t('menu:hitResultSuperEffective')); break; case HitResult.NOT_VERY_EFFECTIVE: - this.scene.queueMessage('It\'s not very effective…'); + this.scene.queueMessage(i18next.t('menu:hitResultNotVeryEffective')); break; case HitResult.NO_EFFECT: - this.scene.queueMessage(`It doesn\'t affect ${this.name}!`); + this.scene.queueMessage(i18next.t('menu:hitResultNoEffect', { pokemonName: this.name })); break; case HitResult.ONE_HIT_KO: - this.scene.queueMessage('It\'s a one-hit KO!'); + this.scene.queueMessage(i18next.t('menu:hitResultOneHitKO')); break; } } @@ -1461,7 +1462,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { defendingSidePlayField.forEach((p) => applyPreDefendAbAttrs(FieldPriorityMoveImmunityAbAttr, p, source, battlerMove, cancelled, typeMultiplier)); } if (!typeMultiplier.value) - this.scene.queueMessage(`It doesn\'t affect ${this.name}!`); + this.scene.queueMessage(i18next.t('menu:hitResultNoEffect', { pokemonName: this.name })); result = cancelled.value || !typeMultiplier.value ? HitResult.NO_EFFECT : HitResult.STATUS; break; } diff --git a/src/locales/de/menu.ts b/src/locales/de/menu.ts index 442cfae218f..a8e0a901f3f 100644 --- a/src/locales/de/menu.ts +++ b/src/locales/de/menu.ts @@ -63,5 +63,10 @@ export const menu: SimpleTranslationEntries = { "weeklyRankings": "Weekly Rankings", "noRankings": "No Rankings", "loading": "Loading…", - "playersOnline": "Players Online" + "playersOnline": "Players Online", + "hitResultCriticalHit": "A critical hit!", + "hitResultSuperEffective": "It's super effective!", + "hitResultNotVeryEffective": "It's not very effective…", + "hitResultNoEffect": "It doesn't affect {{pokemonName}}!", + "hitResultOneHitKO": "It's a one-hit KO!" } as const; \ No newline at end of file diff --git a/src/locales/en/menu.ts b/src/locales/en/menu.ts index 82a09e49d4f..21620e9b30f 100644 --- a/src/locales/en/menu.ts +++ b/src/locales/en/menu.ts @@ -82,5 +82,10 @@ export const menu: SimpleTranslationEntries = { "weeklyRankings": "Weekly Rankings", "noRankings": "No Rankings", "loading": "Loading…", - "playersOnline": "Players Online" + "playersOnline": "Players Online", + "hitResultCriticalHit": "A critical hit!", + "hitResultSuperEffective": "It's super effective!", + "hitResultNotVeryEffective": "It's not very effective…", + "hitResultNoEffect": "It doesn't affect {{pokemonName}}!", + "hitResultOneHitKO": "It's a one-hit KO!" } as const; \ No newline at end of file diff --git a/src/locales/es/menu.ts b/src/locales/es/menu.ts index 5dccc2e4eb3..0a43f19b768 100644 --- a/src/locales/es/menu.ts +++ b/src/locales/es/menu.ts @@ -66,5 +66,10 @@ export const menu: SimpleTranslationEntries = { "weeklyRankings": "Weekly Rankings", "noRankings": "No Rankings", "loading": "Loading…", - "playersOnline": "Players Online" + "playersOnline": "Players Online", + "hitResultCriticalHit": "A critical hit!", + "hitResultSuperEffective": "It's super effective!", + "hitResultNotVeryEffective": "It's not very effective…", + "hitResultNoEffect": "It doesn't affect {{pokemonName}}!", + "hitResultOneHitKO": "It's a one-hit KO!" } as const; \ No newline at end of file diff --git a/src/locales/fr/menu.ts b/src/locales/fr/menu.ts index d5478c67a26..c485412bf1a 100644 --- a/src/locales/fr/menu.ts +++ b/src/locales/fr/menu.ts @@ -77,5 +77,10 @@ export const menu: SimpleTranslationEntries = { "weeklyRankings": "Classement de la Semaine", "noRankings": "Pas de Classement", "loading": "Chargement…", - "playersOnline": "Joueurs Connectés" + "playersOnline": "Joueurs Connectés", + "hitResultCriticalHit": "Coup critique!", + "hitResultSuperEffective": "C'est super efficace!", + "hitResultNotVeryEffective": "Ce n'est pas très efficace…", + "hitResultNoEffect": "Ça n'affecte pas {{pokemonName}}…", + "hitResultOneHitKO": "K.O. en un coup!" } as const; diff --git a/src/locales/it/menu.ts b/src/locales/it/menu.ts index c37a37b5169..118c1dccb5f 100644 --- a/src/locales/it/menu.ts +++ b/src/locales/it/menu.ts @@ -11,5 +11,10 @@ export const menu: SimpleTranslationEntries = { "weeklyRankings": "Weekly Rankings", "noRankings": "No Rankings", "loading": "Loading…", - "playersOnline": "Players Online" + "playersOnline": "Players Online", + "hitResultCriticalHit": "A critical hit!", + "hitResultSuperEffective": "It's super effective!", + "hitResultNotVeryEffective": "It's not very effective…", + "hitResultNoEffect": "It doesn't affect {{pokemonName}}!", + "hitResultOneHitKO": "It's a one-hit KO!" } as const; \ No newline at end of file From 6ac224ab8a4e3e5ec6aa7fdc2d8b60111343f2fd Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Wed, 1 May 2024 18:53:48 -0400 Subject: [PATCH 23/72] Refactor to split battle messages from menu --- src/field/pokemon.ts | 12 ++--- src/locales/de/battle.ts | 52 ++++++++++++++++++ src/locales/de/fight-ui-handler.ts | 6 +++ src/locales/de/menu.ts | 31 +---------- src/locales/en/battle.ts | 52 ++++++++++++++++++ src/locales/en/menu.ts | 50 +---------------- src/locales/es/battle.ts | 52 ++++++++++++++++++ src/locales/es/fight-ui-handler.ts | 6 +++ src/locales/es/menu.ts | 50 +---------------- src/locales/fr/battle.ts | 52 ++++++++++++++++++ src/locales/fr/menu.ts | 50 +---------------- src/locales/it/battle.ts | 52 ++++++++++++++++++ src/locales/it/fight-ui-handler.ts | 6 +++ src/locales/it/menu.ts | 35 +++++++++--- src/phases.ts | 86 +++++++++++++++--------------- src/plugins/i18n.ts | 18 +++++++ 16 files changed, 378 insertions(+), 232 deletions(-) create mode 100644 src/locales/de/battle.ts create mode 100644 src/locales/de/fight-ui-handler.ts create mode 100644 src/locales/en/battle.ts create mode 100644 src/locales/es/battle.ts create mode 100644 src/locales/es/fight-ui-handler.ts create mode 100644 src/locales/fr/battle.ts create mode 100644 src/locales/it/battle.ts create mode 100644 src/locales/it/fight-ui-handler.ts diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 8c9224f5e1f..a966a24303f 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -1418,7 +1418,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { damage.value = this.damageAndUpdate(damage.value, result as DamageResult, isCritical, oneHitKo, oneHitKo); this.turnData.damageTaken += damage.value; if (isCritical) - this.scene.queueMessage(i18next.t('menu:hitResultCriticalHit')); + this.scene.queueMessage(i18next.t('battle:hitResultCriticalHit')); this.scene.setPhaseQueueSplice(); if (source.isPlayer()) { this.scene.validateAchvs(DamageAchv, damage); @@ -1436,16 +1436,16 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (source.turnData.hitsLeft === 1) { switch (result) { case HitResult.SUPER_EFFECTIVE: - this.scene.queueMessage(i18next.t('menu:hitResultSuperEffective')); + this.scene.queueMessage(i18next.t('battle:hitResultSuperEffective')); break; case HitResult.NOT_VERY_EFFECTIVE: - this.scene.queueMessage(i18next.t('menu:hitResultNotVeryEffective')); + this.scene.queueMessage(i18next.t('battle:hitResultNotVeryEffective')); break; case HitResult.NO_EFFECT: - this.scene.queueMessage(i18next.t('menu:hitResultNoEffect', { pokemonName: this.name })); + this.scene.queueMessage(i18next.t('battle:hitResultNoEffect', { pokemonName: this.name })); break; case HitResult.ONE_HIT_KO: - this.scene.queueMessage(i18next.t('menu:hitResultOneHitKO')); + this.scene.queueMessage(i18next.t('battle:hitResultOneHitKO')); break; } } @@ -1462,7 +1462,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { defendingSidePlayField.forEach((p) => applyPreDefendAbAttrs(FieldPriorityMoveImmunityAbAttr, p, source, battlerMove, cancelled, typeMultiplier)); } if (!typeMultiplier.value) - this.scene.queueMessage(i18next.t('menu:hitResultNoEffect', { pokemonName: this.name })); + this.scene.queueMessage(i18next.t('battle:hitResultNoEffect', { pokemonName: this.name })); result = cancelled.value || !typeMultiplier.value ? HitResult.NO_EFFECT : HitResult.STATUS; break; } diff --git a/src/locales/de/battle.ts b/src/locales/de/battle.ts new file mode 100644 index 00000000000..61191a1165a --- /dev/null +++ b/src/locales/de/battle.ts @@ -0,0 +1,52 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const battle: SimpleTranslationEntries = { + "bossAppeared": "{{bossName}} erscheint.", + "trainerAppeared": "{{trainerName}}\nmöchte kämpfen!", + "singleWildAppeared": "Ein wildes {{pokemonName}} erscheint!", + "multiWildAppeared": "Ein wildes {{pokemonName1}}\nund {{pokemonName2}} erscheinen!", + "playerComeBack": "Komm zurück, {{pokemonName}}!", + "trainerComeBack": "{{trainerName}} ruft {{pokemonName}} zurück!", + "playerGo": "Los! {{pokemonName}}!", + "trainerGo": "{{trainerName}} sendet {{pokemonName}} raus!", + "switchQuestion": "Willst du\n{{pokemonName}} auswechseln?", + "trainerDefeated": `You defeated\n{{trainerName}}!`, + "pokemonCaught": "{{pokemonName}} was caught!", + "pokemon": "Pokémon", + "sendOutPokemon": "Los! {{pokemonName}}!", + "hitResultCriticalHit": "A critical hit!", + "hitResultSuperEffective": "It's super effective!", + "hitResultNotVeryEffective": "It's not very effective…", + "hitResultNoEffect": "It doesn't affect {{pokemonName}}!", + "hitResultOneHitKO": "It's a one-hit KO!", + "attackFailed": "But it failed!", + "attackHitsCount": `Hit {{count}} time(s)!`, + "expGain": "{{pokemonName}} gained\n{{exp}} EXP. Points!", + "levelUp": "{{pokemonName}} grew to\nLv. {{level}}!", + "learnMove": "{{pokemonName}} learned\n{{moveName}}!", + "learnMovePrompt": "{{pokemonName}} wants to learn the\nmove {{moveName}}.", + "learnMoveLimitReached": "However, {{pokemonName}} already\nknows four moves.", + "learnMoveReplaceQuestion": "Should a move be forgotten and\nreplaced with {{moveName}}?", + "learnMoveStopTeaching": "Stop trying to teach\n{{moveName}}?", + "learnMoveNotLearned": "{{pokemonName}} did not learn the\nmove {{moveName}}.", + "learnMoveForgetQuestion": "Which move should be forgotten?", + "learnMoveForgetSuccess": "{{pokemonName}} forgot how to\nuse {{moveName}}.", + "levelCapUp": "Das Levellimit\nhat sich zu {{levelCap}} erhöht!", + "moveNotImplemented": "{{moveName}} ist noch nicht implementiert und kann nicht ausgewählt werden.", + "moveDisabled": "{{moveName}} ist deaktiviert!", + "noPokeballForce": "Eine unsichtbare Kraft\nverhindert die Nutzung von Pokébällen.", + "noPokeballTrainer": "Du kannst das Pokémon\neines anderen Trainers nicht fangen!", + "noPokeballMulti": "Du kannst erst einen Pokéball werden,\nwenn nur noch ein Pokémon übrig ist!", + "noPokeballStrong": "Das Ziel-Pokémon ist zu stark, um gefangen zu werden!\nDu musst es zuerst schwächen!", + "noEscapeForce": "Eine unsichtbare Kraft\nverhindert die Flucht.", + "noEscapeTrainer": "Du kannst nicht\naus einem Trainerkampf fliehen!", + "noEscapePokemon": "{{pokemonName}}'s {{moveName}}\nverhindert {{escapeVerb}}!", + "runAwaySuccess": "You got away safely!", + "runAwayCannotEscape": 'You can\'t escape!', + "escapeVerbSwitch": "auswechseln", + "escapeVerbFlee": "flucht", + "notDisabled": "{{moveName}} ist\nnicht mehr deaktiviert!", + "skipItemQuestion": "Are you sure you want to skip taking an item?", + "eggHatching": "Oh?", + "ivScannerUseQuestion": "Use IV Scanner on {{pokemonName}}?" +} as const; \ No newline at end of file diff --git a/src/locales/de/fight-ui-handler.ts b/src/locales/de/fight-ui-handler.ts new file mode 100644 index 00000000000..1ce9e0317bf --- /dev/null +++ b/src/locales/de/fight-ui-handler.ts @@ -0,0 +1,6 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const fightUiHandler: SimpleTranslationEntries = { + "pp": "PP", + "power": "POWER", +} as const; \ No newline at end of file diff --git a/src/locales/de/menu.ts b/src/locales/de/menu.ts index a8e0a901f3f..c648b15bfe8 100644 --- a/src/locales/de/menu.ts +++ b/src/locales/de/menu.ts @@ -35,38 +35,9 @@ export const menu: SimpleTranslationEntries = { "boyOrGirl": "Bist du ein Junge oder ein Mädchen?", "boy": "Junge", "girl": "Mädchen", - "bossAppeared": "{{bossName}} erscheint.", - "trainerAppeared": "{{trainerName}}\nmöchte kämpfen!", - "singleWildAppeared": "Ein wildes {{pokemonName}} erscheint!", - "multiWildAppeared": "Ein wildes {{pokemonName1}}\nund {{pokemonName2}} erscheinen!", - "playerComeBack": "Komm zurück, {{pokemonName}}!", - "trainerComeBack": "{{trainerName}} ruft {{pokemonName}} zurück!", - "playerGo": "Los! {{pokemonName}}!", - "trainerGo": "{{trainerName}} sendet {{pokemonName}} raus!", - "switchQuestion": "Willst du\n{{pokemonName}} auswechseln?", - "pokemon": "Pokémon", - "sendOutPokemon": "Los! {{pokemonName}}!", - "levelCapUp": "Das Levellimit\nhat sich zu {{levelCap}} erhöht!", - "moveNotImplemented": "{{moveName}} ist noch nicht implementiert und kann nicht ausgewählt werden.", - "moveDisabled": "{{moveName}} ist deaktiviert!", - "noPokeballForce": "Eine unsichtbare Kraft\nverhindert die Nutzung von Pokébällen.", - "noPokeballTrainer": "Du kannst das Pokémon\neines anderen Trainers nicht fangen!", - "noPokeballMulti": "Du kannst erst einen Pokéball werden,\nwenn nur noch ein Pokémon übrig ist!", - "noPokeballStrong": "Das Ziel-Pokémon ist zu stark, um gefangen zu werden!\nDu musst es zuerst schwächen!", - "noEscapeForce": "Eine unsichtbare Kraft\nverhindert die Flucht.", - "noEscapeTrainer": "Du kannst nicht\naus einem Trainerkampf fliehen!", - "noEscapePokemon": "{{pokemonName}}'s {{moveName}}\nverhindert {{escapeVerb}}!", - "escapeVerbSwitch": "auswechseln", - "escapeVerbFlee": "flucht", - "notDisabled": "{{moveName}} ist\nnicht mehr deaktiviert!", "dailyRankings": "Daily Rankings", "weeklyRankings": "Weekly Rankings", "noRankings": "No Rankings", "loading": "Loading…", - "playersOnline": "Players Online", - "hitResultCriticalHit": "A critical hit!", - "hitResultSuperEffective": "It's super effective!", - "hitResultNotVeryEffective": "It's not very effective…", - "hitResultNoEffect": "It doesn't affect {{pokemonName}}!", - "hitResultOneHitKO": "It's a one-hit KO!" + "playersOnline": "Players Online" } as const; \ No newline at end of file diff --git a/src/locales/en/battle.ts b/src/locales/en/battle.ts new file mode 100644 index 00000000000..599672a1b19 --- /dev/null +++ b/src/locales/en/battle.ts @@ -0,0 +1,52 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const battle: SimpleTranslationEntries = { + "bossAppeared": "{{bossName}} appeared.", + "trainerAppeared": "{{trainerName}}\nwould like to battle!", + "singleWildAppeared": "A wild {{pokemonName}} appeared!", + "multiWildAppeared": "A wild {{pokemonName1}}\nand {{pokemonName2}} appeared!", + "playerComeBack": "Come back, {{pokemonName}}!", + "trainerComeBack": "{{trainerName}} withdrew {{pokemonName}}!", + "playerGo": "Go! {{pokemonName}}!", + "trainerGo": "{{trainerName}} sent out {{pokemonName}}!", + "switchQuestion": "Will you switch\n{{pokemonName}}?", + "trainerDefeated": `You defeated\n{{trainerName}}!`, + "pokemonCaught": "{{pokemonName}} was caught!", + "pokemon": "Pokémon", + "sendOutPokemon": "Go! {{pokemonName}}!", + "hitResultCriticalHit": "A critical hit!", + "hitResultSuperEffective": "It's super effective!", + "hitResultNotVeryEffective": "It's not very effective…", + "hitResultNoEffect": "It doesn't affect {{pokemonName}}!", + "hitResultOneHitKO": "It's a one-hit KO!", + "attackFailed": "But it failed!", + "attackHitsCount": `Hit {{count}} time(s)!`, + "expGain": "{{pokemonName}} gained\n{{exp}} EXP. Points!", + "levelUp": "{{pokemonName}} grew to\nLv. {{level}}!", + "learnMove": "{{pokemonName}} learned\n{{moveName}}!", + "learnMovePrompt": "{{pokemonName}} wants to learn the\nmove {{moveName}}.", + "learnMoveLimitReached": "However, {{pokemonName}} already\nknows four moves.", + "learnMoveReplaceQuestion": "Should a move be forgotten and\nreplaced with {{moveName}}?", + "learnMoveStopTeaching": "Stop trying to teach\n{{moveName}}?", + "learnMoveNotLearned": "{{pokemonName}} did not learn the\nmove {{moveName}}.", + "learnMoveForgetQuestion": "Which move should be forgotten?", + "learnMoveForgetSuccess": "{{pokemonName}} forgot how to\nuse {{moveName}}.", + "levelCapUp": "The level cap\nhas increased to {{levelCap}}!", + "moveNotImplemented": "{{moveName}} is not yet implemented and cannot be selected.", + "moveDisabled": "{{moveName}} is disabled!", + "noPokeballForce": "An unseen force\nprevents using Poké Balls.", + "noPokeballTrainer": "You can't catch\nanother trainer's Pokémon!", + "noPokeballMulti": "You can only throw a Poké Ball\nwhen there is one Pokémon remaining!", + "noPokeballStrong": "The target Pokémon is too strong to be caught!\nYou need to weaken it first!", + "noEscapeForce": "An unseen force\nprevents escape.", + "noEscapeTrainer": "You can't run\nfrom a trainer battle!", + "noEscapePokemon": "{{pokemonName}}'s {{moveName}}\nprevents {{escapeVerb}}!", + "runAwaySuccess": "You got away safely!", + "runAwayCannotEscape": 'You can\'t escape!', + "escapeVerbSwitch": "switching", + "escapeVerbFlee": "fleeing", + "notDisabled": "{{moveName}} is disabled\nno more!", + "skipItemQuestion": "Are you sure you want to skip taking an item?", + "eggHatching": "Oh?", + "ivScannerUseQuestion": "Use IV Scanner on {{pokemonName}}?" +} as const; \ No newline at end of file diff --git a/src/locales/en/menu.ts b/src/locales/en/menu.ts index 21620e9b30f..42888b17337 100644 --- a/src/locales/en/menu.ts +++ b/src/locales/en/menu.ts @@ -35,57 +35,9 @@ export const menu: SimpleTranslationEntries = { "boyOrGirl": "Are you a boy or a girl?", "boy": "Boy", "girl": "Girl", - "bossAppeared": "{{bossName}} appeared.", - "trainerAppeared": "{{trainerName}}\nwould like to battle!", - "singleWildAppeared": "A wild {{pokemonName}} appeared!", - "multiWildAppeared": "A wild {{pokemonName1}}\nand {{pokemonName2}} appeared!", - "playerComeBack": "Come back, {{pokemonName}}!", - "trainerComeBack": "{{trainerName}} withdrew {{pokemonName}}!", - "playerGo": "Go! {{pokemonName}}!", - "trainerGo": "{{trainerName}} sent out {{pokemonName}}!", - "switchQuestion": "Will you switch\n{{pokemonName}}?", - "trainerDefeated": `You defeated\n{{trainerName}}!`, - "pokemonCaught": "{{pokemonName}} was caught!", - "pokemon": "Pokémon", - "sendOutPokemon": "Go! {{pokemonName}}!", - "attackFailed": "But it failed!", - "attackHitsCount": `Hit {{count}} time(s)!`, - "expGain": "{{pokemonName}} gained\n{{exp}} EXP. Points!", - "levelUp": "{{pokemonName}} grew to\nLv. {{level}}!", - "learnMove": "{{pokemonName}} learned\n{{moveName}}!", - "learnMovePrompt": "{{pokemonName}} wants to learn the\nmove {{moveName}}.", - "learnMoveLimitReached": "However, {{pokemonName}} already\nknows four moves.", - "learnMoveReplaceQuestion": "Should a move be forgotten and\nreplaced with {{moveName}}?", - "learnMoveStopTeaching": "Stop trying to teach\n{{moveName}}?", - "learnMoveNotLearned": "{{pokemonName}} did not learn the\nmove {{moveName}}.", - "learnMoveForgetQuestion": "Which move should be forgotten?", - "learnMoveForgetSuccess": "{{pokemonName}} forgot how to\nuse {{moveName}}.", - "levelCapUp": "The level cap\nhas increased to {{levelCap}}!", - "moveNotImplemented": "{{moveName}} is not yet implemented and cannot be selected.", - "moveDisabled": "{{moveName}} is disabled!", - "noPokeballForce": "An unseen force\nprevents using Poké Balls.", - "noPokeballTrainer": "You can't catch\nanother trainer's Pokémon!", - "noPokeballMulti": "You can only throw a Poké Ball\nwhen there is one Pokémon remaining!", - "noPokeballStrong": "The target Pokémon is too strong to be caught!\nYou need to weaken it first!", - "noEscapeForce": "An unseen force\nprevents escape.", - "noEscapeTrainer": "You can't run\nfrom a trainer battle!", - "noEscapePokemon": "{{pokemonName}}'s {{moveName}}\nprevents {{escapeVerb}}!", - "runAwaySuccess": "You got away safely!", - "runAwayCannotEscape": 'You can\'t escape!', - "escapeVerbSwitch": "switching", - "escapeVerbFlee": "fleeing", - "notDisabled": "{{moveName}} is disabled\nno more!", - "skipItemQuestion": "Are you sure you want to skip taking an item?", - "eggHatching": "Oh?", - "ivScannerUseQuestion": "Use IV Scanner on {{pokemonName}}?", "dailyRankings": "Daily Rankings", "weeklyRankings": "Weekly Rankings", "noRankings": "No Rankings", "loading": "Loading…", - "playersOnline": "Players Online", - "hitResultCriticalHit": "A critical hit!", - "hitResultSuperEffective": "It's super effective!", - "hitResultNotVeryEffective": "It's not very effective…", - "hitResultNoEffect": "It doesn't affect {{pokemonName}}!", - "hitResultOneHitKO": "It's a one-hit KO!" + "playersOnline": "Players Online" } as const; \ No newline at end of file diff --git a/src/locales/es/battle.ts b/src/locales/es/battle.ts new file mode 100644 index 00000000000..1d4345a6f5b --- /dev/null +++ b/src/locales/es/battle.ts @@ -0,0 +1,52 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const battle: SimpleTranslationEntries = { + "bossAppeared": "¡{{bossName}} te corta el paso!", + "trainerAppeared": "¡{{trainerName}}\nte desafía!", + "singleWildAppeared": "¡Un {{pokemonName}} salvaje te corta el paso!", + "multiWildAppeared": "¡Un {{pokemonName1}} y un {{pokemonName2}} salvajes\nte cortan el paso!", + "playerComeBack": "¡{{pokemonName}}, ven aquí!", + "trainerComeBack": "¡{{trainerName}} retira a {{pokemonName}} del combate!", + "playerGo": "¡Adelante, {{pokemonName}}!", + "trainerGo": "¡{{trainerName}} saca a {{pokemonName}}!", + "switchQuestion": "¿Quieres cambiar a\n{{pokemonName}}?", + "trainerDefeated": "¡Has derrotado a\n{{trainerName}}!", + "pokemonCaught": "¡{{pokemonName}} atrapado!", + "pokemon": "Pokémon", + "sendOutPokemon": "¡Adelante, {{pokemonName}}!", + "hitResultCriticalHit": "A critical hit!", + "hitResultSuperEffective": "It's super effective!", + "hitResultNotVeryEffective": "It's not very effective…", + "hitResultNoEffect": "It doesn't affect {{pokemonName}}!", + "hitResultOneHitKO": "It's a one-hit KO!", + "attackFailed": "¡Pero ha fallado!", + "attackHitsCount": `N.º de golpes: {{count}}.`, + "expGain": "{{pokemonName}} ha ganado\n{{exp}} puntos de experiencia.", + "levelUp": "¡{{pokemonName}} ha subido al \nNv. {{level}}!", + "learnMove": "¡{{pokemonName}} ha aprendido {{moveName}}!", + "learnMovePrompt": "{{pokemonName}} quiere aprender {{moveName}}.", + "learnMoveLimitReached": "Pero, {{pokemonName}} ya conoce\ncuatro movimientos.", + "learnMoveReplaceQuestion": "¿Quieres sustituir uno de sus movimientos por {{moveName}}?", + "learnMoveStopTeaching": "¿Prefieres que no aprenda\n{{moveName}}?", + "learnMoveNotLearned": "{{pokemonName}} no ha aprendido {{moveName}}.", + "learnMoveForgetQuestion": "¿Qué movimiento quieres que olvide?", + "learnMoveForgetSuccess": "{{pokemonName}} ha olvidado cómo utilizar {{moveName}}.", + "levelCapUp": "¡Se ha incrementado el\nnivel máximo a {{levelCap}}!", + "moveNotImplemented": "{{moveName}} aún no está implementado y no se puede seleccionar.", + "moveDisabled": "!No puede usar {{moveName}} porque ha sido anulado!", + "noPokeballForce": "Una fuerza misteriosa\nte impide usar Poké Balls.", + "noPokeballTrainer": "¡No puedes atrapar a los\nPokémon de los demás!", + "noPokeballMulti": "¡No se pueden lanzar Poké Balls\ncuando hay más de un Pokémon!", + "noPokeballStrong": "¡Este Pokémon es demasiado fuerte para ser capturado!\nNecesitas bajarle los PS primero!", + "noEscapeForce": "Una fuerza misteriosa\nte impide huir.", + "noEscapeTrainer": "¡No puedes huir de los\ncombates contra Entrenadores!", + "noEscapePokemon": "¡El movimiento {{moveName}} de {{pokemonName}} impide la huida!", + "runAwaySuccess": "¡Escapas sin problemas!", + "runAwayCannotEscape": "¡No has podido escapar!", + "escapeVerbSwitch": "cambiar", + "escapeVerbFlee": "huir", + "notDisabled": "¡El movimiento {{moveName}}\nya no está anulado!", + "skipItemQuestion": "¿Estás seguro de que no quieres coger un objeto?", + "eggHatching": "¿Y esto?", + "ivScannerUseQuestion": "¿Quieres usar el Escáner de IVs en {{pokemonName}}?" +} as const; \ No newline at end of file diff --git a/src/locales/es/fight-ui-handler.ts b/src/locales/es/fight-ui-handler.ts new file mode 100644 index 00000000000..1ce9e0317bf --- /dev/null +++ b/src/locales/es/fight-ui-handler.ts @@ -0,0 +1,6 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const fightUiHandler: SimpleTranslationEntries = { + "pp": "PP", + "power": "POWER", +} as const; \ No newline at end of file diff --git a/src/locales/es/menu.ts b/src/locales/es/menu.ts index 0a43f19b768..c67287ae0cc 100644 --- a/src/locales/es/menu.ts +++ b/src/locales/es/menu.ts @@ -19,57 +19,9 @@ export const menu: SimpleTranslationEntries = { "boyOrGirl": "¿Eres un chico o una chica?", "boy": "Chico", "girl": "Chica", - "bossAppeared": "¡{{bossName}} te corta el paso!", - "trainerAppeared": "¡{{trainerName}}\nte desafía!", - "singleWildAppeared": "¡Un {{pokemonName}} salvaje te corta el paso!", - "multiWildAppeared": "¡Un {{pokemonName1}} y un {{pokemonName2}} salvajes\nte cortan el paso!", - "playerComeBack": "¡{{pokemonName}}, ven aquí!", - "trainerComeBack": "¡{{trainerName}} retira a {{pokemonName}} del combate!", - "playerGo": "¡Adelante, {{pokemonName}}!", - "trainerGo": "¡{{trainerName}} saca a {{pokemonName}}!", - "switchQuestion": "¿Quieres cambiar a\n{{pokemonName}}?", - "trainerDefeated": "¡Has derrotado a\n{{trainerName}}!", - "pokemonCaught": "¡{{pokemonName}} atrapado!", - "pokemon": "Pokémon", - "sendOutPokemon": "¡Adelante, {{pokemonName}}!", - "attackFailed": "¡Pero ha fallado!", - "attackHitsCount": `N.º de golpes: {{count}}.`, - "expGain": "{{pokemonName}} ha ganado\n{{exp}} puntos de experiencia.", - "levelUp": "¡{{pokemonName}} ha subido al \nNv. {{level}}!", - "learnMove": "¡{{pokemonName}} ha aprendido {{moveName}}!", - "learnMovePrompt": "{{pokemonName}} quiere aprender {{moveName}}.", - "learnMoveLimitReached": "Pero, {{pokemonName}} ya conoce\ncuatro movimientos.", - "learnMoveReplaceQuestion": "¿Quieres sustituir uno de sus movimientos por {{moveName}}?", - "learnMoveStopTeaching": "¿Prefieres que no aprenda\n{{moveName}}?", - "learnMoveNotLearned": "{{pokemonName}} no ha aprendido {{moveName}}.", - "learnMoveForgetQuestion": "¿Qué movimiento quieres que olvide?", - "learnMoveForgetSuccess": "{{pokemonName}} ha olvidado cómo utilizar {{moveName}}.", - "levelCapUp": "¡Se ha incrementado el\nnivel máximo a {{levelCap}}!", - "moveNotImplemented": "{{moveName}} aún no está implementado y no se puede seleccionar.", - "moveDisabled": "!No puede usar {{moveName}} porque ha sido anulado!", - "noPokeballForce": "Una fuerza misteriosa\nte impide usar Poké Balls.", - "noPokeballTrainer": "¡No puedes atrapar a los\nPokémon de los demás!", - "noPokeballMulti": "¡No se pueden lanzar Poké Balls\ncuando hay más de un Pokémon!", - "noPokeballStrong": "¡Este Pokémon es demasiado fuerte para ser capturado!\nNecesitas bajarle los PS primero!", - "noEscapeForce": "Una fuerza misteriosa\nte impide huir.", - "noEscapeTrainer": "¡No puedes huir de los\ncombates contra Entrenadores!", - "noEscapePokemon": "¡El movimiento {{moveName}} de {{pokemonName}} impide la huida!", - "runAwaySuccess": "¡Escapas sin problemas!", - "runAwayCannotEscape": "¡No has podido escapar!", - "escapeVerbSwitch": "cambiar", - "escapeVerbFlee": "huir", - "notDisabled": "¡El movimiento {{moveName}}\nya no está anulado!", - "skipItemQuestion": "¿Estás seguro de que no quieres coger un objeto?", - "eggHatching": "¿Y esto?", - "ivScannerUseQuestion": "¿Quieres usar el Escáner de IVs en {{pokemonName}}?", "dailyRankings": "Daily Rankings", "weeklyRankings": "Weekly Rankings", "noRankings": "No Rankings", "loading": "Loading…", - "playersOnline": "Players Online", - "hitResultCriticalHit": "A critical hit!", - "hitResultSuperEffective": "It's super effective!", - "hitResultNotVeryEffective": "It's not very effective…", - "hitResultNoEffect": "It doesn't affect {{pokemonName}}!", - "hitResultOneHitKO": "It's a one-hit KO!" + "playersOnline": "Players Online" } as const; \ No newline at end of file diff --git a/src/locales/fr/battle.ts b/src/locales/fr/battle.ts new file mode 100644 index 00000000000..8768c30155a --- /dev/null +++ b/src/locales/fr/battle.ts @@ -0,0 +1,52 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const battle: SimpleTranslationEntries = { + "bossAppeared": "Un {{bossName}} apparaît.", + "trainerAppeared": "Un combat est lancé\npar {{trainerName}} !", + "singleWildAppeared": "Un {{pokemonName}} sauvage apparaît !", + "multiWildAppeared": "Un {{pokemonName1}} et un {{pokemonName2}}\nsauvages apparaissent !", + "playerComeBack": "{{pokemonName}}, on change !\nReviens !", + "trainerComeBack": "{{trainerName}} retire {{pokemonName}} !", + "playerGo": "{{pokemonName}} ! Go !", + "trainerGo": "{{pokemonName}} est envoyé par\n{{trainerName}} !", + "switchQuestion": "Voulez-vous changer\n{{pokemonName}} ?", + "trainerDefeated": `Vous avez battu\n{{trainerName}} !`, + "pokemonCaught": "Vous avez attrapé {{pokemonName}} !", + "pokemon": "Pokémon", + "sendOutPokemon": "{{pokemonName}} ! Go !", + "hitResultCriticalHit": "Coup critique!", + "hitResultSuperEffective": "C’est super efficace!", + "hitResultNotVeryEffective": "Ce n’est pas très efficace…", + "hitResultNoEffect": "Ça n’affecte pas {{pokemonName}}…", + "hitResultOneHitKO": "K.O. en un coup!", + "attackFailed": "Mais cela échoue !", + "attackHitsCount": `Touché {{count}} fois !`, + "expGain": "{{pokemonName}} gagne\n{{exp}} Points d’Exp !", + "levelUp": "{{pokemonName}} monte au\nN. {{level}} !", + "learnMove": "{{pokemonName}} apprend \n{{moveName}} !", + "learnMovePrompt": "{{pokemonName}} veut apprendre\n{{moveName}}.", + "learnMoveLimitReached": "Cependant, {{pokemonName}} connait\ndéjà quatre capacités.", + "learnMoveReplaceQuestion": "Voulez-vous oublier une capacité\net la remplacer par {{moveName}} ?", + "learnMoveStopTeaching": "Arrêter d’apprendre\n{{moveName}} ?", + "learnMoveNotLearned": "{{pokemonName}} n’a pas appris\n{{moveName}}.", + "learnMoveForgetQuestion": "Quelle capacité doit être oubliée ?", + "learnMoveForgetSuccess": "{{pokemonName}} oublie comment\nutiliser {{moveName}}.", + "levelCapUp": "La limite de niveau\na été augmentée à {{levelCap}} !", + "moveNotImplemented": "{{moveName}} n’est pas encore implémenté et ne peut pas être sélectionné.", + "moveDisabled": "{{moveName}} est sous entrave !", + "noPokeballForce": "Une force mystérieuse\nempêche l’utilisation des Poké Balls.", + "noPokeballTrainer": "Le Dresseur détourne la Ball\nVoler, c’est mal !", + "noPokeballMulti": "Impossible ! On ne peut pas viser\nquand il y a deux Pokémon!", + "noPokeballStrong": "Le Pokémon est trop fort pour être capturé !\nVous devez d’abord l’affaiblir !", + "noEscapeForce": "Une force mystérieuse\nempêche la fuite.", + "noEscapeTrainer": "On ne s’enfuit pas d’un\ncombat de Dresseurs !", + "noEscapePokemon": "{{moveName}} de {{pokemonName}}\nempêche {{escapeVerb}} !", + "runAwaySuccess": "Vous prenez la fuite !", + "runAwayCannotEscape": "Fuite impossible !", + "escapeVerbSwitch": "le changement", + "escapeVerbFlee": "la fuite", + "notDisabled": "{{moveName}} n’est plus sous entrave !", + "skipItemQuestion": "Êtes-vous sûr·e de ne pas vouloir prendre d’objet ?", + "eggHatching": "Oh ?", + "ivScannerUseQuestion": "Utiliser le Scanner d’IV sur {{pokemonName}} ?" +} as const; \ No newline at end of file diff --git a/src/locales/fr/menu.ts b/src/locales/fr/menu.ts index c485412bf1a..1744297089c 100644 --- a/src/locales/fr/menu.ts +++ b/src/locales/fr/menu.ts @@ -30,57 +30,9 @@ export const menu: SimpleTranslationEntries = { "boyOrGirl": "Es-tu un garçon ou une fille ?", "boy": "Garçon", "girl": "Fille", - "bossAppeared": "Un {{bossName}} apparaît.", - "trainerAppeared": "Un combat est lancé\npar {{trainerName}} !", - "singleWildAppeared": "Un {{pokemonName}} sauvage apparaît !", - "multiWildAppeared": "Un {{pokemonName1}} et un {{pokemonName2}}\nsauvages apparaissent !", - "playerComeBack": "{{pokemonName}}, on change !\nReviens !", - "trainerComeBack": "{{trainerName}} retire {{pokemonName}} !", - "playerGo": "{{pokemonName}} ! Go !", - "trainerGo": "{{pokemonName}} est envoyé par\n{{trainerName}} !", - "switchQuestion": "Voulez-vous changer\n{{pokemonName}} ?", - "trainerDefeated": `Vous avez battu\n{{trainerName}} !`, - "pokemonCaught": "Vous avez attrapé {{pokemonName}} !", - "pokemon": "Pokémon", - "sendOutPokemon": "{{pokemonName}} ! Go !", - "attackFailed": "Mais cela échoue !", - "attackHitsCount": `Touché {{count}} fois !`, - "expGain": "{{pokemonName}} gagne\n{{exp}} Points d’Exp !", - "levelUp": "{{pokemonName}} monte au\nN. {{level}} !", - "learnMove": "{{pokemonName}} apprend \n{{moveName}} !", - "learnMovePrompt": "{{pokemonName}} veut apprendre\n{{moveName}}.", - "learnMoveLimitReached": "Cependant, {{pokemonName}} connait\ndéjà quatre capacités.", - "learnMoveReplaceQuestion": "Voulez-vous oublier une capacité\net la remplacer par {{moveName}} ?", - "learnMoveStopTeaching": "Arrêter d’apprendre\n{{moveName}} ?", - "learnMoveNotLearned": "{{pokemonName}} n’a pas appris\n{{moveName}}.", - "learnMoveForgetQuestion": "Quelle capacité doit être oubliée ?", - "learnMoveForgetSuccess": "{{pokemonName}} oublie comment\nutiliser {{moveName}}.", - "levelCapUp": "La limite de niveau\na été augmentée à {{levelCap}} !", - "moveNotImplemented": "{{moveName}} n’est pas encore implémenté et ne peut pas être sélectionné.", - "moveDisabled": "{{moveName}} est sous entrave !", - "noPokeballForce": "Une force mystérieuse\nempêche l’utilisation des Poké Balls.", - "noPokeballTrainer": "Le Dresseur détourne la Ball\nVoler, c’est mal !", - "noPokeballMulti": "Impossible ! On ne peut pas viser\nquand il y a deux Pokémon!", - "noPokeballStrong": "Le Pokémon est trop fort pour être capturé !\nVous devez d’abord l’affaiblir !", - "noEscapeForce": "Une force mystérieuse\nempêche la fuite.", - "noEscapeTrainer": "On ne s’enfuit pas d’un\ncombat de Dresseurs !", - "noEscapePokemon": "{{moveName}} de {{pokemonName}}\nempêche {{escapeVerb}} !", - "runAwaySuccess": "Vous prenez la fuite !", - "runAwayCannotEscape": "Fuite impossible !", - "escapeVerbSwitch": "le changement", - "escapeVerbFlee": "la fuite", - "notDisabled": "{{moveName}} n’est plus sous entrave !", - "skipItemQuestion": "Êtes-vous sûr·e de ne pas vouloir prendre d’objet ?", - "eggHatching": "Oh ?", - "ivScannerUseQuestion": "Utiliser le Scanner d’IV sur {{pokemonName}} ?", "dailyRankings": "Classement du Jour", "weeklyRankings": "Classement de la Semaine", "noRankings": "Pas de Classement", "loading": "Chargement…", - "playersOnline": "Joueurs Connectés", - "hitResultCriticalHit": "Coup critique!", - "hitResultSuperEffective": "C'est super efficace!", - "hitResultNotVeryEffective": "Ce n'est pas très efficace…", - "hitResultNoEffect": "Ça n'affecte pas {{pokemonName}}…", - "hitResultOneHitKO": "K.O. en un coup!" + "playersOnline": "Joueurs Connectés" } as const; diff --git a/src/locales/it/battle.ts b/src/locales/it/battle.ts new file mode 100644 index 00000000000..599672a1b19 --- /dev/null +++ b/src/locales/it/battle.ts @@ -0,0 +1,52 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const battle: SimpleTranslationEntries = { + "bossAppeared": "{{bossName}} appeared.", + "trainerAppeared": "{{trainerName}}\nwould like to battle!", + "singleWildAppeared": "A wild {{pokemonName}} appeared!", + "multiWildAppeared": "A wild {{pokemonName1}}\nand {{pokemonName2}} appeared!", + "playerComeBack": "Come back, {{pokemonName}}!", + "trainerComeBack": "{{trainerName}} withdrew {{pokemonName}}!", + "playerGo": "Go! {{pokemonName}}!", + "trainerGo": "{{trainerName}} sent out {{pokemonName}}!", + "switchQuestion": "Will you switch\n{{pokemonName}}?", + "trainerDefeated": `You defeated\n{{trainerName}}!`, + "pokemonCaught": "{{pokemonName}} was caught!", + "pokemon": "Pokémon", + "sendOutPokemon": "Go! {{pokemonName}}!", + "hitResultCriticalHit": "A critical hit!", + "hitResultSuperEffective": "It's super effective!", + "hitResultNotVeryEffective": "It's not very effective…", + "hitResultNoEffect": "It doesn't affect {{pokemonName}}!", + "hitResultOneHitKO": "It's a one-hit KO!", + "attackFailed": "But it failed!", + "attackHitsCount": `Hit {{count}} time(s)!`, + "expGain": "{{pokemonName}} gained\n{{exp}} EXP. Points!", + "levelUp": "{{pokemonName}} grew to\nLv. {{level}}!", + "learnMove": "{{pokemonName}} learned\n{{moveName}}!", + "learnMovePrompt": "{{pokemonName}} wants to learn the\nmove {{moveName}}.", + "learnMoveLimitReached": "However, {{pokemonName}} already\nknows four moves.", + "learnMoveReplaceQuestion": "Should a move be forgotten and\nreplaced with {{moveName}}?", + "learnMoveStopTeaching": "Stop trying to teach\n{{moveName}}?", + "learnMoveNotLearned": "{{pokemonName}} did not learn the\nmove {{moveName}}.", + "learnMoveForgetQuestion": "Which move should be forgotten?", + "learnMoveForgetSuccess": "{{pokemonName}} forgot how to\nuse {{moveName}}.", + "levelCapUp": "The level cap\nhas increased to {{levelCap}}!", + "moveNotImplemented": "{{moveName}} is not yet implemented and cannot be selected.", + "moveDisabled": "{{moveName}} is disabled!", + "noPokeballForce": "An unseen force\nprevents using Poké Balls.", + "noPokeballTrainer": "You can't catch\nanother trainer's Pokémon!", + "noPokeballMulti": "You can only throw a Poké Ball\nwhen there is one Pokémon remaining!", + "noPokeballStrong": "The target Pokémon is too strong to be caught!\nYou need to weaken it first!", + "noEscapeForce": "An unseen force\nprevents escape.", + "noEscapeTrainer": "You can't run\nfrom a trainer battle!", + "noEscapePokemon": "{{pokemonName}}'s {{moveName}}\nprevents {{escapeVerb}}!", + "runAwaySuccess": "You got away safely!", + "runAwayCannotEscape": 'You can\'t escape!', + "escapeVerbSwitch": "switching", + "escapeVerbFlee": "fleeing", + "notDisabled": "{{moveName}} is disabled\nno more!", + "skipItemQuestion": "Are you sure you want to skip taking an item?", + "eggHatching": "Oh?", + "ivScannerUseQuestion": "Use IV Scanner on {{pokemonName}}?" +} as const; \ No newline at end of file diff --git a/src/locales/it/fight-ui-handler.ts b/src/locales/it/fight-ui-handler.ts new file mode 100644 index 00000000000..1ce9e0317bf --- /dev/null +++ b/src/locales/it/fight-ui-handler.ts @@ -0,0 +1,6 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const fightUiHandler: SimpleTranslationEntries = { + "pp": "PP", + "power": "POWER", +} as const; \ No newline at end of file diff --git a/src/locales/it/menu.ts b/src/locales/it/menu.ts index 118c1dccb5f..9812236b7f0 100644 --- a/src/locales/it/menu.ts +++ b/src/locales/it/menu.ts @@ -1,5 +1,10 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; +/** + * The menu namespace holds most miscellaneous text that isn't directly part of the game's + * contents or directly related to Pokemon data. This includes menu navigation, settings, + * account interactions, descriptive text, etc. + */ export const menu: SimpleTranslationEntries = { "cancel": "Annulla", "continue": "Continua", @@ -7,14 +12,32 @@ export const menu: SimpleTranslationEntries = { "loadGame": "Carica Partita", "dailyRun": "Corsa Giornaliera (Beta)", "selectGameMode": "Seleziona una modalità di gioco.", + "logInOrCreateAccount": "Log in or create an account to start. No email required!", + "username": "Username", + "password": "Password", + "login": "Login", + "register": "Register", + "emptyUsername": "Username must not be empty", + "invalidLoginUsername": "The provided username is invalid", + "invalidRegisterUsername": "Username must only contain letters, numbers, or underscores", + "invalidLoginPassword": "The provided password is invalid", + "invalidRegisterPassword": "Password must be 6 characters or longer", + "usernameAlreadyUsed": "The provided username is already in use", + "accountNonExistent": "The provided user does not exist", + "unmatchingPassword": "The provided password does not match", + "passwordNotMatchingConfirmPassword": "Password must match confirm password", + "confirmPassword": "Confirm Password", + "registrationAgeWarning": "By registering, you confirm you are of 13 years of age or older.", + "backToLogin": "Back to Login", + "failedToLoadSaveData": "Failed to load save data. Please reload the page.\nIf this continues, please contact the administrator.", + "sessionSuccess": "Session loaded successfully.", + "failedToLoadSession": "Your session data could not be loaded.\nIt may be corrupted.", + "boyOrGirl": "Are you a boy or a girl?", + "boy": "Boy", + "girl": "Girl", "dailyRankings": "Daily Rankings", "weeklyRankings": "Weekly Rankings", "noRankings": "No Rankings", "loading": "Loading…", - "playersOnline": "Players Online", - "hitResultCriticalHit": "A critical hit!", - "hitResultSuperEffective": "It's super effective!", - "hitResultNotVeryEffective": "It's not very effective…", - "hitResultNoEffect": "It doesn't affect {{pokemonName}}!", - "hitResultOneHitKO": "It's a one-hit KO!" + "playersOnline": "Players Online" } as const; \ No newline at end of file diff --git a/src/phases.ts b/src/phases.ts index 2e0b8425567..72f0e10cc3e 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -815,14 +815,14 @@ export class EncounterPhase extends BattlePhase { const enemyField = this.scene.getEnemyField(); if (this.scene.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) - return i18next.t('menu:bossAppeared', {bossName: enemyField[0].name}); + return i18next.t('battle:bossAppeared', {bossName: enemyField[0].name}); if (this.scene.currentBattle.battleType === BattleType.TRAINER) - return i18next.t('menu:trainerAppeared', {trainerName: this.scene.currentBattle.trainer.getName(TrainerSlot.NONE, true)}); + return i18next.t('battle:trainerAppeared', {trainerName: this.scene.currentBattle.trainer.getName(TrainerSlot.NONE, true)}); return enemyField.length === 1 - ? i18next.t('menu:singleWildAppeared', {pokemonName: enemyField[0].name}) - : i18next.t('menu:multiWildAppeared', {pokemonName1: enemyField[0].name, pokemonName2: enemyField[1].name}) + ? i18next.t('battle:singleWildAppeared', {pokemonName: enemyField[0].name}) + : i18next.t('battle:multiWildAppeared', {pokemonName1: enemyField[0].name, pokemonName2: enemyField[1].name}) } doEncounterCommon(showEncounterMessage: boolean = true) { @@ -1187,7 +1187,7 @@ export class SummonPhase extends PartyMemberPokemonPhase { } if (this.player) { - this.scene.ui.showText(i18next.t('menu:playerGo', { pokemonName: this.getPokemon().name })); + this.scene.ui.showText(i18next.t('battle:playerGo', { pokemonName: this.getPokemon().name })); if (this.player) this.scene.pbTray.hide(); this.scene.trainer.setTexture(`trainer_${this.scene.gameData.gender === PlayerGender.FEMALE ? 'f' : 'm'}_back_pb`); @@ -1355,8 +1355,8 @@ export class SwitchSummonPhase extends SummonPhase { applyPreSwitchOutAbAttrs(PreSwitchOutAbAttr, pokemon); this.scene.ui.showText(this.player ? - i18next.t('menu:playerComeBack', { pokemonName: pokemon.name }) : - i18next.t('menu:trainerComeBack', { + i18next.t('battle:playerComeBack', { pokemonName: pokemon.name }) : + i18next.t('battle:trainerComeBack', { trainerName: this.scene.currentBattle.trainer.getName(!(this.fieldIndex % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER), pokemonName: pokemon.name }) @@ -1396,8 +1396,8 @@ export class SwitchSummonPhase extends SummonPhase { party[this.fieldIndex] = switchedPokemon; const showTextAndSummon = () => { this.scene.ui.showText(this.player ? - i18next.t('menu:playerGo', { pokemonName: switchedPokemon.name }) : - i18next.t('menu:trainerGo', { + i18next.t('battle:playerGo', { pokemonName: switchedPokemon.name }) : + i18next.t('battle:trainerGo', { trainerName: this.scene.currentBattle.trainer.getName(!(this.fieldIndex % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER), pokemonName: this.getPokemon().name }) @@ -1544,7 +1544,7 @@ export class CheckSwitchPhase extends BattlePhase { return; } - this.scene.ui.showText(i18next.t('menu:switchQuestion', { pokemonName: this.useName ? pokemon.name : i18next.t('menu:pokemon') }), null, () => { + this.scene.ui.showText(i18next.t('battle:switchQuestion', { pokemonName: this.useName ? pokemon.name : i18next.t('battle:pokemon') }), null, () => { this.scene.ui.setMode(Mode.CONFIRM, () => { this.scene.ui.setMode(Mode.MESSAGE); this.scene.tryRemovePhase(p => p instanceof PostSummonPhase && p.player && p.fieldIndex === this.fieldIndex); @@ -1564,7 +1564,7 @@ export class SummonMissingPhase extends SummonPhase { } preSummon(): void { - this.scene.ui.showText(i18next.t('menu:sendOutPokemon', { pokemonName: this.getPokemon().name})); + this.scene.ui.showText(i18next.t('battle:sendOutPokemon', { pokemonName: this.getPokemon().name})); this.scene.time.delayedCall(250, () => this.summon()); } } @@ -1579,7 +1579,7 @@ export class LevelCapPhase extends FieldPhase { this.scene.ui.setMode(Mode.MESSAGE).then(() => { this.scene.playSound('level_up_fanfare'); - this.scene.ui.showText(i18next.t('menu:levelCapUp', { levelCap: this.scene.getMaxExpLevel() }), null, () => this.end(), null, true); + this.scene.ui.showText(i18next.t('battle:levelCapUp', { levelCap: this.scene.getMaxExpLevel() }), null, () => this.end(), null, true); this.executeForAll(pokemon => pokemon.updateInfo(true)); }); } @@ -1673,7 +1673,7 @@ export class CommandPhase extends FieldPhase { const move = playerPokemon.getMoveset()[cursor]; if (move.getName().endsWith(' (N)')) { this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.showText(i18next.t('menu:moveNotImplemented', { moveName: move.getName().slice(0, -4) }), null, () => { + this.scene.ui.showText(i18next.t('battle:moveNotImplemented', { moveName: move.getName().slice(0, -4) }), null, () => { this.scene.ui.clearText(); this.scene.ui.setMode(Mode.FIGHT, this.fieldIndex); }, null, true); @@ -1692,7 +1692,7 @@ export class CommandPhase extends FieldPhase { const move = playerPokemon.getMoveset()[cursor]; if (playerPokemon.summonData.disabledMove === move.moveId) { this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.showText(i18next.t('menu:moveDisabled', { moveName: move.getName() }), null, () => { + this.scene.ui.showText(i18next.t('battle:moveDisabled', { moveName: move.getName() }), null, () => { this.scene.ui.clearText(); this.scene.ui.setMode(Mode.FIGHT, this.fieldIndex); }, null, true); @@ -1703,14 +1703,14 @@ export class CommandPhase extends FieldPhase { if (this.scene.arena.biomeType === Biome.END && (!this.scene.gameMode.isClassic || (this.scene.getEnemyField().filter(p => p.isActive(true)).some(p => !p.scene.gameData.dexData[p.species.speciesId].caughtAttr) && this.scene.gameData.getStarterCount(d => !!d.caughtAttr) < Object.keys(speciesStarters).length - 1))) { this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.showText(i18next.t('menu:noPokeballForce'), null, () => { + this.scene.ui.showText(i18next.t('battle:noPokeballForce'), null, () => { this.scene.ui.showText(null, 0); this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); }, null, true); } else if (this.scene.currentBattle.battleType === BattleType.TRAINER) { this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.showText(i18next.t('menu:noPokeballTrainer'), null, () => { + this.scene.ui.showText(i18next.t('battle:noPokeballTrainer'), null, () => { this.scene.ui.showText(null, 0); this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); }, null, true); @@ -1719,7 +1719,7 @@ export class CommandPhase extends FieldPhase { if (targets.length > 1) { this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.showText(i18next.t('menu:noPokeballMulti'), null, () => { + this.scene.ui.showText(i18next.t('battle:noPokeballMulti'), null, () => { this.scene.ui.showText(null, 0); this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); }, null, true); @@ -1728,7 +1728,7 @@ export class CommandPhase extends FieldPhase { if (targetPokemon.isBoss() && targetPokemon.bossSegmentIndex >= 1 && cursor < PokeballType.MASTER_BALL) { this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.showText(i18next.t('menu:noPokeballStrong'), null, () => { + this.scene.ui.showText(i18next.t('battle:noPokeballStrong'), null, () => { this.scene.ui.showText(null, 0); this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); }, null, true); @@ -1748,14 +1748,14 @@ export class CommandPhase extends FieldPhase { if (!isSwitch && this.scene.arena.biomeType === Biome.END) { this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.showText(i18next.t('menu:noEscapeForce'), null, () => { + this.scene.ui.showText(i18next.t('battle:noEscapeForce'), null, () => { this.scene.ui.showText(null, 0); this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); }, null, true); } else if (!isSwitch && this.scene.currentBattle.battleType === BattleType.TRAINER) { this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.showText(i18next.t('menu:noEscapeTrainer'), null, () => { + this.scene.ui.showText(i18next.t('battle:noEscapeTrainer'), null, () => { this.scene.ui.showText(null, 0); this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); }, null, true); @@ -1778,10 +1778,10 @@ export class CommandPhase extends FieldPhase { this.scene.ui.setMode(Mode.MESSAGE); } this.scene.ui.showText( - i18next.t('menu:noEscapePokemon', { + i18next.t('battle:noEscapePokemon', { pokemonName: this.scene.getPokemonById(trapTag.sourceId).name, moveName: trapTag.getMoveName(), - escapeVerb: isSwitch ? i18next.t('menu:escapeVerbSwitch') : i18next.t('menu:escapeVerbFlee') + escapeVerb: isSwitch ? i18next.t('battle:escapeVerbSwitch') : i18next.t('battle:escapeVerbFlee') }), null, () => { @@ -2031,7 +2031,7 @@ export class TurnEndPhase extends FieldPhase { pokemon.lapseTags(BattlerTagLapseType.TURN_END); if (pokemon.summonData.disabledMove && !--pokemon.summonData.disabledTurns) { - this.scene.pushPhase(new MessagePhase(this.scene, i18next.t('menu:notDisabled', { moveName: allMoves[pokemon.summonData.disabledMove].name }))); + this.scene.pushPhase(new MessagePhase(this.scene, i18next.t('battle:notDisabled', { moveName: allMoves[pokemon.summonData.disabledMove].name }))); pokemon.summonData.disabledMove = Moves.NONE; } @@ -2339,7 +2339,7 @@ export class MovePhase extends BattlePhase { } showFailedText(failedText: string = null): void { - this.scene.queueMessage(failedText || i18next.t('menu:attackFailed')); + this.scene.queueMessage(failedText || i18next.t('battle:attackFailed')); } end() { @@ -2402,7 +2402,7 @@ export class MoveEffectPhase extends PokemonPhase { moveHistoryEntry.result = MoveResult.MISS; applyMoveAttrs(MissEffectAttr, user, null, this.move.getMove()); } else { - this.scene.queueMessage(i18next.t('menu:attackFailed')); + this.scene.queueMessage(i18next.t('battle:attackFailed')); moveHistoryEntry.result = MoveResult.FAIL; } return this.end(); @@ -2486,7 +2486,7 @@ export class MoveEffectPhase extends PokemonPhase { else { const hitsTotal = user.turnData.hitCount - Math.max(user.turnData.hitsLeft, 0); if (hitsTotal > 1) - this.scene.queueMessage(i18next.t('menu:attackHitsCount', { count: hitsTotal })); + this.scene.queueMessage(i18next.t('battle:attackHitsCount', { count: hitsTotal })); this.scene.applyModifiers(HitHealModifier, this.player, user); } } @@ -3342,7 +3342,7 @@ export class TrainerVictoryPhase extends BattlePhase { this.scene.unshiftPhase(new ModifierRewardPhase(this.scene, [ modifierTypes.VOUCHER, modifierTypes.VOUCHER, modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PREMIUM ][vouchers[TrainerType[trainerType]].voucherType])); } - this.scene.ui.showText(i18next.t('menu:trainerDefeated', { trainerName: this.scene.currentBattle.trainer.getName(TrainerSlot.NONE, true) }), null, () => { + this.scene.ui.showText(i18next.t('battle:trainerDefeated', { trainerName: this.scene.currentBattle.trainer.getName(TrainerSlot.NONE, true) }), null, () => { const victoryMessages = this.scene.currentBattle.trainer.getVictoryMessages(); const showMessage = () => { let message: string; @@ -3609,7 +3609,7 @@ export class ExpPhase extends PlayerPartyMemberPokemonPhase { let exp = new Utils.NumberHolder(this.expValue); this.scene.applyModifiers(ExpBoosterModifier, true, exp); exp.value = Math.floor(exp.value); - this.scene.ui.showText(i18next.t('menu:expGain', { pokemonName: pokemon.name, exp: exp.value }), null, () => { + this.scene.ui.showText(i18next.t('battle:expGain', { pokemonName: pokemon.name, exp: exp.value }), null, () => { const lastLevel = pokemon.level; let newLevel: integer; pokemon.addExp(exp.value); @@ -3697,7 +3697,7 @@ export class LevelUpPhase extends PlayerPartyMemberPokemonPhase { pokemon.calculateStats(); pokemon.updateInfo(); this.scene.playSound('level_up_fanfare'); - this.scene.ui.showText(i18next.t('menu:levelUp', { pokemonName: this.getPokemon().name, level: this.level }), null, () => this.scene.ui.getMessageHandler().promptLevelUpStats(this.partyMemberIndex, prevStats, false).then(() => this.end()), null, true); + this.scene.ui.showText(i18next.t('battle:levelUp', { pokemonName: this.getPokemon().name, level: this.level }), null, () => this.scene.ui.getMessageHandler().promptLevelUpStats(this.partyMemberIndex, prevStats, false).then(() => this.end()), null, true); if (this.level <= 100) { const levelMoves = this.getPokemon().getLevelMoves(this.lastLevel + 1); for (let lm of levelMoves) @@ -3746,7 +3746,7 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase { .then(() => { this.scene.ui.setMode(messageMode).then(() => { this.scene.playSound('level_up_fanfare'); - this.scene.ui.showText(i18next.t('menu:learnMove', { pokemonName: pokemon.name, moveName: move.name }), null, () => { + this.scene.ui.showText(i18next.t('battle:learnMove', { pokemonName: pokemon.name, moveName: move.name }), null, () => { this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeMoveLearnedTrigger, true); this.end(); }, messageMode === Mode.EVOLUTION_SCENE ? 1000 : null, true); @@ -3755,15 +3755,15 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase { }); } else { this.scene.ui.setMode(messageMode).then(() => { - this.scene.ui.showText(i18next.t('menu:learnMovePrompt', { pokemonName: pokemon.name, moveName: move.name }), null, () => { - this.scene.ui.showText(i18next.t('menu:learnMoveLimitReached', { pokemonName: pokemon.name }), null, () => { - this.scene.ui.showText(i18next.t('menu:learnMoveReplaceQuestion', { moveName: move.name }), null, () => { + this.scene.ui.showText(i18next.t('battle:learnMovePrompt', { pokemonName: pokemon.name, moveName: move.name }), null, () => { + this.scene.ui.showText(i18next.t('battle:learnMoveLimitReached', { pokemonName: pokemon.name }), null, () => { + this.scene.ui.showText(i18next.t('battle:learnMoveReplaceQuestion', { moveName: move.name }), null, () => { const noHandler = () => { this.scene.ui.setMode(messageMode).then(() => { - this.scene.ui.showText(i18next.t('menu:learnMoveStopTeaching', { moveName: move.name }), null, () => { + this.scene.ui.showText(i18next.t('battle:learnMoveStopTeaching', { moveName: move.name }), null, () => { this.scene.ui.setModeWithoutClear(Mode.CONFIRM, () => { this.scene.ui.setMode(messageMode); - this.scene.ui.showText(i18next.t('menu:learnMoveNotLearned', { pokemonName: pokemon.name, moveName: move.name }), null, () => this.end(), null, true); + this.scene.ui.showText(i18next.t('battle:learnMoveNotLearned', { pokemonName: pokemon.name, moveName: move.name }), null, () => this.end(), null, true); }, () => { this.scene.ui.setMode(messageMode); this.scene.unshiftPhase(new LearnMovePhase(this.scene, this.partyMemberIndex, this.moveId)); @@ -3774,7 +3774,7 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase { }; this.scene.ui.setModeWithoutClear(Mode.CONFIRM, () => { this.scene.ui.setMode(messageMode); - this.scene.ui.showText(i18next.t('menu:learnMoveForgetQuestion'), null, () => { + this.scene.ui.showText(i18next.t('battle:learnMoveForgetQuestion'), null, () => { this.scene.ui.setModeWithoutClear(Mode.SUMMARY, this.getPokemon(), SummaryUiMode.LEARN_MOVE, move, (moveIndex: integer) => { if (moveIndex === 4) { noHandler(); @@ -3782,7 +3782,7 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase { } this.scene.ui.setMode(messageMode).then(() => { this.scene.ui.showText('@d{32}1, @d{15}2, and@d{15}… @d{15}… @d{15}… @d{15}@s{pb_bounce_1}Poof!', null, () => { - this.scene.ui.showText(i18next.t('menu:learnMoveForgetSuccess', { pokemonName: pokemon.name, moveName: pokemon.moveset[moveIndex].getName() }), null, () => { + this.scene.ui.showText(i18next.t('battle:learnMoveForgetSuccess', { pokemonName: pokemon.name, moveName: pokemon.moveset[moveIndex].getName() }), null, () => { this.scene.ui.showText('And…', null, () => { pokemon.setMove(moveIndex, Moves.NONE); this.scene.unshiftPhase(new LearnMovePhase(this.scene, this.partyMemberIndex, this.moveId)); @@ -4097,7 +4097,7 @@ export class AttemptCapturePhase extends PokemonPhase { this.scene.gameData.updateSpeciesDexIvs(pokemon.species.getRootSpeciesId(true), pokemon.ivs); - this.scene.ui.showText(i18next.t('menu:pokemonCaught', { pokemonName: pokemon.name }), null, () => { + this.scene.ui.showText(i18next.t('battle:pokemonCaught', { pokemonName: pokemon.name }), null, () => { const end = () => { this.scene.pokemonInfoContainer.hide(); this.removePb(); @@ -4183,7 +4183,7 @@ export class AttemptRunPhase extends PokemonPhase { if (playerPokemon.randSeedInt(256) < escapeChance.value) { this.scene.playSound('flee'); - this.scene.queueMessage(i18next.t('menu:runAwaySuccess'), null, true, 500); + this.scene.queueMessage(i18next.t('battle:runAwaySuccess'), null, true, 500); this.scene.tweens.add({ targets: [ this.scene.arenaEnemy, enemyField ].flat(), @@ -4204,7 +4204,7 @@ export class AttemptRunPhase extends PokemonPhase { this.scene.pushPhase(new BattleEndPhase(this.scene)); this.scene.pushPhase(new NewBattlePhase(this.scene)); } else - this.scene.queueMessage(i18next.t('menu:runAwayCannotEscape'), null, true, 500); + this.scene.queueMessage(i18next.t('battle:runAwayCannotEscape'), null, true, 500); this.end(); } @@ -4236,7 +4236,7 @@ export class SelectModifierPhase extends BattlePhase { const modifierSelectCallback = (rowCursor: integer, cursor: integer) => { if (rowCursor < 0 || cursor < 0) { - this.scene.ui.showText(i18next.t('menu:skipItemQuestion'), null, () => { + this.scene.ui.showText(i18next.t('battle:skipItemQuestion'), null, () => { this.scene.ui.setOverlayMode(Mode.CONFIRM, () => { this.scene.ui.revertMode(); this.scene.ui.setMode(Mode.MESSAGE); @@ -4415,7 +4415,7 @@ export class EggLapsePhase extends Phase { }); if (eggsToHatch.length) { - this.scene.queueMessage(i18next.t('menu:eggHatching')); + this.scene.queueMessage(i18next.t('battle:eggHatching')); for (let egg of eggsToHatch) this.scene.unshiftPhase(new EggHatchPhase(this.scene, egg)); @@ -4509,7 +4509,7 @@ export class ScanIvsPhase extends PokemonPhase { const pokemon = this.getPokemon(); - this.scene.ui.showText(i18next.t('menu:ivScannerUseQuestion', { pokemonName: pokemon.name }), null, () => { + this.scene.ui.showText(i18next.t('battle:ivScannerUseQuestion', { pokemonName: pokemon.name }), null, () => { this.scene.ui.setMode(Mode.CONFIRM, () => { this.scene.ui.setMode(Mode.MESSAGE); this.scene.ui.clearText(); diff --git a/src/plugins/i18n.ts b/src/plugins/i18n.ts index 22a407c3b42..4d770ae0a12 100644 --- a/src/plugins/i18n.ts +++ b/src/plugins/i18n.ts @@ -13,6 +13,12 @@ import { menuUiHandler as frMenuUiHandler } from '../locales/fr/menu-ui-handler. import { menuUiHandler as itMenuUiHandler } from '../locales/it/menu-ui-handler.js'; import { menuUiHandler as deMenuUiHandler } from '../locales/de/menu-ui-handler.js'; +import { battle as enBattle } from '../locales/en/battle'; +import { battle as esBattle } from '../locales/es/battle'; +import { battle as itBattle } from '../locales/it/battle'; +import { battle as frBattle } from '../locales/fr/battle'; +import { battle as deBattle } from '../locales/de/battle'; + import { move as enMove } from '../locales/en/move'; import { move as esMove } from '../locales/es/move'; import { move as frMove } from '../locales/fr/move'; @@ -45,7 +51,10 @@ import { commandUiHandler as frCommandUiHandler } from '../locales/fr/command-ui import { commandUiHandler as deCommandUiHandler } from '../locales/de/command-ui-handler'; import { fightUiHandler as enFightUiHandler } from '../locales/en/fight-ui-handler'; +import { fightUiHandler as esFightUiHandler } from '../locales/es/fight-ui-handler'; import { fightUiHandler as frFightUiHandler } from '../locales/fr/fight-ui-handler'; +import { fightUiHandler as itFightUiHandler } from '../locales/it/fight-ui-handler'; +import { fightUiHandler as deFightUiHandler } from '../locales/de/fight-ui-handler'; import { tutorial as enTutorial } from '../locales/en/tutorial'; import { tutorial as esTutorial } from '../locales/es/tutorial'; @@ -113,6 +122,7 @@ export function initI18n(): void { en: { menu: enMenu, menuUiHandler: enMenuUiHandler, + battle: enBattle, move: enMove, ability: enAbility, pokeball: enPokeball, @@ -125,17 +135,20 @@ export function initI18n(): void { es: { menu: esMenu, menuUiHandler: esMenuUiHandler, + battle: esBattle, move: esMove, ability: esAbility, pokeball: esPokeball, pokemon: esPokemon, pokemonStat: esPokemonStat, commandUiHandler: esCommandUiHandler, + fightUiHandler: esFightUiHandler, tutorial: esTutorial, }, fr: { menu: frMenu, menuUiHandler: frMenuUiHandler, + battle: frBattle, move: frMove, ability: frAbility, pokeball: frPokeball, @@ -148,18 +161,22 @@ export function initI18n(): void { it: { menu: itMenu, menuUiHandler: itMenuUiHandler, + battle: itBattle, pokemonStat: itPokemonStat, + fightUiHandler: itFightUiHandler, tutorial: itTutorial, }, de: { menu: deMenu, menuUiHandler: deMenuUiHandler, + battle: deBattle, move: deMove, ability: deAbility, pokeball: dePokeball, pokemon: dePokemon, pokemonStat: dePokemonStat, commandUiHandler: deCommandUiHandler, + fightUiHandler: deFightUiHandler, tutorial: deTutorial, } }, @@ -173,6 +190,7 @@ declare module 'i18next' { menu: typeof enMenu; menuUiHandler: typeof enMenuUiHandler; move: typeof enMove; + battle: typeof enBattle, ability: typeof enAbility; pokeball: typeof enPokeball; pokemon: typeof enPokemon; From ad59c0a7c4ae8543aba02e9ed39052545207ceac Mon Sep 17 00:00:00 2001 From: Benjamin Odom Date: Wed, 1 May 2024 18:05:34 -0500 Subject: [PATCH 24/72] Fixed Rounding Error For TargetHalfHpDamageAttr Moves that deal half of a target's HP were not able to deal damage if the target had 1 HP. Used Math.max to ensure 1 is the lowest this value ever evaluates to. --- src/data/move.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/move.ts b/src/data/move.ts index d6367794a35..ad1ae31c06f 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -557,7 +557,7 @@ export class TargetHalfHpDamageAttr extends FixedDamageAttr { } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - (args[0] as Utils.IntegerHolder).value = Math.floor(target.hp / 2); + (args[0] as Utils.IntegerHolder).value = Math.max(Math.floor(target.hp / 2), 1); return true; } From 86b0596a60d831eadc78de3ae57b202ab780d14c Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Wed, 1 May 2024 19:28:07 -0400 Subject: [PATCH 25/72] Add rogue achievement and voucher tier --- public/images/ui/achv_bar_4.png | Bin 458 -> 418 bytes public/images/ui/achv_bar_5.png | Bin 0 -> 458 bytes public/images/ui/legacy/achv_bar_4.png | Bin 433 -> 344 bytes public/images/ui/legacy/achv_bar_5.png | Bin 0 -> 433 bytes src/system/achv.ts | 5 ++++- src/system/voucher.ts | 2 +- 6 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 public/images/ui/achv_bar_5.png create mode 100644 public/images/ui/legacy/achv_bar_5.png diff --git a/public/images/ui/achv_bar_4.png b/public/images/ui/achv_bar_4.png index cc06af91620256e98ab26c762a49fe432cf584ce..debf8bfe2114a634e6f39e696088cca466d3a8d6 100644 GIT binary patch delta 394 zcmV;50d@Y$1EK?v7k?%Q0ssI2#x!fF00001b5ch_0Itp)=>Px$LPe5nZXH! zFc3wpBK4#ItH>!mqy-DuyQkdKgXJs;o?T>M+#TW)c4Hjj!yw5ej4ywZ@7OtG5Q0D_ z=9oHT03}l>fKmn}d0##5Rh3dHjAMy$o##JeiIEq)5tlraDt|->D02anU1ET;v*5Y| z6hJ9EhM^QFK*77B-cF_7tPTmjJD!-mLD1)_}DDB>PJ|%hYjCu6^6oT5=pb!Y! zy*5zP;-JJXgYq0l_A=TA*Fe!sWS!@0plFkZ$Olj|-U?6vrOa?bDF;evZ{Ebgrfs?@ z+(6HB&)Ca o0#&KYjDGtnRR9104rN$LW=%~1DgXcg2mk;800000(v!Ra4yk6PRR910 delta 411 zcmV;M0c8H71Ih!C7k?-S1^@s6b6lN|00001b5ch_0Itp)=>Px$YDq*vRA_DP__;of?62bTd;NQQCQhHNFtOB4BZe*7Di40I}8YfDoB_3*|Oia zMUmn^pOP0RegQ?4r?39U(RGNJ=(r9L8!B8F6)uc;y_*&*X^7a3YUo7pI@nQ#`fV5VOgs5Im<(9|lzo(r!xMo&& z-}A2B{AZ(YPQEzf@0RS;5BDB9#ED&hE3w3Un#k-;jNdNnO}=>J*2h|x>>UOW&0OMc zt=yjrT8X)$q#B=8ROsDu0jaQ>BteDVa??MX7Vv(E4&|GC<6uLL{*U??yJc5Pd0V!AT5KPxnOMwJ q?cnataG_EN7zKQ(5uRzjz6@GGHU|)cz@^~HAj;F#&t;ucLK6T2Ilt8a literal 0 HcmV?d00001 diff --git a/public/images/ui/legacy/achv_bar_4.png b/public/images/ui/legacy/achv_bar_4.png index dae7a30dec065d67334e6c7cbac6c05716d38fef..d52fbfd055e8a4839ab16a495f9dcccbcbdd71a5 100644 GIT binary patch delta 329 zcmdnUe1mC%L_G^L0|P^2QNtb}#aJBV?!<0h-v4*igLY0h6zQhc&hD}*Eg|98VGW)C zo{X+< zFWp}Gqp9Qyz2uY-l{Gwk_ZS)E-p|raFcyCUbTnUTglC$sFM}44%>l$9a4C2)i1Kvx Kb6Mw<&;$VCBZQ*> delta 419 zcmV;U0bKsr0n6zU{cp-{T%Si1Th`~q2ngF_cV1fg~gbjao)E?p$akUdLgUA%IME?RSG;`1Nd zlw5y3(n9lUD0P2!^ZxSo3buWR`v;gTr<(kjR)&tU1aY2H>wgb&3=6Jl7vMF4{rLQZ zI8O@)vEL_eUdOO7>J2ejPBmRT8RsbmR=@B9wq34i!!>OLX}Iy!#O@Xc06>t2wJcEn zz}r-mB>;d?ZwS4-yMr{u)$t7H50^?8wHVLgt^8J^%e%ZIf1`?2W7l;~mA_U*9bReG zMsR`?oDrPhjDO&}nclSDu>`NUi@TF{NFOx-Tbo@x`5Y#$z$gH&I9Hu3-f N002ovPDHLkV1jh6!Y}{; diff --git a/public/images/ui/legacy/achv_bar_5.png b/public/images/ui/legacy/achv_bar_5.png new file mode 100644 index 0000000000000000000000000000000000000000..dae7a30dec065d67334e6c7cbac6c05716d38fef GIT binary patch literal 433 zcmV;i0Z#sjP)7@C0mv(P8pKm(nTD)6%^_uSfNn5=~%k@9sB}WgM&jCK?I?84s^)oATC`b z$&fuuW?j5;i7r}mY2x!A+mu{?J<>w+YAAJocJu!7_6oLrhx-SZET@|Mm{x|4vIKFS zQtJJ2ejPBmRT8RsbmR=@B9wq34i!!>OL zX}Iy!#O@Xc06>t2wJcEnz}r-mB>;d?ZwS4-yMr{u)$t7H50^?8wHVLgt^8J^%e%ZI zf1`?2W7l;~mA_U*9bReGMsR`?oDrPhjNrSO-n8Gb1h2S@yOVZEA2k46>};po}6Pyv8;Os}>i}76fLh3kY9ew$WZD94`t$cWUzVgMi z^>*cN!Q~t9|HB(sS-f5s!5zawlqEYmY9cSViCv%G!Z9oWpA!%qrm8l1ZfY}B#hIRJ b6O(Ko9+rbtUwk(500000NkvXXu0mjfWv;=( literal 0 HcmV?d00001 diff --git a/src/system/achv.ts b/src/system/achv.ts index 2307347db3a..f63dd5b2810 100644 --- a/src/system/achv.ts +++ b/src/system/achv.ts @@ -7,6 +7,7 @@ export enum AchvTier { COMMON, GREAT, ULTRA, + ROGUE, MASTER } @@ -50,8 +51,10 @@ export class Achv { } getTier(): AchvTier { - if (this.score >= 100) + if (this.score >= 150) return AchvTier.MASTER; + if (this.score >= 100) + return AchvTier.ROGUE; if (this.score >= 50) return AchvTier.ULTRA; if (this.score >= 25) diff --git a/src/system/voucher.ts b/src/system/voucher.ts index c3bae6f0878..276e74eeb0d 100644 --- a/src/system/voucher.ts +++ b/src/system/voucher.ts @@ -44,7 +44,7 @@ export class Voucher { case VoucherType.PREMIUM: return AchvTier.ULTRA; case VoucherType.GOLDEN: - return AchvTier.MASTER; + return AchvTier.ROGUE; } } } From 2f8000885e2db76b607fdff06c26b7696284d491 Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Wed, 1 May 2024 19:29:04 -0400 Subject: [PATCH 26/72] Fix coloring error in rogue achievement bar --- public/images/ui/achv_bar_4.png | Bin 418 -> 318 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/public/images/ui/achv_bar_4.png b/public/images/ui/achv_bar_4.png index debf8bfe2114a634e6f39e696088cca466d3a8d6..f14026c7a34c13829053ffaa2291bda986ab9a3c 100644 GIT binary patch delta 270 zcmZ3)ypL&uc)bP-GXn!dV^PB%AjMc5hfTEf3IKb_|iYz z`ktrkcX2!j)5|Irh^<_ql=sx>kNm}{?V1yo#iTQ9o;sXAImK%7!4DyQs>T&o#ClL1!5l5_R&8W;0LU KRzA6gQ4IjBLuz*b delta 394 zcmV;50d@Yq0-^(u7k?%Q0ssI2#x!fF00001b5ch_0Itp)=>Px$LPe5nZXH! zFc3wpBK4#ItH>!mqy-DuyQkdKgXJs;o?T>M+#TW)c4Hjj!yw5ej4ywZ@7OtG5Q0D_ z=9oHT03}l>fKmn}d0##5Rh3dHjAMy$o##JeiIEq)5tlraDt|->D02anU1ET;v*5Y| z6hJ9EhM^QFK*77B-cF_7tPTmjJD!-mLD1)_}DDB>PJ|%hYjCu6^6oT5=pb!Y! zy*5zP;-JJXgYq0l_A=TA*Fe!sWS!@0plFkZ$Olj|-U?6vrOa?bDF;evZ{Ebgrfs?@ z+(6HB&)Ca o0#&KYjDGtnRR9104rN$LW=%~1DgXcg2mk;800000(vvU&4wJ#8yZ`_I From ba5bef123cffbadffd120f90960f94ea99f6efea Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Wed, 1 May 2024 19:42:06 -0400 Subject: [PATCH 27/72] Load missed master achievement bar --- src/loading-scene.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/loading-scene.ts b/src/loading-scene.ts index 875d618ec0f..d0751e9a2da 100644 --- a/src/loading-scene.ts +++ b/src/loading-scene.ts @@ -67,6 +67,7 @@ export class LoadingScene extends SceneBase { this.loadImage('achv_bar_2', 'ui'); this.loadImage('achv_bar_3', 'ui'); this.loadImage('achv_bar_4', 'ui'); + this.loadImage('achv_bar_5', 'ui'); this.loadImage('shiny_star', 'ui', 'shiny.png'); this.loadImage('shiny_star_1', 'ui', 'shiny_1.png'); this.loadImage('shiny_star_2', 'ui', 'shiny_2.png'); From 6d9424e43158123f9bceff53f5499f53f59ea694 Mon Sep 17 00:00:00 2001 From: Xavion3 Date: Thu, 2 May 2024 14:22:30 +1000 Subject: [PATCH 28/72] Implement Gastro Acid (#393) --- src/data/move.ts | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/data/move.ts b/src/data/move.ts index ad1ae31c06f..e1694ede8a3 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -3594,6 +3594,25 @@ export class SwitchAbilitiesAttr extends MoveEffectAttr { } } +export class SuppressAbilitiesAttr extends MoveEffectAttr { + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + if (!super.apply(user, target, move, args)) + return false; + + target.summonData.abilitySuppressed = true; + + target.scene.queueMessage(getPokemonMessage(target, ` ability\nwas suppressed!`)); + + return true; + } + + getCondition(): MoveConditionFunc { + return (user, target, move) => !target.getAbility().hasAttr(UnsuppressableAbilityAbAttr); + } +} + + + export class TransformAttr extends MoveEffectAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise { return new Promise(resolve => { @@ -4831,7 +4850,7 @@ export function initMoves() { new SelfStatusMove(Moves.POWER_TRICK, Type.PSYCHIC, -1, 10, -1, 0, 4) .unimplemented(), new StatusMove(Moves.GASTRO_ACID, Type.POISON, 100, 10, -1, 0, 4) - .unimplemented(), + .attr(SuppressAbilitiesAttr), new StatusMove(Moves.LUCKY_CHANT, Type.NORMAL, -1, 30, -1, 0, 4) .attr(AddBattlerTagAttr, BattlerTagType.NO_CRIT, false, false, 5) .target(MoveTarget.USER_SIDE) From a1bb0e7baf00d4f11929e360652537a2dc7dfc8a Mon Sep 17 00:00:00 2001 From: Lugiad Date: Thu, 2 May 2024 06:26:24 +0200 Subject: [PATCH 29/72] Updated French transaltion for tutorial.ts (#375) Translation of "statChange" + some remaning typos --- src/locales/fr/tutorial.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/locales/fr/tutorial.ts b/src/locales/fr/tutorial.ts index b60ccc03b5d..1502b285356 100644 --- a/src/locales/fr/tutorial.ts +++ b/src/locales/fr/tutorial.ts @@ -8,7 +8,7 @@ export const tutorial: SimpleTranslationEntries = { $Tout signalement de bugs passe par le serveur Discord. $Si le jeu est lent, vérifiez que l’Accélération Matérielle est activée dans les paramètres du navigateur.`, - "accessMenu": `Accédez au menu avec M ou Échap lors de l'attente d’une\naction. + "accessMenu": `Accédez au menu avec M ou Échap lors de l’attente d’une\naction. $Il contient les paramètres et diverses fonctionnalités`, "menu": `Vous pouvez accéder aux paramètres depuis ce menu. @@ -17,17 +17,20 @@ export const tutorial: SimpleTranslationEntries = { $jetez-y un œil !`, "starterSelect": `Choisissez vos starters depuis cet écran.\nIls formeront votre équipe de départ. - $Chacun possède une valeur. Votre équipe peut avoir jusqu’à\n6 membres, tant que vous ne dépassez pas un coût de 10. + $Chacun possède une valeur. Votre équipe peut avoir jusqu’à\n6 membres, tant que vous ne dépassez pas un cout de 10. $Vous pouvez aussi choisir le sexe, le talent et la forme en\nfonction des variants déjà capturés ou éclos. $Les IVs d’un starter sont les meilleurs de tous ceux de son\nespèce déjà obtenus. Essayez donc d’en obtenir plusieurs !`, "pokerus": `Chaque jour, 3 starters tirés aléatoirement ont un contour $violet. Si un starter que vous possédez l’a, essayez de - $ l’ajouter à votre équipe. Vérifiez bien son résumé !`, + $l’ajouter à votre équipe. Vérifiez bien son résumé !`, - "statChange": `Stat changes persist across battles as long as your Pokémon aren't recalled. - $Your Pokémon are recalled before a trainer battle and before entering a new biome. - $You can also view the stat changes for the Pokémon on the field by holding C or Shift.`, + "statChange": `Les changements de stats restent à travers les combats tant que le Pokémon + $n’est pas rappelé. + $Vos Pokémon sont rappelés avant un combat de Dresseur et avant d’entrer + $dans un nouveau biome. + $Vous pouvez également voir en combat les changements de stats d’un Pokémon + $en maintenant C ou Maj.`, "selectItem": `Après chaque combat, vous avez le choix entre 3 objets\ntirés au sort. Vous ne pouvez en prendre qu’un. $Cela peut être des objets consommables, des objets à\nfaire tenir, ou des objets passifs aux effets permanents. @@ -44,4 +47,4 @@ export const tutorial: SimpleTranslationEntries = { $Les Pokémon issus d’Œufs ont généralement de\nmeilleurs IVs que les Pokémon sauvages. $Certains Pokémon ne peuvent être obtenus\nque dans des Œufs. $Il y a 3 différentes machines à actionner avec différents\nbonus, prenez celle qui vous convient le mieux !`, -} as const; \ No newline at end of file +} as const; From c9152cda3f27c0277cedc7782cad00a39428163f Mon Sep 17 00:00:00 2001 From: Benjamin Odom Date: Thu, 2 May 2024 00:17:32 -0500 Subject: [PATCH 30/72] Fix Mobile PWA not showing in true Fullscreen (#394) * Fixed Rounding Error For TargetHalfHpDamageAttr Moves that deal half of a target's HP were not able to deal damage if the target had 1 HP. Used Math.max to ensure 1 is the lowest this value ever evaluates to. * Fix Mobile PWA not showing in true Fullscreen adding "fullscreen" to the display attribute wasn't enough, but adding it to the start_url attribute was. This does not appear to affect PC (which is good since it shouldn't). * Allow any orientation for mobile PWA remove the orientation restriction since it doesn't prevent fullscreen PWA from displaying properly. --- public/manifest.webmanifest | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/public/manifest.webmanifest b/public/manifest.webmanifest index c75c70a8d45..4b5f2dbadd1 100644 --- a/public/manifest.webmanifest +++ b/public/manifest.webmanifest @@ -3,9 +3,8 @@ "short_name": "PokéRogue", "description": "A Pokémon fangame heavily inspired by the roguelite genre. Battle endlessly while gathering stacking items, exploring many different biomes, and reaching Pokémon stats you never thought possible.", "scope": "/", - "start_url": "/", + "start_url": "https://pokerogue.net", "display": "fullscreen", - "orientation": "landscape", "background_color": "#8c8c8c", "theme_color": "#8c8c8c", "icons": [ From 71893e8428f410c8d22ee31abb87223ba0336977 Mon Sep 17 00:00:00 2001 From: Lugiad Date: Thu, 2 May 2024 14:34:59 +0200 Subject: [PATCH 31/72] Update Spanish fight-ui-handler.ts --- src/locales/es/fight-ui-handler.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/locales/es/fight-ui-handler.ts b/src/locales/es/fight-ui-handler.ts index 1ce9e0317bf..b431e3b7065 100644 --- a/src/locales/es/fight-ui-handler.ts +++ b/src/locales/es/fight-ui-handler.ts @@ -2,5 +2,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const fightUiHandler: SimpleTranslationEntries = { "pp": "PP", - "power": "POWER", -} as const; \ No newline at end of file + "power": "POTENCIA", +} as const; From 10506f9cf58975088836db96aad2fca691ab7889 Mon Sep 17 00:00:00 2001 From: Lugiad Date: Thu, 2 May 2024 14:37:05 +0200 Subject: [PATCH 32/72] Update italian pokemon-stat.ts (#389) * Update italian pokemon-stat.ts * Update italian pokemon-stat.ts --- src/locales/it/pokemon-stat.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/locales/it/pokemon-stat.ts b/src/locales/it/pokemon-stat.ts index 7a209461b11..a3a62edebe2 100644 --- a/src/locales/it/pokemon-stat.ts +++ b/src/locales/it/pokemon-stat.ts @@ -1,16 +1,16 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const pokemonStat: SimpleTranslationEntries = { - "HP": "Max. HP", - "HPshortened": "MaxHP", - "ATK": "Attack", - "ATKshortened": "Atk", - "DEF": "Defense", - "DEFshortened": "Def", - "SPATK": "Sp. Atk", - "SPATKshortened": "SpAtk", - "SPDEF": "Sp. Def", - "SPDEFshortened": "SpDef", - "SPD": "Speed", - "SPDshortened": "Spd" -} as const; \ No newline at end of file + "HP": "PS Max", + "HPshortened": "PS", + "ATK": "Attacco", + "ATKshortened": "Att", + "DEF": "Difensa", + "DEFshortened": "Dif", + "SPATK": "Att. Sp.", + "SPATKshortened": "AttSp", + "SPDEF": "Dif. Sp.", + "SPDEFshortened": "DifSp", + "SPD": "Velocità", + "SPDshortened": "Vel" +} as const; From 0185dd639e0238b60a248d4f0f51dc89c245bebe Mon Sep 17 00:00:00 2001 From: James Lin Date: Thu, 2 May 2024 05:44:10 -0700 Subject: [PATCH 33/72] Catch global errors and rejected promises and display them in an alert box. (#351) * Catch errors and rejected promises. * Clean up --- src/main.ts | 16 ++++++++++++++++ src/phases.ts | 2 ++ src/ui/daily-run-scoreboard.ts | 2 +- src/ui/title-ui-handler.ts | 3 +++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/main.ts b/src/main.ts index 6a00693fc71..4b181f58174 100644 --- a/src/main.ts +++ b/src/main.ts @@ -9,6 +9,22 @@ import BBCodeText from 'phaser3-rex-plugins/plugins/bbcodetext'; import TransitionImagePackPlugin from 'phaser3-rex-plugins/templates/transitionimagepack/transitionimagepack-plugin.js'; import { LoadingScene } from './loading-scene'; + +// Catch global errors and display them in an alert so users can report the issue. +window.onerror = function (message, source, lineno, colno, error) { + console.error(error); + let errorString = `Received unhandled error. Open browser console and click OK to see details.\nError: ${message}\nSource: ${source}\nLine: ${lineno}\nColumn: ${colno}\nStack: ${error.stack}`; + alert(errorString); + // Avoids logging the error a second time. + return true; +}; + +// Catch global promise rejections and display them in an alert so users can report the issue. +window.addEventListener('unhandledrejection', (event) => { + let errorString = `Received unhandled promise rejection. Open browser console and click OK to see details.\nReason: ${event.reason}`; + alert(errorString); + }); + const config: Phaser.Types.Core.GameConfig = { type: Phaser.WEBGL, parent: 'app', diff --git a/src/phases.ts b/src/phases.ts index 72f0e10cc3e..2ffa25aef0f 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -331,6 +331,8 @@ export class TitlePhase extends Phase { this.scene.sessionPlayTime = 0; this.end(); }); + }).catch(err => { + console.error("Failed to load daily run:\n", err); }); }); } diff --git a/src/ui/daily-run-scoreboard.ts b/src/ui/daily-run-scoreboard.ts index 8f7ca0bf110..8b258b3a702 100644 --- a/src/ui/daily-run-scoreboard.ts +++ b/src/ui/daily-run-scoreboard.ts @@ -167,7 +167,7 @@ export class DailyRunScoreboard extends Phaser.GameObjects.Container { } else this.loadingLabel.setText(i18next.t('menu:noRankings')); }); - }); + }).catch(err => { console.error("Failed to load daily rankings:\n", err) }); } } diff --git a/src/ui/title-ui-handler.ts b/src/ui/title-ui-handler.ts index c430764e4da..6f873c6b0a1 100644 --- a/src/ui/title-ui-handler.ts +++ b/src/ui/title-ui-handler.ts @@ -65,6 +65,9 @@ export default class TitleUiHandler extends OptionSelectUiHandler { this.playerCountLabel.setText(`${stats.playerCount} ${i18next.t("menu:playersOnline")}`); if (this.splashMessage === battleCountSplashMessage) this.splashMessageText.setText(battleCountSplashMessage.replace('{COUNT}', stats.battleCount.toLocaleString('en-US'))); + }) + .catch(err => { + console.error("Failed to fetch title stats:\n", err); }); } From 3a7a48fe833f9ab1a10339f3fdd4b10b190cdae3 Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Thu, 2 May 2024 09:00:36 -0400 Subject: [PATCH 34/72] Temporarily disable error handling --- src/main.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main.ts b/src/main.ts index 4b181f58174..b3b4d5f3cc6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -14,7 +14,7 @@ import { LoadingScene } from './loading-scene'; window.onerror = function (message, source, lineno, colno, error) { console.error(error); let errorString = `Received unhandled error. Open browser console and click OK to see details.\nError: ${message}\nSource: ${source}\nLine: ${lineno}\nColumn: ${colno}\nStack: ${error.stack}`; - alert(errorString); + //alert(errorString); // Avoids logging the error a second time. return true; }; @@ -22,8 +22,9 @@ window.onerror = function (message, source, lineno, colno, error) { // Catch global promise rejections and display them in an alert so users can report the issue. window.addEventListener('unhandledrejection', (event) => { let errorString = `Received unhandled promise rejection. Open browser console and click OK to see details.\nReason: ${event.reason}`; - alert(errorString); - }); + console.error(event.reason); + //alert(errorString); +}); const config: Phaser.Types.Core.GameConfig = { type: Phaser.WEBGL, From 322838cfb5a9d486e0f46e60c85efbeb7f1b564b Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Thu, 2 May 2024 11:37:06 -0400 Subject: [PATCH 35/72] Move service-worker to public folder --- service-worker.js => public/service-worker.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename service-worker.js => public/service-worker.js (100%) diff --git a/service-worker.js b/public/service-worker.js similarity index 100% rename from service-worker.js rename to public/service-worker.js From ddb4383b1f9620fbc5040189076eba57668e3985 Mon Sep 17 00:00:00 2001 From: Madmadness65 Date: Thu, 2 May 2024 14:01:57 -0500 Subject: [PATCH 36/72] Move Porygon line down to Rare in Factory biome This makes the Porygon line more common than before. --- src/data/biomes.ts | 12 ++++++------ src/data/move.ts | 5 +---- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/data/biomes.ts b/src/data/biomes.ts index d6e84bcbc7c..c6a3c95b631 100644 --- a/src/data/biomes.ts +++ b/src/data/biomes.ts @@ -615,7 +615,7 @@ export const biomePokemonPools: BiomePokemonPools = { [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], - [TimeOfDay.ALL]: [ Species.QWILFISH, Species.CORSOLA, Species.OCTILLERY, { 1: [ Species.MANTYKE ], 20: [ Species.MANTINE ] }, Species.ALOMOMOLA, { 1: [ Species.TYNAMO ], 39: [ Species.EELEKTRIK ] }, Species.DHELMISE ] + [TimeOfDay.ALL]: [ Species.QWILFISH, Species.CORSOLA, Species.OCTILLERY, { 1: [ Species.MANTYKE ], 52: [ Species.MANTINE ] }, Species.ALOMOMOLA, { 1: [ Species.TYNAMO ], 39: [ Species.EELEKTRIK ] }, Species.DHELMISE ] }, [BiomePoolTier.SUPER_RARE]: { [TimeOfDay.DAWN]: [], @@ -1128,8 +1128,8 @@ export const biomePokemonPools: BiomePokemonPools = { ] }, [BiomePoolTier.UNCOMMON]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ { 1: [ Species.BRONZOR ], 33: [ Species.BRONZONG ] }, Species.KLEFKI ] }, - [BiomePoolTier.RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] }, - [BiomePoolTier.SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ { 1: [ Species.PORYGON ], 30: [ Species.PORYGON2 ] }, { 1: [ Species.BELDUM ], 20: [ Species.METANG ], 45: [ Species.METAGROSS ] } ] }, + [BiomePoolTier.RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ { 1: [ Species.PORYGON ], 30: [ Species.PORYGON2 ] } ] }, + [BiomePoolTier.SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ { 1: [ Species.BELDUM ], 20: [ Species.METANG ], 45: [ Species.METAGROSS ] } ] }, [BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.GENESECT, Species.MAGEARNA ] }, [BiomePoolTier.BOSS]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.KLINKLANG, Species.KLEFKI ] }, [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] }, @@ -1319,7 +1319,7 @@ export const biomePokemonPools: BiomePokemonPools = { [TimeOfDay.DAY]: [ Species.VESPIQUEN, { 1: [ Species.CHERUBI ], 25: [ Species.CHERRIM ] }, { 1: [ Species.SEWADDLE ], 20: [ Species.SWADLOON ], 30: [ Species.LEAVANNY ] } ], [TimeOfDay.DUSK]: [ Species.SHROOMISH, { 1: [ Species.PURRLOIN ], 20: [ Species.LIEPARD ] }, { 1: [ Species.FOONGUS ], 39: [ Species.AMOONGUSS ] } ], [TimeOfDay.NIGHT]: [ { 1: [ Species.SPINARAK ], 22: [ Species.ARIADOS ] }, Species.SHROOMISH, { 1: [ Species.PURRLOIN ], 20: [ Species.LIEPARD ] }, { 1: [ Species.FOONGUS ], 39: [ Species.AMOONGUSS ] } ], - [TimeOfDay.ALL]: [ Species.AIPOM, { 1: [ Species.BLITZLE ], 27: [ Species.ZEBSTRIKA ] }, { 1: [ Species.PIKIPEK ], 14: [ Species.TRUMBEAK ], 36: [ Species.TOUCANNON ] } ] + [TimeOfDay.ALL]: [ Species.AIPOM, { 1: [ Species.BLITZLE ], 27: [ Species.ZEBSTRIKA ] }, { 1: [ Species.PIKIPEK ], 14: [ Species.TRUMBEAK ], 28: [ Species.TOUCANNON ] } ] }, [BiomePoolTier.UNCOMMON]: { [TimeOfDay.DAWN]: [ Species.EXEGGCUTE, Species.TROPIUS, Species.COMBEE, Species.KOMALA ], @@ -2708,7 +2708,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { ] ], [ Species.PORYGON, Type.NORMAL, -1, [ - [ Biome.FACTORY, BiomePoolTier.SUPER_RARE ], + [ Biome.FACTORY, BiomePoolTier.RARE ], [ Biome.SPACE, BiomePoolTier.SUPER_RARE ], [ Biome.LABORATORY, BiomePoolTier.RARE ] ] @@ -3165,7 +3165,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { ] ], [ Species.PORYGON2, Type.NORMAL, -1, [ - [ Biome.FACTORY, BiomePoolTier.SUPER_RARE ], + [ Biome.FACTORY, BiomePoolTier.RARE ], [ Biome.SPACE, BiomePoolTier.SUPER_RARE ], [ Biome.LABORATORY, BiomePoolTier.RARE ] ] diff --git a/src/data/move.ts b/src/data/move.ts index e1694ede8a3..e300b3ae20d 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -3611,8 +3611,6 @@ export class SuppressAbilitiesAttr extends MoveEffectAttr { } } - - export class TransformAttr extends MoveEffectAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise { return new Promise(resolve => { @@ -6357,8 +6355,7 @@ export function initMoves() { }), // TODO Add Instruct/Encore interaction new AttackMove(Moves.COMEUPPANCE, Type.DARK, MoveCategory.PHYSICAL, 1, 100, 10, -1, 0, 9) .attr(CounterDamageAttr, (move: Move) => (move.category === MoveCategory.PHYSICAL || move.category === MoveCategory.SPECIAL), 1.5) - .target(MoveTarget.ATTACKER) - .partial(), + .target(MoveTarget.ATTACKER), new AttackMove(Moves.AQUA_CUTTER, Type.WATER, MoveCategory.PHYSICAL, 70, 100, 20, -1, 0, 9) .attr(HighCritAttr) .slicingMove() From 9d8f7ddcf0b8afb07df95a10ec7839b8f83b1594 Mon Sep 17 00:00:00 2001 From: Benjamin Odom Date: Thu, 2 May 2024 14:10:21 -0500 Subject: [PATCH 37/72] Implement Tailwind (#398) Added a new ArenaTagType for Tailwind. Lasts 4 turns including the turn used. --- src/data/arena-tag.ts | 16 ++++++++++++++++ src/data/enums/arena-tag-type.ts | 3 ++- src/data/move.ts | 4 ++-- src/field/pokemon.ts | 5 +++++ 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/data/arena-tag.ts b/src/data/arena-tag.ts index a879c68d4ce..8942cfe4b3e 100644 --- a/src/data/arena-tag.ts +++ b/src/data/arena-tag.ts @@ -482,6 +482,20 @@ export class GravityTag extends ArenaTag { } } +class TailwindTag extends ArenaTag { + constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) { + super(ArenaTagType.TAILWIND, turnCount, Moves.TAILWIND, sourceId, side); + } + + onAdd(arena: Arena): void { + arena.scene.queueMessage(`The Tailwind blew from behind${this.side === ArenaTagSide.PLAYER ? '\nyour' : this.side === ArenaTagSide.ENEMY ? '\nthe opposing' : ''} team!`); + } + + onRemove(arena: Arena): void { + arena.scene.queueMessage(`${this.side === ArenaTagSide.PLAYER ? 'Your' : this.side === ArenaTagSide.ENEMY ? 'The opposing' : ''} team's Tailwind petered out!`); + } +} + export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves, sourceId: integer, targetIndex?: BattlerIndex, side: ArenaTagSide = ArenaTagSide.BOTH): ArenaTag { switch (tagType) { case ArenaTagType.MIST: @@ -513,5 +527,7 @@ export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMov return new LightScreenTag(turnCount, sourceId, side); case ArenaTagType.AURORA_VEIL: return new AuroraVeilTag(turnCount, sourceId, side); + case ArenaTagType.TAILWIND: + return new TailwindTag(turnCount, sourceId, side); } } diff --git a/src/data/enums/arena-tag-type.ts b/src/data/enums/arena-tag-type.ts index 8478b6f3f57..2ecac8b5677 100644 --- a/src/data/enums/arena-tag-type.ts +++ b/src/data/enums/arena-tag-type.ts @@ -15,5 +15,6 @@ export enum ArenaTagType { GRAVITY = "GRAVITY", REFLECT = "REFLECT", LIGHT_SCREEN = "LIGHT_SCREEN", - AURORA_VEIL = "AURORA_VEIL" + AURORA_VEIL = "AURORA_VEIL", + TAILWIND = "TAILWIND" } diff --git a/src/data/move.ts b/src/data/move.ts index e300b3ae20d..b26af03fc5e 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -4805,8 +4805,8 @@ export function initMoves() { .partial(), new StatusMove(Moves.TAILWIND, Type.FLYING, -1, 15, -1, 0, 4) .windMove() - .target(MoveTarget.USER_SIDE) - .unimplemented(), + .attr(AddArenaTagAttr, ArenaTagType.TAILWIND, 4, true) + .target(MoveTarget.USER_SIDE), new StatusMove(Moves.ACUPRESSURE, Type.NORMAL, -1, 30, -1, 0, 4) .attr(StatChangeAttr, BattleStat.RAND, 2) .target(MoveTarget.USER_OR_NEAR_ALLY), diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index a966a24303f..daa7876853b 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -589,6 +589,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { ret *= 1.5; break; case Stat.SPD: + // Check both the player and enemy to see if Tailwind should be multiplying the speed of the Pokemon + if ((this.isPlayer() && this.scene.arena.getTagOnSide(ArenaTagType.TAILWIND, ArenaTagSide.PLAYER)) + || (!this.isPlayer() && this.scene.arena.getTagOnSide(ArenaTagType.TAILWIND, ArenaTagSide.ENEMY))) + ret *= 2; + if (this.getTag(BattlerTagType.SLOW_START)) ret >>= 1; if (this.status && this.status.effect === StatusEffect.PARALYSIS) From dffa9b2704dba212dfbaf1f1c518c4e65edb8737 Mon Sep 17 00:00:00 2001 From: maru Date: Thu, 2 May 2024 15:48:59 -0400 Subject: [PATCH 38/72] Add more files to be purged from CF cache on deploy --- .github/workflows/deploy.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index e678a297852..07aed42a5a7 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -41,4 +41,6 @@ jobs: files: | https://pokerogue.net/ https://pokerogue.net/index.html - https://pokerogue.net/manifest.json \ No newline at end of file + https://pokerogue.net/manifest.json + https://pokerogue.net/manifest.webmanifest + https://pokerogue.net/service-worker.js \ No newline at end of file From 991f097e9e2488192dd7a6d8084365e49aa9200b Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Thu, 2 May 2024 17:48:08 -0400 Subject: [PATCH 39/72] Rebalance friendship and add starter friendship with candy reward --- src/data/pokemon-species.ts | 26 +++++++++++++++++++++++++- src/field/pokemon.ts | 27 +++++++++++++++++++++++++-- src/modifier/modifier-type.ts | 2 +- src/modifier/modifier.ts | 9 ++++----- src/phases.ts | 15 +++++---------- src/system/game-data.ts | 5 ++++- 6 files changed, 64 insertions(+), 20 deletions(-) diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index 2f8edefa403..c67f0c14b47 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -367,8 +367,8 @@ export abstract class PokemonSpeciesForm { loadAssets(scene: BattleScene, female: boolean, formIndex?: integer, shiny?: boolean, variant?: Variant, startLoad?: boolean): Promise { return new Promise(resolve => { const spriteKey = this.getSpriteKey(female, formIndex, shiny, variant); - scene.load.audio(this.getCryKey(formIndex), `audio/cry/${this.getCryKey(formIndex)}.m4a`); scene.loadPokemonAtlas(spriteKey, this.getSpriteAtlasPath(female, formIndex, shiny, variant)); + scene.load.audio(this.getCryKey(formIndex), `audio/cry/${this.getCryKey(formIndex)}.m4a`); scene.load.once(Phaser.Loader.Events.COMPLETE, () => { const originalWarn = console.warn; // Ignore warnings for missing frames, because there will be a lot @@ -3156,6 +3156,30 @@ export const noStarterFormKeys: string[] = [ SpeciesFormKey.ETERNAMAX ].map(k => k.toString()); +export function getStarterValueFriendshipCap(value: integer): integer { + switch (value) { + case 1: + return 20; + case 2: + return 40; + case 3: + return 60; + case 4: + return 100; + case 5: + return 140; + case 6: + return 200; + case 7: + return 280; + case 8: + case 9: + return 450; + default: + return 600; + } +} + export const starterPassiveAbilities = { [Species.BULBASAUR]: Abilities.SOLAR_POWER, [Species.CHARMANDER]: Abilities.INTIMIDATE, diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index daa7876853b..08482bbd914 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -5,12 +5,12 @@ import { variantData } from '#app/data/variant'; import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from '../ui/battle-info'; import { Moves } from "../data/enums/moves"; import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, VariablePowerAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, MultiHitAttr, StatusMoveTypeImmunityAttr, MoveTarget, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatChangesAttr, SacrificialAttr, VariableMoveTypeAttr, VariableMoveCategoryAttr } from "../data/move"; -import { default as PokemonSpecies, PokemonSpeciesForm, SpeciesFormKey, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm, starterPassiveAbilities } from '../data/pokemon-species'; +import { default as PokemonSpecies, PokemonSpeciesForm, SpeciesFormKey, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm, getStarterValueFriendshipCap, speciesStarters, starterPassiveAbilities } from '../data/pokemon-species'; import * as Utils from '../utils'; import { Type, TypeDamageMultiplier, getTypeDamageMultiplier, getTypeRgb } from '../data/type'; import { getLevelTotalExp } from '../data/exp'; import { Stat } from '../data/pokemon-stat'; -import { AttackTypeBoosterModifier, DamageMoneyRewardModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, EnemyEndureChanceModifier, EnemyFusionChanceModifier, HiddenAbilityRateBoosterModifier, PokemonBaseStatModifier, PokemonHeldItemModifier, PokemonMultiHitModifier, PokemonNatureWeightModifier, ShinyRateBoosterModifier, SurviveDamageModifier, TempBattleStatBoosterModifier, TerastallizeModifier } from '../modifier/modifier'; +import { AttackTypeBoosterModifier, DamageMoneyRewardModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, EnemyEndureChanceModifier, EnemyFusionChanceModifier, HiddenAbilityRateBoosterModifier, PokemonBaseStatModifier, PokemonFriendshipBoosterModifier, PokemonHeldItemModifier, PokemonMultiHitModifier, PokemonNatureWeightModifier, ShinyRateBoosterModifier, SurviveDamageModifier, TempBattleStatBoosterModifier, TerastallizeModifier } from '../modifier/modifier'; import { PokeballType } from '../data/pokeball'; import { Gender } from '../data/gender'; import { initMoveAnim, loadMoveAnimAssets } from '../data/battle-anims'; @@ -2367,6 +2367,29 @@ export class PlayerPokemon extends Pokemon { }, PartyUiHandler.FilterNonFainted); }); } + + addFriendship(friendship: integer): void { + const starterSpeciesId = this.species.getRootSpeciesId(); + const starterData = this.scene.gameData.starterData[starterSpeciesId]; + const amount = new Utils.IntegerHolder(friendship); + const starterAmount = new Utils.IntegerHolder(friendship * (this.scene.gameMode.isClassic ? 2 : 1)); + if (amount.value > 0) { + this.scene.applyModifier(PokemonFriendshipBoosterModifier, true, this, amount); + this.scene.applyModifier(PokemonFriendshipBoosterModifier, true, this, starterAmount); + + this.friendship = Math.min(this.friendship + amount.value, 255); + if (this.friendship === 255) + this.scene.validateAchv(achvs.MAX_FRIENDSHIP); + starterData.friendship = (starterData.friendship || 0) + starterAmount.value; + if (starterData.friendship >= getStarterValueFriendshipCap(speciesStarters[starterSpeciesId])) { + this.scene.gameData.addStarterCandy(getPokemonSpecies(starterSpeciesId), 1); + starterData.friendship = 0; + } + } else { + this.friendship = Math.max(this.friendship + amount.value, 0); + starterData.friendship = Math.max((starterData.friendship || 0) + starterAmount.value, 0); + } + } getPossibleEvolution(evolution: SpeciesFormEvolution): Promise { return new Promise(resolve => { diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 6237e8b5a50..4229b8be3b7 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -1058,7 +1058,6 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.ATTACK_TYPE_BOOSTER, 10), new WeightedModifierType(modifierTypes.TM_ULTRA, 8), new WeightedModifierType(modifierTypes.RARER_CANDY, 4), - new WeightedModifierType(modifierTypes.SOOTHE_BELL, (party: Pokemon[]) => party.find(p => (pokemonEvolutions.hasOwnProperty(p.species.speciesId) && pokemonEvolutions[p.species.speciesId].find(e => e.condition && e.condition instanceof SpeciesFriendshipEvolutionCondition)) || p.moveset.find(m => m.moveId === Moves.RETURN)) ? 16 : 0, 16), new WeightedModifierType(modifierTypes.GOLDEN_PUNCH, 2), new WeightedModifierType(modifierTypes.IV_SCANNER, 4), new WeightedModifierType(modifierTypes.EXP_CHARM, 8), @@ -1078,6 +1077,7 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.BATON, 2), new WeightedModifierType(modifierTypes.SOUL_DEW, 8), //new WeightedModifierType(modifierTypes.OVAL_CHARM, 6), + new WeightedModifierType(modifierTypes.SOOTHE_BELL, 4), new WeightedModifierType(modifierTypes.ABILITY_CHARM, 6), new WeightedModifierType(modifierTypes.FOCUS_BAND, 5), new WeightedModifierType(modifierTypes.KINGS_ROCK, 3), diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index d8fad1466b9..88b009d3a48 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -1111,9 +1111,7 @@ export class PokemonLevelIncrementModifier extends ConsumablePokemonModifier { pokemon.levelExp = 0; } - const friendshipIncrease = new Utils.IntegerHolder(5); - pokemon.scene.applyModifier(PokemonFriendshipBoosterModifier, true, pokemon, friendshipIncrease); - pokemon.friendship = Math.min(pokemon.friendship + friendshipIncrease.value, 255); + pokemon.addFriendship(5); pokemon.scene.unshiftPhase(new LevelUpPhase(pokemon.scene, pokemon.scene.getParty().indexOf(pokemon), pokemon.level - levelCount.value, pokemon.level)); @@ -1392,13 +1390,14 @@ export class PokemonFriendshipBoosterModifier extends PokemonHeldItemModifier { } apply(args: any[]): boolean { - (args[1] as Utils.IntegerHolder).value *= 1 + 0.5 * this.getStackCount(); + const friendship = args[1] as Utils.IntegerHolder; + friendship.value = Math.floor(friendship.value * (1 + 0.5 * this.getStackCount())); return true; } getMaxHeldItemCount(pokemon: Pokemon): integer { - return 5; + return 3; } } diff --git a/src/phases.ts b/src/phases.ts index 2ffa25aef0f..4c2f5536268 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -6,7 +6,7 @@ import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMov import { Mode } from './ui/ui'; import { Command } from "./ui/command-ui-handler"; import { Stat } from "./data/pokemon-stat"; -import { BerryModifier, ContactHeldItemTransferChanceModifier, EnemyAttackStatusEffectChanceModifier, EnemyPersistentModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, FusePokemonModifier, HealingBoosterModifier, HitHealModifier, LapsingPersistentModifier, MapModifier, Modifier, MultipleParticipantExpBonusModifier, PersistentModifier, PokemonExpBoosterModifier, PokemonHeldItemModifier, PokemonInstantReviveModifier, SwitchEffectTransferModifier, TempBattleStatBoosterModifier, TurnHealModifier, TurnHeldItemTransferModifier, MoneyMultiplierModifier, MoneyInterestModifier, IvScannerModifier, PokemonFriendshipBoosterModifier, LapsingPokemonHeldItemModifier, PokemonMultiHitModifier, PokemonMoveAccuracyBoosterModifier } from "./modifier/modifier"; +import { BerryModifier, ContactHeldItemTransferChanceModifier, EnemyAttackStatusEffectChanceModifier, EnemyPersistentModifier, EnemyStatusEffectHealChanceModifier, EnemyTurnHealModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, FusePokemonModifier, HealingBoosterModifier, HitHealModifier, LapsingPersistentModifier, MapModifier, Modifier, MultipleParticipantExpBonusModifier, PersistentModifier, PokemonExpBoosterModifier, PokemonHeldItemModifier, PokemonInstantReviveModifier, SwitchEffectTransferModifier, TempBattleStatBoosterModifier, TurnHealModifier, TurnHeldItemTransferModifier, MoneyMultiplierModifier, MoneyInterestModifier, IvScannerModifier, LapsingPokemonHeldItemModifier, PokemonMultiHitModifier, PokemonMoveAccuracyBoosterModifier } from "./modifier/modifier"; import PartyUiHandler, { PartyOption, PartyUiMode } from "./ui/party-ui-handler"; import { doPokeballBounceAnim, getPokeballAtlasKey, getPokeballCatchMultiplier, getPokeballTintColor, PokeballType } from "./data/pokeball"; import { CommonAnim, CommonBattleAnim, MoveAnim, initMoveAnim, loadMoveAnimAssets } from "./data/battle-anims"; @@ -3154,8 +3154,8 @@ export class FaintPhase extends PokemonPhase { this.scene.getField(true).filter(p => p !== pokemon).forEach(p => p.removeTagsBySourceId(pokemon.id)); pokemon.faintCry(() => { - const friendshipDecrease = new Utils.IntegerHolder(10); - pokemon.friendship = Math.max(pokemon.friendship - friendshipDecrease.value, 0); + if (pokemon instanceof PlayerPokemon) + pokemon.addFriendship(-10); pokemon.hideInfo(); this.scene.playSound('faint'); this.scene.tweens.add({ @@ -3226,13 +3226,8 @@ export class VictoryPhase extends PokemonPhase { for (let partyMember of expPartyMembers) { const pId = partyMember.id; const participated = participantIds.has(pId); - if (participated) { - const friendshipIncrease = new Utils.IntegerHolder(2); - this.scene.applyModifier(PokemonFriendshipBoosterModifier, true, partyMember, friendshipIncrease); - partyMember.friendship = Math.min(partyMember.friendship + friendshipIncrease.value, 255); - if (partyMember.friendship === 255) - this.scene.validateAchv(achvs.MAX_FRIENDSHIP); - } + if (participated) + partyMember.addFriendship(2); else if (!expShareModifier) { partyMemberExp.push(0); continue; diff --git a/src/system/game-data.ts b/src/system/game-data.ts index e11c2dcc572..b7495a1eac9 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -169,6 +169,7 @@ export interface StarterDataEntry { moveset: StarterMoveset | StarterFormMoveData; eggMoves: integer; candyCount: integer; + friendship: integer; abilityAttr: integer; passiveAttr: integer; valueReduction: integer; @@ -988,6 +989,7 @@ export class GameData { moveset: null, eggMoves: 0, candyCount: 0, + friendship: 0, abilityAttr: defaultStarterSpecies.includes(speciesId) ? AbilityAttr.ABILITY_1 : 0, passiveAttr: 0, valueReduction: 0 @@ -1035,6 +1037,7 @@ export class GameData { const hasPrevolution = pokemonPrevolutions.hasOwnProperty(species.speciesId); const newCatch = !caughtAttr; + const hasNewAttr = (caughtAttr & dexAttr) !== dexAttr; if (incrementCount) { if (!fromEgg) { @@ -1057,7 +1060,7 @@ export class GameData { this.gameStats.shinyPokemonHatched++; } - if (!hasPrevolution) + if (!hasPrevolution && (!pokemon.scene.gameMode.isDaily || hasNewAttr)) this.addStarterCandy(species, (1 * (pokemon.isShiny() ? 5 * Math.pow(2, pokemon.variant || 0) : 1)) * (fromEgg || pokemon.isBoss() ? 2 : 1)); } From fec87718300aa5d0bd56f1679ed853815316a33d Mon Sep 17 00:00:00 2001 From: Benjamin Odom Date: Thu, 2 May 2024 16:49:22 -0500 Subject: [PATCH 40/72] Fix Shedinja Luck and Crash Shedinja wasn't taking the luck value from Ninjask so when it calculated its luck it just took the entire fused Pokemon's luck somehow. This has been fixed so it takes both the first and second part of the fusion's luck values instead. Also fixes an issue where Shedinja crashed the game if it was the second part of a fusion combo. Now the correct pokemon species gets checked against and the correct pokemon evolution occurs to create Shedinja. --- src/field/pokemon.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 08482bbd914..c5036ce72c6 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -2457,12 +2457,17 @@ export class PlayerPokemon extends Pokemon { private handleSpecialEvolutions(evolution: SpeciesFormEvolution) { const isFusion = evolution instanceof FusionSpeciesFormEvolution; - if ((!isFusion ? this.species : this.fusionSpecies).speciesId === Species.NINCADA && evolution.speciesId === Species.NINJASK) { - const newEvolution = pokemonEvolutions[this.species.speciesId][1]; + + const evoSpecies = (!isFusion ? this.species : this.fusionSpecies) + if (evoSpecies.speciesId === Species.NINCADA && evolution.speciesId === Species.NINJASK) { + const newEvolution = pokemonEvolutions[evoSpecies.speciesId][1]; + if (newEvolution.condition.predicate(this)) { const newPokemon = this.scene.addPlayerPokemon(this.species, this.level, this.abilityIndex, this.formIndex, undefined, this.shiny, this.variant, this.ivs, this.nature); newPokemon.natureOverride = this.natureOverride; newPokemon.moveset = this.moveset.slice(); + newPokemon.luck = this.luck; + newPokemon.fusionSpecies = this.fusionSpecies; newPokemon.fusionFormIndex = this.fusionFormIndex; newPokemon.fusionAbilityIndex = this.fusionAbilityIndex; @@ -2470,8 +2475,9 @@ export class PlayerPokemon extends Pokemon { newPokemon.fusionVariant = this.fusionVariant; newPokemon.fusionGender = this.fusionGender; newPokemon.fusionLuck = this.fusionLuck; + this.scene.getParty().push(newPokemon); - newPokemon.evolve(newEvolution); + newPokemon.evolve(!isFusion ? newEvolution : new FusionSpeciesFormEvolution(this.id, newEvolution)); const modifiers = this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier && (m as PokemonHeldItemModifier).pokemonId === this.id, true) as PokemonHeldItemModifier[]; modifiers.forEach(m => { From 67431fb83b82d45cc98f59a324a3a8ecbd7fb7ff Mon Sep 17 00:00:00 2001 From: Simoninoo <105045724+Simoninoo@users.noreply.github.com> Date: Fri, 3 May 2024 02:45:45 +0200 Subject: [PATCH 41/72] Patch Ita (#399) * Syntax correction * Tutorial translation --- src/locales/it/pokemon-stat.ts | 2 +- src/locales/it/tutorial.ts | 62 +++++++++++++++++----------------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/locales/it/pokemon-stat.ts b/src/locales/it/pokemon-stat.ts index a3a62edebe2..b2c023aa383 100644 --- a/src/locales/it/pokemon-stat.ts +++ b/src/locales/it/pokemon-stat.ts @@ -5,7 +5,7 @@ export const pokemonStat: SimpleTranslationEntries = { "HPshortened": "PS", "ATK": "Attacco", "ATKshortened": "Att", - "DEF": "Difensa", + "DEF": "Difesa", "DEFshortened": "Dif", "SPATK": "Att. Sp.", "SPATKshortened": "AttSp", diff --git a/src/locales/it/tutorial.ts b/src/locales/it/tutorial.ts index 2773b6710ba..898dcead8a4 100644 --- a/src/locales/it/tutorial.ts +++ b/src/locales/it/tutorial.ts @@ -1,42 +1,42 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const tutorial: SimpleTranslationEntries = { - "intro": `Welcome to PokéRogue! This is a battle-focused Pokémon fangame with roguelite elements. - $This game is not monetized and we claim no ownership of Pokémon nor of the copyrighted assets used. - $The game is a work in progress, but fully playable.\nFor bug reports, please use the Discord community. - $If the game runs slowly, please ensure 'Hardware Acceleration' is turned on in your browser settings.`, + "intro": `Benvenuto in PokéRogue! Questo gioco si concentra sulle battaglie, con elementi roguelite. + $Questo gioco non è monetizzato e non siamo proprietari di Pokemon e Assets presenti nel gioco. + $Il gioco è work-in-progress ma giocabile al 100%.\nPer reportare eventuali bugs è possibile discuterne sul nostro Discord. + $Se il game risulta 'lento', assicurati di aver abilitato l'Accelerazione Hardware nelle impostazioni del tuo Browser`, - "accessMenu": `To access the menu, press M or Escape while awaiting input.\nThe menu contains settings and various features.`, + "accessMenu": `Per accedere al menù, press M o Esc.\nDal menù puoi cambiare impostazioni, controllare la wiki e accedere a varie features.`, - "menu": `From this menu you can access the settings. - $From the settings you can change game speed, window style, and other options. - $There are also various other features here, so be sure to check them all!`, + "menu": `Da questo menù puoi accedere alle impostazioni. + $Dalle impostazioni puoi cambiare velocità di gioco, stile di finestra e altre opzioni. + $Ci sono varie funzionalità, controlla bene e non perderti nulla!`, - "starterSelect": `From this screen, you can select your starters.\nThese are your initial party members. - $Each starter has a value. Your party can have up to\n6 members as long as the total does not exceed 10. - $You can also select gender, ability, and form depending on\nthe variants you've caught or hatched. - $The IVs for a species are also the best of every one you've\ncaught or hatched, so try to get lots of the same species!`, + "starterSelect": `Da questa schermata puoi selezionare il tuo starter.\nQuesti sono i membri iniziali del tuo parti. + $Ogni starter ha un valore. Puoi avere fino a \n6 Pokèmon, avendo a disposizione un massimo di 10 punti. + $Puoi anche selezionare Sesso, Abilità, e Forma a seconda delle\nvarianti che hai catturato o schiuso. + $Le IVs di una specie sono le migliori rispetto a tutte quelle che hai\ncatturato o schiuso, quindi prova a catturarne il piu possibile!`, - "pokerus": `A daily random 3 selectable starters have a purple border. - $If you see a starter you own with one of these,\ntry adding it to your party. Be sure to check its summary!`, + "pokerus": `Giornalmente 3 Starter casuali disponibili avranno il bordo viola. + $Se possiedi uno di questi starter,\nprova ad aggiungerlo al party. Ricorda di controllare le info!`, - "statChange": `Stat changes persist across battles as long as your Pokémon aren't recalled. - $Your Pokémon are recalled before a trainer battle and before entering a new biome. - $You can also view the stat changes for the Pokémon on the field by holding C or Shift.`, + "statChange": `I cambiamenti alle statistiche persistono fintanto che i tuoi pokèmon resteranno in campo. + $I tuoi pokemon verranno richiamati quando incontrerai un allenatore o al cambiamento di bioma. + $Puoi anche vedere i cambiamenti alle statistiche in corso tenendo premuto C o Shift`, - "selectItem": `After every battle, you are given a choice of 3 random items.\nYou may only pick one. - $These range from consumables, to Pokémon held items, to passive permanent items. - $Most non-consumable item effects will stack in various ways. - $Some items will only show up if they can be used, such as evolution items. - $You can also transfer held items between Pokémon using the transfer option. - $The transfer option will appear in the bottom right once you have obtained a held item. - $You may purchase consumable items with money, and a larger variety will be available the further you get. - $Be sure to buy these before you pick your random item, as it will progress to the next battle once you do.`, + "selectItem": `Dopo ogni battaglia avrai disponibili tre item.\nPotrai prenderne solo uno. + $Questi spaziano tra consumabili, item tenuti da Pokèmon o con un effetto passivo permanente. + $La maggior parte degli Item non Consumabili possono stackare in diversi modi. + $Alcuni Item risulteranno disponibili solo se possono essere usati, come Item Evolutivi. + $Puoi anche passare un Item tenuto da un Pokèmon ad un altro attraverso l'opzione 'trasferisci strumento'. + $L'opzione 'trasferisci strumento' sarà disponibile solo dopo aver assegnato uno strumento ad un Pokèmon. + $Puoi acquistare consumabili con le monete, progredendo saranno poi disponibili ulteriori oggetti. + $Assicurati di fare un acquisto prima di selezionare un item casuale, poichè passerai subito alla lotta successiva.`, - "eggGacha": `From this screen, you can redeem your vouchers for\nPokémon eggs. - $Eggs have to be hatched and get closer to hatching after\nevery battle. Rarer eggs take longer to hatch. - $Hatched Pokémon also won't be added to your party, they will\nbe added to your starters. - $Pokémon hatched from eggs generally have better IVs than\nwild Pokémon. - $Some Pokémon can only even be obtained from eggs. - $There are 3 different machines to pull from with different\nbonuses, so pick the one that suits you best!`, + "eggGacha": `Da questa schermata, puoi riscattare i tuoi vouchers in cambio di\nuova Pokèmon. + $Le uova vanno schiuse e saranno sempre più vicine alla schiusura dopo\nogni battaglia. Le uova più rare impiegheranno più battaglie per la schiusura. + $I Pokémon schiusi non verranno aggiunti alla tua squadra, saranno\naggiunti ai tuoi starters. + $I Pokémon schiusi generalmente hanno IVs migliori rispetto ai\n Pokémon selvatici. + $Alcuni Pokémon possono essere ottenuti solo tramite uova. + $Ci sono 3 diversi macchinari con differenti\nbonus, scegli quello che preferisci!`, } as const; \ No newline at end of file From b30ab6136e8df4c792420d1c0e7f3777ca984330 Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Thu, 2 May 2024 21:55:11 -0400 Subject: [PATCH 42/72] Starter friendship for candies is split between spliced species --- src/field/pokemon.ts | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index c5036ce72c6..7720d741b20 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -37,7 +37,7 @@ import PartyUiHandler, { PartyOption, PartyUiMode } from '../ui/party-ui-handler import SoundFade from 'phaser3-rex-plugins/plugins/soundfade'; import { LevelMoves } from '../data/pokemon-level-moves'; import { DamageAchv, achvs } from '../system/achv'; -import { DexAttr, StarterMoveset } from '../system/game-data'; +import { DexAttr, StarterDataEntry, StarterMoveset } from '../system/game-data'; import { QuantizerCelebi, argbFromRgba, rgbaFromArgb } from '@material/material-color-utilities'; import { Nature, getNatureStatMultiplier } from '../data/nature'; import { SpeciesFormChange, SpeciesFormChangeActiveTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangeStatusEffectTrigger } from '../data/pokemon-forms'; @@ -2370,9 +2370,13 @@ export class PlayerPokemon extends Pokemon { addFriendship(friendship: integer): void { const starterSpeciesId = this.species.getRootSpeciesId(); - const starterData = this.scene.gameData.starterData[starterSpeciesId]; + const fusionStarterSpeciesId = this.isFusion() ? this.fusionSpecies.getRootSpeciesId() : 0; + const starterData = [ + this.scene.gameData.starterData[starterSpeciesId], + fusionStarterSpeciesId ? this.scene.gameData.starterData[fusionStarterSpeciesId] : null + ].filter(d => d); const amount = new Utils.IntegerHolder(friendship); - const starterAmount = new Utils.IntegerHolder(friendship * (this.scene.gameMode.isClassic ? 2 : 1)); + const starterAmount = new Utils.IntegerHolder(Math.floor(friendship * (this.scene.gameMode.isClassic ? 2 : 1) / (fusionStarterSpeciesId ? 2 : 1))); if (amount.value > 0) { this.scene.applyModifier(PokemonFriendshipBoosterModifier, true, this, amount); this.scene.applyModifier(PokemonFriendshipBoosterModifier, true, this, starterAmount); @@ -2380,14 +2384,18 @@ export class PlayerPokemon extends Pokemon { this.friendship = Math.min(this.friendship + amount.value, 255); if (this.friendship === 255) this.scene.validateAchv(achvs.MAX_FRIENDSHIP); - starterData.friendship = (starterData.friendship || 0) + starterAmount.value; - if (starterData.friendship >= getStarterValueFriendshipCap(speciesStarters[starterSpeciesId])) { - this.scene.gameData.addStarterCandy(getPokemonSpecies(starterSpeciesId), 1); - starterData.friendship = 0; - } + starterData.forEach((sd: StarterDataEntry, i: integer) => { + const speciesId = !i ? starterSpeciesId : fusionStarterSpeciesId as Species; + sd.friendship = (sd.friendship || 0) + starterAmount.value; + if (sd.friendship >= getStarterValueFriendshipCap(speciesStarters[speciesId])) { + this.scene.gameData.addStarterCandy(getPokemonSpecies(speciesId), 1); + sd.friendship = 0; + } + }); } else { this.friendship = Math.max(this.friendship + amount.value, 0); - starterData.friendship = Math.max((starterData.friendship || 0) + starterAmount.value, 0); + for (let sd of starterData) + sd.friendship = Math.max((sd.friendship || 0) + starterAmount.value, 0); } } From 60117947322354f51801e01d295d9657bae1af66 Mon Sep 17 00:00:00 2001 From: Madmadness65 Date: Thu, 2 May 2024 21:58:38 -0500 Subject: [PATCH 43/72] Minor egg move fix Gen 8 fossils unintentionally had Earthquake. They have now been replaced. --- src/data/egg-moves.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data/egg-moves.ts b/src/data/egg-moves.ts index 800c9a0ef25..221496a177d 100644 --- a/src/data/egg-moves.ts +++ b/src/data/egg-moves.ts @@ -458,9 +458,9 @@ export const speciesEggMoves = { [Species.MORPEKO]: [ Moves.TRIPLE_AXEL, Moves.OBSTRUCT, Moves.PARTING_SHOT, Moves.SWORDS_DANCE ], [Species.CUFANT]: [ Moves.LIQUIDATION, Moves.HEAVY_SLAM, Moves.CLOSE_COMBAT, Moves.GIGATON_HAMMER ], [Species.DRACOZOLT]: [ Moves.TRIPLE_AXEL, Moves.DRAGON_HAMMER, Moves.FIRE_LASH, Moves.DRAGON_DANCE ], - [Species.ARCTOZOLT]: [ Moves.TRIPLE_AXEL, Moves.EARTHQUAKE, Moves.HIGH_HORSEPOWER, Moves.SHIFT_GEAR ], + [Species.ARCTOZOLT]: [ Moves.TRIPLE_AXEL, Moves.LIQUIDATION, Moves.HIGH_HORSEPOWER, Moves.SHIFT_GEAR ], [Species.DRACOVISH]: [ Moves.TRIPLE_AXEL, Moves.DRAGON_HAMMER, Moves.THUNDER_FANG, Moves.DRAGON_DANCE ], - [Species.ARCTOVISH]: [ Moves.TRIPLE_AXEL, Moves.EARTHQUAKE, Moves.HIGH_HORSEPOWER, Moves.SHIFT_GEAR ], + [Species.ARCTOVISH]: [ Moves.TRIPLE_AXEL, Moves.SUPERCELL_SLAM, Moves.HIGH_HORSEPOWER, Moves.SHIFT_GEAR ], [Species.DURALUDON]: [ Moves.CALM_MIND, Moves.BODY_PRESS, Moves.EARTH_POWER, Moves.RECOVER ], [Species.DREEPY]: [ Moves.DRAGON_ENERGY, Moves.SHED_TAIL, Moves.BLAZING_TORQUE, Moves.SPECTRAL_THIEF ], [Species.ZACIAN]: [ Moves.MAGICAL_TORQUE, Moves.BITTER_BLADE, Moves.LEAF_BLADE, Moves.VICTORY_DANCE ], From fbc08005715ac1b1bdb4a3e38e6bf468ad3625e7 Mon Sep 17 00:00:00 2001 From: Matt Ross <13306707+mattrossdev@users.noreply.github.com> Date: Thu, 2 May 2024 22:20:41 -0700 Subject: [PATCH 44/72] Issue/smack down should cancel fly (#407) * Smack down and thousand arrows should cancel charging fly * Remove console log * Update interruptible check to use flying tag instead of move history * Remove extra comma --- src/data/battler-tags.ts | 25 +++++++++++++++++++++++++ src/data/enums/battler-tag-type.ts | 1 + src/data/move.ts | 4 ++++ src/phases.ts | 2 +- 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index aaab9f9a4a2..2521a0e03c5 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -163,6 +163,29 @@ export class FlinchedTag extends BattlerTag { } } +export class InterruptedTag extends BattlerTag { + constructor(sourceMove: Moves){ + super(BattlerTagType.INTERRUPTED, BattlerTagLapseType.PRE_MOVE, 0, sourceMove) + } + + canAdd(pokemon: Pokemon): boolean { + return !!pokemon.getTag(BattlerTagType.FLYING) + } + + onAdd(pokemon: Pokemon): void { + super.onAdd(pokemon); + + pokemon.getMoveQueue().shift() + pokemon.pushMoveHistory({move: Moves.NONE, result: MoveResult.OTHER}) + } + + lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { + super.lapse(pokemon, lapseType); + (pokemon.scene.getCurrentPhase() as MovePhase).cancel(); + return true + } +} + export class ConfusedTag extends BattlerTag { constructor(turnCount: integer, sourceMove: Moves) { super(BattlerTagType.CONFUSED, BattlerTagLapseType.MOVE, turnCount, sourceMove); @@ -1081,6 +1104,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc return new RechargingTag(sourceMove); case BattlerTagType.FLINCHED: return new FlinchedTag(sourceMove); + case BattlerTagType.INTERRUPTED: + return new InterruptedTag(sourceMove); case BattlerTagType.CONFUSED: return new ConfusedTag(turnCount, sourceMove); case BattlerTagType.INFATUATED: diff --git a/src/data/enums/battler-tag-type.ts b/src/data/enums/battler-tag-type.ts index 4d810b737aa..f76e5526f7e 100644 --- a/src/data/enums/battler-tag-type.ts +++ b/src/data/enums/battler-tag-type.ts @@ -3,6 +3,7 @@ export enum BattlerTagType { NONE = "NONE", RECHARGING = "RECHARGING", FLINCHED = "FLINCHED", + INTERRUPTED = "INTERRUPTED", CONFUSED = "CONFUSED", INFATUATED = "INFATUATED", SEEDED = "SEEDED", diff --git a/src/data/move.ts b/src/data/move.ts index b26af03fc5e..a227c522a86 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -5106,6 +5106,8 @@ export function initMoves() { .unimplemented(), new AttackMove(Moves.SMACK_DOWN, Type.ROCK, MoveCategory.PHYSICAL, 50, 100, 15, 100, 0, 5) .attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, false, false, 5) + .attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED) + .attr(RemoveBattlerTagAttr, [BattlerTagType.FLYING]) .attr(HitsTagAttr, BattlerTagType.FLYING, false) .makesContact(false), new AttackMove(Moves.STORM_THROW, Type.FIGHTING, MoveCategory.PHYSICAL, 60, 100, 10, -1, 0, 5) @@ -5469,6 +5471,8 @@ export function initMoves() { new AttackMove(Moves.THOUSAND_ARROWS, Type.GROUND, MoveCategory.PHYSICAL, 90, 100, 10, 100, 0, 6) .attr(NeutralDamageAgainstFlyingTypeMultiplierAttr) .attr(HitsTagAttr, BattlerTagType.FLYING, false) + .attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED) + .attr(RemoveBattlerTagAttr, [BattlerTagType.FLYING]) .makesContact(false) .target(MoveTarget.ALL_NEAR_ENEMIES), new AttackMove(Moves.THOUSAND_WAVES, Type.GROUND, MoveCategory.PHYSICAL, 90, 100, 10, -1, 0, 6) diff --git a/src/phases.ts b/src/phases.ts index 4c2f5536268..40ab1f30637 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -2333,7 +2333,7 @@ export class MovePhase extends BattlePhase { return; } - if (this.pokemon.getTag(BattlerTagType.RECHARGING)) + if (this.pokemon.getTag(BattlerTagType.RECHARGING|| BattlerTagType.INTERRUPTED)) return; this.scene.queueMessage(getPokemonMessage(this.pokemon, ` used\n${this.move.getName()}!`), 500); From f7b391746ed0076f2c548dd6836f5f8dc40c5265 Mon Sep 17 00:00:00 2001 From: Jaime Date: Fri, 3 May 2024 13:29:22 +0200 Subject: [PATCH 45/72] Fix Gyro Ball only checking base stat --- src/data/move.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data/move.ts b/src/data/move.ts index a227c522a86..ea89788cf93 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -1770,13 +1770,13 @@ export class BattleStatRatioPowerAttr extends VariablePowerAttr { if (this.invert) { // Gyro ball uses a specific formula - let userSpeed = user.getStat(this.stat); + let userSpeed = user.getBattleStat(this.stat); if (userSpeed < 1) { // Gen 6+ always have 1 base power power.value = 1; return true; } - let bp = Math.floor(Math.min(150, 25 * target.getStat(this.stat) / userSpeed + 1)); + let bp = Math.floor(Math.min(150, 25 * target.getBattleStat(this.stat) / userSpeed + 1)); power.value = bp; return true; } From b84a4b4ee5fde701464383c271e67fea0248f38f Mon Sep 17 00:00:00 2001 From: Benjamin Odom Date: Fri, 3 May 2024 01:46:19 -0500 Subject: [PATCH 46/72] Fix Shedinja PPused Share Fixed having Shedinja share PP usage with the Ninjask it evolved from and vice versa. The solution was to make a deep copy of each move in the moveset array rather than copying the array itself. --- src/field/pokemon.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 7720d741b20..bc51323075b 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -2473,7 +2473,7 @@ export class PlayerPokemon extends Pokemon { if (newEvolution.condition.predicate(this)) { const newPokemon = this.scene.addPlayerPokemon(this.species, this.level, this.abilityIndex, this.formIndex, undefined, this.shiny, this.variant, this.ivs, this.nature); newPokemon.natureOverride = this.natureOverride; - newPokemon.moveset = this.moveset.slice(); + newPokemon.moveset = this.copyMoveset(); newPokemon.luck = this.luck; newPokemon.fusionSpecies = this.fusionSpecies; @@ -2583,6 +2583,15 @@ export class PlayerPokemon extends Pokemon { this.updateFusionPalette(); }); } + + /** Returns a deep copy of this Pokemon's moveset array */ + copyMoveset(): PokemonMove[] { + let newMoveset = []; + this.moveset.forEach(move => + newMoveset.push(new PokemonMove(move.moveId, 0, move.ppUp, move.virtual))); + + return newMoveset; + } } export class EnemyPokemon extends Pokemon { From 24a9dba2c46e70fb2d06b87dec7dec952dc98686 Mon Sep 17 00:00:00 2001 From: Paul Beslin Date: Fri, 3 May 2024 00:18:05 +0200 Subject: [PATCH 47/72] Fix attacks with charge (solar beam, dig...) allowing to switch target on second turn --- src/data/battler-tags.ts | 8 ++++++++ src/data/enums/battler-tag-type.ts | 1 + src/data/move.ts | 5 ++++- src/phases.ts | 9 ++++++--- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 2521a0e03c5..8ff684394ec 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -391,6 +391,12 @@ export class FrenzyTag extends BattlerTag { } } +export class ChargingTag extends BattlerTag { + constructor(sourceMove: Moves, sourceId: integer) { + super(BattlerTagType.CHARGING, BattlerTagLapseType.CUSTOM, 1, sourceMove, sourceId); + } +} + export class EncoreTag extends BattlerTag { public moveId: Moves; @@ -1116,6 +1122,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc return new NightmareTag(); case BattlerTagType.FRENZY: return new FrenzyTag(sourceMove, sourceId); + case BattlerTagType.CHARGING: + return new ChargingTag(sourceMove, sourceId); case BattlerTagType.ENCORE: return new EncoreTag(sourceId); case BattlerTagType.HELPING_HAND: diff --git a/src/data/enums/battler-tag-type.ts b/src/data/enums/battler-tag-type.ts index f76e5526f7e..7a9f6ba8bb2 100644 --- a/src/data/enums/battler-tag-type.ts +++ b/src/data/enums/battler-tag-type.ts @@ -9,6 +9,7 @@ export enum BattlerTagType { SEEDED = "SEEDED", NIGHTMARE = "NIGHTMARE", FRENZY = "FRENZY", + CHARGING = "CHARGING", ENCORE = "ENCORE", HELPING_HAND = "HELPING_HAND", INGRAIN = "INGRAIN", diff --git a/src/data/move.ts b/src/data/move.ts index ea89788cf93..21f376254f7 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -1325,10 +1325,13 @@ export class ChargeAttr extends OverrideMoveEffectAttr { user.getMoveQueue().push({ move: move.id, targets: [ target.getBattlerIndex() ], ignorePP: true }); if (this.sameTurn) user.scene.pushMovePhase(new MovePhase(user.scene, user, [ target.getBattlerIndex() ], user.moveset.find(m => m.moveId === move.id), true), this.followUpPriority); + user.addTag(BattlerTagType.CHARGING, 1, move.id, user.id); resolve(true); }); - } else + } else { + user.lapseTag(BattlerTagType.CHARGING); resolve(false); + } }); } diff --git a/src/phases.ts b/src/phases.ts index 40ab1f30637..e4ed8d2938c 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -1686,6 +1686,8 @@ export class CommandPhase extends FieldPhase { console.log(moveTargets, playerPokemon.name); if (moveTargets.targets.length <= 1 || moveTargets.multiple) turnCommand.move.targets = moveTargets.targets; + else if(playerPokemon.getTag(BattlerTagType.CHARGING) && playerPokemon.getMoveQueue().length >= 1) + turnCommand.move.targets = playerPokemon.getMoveQueue()[0].targets; else this.scene.unshiftPhase(new SelectTargetPhase(this.scene, this.fieldIndex)); this.scene.currentBattle.turnCommands[this.fieldIndex] = turnCommand; @@ -2327,13 +2329,14 @@ export class MovePhase extends BattlePhase { showMoveText(): void { if (this.move.getMove().getAttrs(ChargeAttr).length) { - this.scene.queueMessage(getPokemonMessage(this.pokemon, ` used\n${this.move.getName()}!`), 500); const lastMove = this.pokemon.getLastXMoves() as TurnMove[]; - if (!lastMove.length || lastMove[0].move !== this.move.getMove().id || lastMove[0].result !== MoveResult.OTHER) + if (!lastMove.length || lastMove[0].move !== this.move.getMove().id || lastMove[0].result !== MoveResult.OTHER){ + this.scene.queueMessage(getPokemonMessage(this.pokemon, ` used\n${this.move.getName()}!`), 500); return; + } } - if (this.pokemon.getTag(BattlerTagType.RECHARGING|| BattlerTagType.INTERRUPTED)) + if (this.pokemon.getTag(BattlerTagType.RECHARGING || BattlerTagType.INTERRUPTED)) return; this.scene.queueMessage(getPokemonMessage(this.pokemon, ` used\n${this.move.getName()}!`), 500); From bc319a8eda6807501befcd2c756dbb4579024d82 Mon Sep 17 00:00:00 2001 From: Xavion3 Date: Sat, 4 May 2024 00:27:20 +1000 Subject: [PATCH 48/72] Fix eggs during dailies --- src/system/game-data.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/system/game-data.ts b/src/system/game-data.ts index b7495a1eac9..6410c52a2b8 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -1060,7 +1060,7 @@ export class GameData { this.gameStats.shinyPokemonHatched++; } - if (!hasPrevolution && (!pokemon.scene.gameMode.isDaily || hasNewAttr)) + if (!hasPrevolution && (!pokemon.scene.gameMode.isDaily || hasNewAttr || fromEgg)) this.addStarterCandy(species, (1 * (pokemon.isShiny() ? 5 * Math.pow(2, pokemon.variant || 0) : 1)) * (fromEgg || pokemon.isBoss() ? 2 : 1)); } From e082dd90892342669670b9d6c2b6a843b9a624d3 Mon Sep 17 00:00:00 2001 From: Lugiad Date: Fri, 3 May 2024 16:51:00 +0200 Subject: [PATCH 49/72] Minor correction to apostrophes in French menu-ui-handler.ts (#415) --- src/locales/fr/menu-ui-handler.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/locales/fr/menu-ui-handler.ts b/src/locales/fr/menu-ui-handler.ts index 684a8cc07ba..54328a05eb1 100644 --- a/src/locales/fr/menu-ui-handler.ts +++ b/src/locales/fr/menu-ui-handler.ts @@ -13,9 +13,9 @@ export const menuUiHandler: SimpleTranslationEntries = { "LOG_OUT": "Déconnexion", "slot": "Emplacement {{slotNumber}}", "importSession": "Importer session", - "importSlotSelect": "Sélectionnez l'emplacement vers lequel importer les données.", + "importSlotSelect": "Sélectionnez l’emplacement vers lequel importer les données.", "exportSession": "Exporter session", - "exportSlotSelect": "Sélectionnez l'emplacement depuis lequel exporter les données.", + "exportSlotSelect": "Sélectionnez l’emplacement depuis lequel exporter les données.", "importData": "Importer données", "exportData": "Exporter données", "cancel": "Retour", From c7c4deb416413e0077c5830a78dd47001d5f4bad Mon Sep 17 00:00:00 2001 From: Xavion3 Date: Sat, 4 May 2024 01:56:13 +1000 Subject: [PATCH 50/72] Implement Sniper --- src/data/ability.ts | 23 ++++++++++++++++++++++- src/field/pokemon.ts | 7 ++++--- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index 7c350f025be..a0f85e2fd5e 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -1609,6 +1609,27 @@ export class BonusCritAbAttr extends AbAttr { } } +export class MultCritAbAttr extends AbAttr { + public multAmount: number; + + constructor(multAmount: number) { + super(true); + + this.multAmount = multAmount; + } + + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { + const critMult = args[0] as Utils.NumberHolder; + if (critMult.value > 1){ + critMult.value *= this.multAmount; + return true; + } + + return false; + } +} + + export class BlockNonDirectDamageAbAttr extends AbAttr { apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { cancelled.value = true; @@ -2776,7 +2797,7 @@ export function initAbilities() { .attr(MoveTypeChangeAttr, Type.NORMAL, 1.2, (user, target, move) => move.id !== Moves.HIDDEN_POWER && move.id !== Moves.WEATHER_BALL && move.id !== Moves.NATURAL_GIFT && move.id !== Moves.JUDGMENT && move.id !== Moves.TECHNO_BLAST), new Ability(Abilities.SNIPER, 4) - .unimplemented(), + .attr(MultCritAbAttr, 1.5), new Ability(Abilities.MAGIC_GUARD, 4) .attr(BlockNonDirectDamageAbAttr), new Ability(Abilities.NO_GUARD, 4) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index bc51323075b..909d255eef8 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -27,7 +27,7 @@ import { TempBattleStat } from '../data/temp-battle-stat'; import { ArenaTagSide, WeakenMoveScreenTag, WeakenMoveTypeTag } from '../data/arena-tag'; import { ArenaTagType } from "../data/enums/arena-tag-type"; import { Biome } from "../data/enums/biome"; -import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, MoveTypeChangeAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, VariableMoveTypeAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr } from '../data/ability'; +import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, MoveTypeChangeAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, VariableMoveTypeAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr } from '../data/ability'; import { Abilities } from "#app/data/enums/abilities"; import PokemonData from '../system/pokemon-data'; import Battle, { BattlerIndex } from '../battle'; @@ -1332,7 +1332,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } const sourceAtk = new Utils.IntegerHolder(source.getBattleStat(isPhysical ? Stat.ATK : Stat.SPATK, this, null, isCritical)); const targetDef = new Utils.IntegerHolder(this.getBattleStat(isPhysical ? Stat.DEF : Stat.SPDEF, source, move, isCritical)); - const criticalMultiplier = isCritical ? 1.5 : 1; + const criticalMultiplier = new Utils.NumberHolder(isCritical ? 1.5 : 1); + applyAbAttrs(MultCritAbAttr, source, null, criticalMultiplier); const screenMultiplier = new Utils.NumberHolder(1); if (!isCritical) { this.scene.arena.applyTagsForSide(WeakenMoveScreenTag, this.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY, move.category, this.scene.currentBattle.double, screenMultiplier); @@ -1355,7 +1356,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { applyMoveAttrs(VariableDefAttr, source, this, move, targetDef); if (!isTypeImmune) { - damage.value = Math.ceil(((((2 * source.level / 5 + 2) * power.value * sourceAtk.value / targetDef.value) / 50) + 2) * stabMultiplier.value * typeMultiplier.value * arenaAttackTypeMultiplier * screenMultiplier.value * ((this.scene.randBattleSeedInt(15) + 85) / 100) * criticalMultiplier); + damage.value = Math.ceil(((((2 * source.level / 5 + 2) * power.value * sourceAtk.value / targetDef.value) / 50) + 2) * stabMultiplier.value * typeMultiplier.value * arenaAttackTypeMultiplier * screenMultiplier.value * ((this.scene.randBattleSeedInt(15) + 85) / 100) * criticalMultiplier.value); if (isPhysical && source.status && source.status.effect === StatusEffect.BURN) { const burnDamageReductionCancelled = new Utils.BooleanHolder(false); applyAbAttrs(BypassBurnDamageReductionAbAttr, source, burnDamageReductionCancelled); From c44ec421b08b7c193c67e3d57c8e30fb9f9a4c95 Mon Sep 17 00:00:00 2001 From: Dario Krause Date: Fri, 3 May 2024 16:49:26 +0200 Subject: [PATCH 51/72] Update pokemon.ts --- src/locales/de/pokemon.ts | 354 +++++++++++++++++++------------------- 1 file changed, 177 insertions(+), 177 deletions(-) diff --git a/src/locales/de/pokemon.ts b/src/locales/de/pokemon.ts index db92ccc5c18..9efecb819cd 100644 --- a/src/locales/de/pokemon.ts +++ b/src/locales/de/pokemon.ts @@ -605,208 +605,208 @@ export const pokemon: SimpleTranslationEntries = { "tynamo": "Zapplardin", "eelektrik": "Zapplalek", "eelektross": "Zapplarang", - "elgyem": "Elgyem", - "beheeyem": "Beheeyem", - "litwick": "Litwick", - "lampent": "Lampent", - "chandelure": "Chandelure", - "axew": "Axew", - "fraxure": "Fraxure", - "haxorus": "Haxorus", - "cubchoo": "Cubchoo", - "beartic": "Beartic", - "cryogonal": "Cryogonal", - "shelmet": "Shelmet", - "accelgor": "Accelgor", - "stunfisk": "Stunfisk", - "mienfoo": "Mienfoo", - "mienshao": "Mienshao", - "druddigon": "Druddigon", - "golett": "Golett", - "golurk": "Golurk", - "pawniard": "Pawniard", - "bisharp": "Bisharp", - "bouffalant": "Bouffalant", - "rufflet": "Rufflet", - "braviary": "Braviary", - "vullaby": "Vullaby", - "mandibuzz": "Mandibuzz", - "heatmor": "Heatmor", - "durant": "Durant", - "deino": "Deino", - "zweilous": "Zweilous", - "hydreigon": "Hydreigon", - "larvesta": "Larvesta", - "volcarona": "Volcarona", - "cobalion": "Cobalion", - "terrakion": "Terrakion", - "virizion": "Virizion", - "tornadus": "Tornadus", - "thundurus": "Thundurus", + "elgyem": "Pygraulon", + "beheeyem": "Megalon", + "litwick": "Lichtel", + "lampent": "Laternecto", + "chandelure": "Skelabra", + "axew": "Milza", + "fraxure": "Scharfax", + "haxorus": "Maxax", + "cubchoo": "Petznief", + "beartic": "Siberio", + "cryogonal": "Frigometri", + "shelmet": "Schnuthelm", + "accelgor": "Hydragil", + "stunfisk": "Flunschlik", + "mienfoo": "Lin-Fu", + "mienshao": "Wie-Shu", + "druddigon": "Shardrago", + "golett": "Golbit", + "golurk": "Golgantes", + "pawniard": "Gladiantri", + "bisharp": "Ceasurio", + "bouffalant": "Bisofank", + "rufflet": "Geronimatz", + "braviary": "Washakwil", + "vullaby": "Skallyk", + "mandibuzz": "Grypheldis", + "heatmor": "Furnifraß", + "durant": "Fermicula", + "deino": "Kapuno", + "zweilous": "Duodino", + "hydreigon": "Trikephalo", + "larvesta": "Ignivor", + "volcarona": "Ramoth", + "cobalion": "Kobalium", + "terrakion": "Terrakium", + "virizion": "Viridium", + "tornadus": "Boreos", + "thundurus": "Voltolos", "reshiram": "Reshiram", "zekrom": "Zekrom", - "landorus": "Landorus", + "landorus": "Dementeros", "kyurem": "Kyurem", "keldeo": "Keldeo", "meloetta": "Meloetta", "genesect": "Genesect", - "chespin": "Chespin", - "quilladin": "Quilladin", - "chesnaught": "Chesnaught", - "fennekin": "Fennekin", - "braixen": "Braixen", - "delphox": "Delphox", - "froakie": "Froakie", - "frogadier": "Frogadier", - "greninja": "Greninja", - "bunnelby": "Bunnelby", - "diggersby": "Diggersby", - "fletchling": "Fletchling", - "fletchinder": "Fletchinder", - "talonflame": "Talonflame", - "scatterbug": "Scatterbug", - "spewpa": "Spewpa", + "chespin": "Igamaro", + "quilladin": "Igastarnish", + "chesnaught": "Brigaron", + "fennekin": "Fynx", + "braixen": "Rutena", + "delphox": "Fennexis", + "froakie": "Froxy", + "frogadier": "Amphizel", + "greninja": "Quajutsu", + "bunnelby": "Scoppel", + "diggersby": "Grebbit", + "fletchling": "Dartiri", + "fletchinder": "Dartignis", + "talonflame": "Fiaro", + "scatterbug": "Purmel", + "spewpa": "Puponcho", "vivillon": "Vivillon", - "litleo": "Litleo", - "pyroar": "Pyroar", + "litleo": "Leufeo", + "pyroar": "Pyroleo", "flabebe": "Flabébé", "floette": "Floette", "florges": "Florges", - "skiddo": "Skiddo", - "gogoat": "Gogoat", - "pancham": "Pancham", - "pangoro": "Pangoro", - "furfrou": "Furfrou", - "espurr": "Espurr", - "meowstic": "Meowstic", - "honedge": "Honedge", - "doublade": "Doublade", - "aegislash": "Aegislash", - "spritzee": "Spritzee", - "aromatisse": "Aromatisse", - "swirlix": "Swirlix", - "slurpuff": "Slurpuff", - "inkay": "Inkay", - "malamar": "Malamar", - "binacle": "Binacle", - "barbaracle": "Barbaracle", - "skrelp": "Skrelp", - "dragalge": "Dragalge", - "clauncher": "Clauncher", - "clawitzer": "Clawitzer", - "helioptile": "Helioptile", - "heliolisk": "Heliolisk", - "tyrunt": "Tyrunt", - "tyrantrum": "Tyrantrum", - "amaura": "Amaura", - "aurorus": "Aurorus", - "sylveon": "Sylveon", - "hawlucha": "Hawlucha", + "skiddo": "Mähikel", + "gogoat": "Chevrumm", + "pancham": "Pam-Pam", + "pangoro": "Pandrago", + "furfrou": "Coiffwaff", + "espurr": "Psiau", + "meowstic": "Psiaugon", + "honedge": "Gramokles", + "doublade": "Duokles", + "aegislash": "Durengard", + "spritzee": "Parfi", + "aromatisse": "Parfinesse", + "swirlix": "Flauschling", + "slurpuff": "Sabbaione", + "inkay": "Iscalar", + "malamar": "Calamanero", + "binacle": "Bithora", + "barbaracle": "Thanathora", + "skrelp": "Algitt", + "dragalge": "Tandrak", + "clauncher": "Scampisto", + "clawitzer": "Wummer", + "helioptile": "Eguana", + "heliolisk": "Elezard", + "tyrunt": "Balgoras", + "tyrantrum": "Monargoras", + "amaura": "Amarino", + "aurorus": "Amagarga", + "sylveon": "Feelinara", + "hawlucha": "Resladero", "dedenne": "Dedenne", - "carbink": "Carbink", - "goomy": "Goomy", - "sliggoo": "Sliggoo", - "goodra": "Goodra", - "klefki": "Klefki", - "phantump": "Phantump", - "trevenant": "Trevenant", - "pumpkaboo": "Pumpkaboo", - "gourgeist": "Gourgeist", - "bergmite": "Bergmite", - "avalugg": "Avalugg", - "noibat": "Noibat", - "noivern": "Noivern", + "carbink": "Rocara", + "goomy": "Viscora", + "sliggoo": "Viscargot", + "goodra": "Viscogon", + "klefki": "Clavion", + "phantump": "Paragoni", + "trevenant": "Trombork", + "pumpkaboo": "Irrbis", + "gourgeist": "Pumpdjinn", + "bergmite": "Arktip", + "avalugg": "Arktilas", + "noibat": "eF-eM", + "noivern": "UHaFnir", "xerneas": "Xerneas", "yveltal": "Yveltal", "zygarde": "Zygarde", "diancie": "Diancie", "hoopa": "Hoopa", "volcanion": "Volcanion", - "rowlet": "Rowlet", - "dartrix": "Dartrix", - "decidueye": "Decidueye", - "litten": "Litten", - "torracat": "Torracat", - "incineroar": "Incineroar", - "popplio": "Popplio", - "brionne": "Brionne", - "primarina": "Primarina", - "pikipek": "Pikipek", - "trumbeak": "Trumbeak", - "toucannon": "Toucannon", - "yungoos": "Yungoos", - "gumshoos": "Gumshoos", - "grubbin": "Grubbin", - "charjabug": "Charjabug", - "vikavolt": "Vikavolt", - "crabrawler": "Crabrawler", - "crabominable": "Crabominable", - "oricorio": "Oricorio", - "cutiefly": "Cutiefly", - "ribombee": "Ribombee", - "rockruff": "Rockruff", - "lycanroc": "Lycanroc", - "wishiwashi": "Wishiwashi", - "mareanie": "Mareanie", - "toxapex": "Toxapex", - "mudbray": "Mudbray", - "mudsdale": "Mudsdale", - "dewpider": "Dewpider", - "araquanid": "Araquanid", - "fomantis": "Fomantis", - "lurantis": "Lurantis", - "morelull": "Morelull", - "shiinotic": "Shiinotic", - "salandit": "Salandit", - "salazzle": "Salazzle", - "stufful": "Stufful", - "bewear": "Bewear", - "bounsweet": "Bounsweet", - "steenee": "Steenee", - "tsareena": "Tsareena", - "comfey": "Comfey", - "oranguru": "Oranguru", - "passimian": "Passimian", - "wimpod": "Wimpod", - "golisopod": "Golisopod", - "sandygast": "Sandygast", - "palossand": "Palossand", - "pyukumuku": "Pyukumuku", - "type_null": "Type: Null", - "silvally": "Silvally", - "minior": "Minior", - "komala": "Komala", + "rowlet": "Bauz", + "dartrix": "Arboretoss", + "decidueye": "Silvarro", + "litten": "Flamiau", + "torracat": "Miezunder", + "incineroar": "Fuegro", + "popplio": "Robball", + "brionne": "Marikeck", + "primarina": "Primarene", + "pikipek": "Peppeck", + "trumbeak": "Trompeck", + "toucannon": "Tukanon", + "yungoos": "Mangunior", + "gumshoos": "Manguspektor", + "grubbin": "Mabula", + "charjabug": "Akkup", + "vikavolt": "Donarion", + "crabrawler": "Krabbox", + "crabominable": "Krawell", + "oricorio": "Choreogel", + "cutiefly": "Wommel", + "ribombee": "Bandelby", + "rockruff": "Wuffels", + "lycanroc": "Wolwerock", + "wishiwashi": "Lusardin", + "mareanie": "Garstella", + "toxapex": "Aggrostella", + "mudbray": "Pampuli", + "mudsdale": "Pampross", + "dewpider": "Araqua", + "araquanid": "Aranestro", + "fomantis": "Imantis", + "lurantis": "Mantidea", + "morelull": "Bubungus", + "shiinotic": "Lamellus", + "salandit": "Molunk", + "salazzle": "Amfira", + "stufful": "Velursi", + "bewear": "Kosturso", + "bounsweet": "Frubberl", + "steenee": "Frubaila", + "tsareena": "Fruyal", + "comfey": "Curelei", + "oranguru": "Kommandutan", + "passimian": "Quartermak", + "wimpod": "Reißlaus", + "golisopod": "Tectass", + "sandygast": "Sankabuh", + "palossand": "Colossand", + "pyukumuku": "Gufa", + "type_null": "Typ:Null", + "silvally": "Amigento", + "minior": "Meteno", + "komala": "Koalelu", "turtonator": "Turtonator", "togedemaru": "Togedemaru", - "mimikyu": "Mimikyu", - "bruxish": "Bruxish", - "drampa": "Drampa", - "dhelmise": "Dhelmise", - "jangmo_o": "Jangmo-o", - "hakamo_o": "Hakamo-o", - "kommo_o": "Kommo-o", - "tapu_koko": "Tapu Koko", - "tapu_lele": "Tapu Lele", - "tapu_bulu": "Tapu Bulu", - "tapu_fini": "Tapu Fini", + "mimikyu": "Mimigma", + "bruxish": "Knirfish", + "drampa": "Sen-Long", + "dhelmise": "Moruda", + "jangmo_o": "Miniras", + "hakamo_o": "Mediras", + "kommo_o": "Grandiras", + "tapu_koko": "Kapu-Riki", + "tapu_lele": "Kapu-Fala", + "tapu_bulu": "Kapu-Toro", + "tapu_fini": "Kapu-Kime", "cosmog": "Cosmog", - "cosmoem": "Cosmoem", + "cosmoem": "Cosmovum", "solgaleo": "Solgaleo", "lunala": "Lunala", - "nihilego": "Nihilego", - "buzzwole": "Buzzwole", - "pheromosa": "Pheromosa", - "xurkitree": "Xurkitree", - "celesteela": "Celesteela", - "kartana": "Kartana", - "guzzlord": "Guzzlord", + "nihilego": "Anego", + "buzzwole": "Masskito", + "pheromosa": "Schabelle", + "xurkitree": "Voltriant", + "celesteela": "Kaguron", + "kartana": "Katagami", + "guzzlord": "Schlingking", "necrozma": "Necrozma", "magearna": "Magearna", "marshadow": "Marshadow", - "poipole": "Poipole", - "naganadel": "Naganadel", - "stakataka": "Stakataka", - "blacephalon": "Blacephalon", + "poipole": "Venicro", + "naganadel": "Agoyon", + "stakataka": "Muramura", + "blacephalon": "Kopplosio", "zeraora": "Zeraora", "meltan": "Meltan", "melmetal": "Melmetal", From 70324c415955477a3f569a5c342df4561537da56 Mon Sep 17 00:00:00 2001 From: Greenlamp2 <44787002+Greenlamp2@users.noreply.github.com> Date: Fri, 3 May 2024 18:59:10 +0200 Subject: [PATCH 52/72] Rework - Inputs management to include all gamepad mapping (#390) * rework of the input handling, including different gamepad and keyboard * rework of the input handling, including different gamepad and keyboard * first version of a too complex inputHandler based on phaser3-merged-input * removed useless control management and kept it simple for our use case, investigating to put out button_XX() * renamed inputHandler to inputController * aggregate directions and some action into a same method + fix menu return value * added back repeated input feature on keeping down a key * cleanup + return type * fix submit/action doing two things simultaneously, still same behaviour as before * extracted UI inputs out of battle-scene * tab -> spaces * tab -> spaces what about now github ? --- src/battle-scene.ts | 272 +-------------------- src/configs/pad_dualshock.ts | 29 +++ src/configs/pad_generic.ts | 27 ++ src/configs/pad_unlicensedSNES.ts | 23 ++ src/configs/pad_xbox360.ts | 28 +++ src/inputs-controller.ts | 266 ++++++++++++++++++++ src/ui-inputs.ts | 159 ++++++++++++ src/ui/abstact-option-select-ui-handler.ts | 3 +- src/ui/achvs-ui-handler.ts | 3 +- src/ui/awaitable-ui-handler.ts | 3 +- src/ui/ball-ui-handler.ts | 3 +- src/ui/battle-message-ui-handler.ts | 3 +- src/ui/command-ui-handler.ts | 3 +- src/ui/confirm-ui-handler.ts | 3 +- src/ui/egg-gacha-ui-handler.ts | 3 +- src/ui/egg-hatch-scene-handler.ts | 3 +- src/ui/egg-list-ui-handler.ts | 3 +- src/ui/evolution-scene-handler.ts | 3 +- src/ui/fight-ui-handler.ts | 3 +- src/ui/form-modal-ui-handler.ts | 3 +- src/ui/game-stats-ui-handler.ts | 3 +- src/ui/menu-ui-handler.ts | 3 +- src/ui/modal-ui-handler.ts | 3 +- src/ui/modifier-select-ui-handler.ts | 3 +- src/ui/party-ui-handler.ts | 3 +- src/ui/save-slot-select-ui-handler.ts | 3 +- src/ui/settings-ui-handler.ts | 3 +- src/ui/starter-select-ui-handler.ts | 3 +- src/ui/summary-ui-handler.ts | 3 +- src/ui/target-select-ui-handler.ts | 3 +- src/ui/ui-handler.ts | 3 +- src/ui/ui.ts | 3 +- src/ui/vouchers-ui-handler.ts | 3 +- 33 files changed, 593 insertions(+), 289 deletions(-) create mode 100644 src/configs/pad_dualshock.ts create mode 100644 src/configs/pad_generic.ts create mode 100644 src/configs/pad_unlicensedSNES.ts create mode 100644 src/configs/pad_xbox360.ts create mode 100644 src/inputs-controller.ts create mode 100644 src/ui-inputs.ts diff --git a/src/battle-scene.ts b/src/battle-scene.ts index cbf363f689a..f6e5a9c5948 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -1,4 +1,4 @@ -import Phaser, { Time } from 'phaser'; +import Phaser from 'phaser'; import UI, { Mode } from './ui/ui'; import { NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, TurnInitPhase, ReturnPhase, LevelCapPhase, ShowTrainerPhase, LoginPhase, MovePhase, TitlePhase, SwitchPhase } from './phases'; import Pokemon, { PlayerPokemon, EnemyPokemon } from './field/pokemon'; @@ -54,13 +54,14 @@ import CharSprite from './ui/char-sprite'; import DamageNumberHandler from './field/damage-number-handler'; import PokemonInfoContainer from './ui/pokemon-info-container'; import { biomeDepths } from './data/biomes'; -import { initTouchControls } from './touch-controls'; import { UiTheme } from './enums/ui-theme'; import { SceneBase } from './scene-base'; import CandyBar from './ui/candy-bar'; import { Variant, variantData } from './data/variant'; import { Localizable } from './plugins/i18n'; import { STARTING_WAVE_OVERRIDE, OPP_SPECIES_OVERRIDE, SEED_OVERRIDE, STARTING_BIOME_OVERRIDE } from './overrides'; +import {InputsController} from "./inputs-controller"; +import {UiInputs} from "./ui-inputs"; export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1"; @@ -69,33 +70,12 @@ const DEBUG_RNG = false; export const startingWave = STARTING_WAVE_OVERRIDE || 1; const expSpriteKeys: string[] = []; -const repeatInputDelayMillis = 250; export let starterColors: StarterColors; interface StarterColors { [key: string]: [string, string] } -export enum Button { - UP, - DOWN, - LEFT, - RIGHT, - SUBMIT, - ACTION, - CANCEL, - MENU, - STATS, - CYCLE_SHINY, - CYCLE_FORM, - CYCLE_GENDER, - CYCLE_ABILITY, - CYCLE_NATURE, - CYCLE_VARIANT, - SPEED_UP, - SLOW_DOWN -} - export interface PokeballCounts { [pb: string]: integer; } @@ -104,6 +84,8 @@ export type AnySound = Phaser.Sound.WebAudioSound | Phaser.Sound.HTML5AudioSound export default class BattleScene extends SceneBase { public rexUI: UIPlugin; + public inputController: InputsController; + public uiInputs: UiInputs; public sessionPlayTime: integer = null; public masterVolume: number = 0.5; @@ -189,34 +171,6 @@ export default class BattleScene extends SceneBase { private bgmResumeTimer: Phaser.Time.TimerEvent; private bgmCache: Set = new Set(); private playTimeTimer: Phaser.Time.TimerEvent; - - private buttonKeys: Phaser.Input.Keyboard.Key[][]; - private lastProcessedButtonPressTimes: Map = new Map(); - // movementButtonLock ensures only a single movement key is firing repeated inputs - // (i.e. by holding down a button) at a time - private movementButtonLock: Button; - - // using a dualshock controller as a map - private gamepadKeyConfig = { - [Button.UP]: 12, // up - [Button.DOWN]: 13, // down - [Button.LEFT]: 14, // left - [Button.RIGHT]: 15, // right - [Button.SUBMIT]: 17, // touchpad - [Button.ACTION]: 0, // X - [Button.CANCEL]: 1, // O - [Button.MENU]: 9, // options - [Button.STATS]: 8, // share - [Button.CYCLE_SHINY]: 5, // RB - [Button.CYCLE_FORM]: 4, // LB - [Button.CYCLE_GENDER]: 6, // LT - [Button.CYCLE_ABILITY]: 7, // RT - [Button.CYCLE_NATURE]: 2, // square - [Button.CYCLE_VARIANT]: 3, // triangle - [Button.SPEED_UP]: 10, // L3 - [Button.SLOW_DOWN]: 11 // R3 - }; - public gamepadButtonStates: boolean[] = new Array(17).fill(false); public rngCounter: integer = 0; public rngSeedOverride: string = ''; @@ -246,7 +200,9 @@ export default class BattleScene extends SceneBase { this.load.atlas(key, `images/pokemon/${variant ? 'variant/' : ''}${experimental ? 'exp/' : ''}${atlasPath}.png`, `images/pokemon/${variant ? 'variant/' : ''}${experimental ? 'exp/' : ''}${atlasPath}.json`); } - async preload() { + async preload() { + this.load.scenePlugin('inputController', InputsController); + this.load.scenePlugin('uiInputs', UiInputs); if (DEBUG_RNG) { const scene = this; const originalRealInRange = Phaser.Math.RND.realInRange; @@ -260,7 +216,7 @@ export default class BattleScene extends SceneBase { return ret; }; } - + populateAnims(); await this.initVariantData(); @@ -273,8 +229,6 @@ export default class BattleScene extends SceneBase { addUiThemeOverrides(this); - this.setupControls(); - this.load.setBaseURL(); this.spritePipeline = new SpritePipeline(this.game); @@ -287,7 +241,6 @@ export default class BattleScene extends SceneBase { } update() { - this.checkInput(); this.ui?.update(); } @@ -606,42 +559,6 @@ export default class BattleScene extends SceneBase { return true; } - setupControls() { - const keyCodes = Phaser.Input.Keyboard.KeyCodes; - const keyConfig = { - [Button.UP]: [keyCodes.UP, keyCodes.W], - [Button.DOWN]: [keyCodes.DOWN, keyCodes.S], - [Button.LEFT]: [keyCodes.LEFT, keyCodes.A], - [Button.RIGHT]: [keyCodes.RIGHT, keyCodes.D], - [Button.SUBMIT]: [keyCodes.ENTER], - [Button.ACTION]: [keyCodes.SPACE, keyCodes.ENTER, keyCodes.Z], - [Button.CANCEL]: [keyCodes.BACKSPACE, keyCodes.X], - [Button.MENU]: [keyCodes.ESC, keyCodes.M], - [Button.STATS]: [keyCodes.SHIFT, keyCodes.C], - [Button.CYCLE_SHINY]: [keyCodes.R], - [Button.CYCLE_FORM]: [keyCodes.F], - [Button.CYCLE_GENDER]: [keyCodes.G], - [Button.CYCLE_ABILITY]: [keyCodes.E], - [Button.CYCLE_NATURE]: [keyCodes.N], - [Button.CYCLE_VARIANT]: [keyCodes.V], - [Button.SPEED_UP]: [keyCodes.PLUS], - [Button.SLOW_DOWN]: [keyCodes.MINUS] - }; - const mobileKeyConfig = {}; - this.buttonKeys = []; - for (let b of Utils.getEnumValues(Button)) { - const keys: Phaser.Input.Keyboard.Key[] = []; - if (keyConfig.hasOwnProperty(b)) { - for (let k of keyConfig[b]) - keys.push(this.input.keyboard.addKey(k, false)); - mobileKeyConfig[Button[b]] = keys[0]; - } - this.buttonKeys[b] = keys; - } - - initTouchControls(mobileKeyConfig); - } - getParty(): PlayerPokemon[] { return this.party; } @@ -1343,177 +1260,6 @@ export default class BattleScene extends SceneBase { return biomes[Utils.randSeedInt(biomes.length)]; } - checkInput(): boolean { - let inputSuccess = false; - let vibrationLength = 0; - if (this.buttonJustPressed(Button.UP) || this.repeatInputDurationJustPassed(Button.UP)) { - inputSuccess = this.ui.processInput(Button.UP); - vibrationLength = 5; - this.setLastProcessedMovementTime(Button.UP) - } else if (this.buttonJustPressed(Button.DOWN) || this.repeatInputDurationJustPassed(Button.DOWN)) { - inputSuccess = this.ui.processInput(Button.DOWN); - vibrationLength = 5; - this.setLastProcessedMovementTime(Button.DOWN) - } else if (this.buttonJustPressed(Button.LEFT) || this.repeatInputDurationJustPassed(Button.LEFT)) { - inputSuccess = this.ui.processInput(Button.LEFT); - vibrationLength = 5; - this.setLastProcessedMovementTime(Button.LEFT) - } else if (this.buttonJustPressed(Button.RIGHT) || this.repeatInputDurationJustPassed(Button.RIGHT)) { - inputSuccess = this.ui.processInput(Button.RIGHT); - vibrationLength = 5; - this.setLastProcessedMovementTime(Button.RIGHT) - } else if (this.buttonJustPressed(Button.SUBMIT) || this.repeatInputDurationJustPassed(Button.SUBMIT)) { - inputSuccess = this.ui.processInput(Button.SUBMIT) || this.ui.processInput(Button.ACTION); - this.setLastProcessedMovementTime(Button.SUBMIT); - } else if (this.buttonJustPressed(Button.ACTION) || this.repeatInputDurationJustPassed(Button.ACTION)) { - inputSuccess = this.ui.processInput(Button.ACTION); - this.setLastProcessedMovementTime(Button.ACTION); - } else if (this.buttonJustPressed(Button.CANCEL)|| this.repeatInputDurationJustPassed(Button.CANCEL)) { - inputSuccess = this.ui.processInput(Button.CANCEL); - this.setLastProcessedMovementTime(Button.CANCEL); - } else if (this.buttonJustPressed(Button.MENU)) { - if (this.disableMenu) - return; - switch (this.ui?.getMode()) { - case Mode.MESSAGE: - if (!(this.ui.getHandler() as MessageUiHandler).pendingPrompt) - return; - case Mode.TITLE: - case Mode.COMMAND: - case Mode.FIGHT: - case Mode.BALL: - case Mode.TARGET_SELECT: - case Mode.SAVE_SLOT: - case Mode.PARTY: - case Mode.SUMMARY: - case Mode.STARTER_SELECT: - case Mode.CONFIRM: - case Mode.OPTION_SELECT: - this.ui.setOverlayMode(Mode.MENU); - inputSuccess = true; - break; - case Mode.MENU: - case Mode.SETTINGS: - case Mode.ACHIEVEMENTS: - this.ui.revertMode(); - this.playSound('select'); - inputSuccess = true; - break; - default: - return; - } - } else if (this.ui?.getHandler() instanceof StarterSelectUiHandler) { - if (this.buttonJustPressed(Button.CYCLE_SHINY)) { - inputSuccess = this.ui.processInput(Button.CYCLE_SHINY); - this.setLastProcessedMovementTime(Button.CYCLE_SHINY); - } else if (this.buttonJustPressed(Button.CYCLE_FORM)) { - inputSuccess = this.ui.processInput(Button.CYCLE_FORM); - this.setLastProcessedMovementTime(Button.CYCLE_FORM); - } else if (this.buttonJustPressed(Button.CYCLE_GENDER)) { - inputSuccess = this.ui.processInput(Button.CYCLE_GENDER); - this.setLastProcessedMovementTime(Button.CYCLE_GENDER); - } else if (this.buttonJustPressed(Button.CYCLE_ABILITY)) { - inputSuccess = this.ui.processInput(Button.CYCLE_ABILITY); - this.setLastProcessedMovementTime(Button.CYCLE_ABILITY); - } else if (this.buttonJustPressed(Button.CYCLE_NATURE)) { - inputSuccess = this.ui.processInput(Button.CYCLE_NATURE); - this.setLastProcessedMovementTime(Button.CYCLE_NATURE); - } else if (this.buttonJustPressed(Button.CYCLE_VARIANT)) { - inputSuccess = this.ui.processInput(Button.CYCLE_VARIANT); - this.setLastProcessedMovementTime(Button.CYCLE_VARIANT); - } else - return; - } else if (this.buttonJustPressed(Button.SPEED_UP)) { - if (this.gameSpeed < 5) { - this.gameData.saveSetting(Setting.Game_Speed, settingOptions[Setting.Game_Speed].indexOf(`${this.gameSpeed}x`) + 1); - if (this.ui?.getMode() === Mode.SETTINGS) - (this.ui.getHandler() as SettingsUiHandler).show([]); - } - } else if (this.buttonJustPressed(Button.SLOW_DOWN)) { - if (this.gameSpeed > 1) { - this.gameData.saveSetting(Setting.Game_Speed, Math.max(settingOptions[Setting.Game_Speed].indexOf(`${this.gameSpeed}x`) - 1, 0)); - if (this.ui?.getMode() === Mode.SETTINGS) - (this.ui.getHandler() as SettingsUiHandler).show([]); - } - } else { - let pressed = false; - if (this.ui && (this.buttonJustReleased(Button.STATS) || (pressed = this.buttonJustPressed(Button.STATS)))) { - for (let p of this.getField().filter(p => p?.isActive(true))) - p.toggleStats(pressed); - if (pressed) - this.setLastProcessedMovementTime(Button.STATS); - } else - return; - } - if (inputSuccess && this.enableVibration && typeof navigator.vibrate !== 'undefined') - navigator.vibrate(vibrationLength || 10); - } - - /** - * gamepadButtonJustDown returns true if @param button has just been pressed down - * or not. It will only return true once, until the key is released and pressed down - * again. - */ - gamepadButtonJustDown(button: Phaser.Input.Gamepad.Button): boolean { - if (!button || !this.gamepadSupport) - return false; - - let ret = false; - if (button.pressed) { - if (!this.gamepadButtonStates[button.index]) - ret = true; - this.gamepadButtonStates[button.index] = true; - } else - this.gamepadButtonStates[button.index] = false; - - return ret; - } - - buttonJustPressed(button: Button): boolean { - const gamepad = this.input.gamepad?.gamepads[0]; - return this.buttonKeys[button].some(k => Phaser.Input.Keyboard.JustDown(k)) || this.gamepadButtonJustDown(gamepad?.buttons[this.gamepadKeyConfig[button]]); - } - - /** - * gamepadButtonJustUp returns true if @param button has just been released - * or not. It will only return true once, until the key is released and pressed down - * again. - */ - gamepadButtonJustUp(button: Phaser.Input.Gamepad.Button): boolean { - if (!button || !this.gamepadSupport) - return false; - - return !this.gamepadButtonStates[button.index]; - } - - buttonJustReleased(button: Button): boolean { - const gamepad = this.input.gamepad?.gamepads[0]; - return this.buttonKeys[button].some(k => Phaser.Input.Keyboard.JustUp(k)) || this.gamepadButtonJustUp(gamepad?.buttons[this.gamepadKeyConfig[button]]); - } - - /** - * repeatInputDurationJustPassed returns true if @param button has been held down long - * enough to fire a repeated input. A button must claim the movementButtonLock before - * firing a repeated input - this is to prevent multiple buttons from firing repeatedly. - */ - repeatInputDurationJustPassed(button: Button): boolean { - if (this.movementButtonLock !== null && this.movementButtonLock !== button) { - return false; - } - if (this.buttonKeys[button].every(k => k.isUp) && this.gamepadButtonStates.every(b => b == false)) { - this.movementButtonLock = null; - return false; - } - if (this.time.now - this.lastProcessedButtonPressTimes.get(button) >= repeatInputDelayMillis) { - return true; - } - } - - setLastProcessedMovementTime(button: Button) { - this.lastProcessedButtonPressTimes.set(button, this.time.now); - this.movementButtonLock = button; - } - isBgmPlaying(): boolean { return this.bgm && this.bgm.isPlaying; } diff --git a/src/configs/pad_dualshock.ts b/src/configs/pad_dualshock.ts new file mode 100644 index 00000000000..4f66ff8c00a --- /dev/null +++ b/src/configs/pad_dualshock.ts @@ -0,0 +1,29 @@ +/** + * Dualshock mapping + */ +const pad_dualshock = { + padID: 'Dualshock', + padType: 'Sony', + gamepadMapping: { + RC_S: 0, + RC_E: 1, + RC_W: 2, + RC_N: 3, + START: 9, // Options + SELECT: 8, // Share + LB: 4, + RB: 5, + LT: 6, + RT: 7, + LS: 10, + RS: 11, + LC_N: 12, + LC_S: 13, + LC_W: 14, + LC_E: 15, + MENU: 16, + TOUCH: 17 + }, +}; + +export default pad_dualshock; diff --git a/src/configs/pad_generic.ts b/src/configs/pad_generic.ts new file mode 100644 index 00000000000..19b5d3df16e --- /dev/null +++ b/src/configs/pad_generic.ts @@ -0,0 +1,27 @@ +/** + * Generic pad mapping + */ +const pad_generic = { + padID: 'Generic', + padType: 'generic', + gamepadMapping: { + RC_S: 0, + RC_E: 1, + RC_W: 2, + RC_N: 3, + START: 9, + SELECT: 8, + LB: 4, + RB: 5, + LT: 6, + RT: 7, + LS: 10, + RS: 11, + LC_N: 12, + LC_S: 13, + LC_W: 14, + LC_E: 15 + }, +}; + +export default pad_generic; diff --git a/src/configs/pad_unlicensedSNES.ts b/src/configs/pad_unlicensedSNES.ts new file mode 100644 index 00000000000..ba8ee538d30 --- /dev/null +++ b/src/configs/pad_unlicensedSNES.ts @@ -0,0 +1,23 @@ +/** + * 081f-e401 - UnlicensedSNES + */ +const pad_unlicensedSNES = { + padID: '081f-e401', + padType: 'snes', + gamepadMapping : { + RC_S: 2, + RC_E: 1, + RC_W: 3, + RC_N: 0, + START: 9, + SELECT: 8, + LB: 4, + RB: 5, + LC_N: 12, + LC_S: 13, + LC_W: 14, + LC_E: 15 + } +}; + +export default pad_unlicensedSNES; diff --git a/src/configs/pad_xbox360.ts b/src/configs/pad_xbox360.ts new file mode 100644 index 00000000000..e44ebb54b64 --- /dev/null +++ b/src/configs/pad_xbox360.ts @@ -0,0 +1,28 @@ +/** + * Generic pad mapping + */ +const pad_xbox360 = { + padID: 'Xbox 360 controller (XInput STANDARD GAMEPAD)', + padType: 'xbox', + gamepadMapping: { + RC_S: 0, + RC_E: 1, + RC_W: 2, + RC_N: 3, + START: 9, + SELECT: 8, + LB: 4, + RB: 5, + LT: 6, + RT: 7, + LS: 10, + RS: 11, + LC_N: 12, + LC_S: 13, + LC_W: 14, + LC_E: 15, + MENU: 16 + }, +}; + +export default pad_xbox360; diff --git a/src/inputs-controller.ts b/src/inputs-controller.ts new file mode 100644 index 00000000000..441649a5199 --- /dev/null +++ b/src/inputs-controller.ts @@ -0,0 +1,266 @@ +import Phaser, {Time} from "phaser"; +import * as Utils from "./utils"; +import {initTouchControls} from './touch-controls'; +import pad_generic from "#app/configs/pad_generic"; +import pad_unlicensedSNES from "#app/configs/pad_unlicensedSNES"; +import pad_xbox360 from "#app/configs/pad_xbox360"; +import pad_dualshock from "#app/configs/pad_dualshock"; + + +export enum Button { + UP, + DOWN, + LEFT, + RIGHT, + SUBMIT, + ACTION, + CANCEL, + MENU, + STATS, + CYCLE_SHINY, + CYCLE_FORM, + CYCLE_GENDER, + CYCLE_ABILITY, + CYCLE_NATURE, + CYCLE_VARIANT, + SPEED_UP, + SLOW_DOWN +} + +const repeatInputDelayMillis = 250; + +export class InputsController extends Phaser.Plugins.ScenePlugin { + private game: Phaser.Game; + private buttonKeys: Phaser.Input.Keyboard.Key[][]; + private gamepads: Array = new Array(); + private scene: Phaser.Scene; + + // buttonLock ensures only a single movement key is firing repeated inputs + // (i.e. by holding down a button) at a time + private buttonLock: Button; + private interactions: Map> = new Map(); + private time: Time; + + constructor(scene: Phaser.Scene, pluginManager: Phaser.Plugins.PluginManager, pluginKey: string) { + super(scene, pluginManager, pluginKey); + this.game = pluginManager.game; + this.scene = scene; + this.time = this.scene.time; + this.buttonKeys = []; + + for (const b of Utils.getEnumValues(Button)) { + this.interactions[b] = { + pressTime: false, + isPressed: false, + } + } + // We don't want the menu key to be repeated + delete this.interactions[Button.MENU]; + } + + boot() { + this.eventEmitter = this.systems.events; + this.events = new Phaser.Events.EventEmitter(); + this.game.events.on(Phaser.Core.Events.STEP, this.update, this); + + if (typeof this.systems.input.gamepad !== 'undefined') { + this.systems.input.gamepad.on('connected', function (thisGamepad) { + this.refreshGamepads(); + this.setupGamepad(thisGamepad); + }, this); + + // Check to see if the gamepad has already been setup by the browser + this.systems.input.gamepad.refreshPads(); + if (this.systems.input.gamepad.total) { + this.refreshGamepads(); + for (const thisGamepad of this.gamepads) { + this.systems.input.gamepad.emit('connected', thisGamepad); + } + } + + this.systems.input.gamepad.on('down', this.gamepadButtonDown, this); + this.systems.input.gamepad.on('up', this.gamepadButtonUp, this); + } + + // Keyboard + this.setupKeyboardControls(); + } + + update() { + for (const b of Utils.getEnumValues(Button)) { + if (!this.interactions.hasOwnProperty(b)) continue; + if (this.repeatInputDurationJustPassed(b)) { + this.events.emit('input_down', { + controller_type: 'keyboard', + button: b, + }); + this.setLastProcessedMovementTime(b); + } + } + } + + setupGamepad(thisGamepad): void { + let gamepadID = thisGamepad.id.toLowerCase(); + const mappedPad = this.mapGamepad(gamepadID); + this.player = { + 'mapping': mappedPad.gamepadMapping, + } + } + + refreshGamepads(): void { + // Sometimes, gamepads are undefined. For some reason. + this.gamepads = this.systems.input.gamepad.gamepads.filter(function (el) { + return el != null; + }); + + for (const [index, thisGamepad] of this.gamepads.entries()) { + thisGamepad.index = index; // Overwrite the gamepad index, in case we had undefined gamepads earlier + } + } + + getActionGamepadMapping() { + const gamepadMapping = {}; + gamepadMapping[this.player.mapping.LC_N] = Button.UP; + gamepadMapping[this.player.mapping.LC_S] = Button.DOWN; + gamepadMapping[this.player.mapping.LC_W] = Button.LEFT; + gamepadMapping[this.player.mapping.LC_E] = Button.RIGHT; + gamepadMapping[this.player.mapping.TOUCH] = Button.SUBMIT; + gamepadMapping[this.player.mapping.RC_S] = Button.ACTION; + gamepadMapping[this.player.mapping.RC_E] = Button.CANCEL; + gamepadMapping[this.player.mapping.SELECT] = Button.STATS; + gamepadMapping[this.player.mapping.START] = Button.MENU; + gamepadMapping[this.player.mapping.RB] = Button.CYCLE_SHINY; + gamepadMapping[this.player.mapping.LB] = Button.CYCLE_FORM; + gamepadMapping[this.player.mapping.LT] = Button.CYCLE_GENDER; + gamepadMapping[this.player.mapping.RT] = Button.CYCLE_ABILITY; + gamepadMapping[this.player.mapping.RC_W] = Button.CYCLE_NATURE; + gamepadMapping[this.player.mapping.RC_N] = Button.CYCLE_VARIANT; + gamepadMapping[this.player.mapping.LS] = Button.SPEED_UP; + gamepadMapping[this.player.mapping.RS] = Button.SLOW_DOWN; + + return gamepadMapping; + } + + gamepadButtonDown(pad, button, value): void { + const actionMapping = this.getActionGamepadMapping(); + const buttonDown = actionMapping.hasOwnProperty(button.index) && actionMapping[button.index]; + if (buttonDown !== undefined) { + this.events.emit('input_down', { + controller_type: 'gamepad', + button: buttonDown, + }); + this.setLastProcessedMovementTime(buttonDown); + } + } + + gamepadButtonUp(pad, button, value): void { + const actionMapping = this.getActionGamepadMapping(); + const buttonUp = actionMapping.hasOwnProperty(button.index) && actionMapping[button.index]; + if (buttonUp !== undefined) { + this.events.emit('input_up', { + controller_type: 'gamepad', + button: buttonUp, + }); + this.delLastProcessedMovementTime(buttonUp); + } + } + + setupKeyboardControls(): void { + const keyCodes = Phaser.Input.Keyboard.KeyCodes; + const keyConfig = { + [Button.UP]: [keyCodes.UP, keyCodes.W], + [Button.DOWN]: [keyCodes.DOWN, keyCodes.S], + [Button.LEFT]: [keyCodes.LEFT, keyCodes.A], + [Button.RIGHT]: [keyCodes.RIGHT, keyCodes.D], + [Button.SUBMIT]: [keyCodes.ENTER], + [Button.ACTION]: [keyCodes.SPACE, keyCodes.Z], + [Button.CANCEL]: [keyCodes.BACKSPACE, keyCodes.X], + [Button.MENU]: [keyCodes.ESC, keyCodes.M], + [Button.STATS]: [keyCodes.SHIFT, keyCodes.C], + [Button.CYCLE_SHINY]: [keyCodes.R], + [Button.CYCLE_FORM]: [keyCodes.F], + [Button.CYCLE_GENDER]: [keyCodes.G], + [Button.CYCLE_ABILITY]: [keyCodes.E], + [Button.CYCLE_NATURE]: [keyCodes.N], + [Button.CYCLE_VARIANT]: [keyCodes.V], + [Button.SPEED_UP]: [keyCodes.PLUS], + [Button.SLOW_DOWN]: [keyCodes.MINUS] + }; + const mobileKeyConfig = {}; + for (const b of Utils.getEnumValues(Button)) { + const keys: Phaser.Input.Keyboard.Key[] = []; + if (keyConfig.hasOwnProperty(b)) { + for (let k of keyConfig[b]) + keys.push(this.systems.input.keyboard.addKey(k, false)); + mobileKeyConfig[Button[b]] = keys[0]; + } + this.buttonKeys[b] = keys; + } + + initTouchControls(mobileKeyConfig); + this.listenInputKeyboard(); + } + + listenInputKeyboard(): void { + this.buttonKeys.forEach((row, index) => { + for (const key of row) { + key.on('down', () => { + this.events.emit('input_down', { + controller_type: 'keyboard', + button: index, + }); + this.setLastProcessedMovementTime(index); + }); + key.on('up', () => { + this.events.emit('input_up', { + controller_type: 'keyboard', + button: index, + }); + this.delLastProcessedMovementTime(index); + }); + } + }); + } + + mapGamepad(id) { + id = id.toLowerCase(); + let padConfig = pad_generic; + + if (id.includes('081f') && id.includes('e401')) { + padConfig = pad_unlicensedSNES; + } else if (id.includes('xbox') && id.includes('360')) { + padConfig = pad_xbox360; + } else if (id.includes('054c')) { + padConfig = pad_dualshock; + } + + return padConfig; + } + + /** + * repeatInputDurationJustPassed returns true if @param button has been held down long + * enough to fire a repeated input. A button must claim the buttonLock before + * firing a repeated input - this is to prevent multiple buttons from firing repeatedly. + */ + repeatInputDurationJustPassed(button: Button): boolean { + if (this.buttonLock === null || this.buttonLock !== button) { + return false; + } + if (this.time.now - this.interactions[button].pressTime >= repeatInputDelayMillis) { + this.buttonLock = null; + return true; + } + } + + setLastProcessedMovementTime(button: Button): void { + if (!this.interactions.hasOwnProperty(button)) return; + this.buttonLock = button; + this.interactions[button].pressTime = this.time.now; + } + + delLastProcessedMovementTime(button: Button): void { + if (!this.interactions.hasOwnProperty(button)) return; + this.buttonLock = null; + this.interactions[button].pressTime = null; + } +} \ No newline at end of file diff --git a/src/ui-inputs.ts b/src/ui-inputs.ts new file mode 100644 index 00000000000..bcdcc34b1fa --- /dev/null +++ b/src/ui-inputs.ts @@ -0,0 +1,159 @@ +import Phaser from "phaser"; +import UI, {Mode} from "./ui/ui"; +import {Button} from "#app/inputs-controller"; +import MessageUiHandler from "#app/ui/message-ui-handler"; +import StarterSelectUiHandler from "#app/ui/starter-select-ui-handler"; +import {Setting, settingOptions} from "#app/system/settings"; +import SettingsUiHandler from "#app/ui/settings-ui-handler"; + + +export class UiInputs extends Phaser.Plugins.ScenePlugin { + private game: Phaser.Game; + private scene: Phaser.Scene; + private events; + + constructor(scene: Phaser.Scene, pluginManager: Phaser.Plugins.PluginManager, pluginKey: string) { + super(scene, pluginManager, pluginKey); + this.game = pluginManager.game; + this.scene = scene; + this.events = this.scene.inputController.events + } + + boot() { + this.listenInputs(); + } + + listenInputs(): void { + this.events.on('input_down', (event) => { + const actions = this.getActionsKeyDown(); + if (!actions.hasOwnProperty(event.button)) return; + const [inputSuccess, vibrationLength] = actions[event.button](); + if (inputSuccess && this.scene.enableVibration && typeof navigator.vibrate !== 'undefined') + navigator.vibrate(vibrationLength); + }, this); + + this.events.on('input_up', (event) => { + const actions = this.getActionsKeyUp(); + if (!actions.hasOwnProperty(event.button)) return; + const [inputSuccess, vibrationLength] = actions[event.button](); + if (inputSuccess && this.scene.enableVibration && typeof navigator.vibrate !== 'undefined') + navigator.vibrate(vibrationLength); + }, this); + } + + getActionsKeyDown() { + const actions = {}; + actions[Button.UP] = () => this.buttonDirection(Button.UP); + actions[Button.DOWN] = () => this.buttonDirection(Button.DOWN); + actions[Button.LEFT] = () => this.buttonDirection(Button.LEFT); + actions[Button.RIGHT] = () => this.buttonDirection(Button.RIGHT); + actions[Button.SUBMIT] = () => this.buttonTouch(); + actions[Button.ACTION] = () => this.buttonAb(Button.ACTION); + actions[Button.CANCEL] = () => this.buttonAb(Button.CANCEL); + actions[Button.MENU] = () => this.buttonMenu(); + actions[Button.STATS] = () => this.buttonStats(true); + actions[Button.CYCLE_SHINY] = () => this.buttonCycleOption(Button.CYCLE_SHINY); + actions[Button.CYCLE_FORM] = () => this.buttonCycleOption(Button.CYCLE_FORM); + actions[Button.CYCLE_GENDER] = () => this.buttonCycleOption(Button.CYCLE_GENDER); + actions[Button.CYCLE_ABILITY] = () => this.buttonCycleOption(Button.CYCLE_ABILITY); + actions[Button.CYCLE_NATURE] = () => this.buttonCycleOption(Button.CYCLE_NATURE); + actions[Button.CYCLE_VARIANT] = () => this.buttonCycleOption(Button.CYCLE_VARIANT); + actions[Button.SPEED_UP] = () => this.buttonSpeedChange(); + actions[Button.SLOW_DOWN] = () => this.buttonSpeedChange(false); + return actions; + } + + getActionsKeyUp() { + const actions = {}; + actions[Button.STATS] = () => this.buttonStats(false); + return actions; + } + + buttonDirection(direction): Array { + const inputSuccess = this.scene.ui.processInput(direction); + const vibrationLength = 5; + return [inputSuccess, vibrationLength]; + } + + buttonAb(button): Array { + const inputSuccess = this.scene.ui.processInput(button); + return [inputSuccess, 0]; + } + + buttonTouch(): Array { + const inputSuccess = this.scene.ui.processInput(Button.SUBMIT) || this.scene.ui.processInput(Button.ACTION); + return [inputSuccess, 0]; + } + + buttonStats(pressed = true): Array { + if (pressed) { + for (let p of this.scene.getField().filter(p => p?.isActive(true))) + p.toggleStats(true); + } else { + for (let p of this.scene.getField().filter(p => p?.isActive(true))) + p.toggleStats(false); + } + return [true, 0]; + } + + buttonMenu(): Array { + let inputSuccess; + if (this.scene.disableMenu) + return [true, 0]; + switch (this.scene.ui?.getMode()) { + case Mode.MESSAGE: + if (!(this.scene.ui.getHandler() as MessageUiHandler).pendingPrompt) + return [true, 0]; + case Mode.TITLE: + case Mode.COMMAND: + case Mode.FIGHT: + case Mode.BALL: + case Mode.TARGET_SELECT: + case Mode.SAVE_SLOT: + case Mode.PARTY: + case Mode.SUMMARY: + case Mode.STARTER_SELECT: + case Mode.CONFIRM: + case Mode.OPTION_SELECT: + this.scene.ui.setOverlayMode(Mode.MENU); + inputSuccess = true; + break; + case Mode.MENU: + case Mode.SETTINGS: + case Mode.ACHIEVEMENTS: + this.scene.ui.revertMode(); + this.scene.playSound('select'); + inputSuccess = true; + break; + default: + return [true, 0]; + } + return [inputSuccess, 0]; + } + + buttonCycleOption(button): Array { + let inputSuccess; + if (this.scene.ui?.getHandler() instanceof StarterSelectUiHandler) { + inputSuccess = this.scene.ui.processInput(button); + } + return [inputSuccess, 0]; + } + + buttonSpeedChange(up = true): Array { + if (up) { + if (this.scene.gameSpeed < 5) { + this.scene.gameData.saveSetting(Setting.Game_Speed, settingOptions[Setting.Game_Speed].indexOf(`${this.scene.gameSpeed}x`) + 1); + if (this.scene.ui?.getMode() === Mode.SETTINGS) + (this.scene.ui.getHandler() as SettingsUiHandler).show([]); + } + return [0, 0]; + } + if (this.scene.gameSpeed > 1) { + this.scene.gameData.saveSetting(Setting.Game_Speed, Math.max(settingOptions[Setting.Game_Speed].indexOf(`${this.scene.gameSpeed}x`) - 1, 0)); + if (this.scene.ui?.getMode() === Mode.SETTINGS) + (this.scene.ui.getHandler() as SettingsUiHandler).show([]); + } + return [0, 0]; + } + +} \ No newline at end of file diff --git a/src/ui/abstact-option-select-ui-handler.ts b/src/ui/abstact-option-select-ui-handler.ts index 2f2c4face89..ac2dca03ed3 100644 --- a/src/ui/abstact-option-select-ui-handler.ts +++ b/src/ui/abstact-option-select-ui-handler.ts @@ -1,10 +1,11 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { TextStyle, addTextObject } from "./text"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import { addWindow } from "./ui-theme"; import * as Utils from "../utils"; import { argbFromRgba } from "@material/material-color-utilities"; +import {Button} from "#app/inputs-controller"; export interface OptionSelectConfig { xOffset?: number; diff --git a/src/ui/achvs-ui-handler.ts b/src/ui/achvs-ui-handler.ts index cadda64e032..778a5d5f131 100644 --- a/src/ui/achvs-ui-handler.ts +++ b/src/ui/achvs-ui-handler.ts @@ -1,9 +1,10 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { Achv, achvs } from "../system/achv"; import MessageUiHandler from "./message-ui-handler"; import { TextStyle, addTextObject } from "./text"; import { Mode } from "./ui"; import { addWindow } from "./ui-theme"; +import {Button} from "#app/inputs-controller"; export default class AchvsUiHandler extends MessageUiHandler { private achvsContainer: Phaser.GameObjects.Container; diff --git a/src/ui/awaitable-ui-handler.ts b/src/ui/awaitable-ui-handler.ts index e8cc979e423..5d5f0b7a094 100644 --- a/src/ui/awaitable-ui-handler.ts +++ b/src/ui/awaitable-ui-handler.ts @@ -1,6 +1,7 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; +import {Button} from "#app/inputs-controller"; export default abstract class AwaitableUiHandler extends UiHandler { protected awaitingActionInput: boolean; diff --git a/src/ui/ball-ui-handler.ts b/src/ui/ball-ui-handler.ts index f2ebdc342a4..a4ee6c99d46 100644 --- a/src/ui/ball-ui-handler.ts +++ b/src/ui/ball-ui-handler.ts @@ -1,11 +1,12 @@ import { CommandPhase } from "../phases"; -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { getPokeballName } from "../data/pokeball"; import { addTextObject, TextStyle } from "./text"; import { Command } from "./command-ui-handler"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import { addWindow } from "./ui-theme"; +import {Button} from "#app/inputs-controller"; export default class BallUiHandler extends UiHandler { private pokeballSelectContainer: Phaser.GameObjects.Container; diff --git a/src/ui/battle-message-ui-handler.ts b/src/ui/battle-message-ui-handler.ts index 5e2cb56518f..7bba9657cd9 100644 --- a/src/ui/battle-message-ui-handler.ts +++ b/src/ui/battle-message-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { addBBCodeTextObject, addTextObject, getTextColor, TextStyle } from "./text"; import { Mode } from "./ui"; import * as Utils from "../utils"; @@ -6,6 +6,7 @@ import MessageUiHandler from "./message-ui-handler"; import { getStatName, Stat } from "../data/pokemon-stat"; import { addWindow } from "./ui-theme"; import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext"; +import {Button} from "#app/inputs-controller"; export default class BattleMessageUiHandler extends MessageUiHandler { private levelUpStatsContainer: Phaser.GameObjects.Container; diff --git a/src/ui/command-ui-handler.ts b/src/ui/command-ui-handler.ts index b8223694b4c..4c49246ebb6 100644 --- a/src/ui/command-ui-handler.ts +++ b/src/ui/command-ui-handler.ts @@ -1,10 +1,11 @@ import { CommandPhase } from "../phases"; -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { addTextObject, TextStyle } from "./text"; import PartyUiHandler, { PartyUiMode } from "./party-ui-handler"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import i18next from '../plugins/i18n'; +import {Button} from "#app/inputs-controller"; export enum Command { FIGHT = 0, diff --git a/src/ui/confirm-ui-handler.ts b/src/ui/confirm-ui-handler.ts index d9e7726d826..600a84e614d 100644 --- a/src/ui/confirm-ui-handler.ts +++ b/src/ui/confirm-ui-handler.ts @@ -1,6 +1,7 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import AbstractOptionSelectUiHandler, { OptionSelectConfig } from "./abstact-option-select-ui-handler"; import { Mode } from "./ui"; +import {Button} from "#app/inputs-controller"; export default class ConfirmUiHandler extends AbstractOptionSelectUiHandler { private switchCheck: boolean; diff --git a/src/ui/egg-gacha-ui-handler.ts b/src/ui/egg-gacha-ui-handler.ts index f0e32dbc2e9..0f8b999ba59 100644 --- a/src/ui/egg-gacha-ui-handler.ts +++ b/src/ui/egg-gacha-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { Mode } from "./ui"; import { TextStyle, addTextObject, getEggTierTextTint } from "./text"; import MessageUiHandler from "./message-ui-handler"; @@ -9,6 +9,7 @@ import { getPokemonSpecies } from "../data/pokemon-species"; import { addWindow } from "./ui-theme"; import { Tutorial, handleTutorial } from "../tutorial"; import { EggTier } from "../data/enums/egg-type"; +import {Button} from "#app/inputs-controller"; const defaultText = 'Select a machine.'; diff --git a/src/ui/egg-hatch-scene-handler.ts b/src/ui/egg-hatch-scene-handler.ts index f841bafc268..fefd5197be2 100644 --- a/src/ui/egg-hatch-scene-handler.ts +++ b/src/ui/egg-hatch-scene-handler.ts @@ -1,7 +1,8 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { EggHatchPhase } from "../egg-hatch-phase"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; +import {Button} from "#app/inputs-controller"; export default class EggHatchSceneHandler extends UiHandler { public eggHatchContainer: Phaser.GameObjects.Container; diff --git a/src/ui/egg-list-ui-handler.ts b/src/ui/egg-list-ui-handler.ts index 7537b8deeb0..8271ee00788 100644 --- a/src/ui/egg-list-ui-handler.ts +++ b/src/ui/egg-list-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { Mode } from "./ui"; import PokemonIconAnimHandler, { PokemonIconAnimMode } from "./pokemon-icon-anim-handler"; import { TextStyle, addTextObject } from "./text"; @@ -6,6 +6,7 @@ import MessageUiHandler from "./message-ui-handler"; import { EGG_SEED, Egg, GachaType, getEggGachaTypeDescriptor, getEggHatchWavesMessage, getEggDescriptor } from "../data/egg"; import * as Utils from "../utils"; import { addWindow } from "./ui-theme"; +import {Button} from "#app/inputs-controller"; export default class EggListUiHandler extends MessageUiHandler { private eggListContainer: Phaser.GameObjects.Container; diff --git a/src/ui/evolution-scene-handler.ts b/src/ui/evolution-scene-handler.ts index 7e0ef063ea0..21b39b593cf 100644 --- a/src/ui/evolution-scene-handler.ts +++ b/src/ui/evolution-scene-handler.ts @@ -1,7 +1,8 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import MessageUiHandler from "./message-ui-handler"; import { TextStyle, addTextObject } from "./text"; import { Mode } from "./ui"; +import {Button} from "#app/inputs-controller"; export default class EvolutionSceneHandler extends MessageUiHandler { public evolutionContainer: Phaser.GameObjects.Container; diff --git a/src/ui/fight-ui-handler.ts b/src/ui/fight-ui-handler.ts index 1a7a8bef597..b35292ebd45 100644 --- a/src/ui/fight-ui-handler.ts +++ b/src/ui/fight-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { addTextObject, TextStyle } from "./text"; import { Type } from "../data/type"; import { Command } from "./command-ui-handler"; @@ -8,6 +8,7 @@ import * as Utils from "../utils"; import { CommandPhase } from "../phases"; import { MoveCategory } from "#app/data/move.js"; import i18next from '../plugins/i18n'; +import {Button} from "#app/inputs-controller"; export default class FightUiHandler extends UiHandler { private movesContainer: Phaser.GameObjects.Container; diff --git a/src/ui/form-modal-ui-handler.ts b/src/ui/form-modal-ui-handler.ts index ec5f4147c58..4830bd191f9 100644 --- a/src/ui/form-modal-ui-handler.ts +++ b/src/ui/form-modal-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { ModalConfig, ModalUiHandler } from "./modal-ui-handler"; import { Mode } from "./ui"; import { TextStyle, addTextInputObject, addTextObject } from "./text"; @@ -6,6 +6,7 @@ import { WindowVariant, addWindow } from "./ui-theme"; import InputText from "phaser3-rex-plugins/plugins/inputtext"; import * as Utils from "../utils"; import i18next from '../plugins/i18n'; +import {Button} from "#app/inputs-controller"; export interface FormModalConfig extends ModalConfig { errorMessage?: string; diff --git a/src/ui/game-stats-ui-handler.ts b/src/ui/game-stats-ui-handler.ts index 00e358ff8e4..5b271159f4a 100644 --- a/src/ui/game-stats-ui-handler.ts +++ b/src/ui/game-stats-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { TextStyle, addTextObject, getTextColor } from "./text"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; @@ -6,6 +6,7 @@ import { addWindow } from "./ui-theme"; import * as Utils from "../utils"; import { DexAttr, GameData } from "../system/game-data"; import { speciesStarters } from "../data/pokemon-species"; +import {Button} from "#app/inputs-controller"; interface DisplayStat { label?: string; diff --git a/src/ui/menu-ui-handler.ts b/src/ui/menu-ui-handler.ts index 03d93699e75..7ce5302aa0e 100644 --- a/src/ui/menu-ui-handler.ts +++ b/src/ui/menu-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene, { Button, bypassLogin } from "../battle-scene"; +import BattleScene, { bypassLogin } from "../battle-scene"; import { TextStyle, addTextObject } from "./text"; import { Mode } from "./ui"; import * as Utils from "../utils"; @@ -9,6 +9,7 @@ import { OptionSelectConfig, OptionSelectItem } from "./abstact-option-select-ui import { Tutorial, handleTutorial } from "../tutorial"; import { updateUserInfo } from "../account"; import i18next from '../plugins/i18n'; +import {Button} from "#app/inputs-controller"; export enum MenuOptions { GAME_SETTINGS, diff --git a/src/ui/modal-ui-handler.ts b/src/ui/modal-ui-handler.ts index f193a3db54f..507e3292fb9 100644 --- a/src/ui/modal-ui-handler.ts +++ b/src/ui/modal-ui-handler.ts @@ -1,8 +1,9 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { TextStyle, addTextObject } from "./text"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import { WindowVariant, addWindow } from "./ui-theme"; +import {Button} from "#app/inputs-controller"; export interface ModalConfig { buttonActions: Function[]; diff --git a/src/ui/modifier-select-ui-handler.ts b/src/ui/modifier-select-ui-handler.ts index e5252e02a8f..7597503d645 100644 --- a/src/ui/modifier-select-ui-handler.ts +++ b/src/ui/modifier-select-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { getPlayerShopModifierTypeOptionsForWave, ModifierTypeOption } from "../modifier/modifier-type"; import { getPokeballAtlasKey, PokeballType } from "../data/pokeball"; import { addTextObject, getModifierTierTextTint, getTextColor, TextStyle } from "./text"; @@ -6,6 +6,7 @@ import AwaitableUiHandler from "./awaitable-ui-handler"; import { Mode } from "./ui"; import { LockModifierTiersModifier, PokemonHeldItemModifier } from "../modifier/modifier"; import { handleTutorial, Tutorial } from "../tutorial"; +import {Button} from "#app/inputs-controller"; export const SHOP_OPTIONS_ROW_LIMIT = 6; diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts index 35014fa7027..29b0bb85011 100644 --- a/src/ui/party-ui-handler.ts +++ b/src/ui/party-ui-handler.ts @@ -1,5 +1,5 @@ import { CommandPhase } from "../phases"; -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { PlayerPokemon, PokemonMove } from "../field/pokemon"; import { addTextObject, TextStyle } from "./text"; import { Command } from "./command-ui-handler"; @@ -16,6 +16,7 @@ import { pokemonEvolutions } from "../data/pokemon-evolutions"; import { addWindow } from "./ui-theme"; import { SpeciesFormChangeItemTrigger } from "../data/pokemon-forms"; import { getVariantTint } from "#app/data/variant"; +import {Button} from "#app/inputs-controller"; const defaultMessage = 'Choose a Pokémon.'; diff --git a/src/ui/save-slot-select-ui-handler.ts b/src/ui/save-slot-select-ui-handler.ts index 181b0643cb9..07a9283f7e8 100644 --- a/src/ui/save-slot-select-ui-handler.ts +++ b/src/ui/save-slot-select-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { gameModes } from "../game-mode"; import { SessionSaveData } from "../system/game-data"; import { TextStyle, addTextObject } from "./text"; @@ -8,6 +8,7 @@ import * as Utils from "../utils"; import PokemonData from "../system/pokemon-data"; import { PokemonHeldItemModifier } from "../modifier/modifier"; import MessageUiHandler from "./message-ui-handler"; +import {Button} from "#app/inputs-controller"; const sessionSlotCount = 5; diff --git a/src/ui/settings-ui-handler.ts b/src/ui/settings-ui-handler.ts index 8f43b377d21..6b1b7467d67 100644 --- a/src/ui/settings-ui-handler.ts +++ b/src/ui/settings-ui-handler.ts @@ -1,10 +1,11 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { Setting, reloadSettings, settingDefaults, settingOptions } from "../system/settings"; import { hasTouchscreen, isMobile } from "../touch-controls"; import { TextStyle, addTextObject } from "./text"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import { addWindow } from "./ui-theme"; +import {Button} from "#app/inputs-controller"; export default class SettingsUiHandler extends UiHandler { private settingsContainer: Phaser.GameObjects.Container; diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index f1e058b12cf..ad3e51d24a2 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene, { Button, starterColors } from "../battle-scene"; +import BattleScene, { starterColors } from "../battle-scene"; import PokemonSpecies, { allSpecies, getPokemonSpecies, getPokemonSpeciesForm, speciesStarters, starterPassiveAbilities } from "../data/pokemon-species"; import { Species } from "../data/enums/species"; import { TextStyle, addBBCodeTextObject, addTextObject } from "./text"; @@ -27,6 +27,7 @@ import { argbFromRgba } from "@material/material-color-utilities"; import { OptionSelectItem } from "./abstact-option-select-ui-handler"; import { pokemonPrevolutions } from "#app/data/pokemon-evolutions"; import { Variant, getVariantTint } from "#app/data/variant"; +import {Button} from "#app/inputs-controller"; export type StarterSelectCallback = (starters: Starter[]) => void; diff --git a/src/ui/summary-ui-handler.ts b/src/ui/summary-ui-handler.ts index cf5eb3639fd..4b014b83778 100644 --- a/src/ui/summary-ui-handler.ts +++ b/src/ui/summary-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import * as Utils from "../utils"; @@ -17,6 +17,7 @@ import { Nature, getNatureStatMultiplier } from "../data/nature"; import { loggedInUser } from "../account"; import { PlayerGender } from "../system/game-data"; import { Variant, getVariantTint } from "#app/data/variant"; +import {Button} from "#app/inputs-controller"; enum Page { PROFILE, diff --git a/src/ui/target-select-ui-handler.ts b/src/ui/target-select-ui-handler.ts index f8a7c9d28a3..b5242e713d7 100644 --- a/src/ui/target-select-ui-handler.ts +++ b/src/ui/target-select-ui-handler.ts @@ -1,10 +1,11 @@ import { BattlerIndex } from "../battle"; -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { Moves } from "../data/enums/moves"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import * as Utils from "../utils"; import { getMoveTargets } from "../data/move"; +import {Button} from "#app/inputs-controller"; export type TargetSelectCallback = (cursor: integer) => void; diff --git a/src/ui/ui-handler.ts b/src/ui/ui-handler.ts index e3c94b76467..20f34a33388 100644 --- a/src/ui/ui-handler.ts +++ b/src/ui/ui-handler.ts @@ -1,6 +1,7 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { TextStyle, getTextColor } from "./text"; import UI, { Mode } from "./ui"; +import {Button} from "#app/inputs-controller"; export default abstract class UiHandler { protected scene: BattleScene; diff --git a/src/ui/ui.ts b/src/ui/ui.ts index 6e20b2cb8b8..0555c54193d 100644 --- a/src/ui/ui.ts +++ b/src/ui/ui.ts @@ -1,4 +1,4 @@ -import { Button, default as BattleScene } from '../battle-scene'; +import { default as BattleScene } from '../battle-scene'; import UiHandler from './ui-handler'; import BattleMessageUiHandler from './battle-message-ui-handler'; import CommandUiHandler from './command-ui-handler'; @@ -35,6 +35,7 @@ import SavingIconHandler from './saving-icon-handler'; import UnavailableModalUiHandler from './unavailable-modal-ui-handler'; import OutdatedModalUiHandler from './outdated-modal-ui-handler'; import SessionReloadModalUiHandler from './session-reload-modal-ui-handler'; +import {Button} from "#app/inputs-controller"; export enum Mode { MESSAGE, diff --git a/src/ui/vouchers-ui-handler.ts b/src/ui/vouchers-ui-handler.ts index 3f41cf9ae74..36926c6fa71 100644 --- a/src/ui/vouchers-ui-handler.ts +++ b/src/ui/vouchers-ui-handler.ts @@ -1,9 +1,10 @@ -import BattleScene, { Button } from "../battle-scene"; +import BattleScene from "../battle-scene"; import { Voucher, getVoucherTypeIcon, getVoucherTypeName, vouchers } from "../system/voucher"; import MessageUiHandler from "./message-ui-handler"; import { TextStyle, addTextObject } from "./text"; import { Mode } from "./ui"; import { addWindow } from "./ui-theme"; +import {Button} from "#app/inputs-controller"; const itemRows = 4; const itemCols = 17; From 9fc6bdde21dd36e297ece74c1e471f22ba5364c4 Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Fri, 3 May 2024 13:04:32 -0400 Subject: [PATCH 53/72] Revert "Rework - Inputs management to include all gamepad mapping (#390)" This reverts commit 70324c415955477a3f569a5c342df4561537da56. --- src/battle-scene.ts | 272 ++++++++++++++++++++- src/configs/pad_dualshock.ts | 29 --- src/configs/pad_generic.ts | 27 -- src/configs/pad_unlicensedSNES.ts | 23 -- src/configs/pad_xbox360.ts | 28 --- src/inputs-controller.ts | 266 -------------------- src/ui-inputs.ts | 159 ------------ src/ui/abstact-option-select-ui-handler.ts | 3 +- src/ui/achvs-ui-handler.ts | 3 +- src/ui/awaitable-ui-handler.ts | 3 +- src/ui/ball-ui-handler.ts | 3 +- src/ui/battle-message-ui-handler.ts | 3 +- src/ui/command-ui-handler.ts | 3 +- src/ui/confirm-ui-handler.ts | 3 +- src/ui/egg-gacha-ui-handler.ts | 3 +- src/ui/egg-hatch-scene-handler.ts | 3 +- src/ui/egg-list-ui-handler.ts | 3 +- src/ui/evolution-scene-handler.ts | 3 +- src/ui/fight-ui-handler.ts | 3 +- src/ui/form-modal-ui-handler.ts | 3 +- src/ui/game-stats-ui-handler.ts | 3 +- src/ui/menu-ui-handler.ts | 3 +- src/ui/modal-ui-handler.ts | 3 +- src/ui/modifier-select-ui-handler.ts | 3 +- src/ui/party-ui-handler.ts | 3 +- src/ui/save-slot-select-ui-handler.ts | 3 +- src/ui/settings-ui-handler.ts | 3 +- src/ui/starter-select-ui-handler.ts | 3 +- src/ui/summary-ui-handler.ts | 3 +- src/ui/target-select-ui-handler.ts | 3 +- src/ui/ui-handler.ts | 3 +- src/ui/ui.ts | 3 +- src/ui/vouchers-ui-handler.ts | 3 +- 33 files changed, 289 insertions(+), 593 deletions(-) delete mode 100644 src/configs/pad_dualshock.ts delete mode 100644 src/configs/pad_generic.ts delete mode 100644 src/configs/pad_unlicensedSNES.ts delete mode 100644 src/configs/pad_xbox360.ts delete mode 100644 src/inputs-controller.ts delete mode 100644 src/ui-inputs.ts diff --git a/src/battle-scene.ts b/src/battle-scene.ts index f6e5a9c5948..cbf363f689a 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -1,4 +1,4 @@ -import Phaser from 'phaser'; +import Phaser, { Time } from 'phaser'; import UI, { Mode } from './ui/ui'; import { NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, TurnInitPhase, ReturnPhase, LevelCapPhase, ShowTrainerPhase, LoginPhase, MovePhase, TitlePhase, SwitchPhase } from './phases'; import Pokemon, { PlayerPokemon, EnemyPokemon } from './field/pokemon'; @@ -54,14 +54,13 @@ import CharSprite from './ui/char-sprite'; import DamageNumberHandler from './field/damage-number-handler'; import PokemonInfoContainer from './ui/pokemon-info-container'; import { biomeDepths } from './data/biomes'; +import { initTouchControls } from './touch-controls'; import { UiTheme } from './enums/ui-theme'; import { SceneBase } from './scene-base'; import CandyBar from './ui/candy-bar'; import { Variant, variantData } from './data/variant'; import { Localizable } from './plugins/i18n'; import { STARTING_WAVE_OVERRIDE, OPP_SPECIES_OVERRIDE, SEED_OVERRIDE, STARTING_BIOME_OVERRIDE } from './overrides'; -import {InputsController} from "./inputs-controller"; -import {UiInputs} from "./ui-inputs"; export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1"; @@ -70,12 +69,33 @@ const DEBUG_RNG = false; export const startingWave = STARTING_WAVE_OVERRIDE || 1; const expSpriteKeys: string[] = []; +const repeatInputDelayMillis = 250; export let starterColors: StarterColors; interface StarterColors { [key: string]: [string, string] } +export enum Button { + UP, + DOWN, + LEFT, + RIGHT, + SUBMIT, + ACTION, + CANCEL, + MENU, + STATS, + CYCLE_SHINY, + CYCLE_FORM, + CYCLE_GENDER, + CYCLE_ABILITY, + CYCLE_NATURE, + CYCLE_VARIANT, + SPEED_UP, + SLOW_DOWN +} + export interface PokeballCounts { [pb: string]: integer; } @@ -84,8 +104,6 @@ export type AnySound = Phaser.Sound.WebAudioSound | Phaser.Sound.HTML5AudioSound export default class BattleScene extends SceneBase { public rexUI: UIPlugin; - public inputController: InputsController; - public uiInputs: UiInputs; public sessionPlayTime: integer = null; public masterVolume: number = 0.5; @@ -171,6 +189,34 @@ export default class BattleScene extends SceneBase { private bgmResumeTimer: Phaser.Time.TimerEvent; private bgmCache: Set = new Set(); private playTimeTimer: Phaser.Time.TimerEvent; + + private buttonKeys: Phaser.Input.Keyboard.Key[][]; + private lastProcessedButtonPressTimes: Map = new Map(); + // movementButtonLock ensures only a single movement key is firing repeated inputs + // (i.e. by holding down a button) at a time + private movementButtonLock: Button; + + // using a dualshock controller as a map + private gamepadKeyConfig = { + [Button.UP]: 12, // up + [Button.DOWN]: 13, // down + [Button.LEFT]: 14, // left + [Button.RIGHT]: 15, // right + [Button.SUBMIT]: 17, // touchpad + [Button.ACTION]: 0, // X + [Button.CANCEL]: 1, // O + [Button.MENU]: 9, // options + [Button.STATS]: 8, // share + [Button.CYCLE_SHINY]: 5, // RB + [Button.CYCLE_FORM]: 4, // LB + [Button.CYCLE_GENDER]: 6, // LT + [Button.CYCLE_ABILITY]: 7, // RT + [Button.CYCLE_NATURE]: 2, // square + [Button.CYCLE_VARIANT]: 3, // triangle + [Button.SPEED_UP]: 10, // L3 + [Button.SLOW_DOWN]: 11 // R3 + }; + public gamepadButtonStates: boolean[] = new Array(17).fill(false); public rngCounter: integer = 0; public rngSeedOverride: string = ''; @@ -200,9 +246,7 @@ export default class BattleScene extends SceneBase { this.load.atlas(key, `images/pokemon/${variant ? 'variant/' : ''}${experimental ? 'exp/' : ''}${atlasPath}.png`, `images/pokemon/${variant ? 'variant/' : ''}${experimental ? 'exp/' : ''}${atlasPath}.json`); } - async preload() { - this.load.scenePlugin('inputController', InputsController); - this.load.scenePlugin('uiInputs', UiInputs); + async preload() { if (DEBUG_RNG) { const scene = this; const originalRealInRange = Phaser.Math.RND.realInRange; @@ -216,7 +260,7 @@ export default class BattleScene extends SceneBase { return ret; }; } - + populateAnims(); await this.initVariantData(); @@ -229,6 +273,8 @@ export default class BattleScene extends SceneBase { addUiThemeOverrides(this); + this.setupControls(); + this.load.setBaseURL(); this.spritePipeline = new SpritePipeline(this.game); @@ -241,6 +287,7 @@ export default class BattleScene extends SceneBase { } update() { + this.checkInput(); this.ui?.update(); } @@ -559,6 +606,42 @@ export default class BattleScene extends SceneBase { return true; } + setupControls() { + const keyCodes = Phaser.Input.Keyboard.KeyCodes; + const keyConfig = { + [Button.UP]: [keyCodes.UP, keyCodes.W], + [Button.DOWN]: [keyCodes.DOWN, keyCodes.S], + [Button.LEFT]: [keyCodes.LEFT, keyCodes.A], + [Button.RIGHT]: [keyCodes.RIGHT, keyCodes.D], + [Button.SUBMIT]: [keyCodes.ENTER], + [Button.ACTION]: [keyCodes.SPACE, keyCodes.ENTER, keyCodes.Z], + [Button.CANCEL]: [keyCodes.BACKSPACE, keyCodes.X], + [Button.MENU]: [keyCodes.ESC, keyCodes.M], + [Button.STATS]: [keyCodes.SHIFT, keyCodes.C], + [Button.CYCLE_SHINY]: [keyCodes.R], + [Button.CYCLE_FORM]: [keyCodes.F], + [Button.CYCLE_GENDER]: [keyCodes.G], + [Button.CYCLE_ABILITY]: [keyCodes.E], + [Button.CYCLE_NATURE]: [keyCodes.N], + [Button.CYCLE_VARIANT]: [keyCodes.V], + [Button.SPEED_UP]: [keyCodes.PLUS], + [Button.SLOW_DOWN]: [keyCodes.MINUS] + }; + const mobileKeyConfig = {}; + this.buttonKeys = []; + for (let b of Utils.getEnumValues(Button)) { + const keys: Phaser.Input.Keyboard.Key[] = []; + if (keyConfig.hasOwnProperty(b)) { + for (let k of keyConfig[b]) + keys.push(this.input.keyboard.addKey(k, false)); + mobileKeyConfig[Button[b]] = keys[0]; + } + this.buttonKeys[b] = keys; + } + + initTouchControls(mobileKeyConfig); + } + getParty(): PlayerPokemon[] { return this.party; } @@ -1260,6 +1343,177 @@ export default class BattleScene extends SceneBase { return biomes[Utils.randSeedInt(biomes.length)]; } + checkInput(): boolean { + let inputSuccess = false; + let vibrationLength = 0; + if (this.buttonJustPressed(Button.UP) || this.repeatInputDurationJustPassed(Button.UP)) { + inputSuccess = this.ui.processInput(Button.UP); + vibrationLength = 5; + this.setLastProcessedMovementTime(Button.UP) + } else if (this.buttonJustPressed(Button.DOWN) || this.repeatInputDurationJustPassed(Button.DOWN)) { + inputSuccess = this.ui.processInput(Button.DOWN); + vibrationLength = 5; + this.setLastProcessedMovementTime(Button.DOWN) + } else if (this.buttonJustPressed(Button.LEFT) || this.repeatInputDurationJustPassed(Button.LEFT)) { + inputSuccess = this.ui.processInput(Button.LEFT); + vibrationLength = 5; + this.setLastProcessedMovementTime(Button.LEFT) + } else if (this.buttonJustPressed(Button.RIGHT) || this.repeatInputDurationJustPassed(Button.RIGHT)) { + inputSuccess = this.ui.processInput(Button.RIGHT); + vibrationLength = 5; + this.setLastProcessedMovementTime(Button.RIGHT) + } else if (this.buttonJustPressed(Button.SUBMIT) || this.repeatInputDurationJustPassed(Button.SUBMIT)) { + inputSuccess = this.ui.processInput(Button.SUBMIT) || this.ui.processInput(Button.ACTION); + this.setLastProcessedMovementTime(Button.SUBMIT); + } else if (this.buttonJustPressed(Button.ACTION) || this.repeatInputDurationJustPassed(Button.ACTION)) { + inputSuccess = this.ui.processInput(Button.ACTION); + this.setLastProcessedMovementTime(Button.ACTION); + } else if (this.buttonJustPressed(Button.CANCEL)|| this.repeatInputDurationJustPassed(Button.CANCEL)) { + inputSuccess = this.ui.processInput(Button.CANCEL); + this.setLastProcessedMovementTime(Button.CANCEL); + } else if (this.buttonJustPressed(Button.MENU)) { + if (this.disableMenu) + return; + switch (this.ui?.getMode()) { + case Mode.MESSAGE: + if (!(this.ui.getHandler() as MessageUiHandler).pendingPrompt) + return; + case Mode.TITLE: + case Mode.COMMAND: + case Mode.FIGHT: + case Mode.BALL: + case Mode.TARGET_SELECT: + case Mode.SAVE_SLOT: + case Mode.PARTY: + case Mode.SUMMARY: + case Mode.STARTER_SELECT: + case Mode.CONFIRM: + case Mode.OPTION_SELECT: + this.ui.setOverlayMode(Mode.MENU); + inputSuccess = true; + break; + case Mode.MENU: + case Mode.SETTINGS: + case Mode.ACHIEVEMENTS: + this.ui.revertMode(); + this.playSound('select'); + inputSuccess = true; + break; + default: + return; + } + } else if (this.ui?.getHandler() instanceof StarterSelectUiHandler) { + if (this.buttonJustPressed(Button.CYCLE_SHINY)) { + inputSuccess = this.ui.processInput(Button.CYCLE_SHINY); + this.setLastProcessedMovementTime(Button.CYCLE_SHINY); + } else if (this.buttonJustPressed(Button.CYCLE_FORM)) { + inputSuccess = this.ui.processInput(Button.CYCLE_FORM); + this.setLastProcessedMovementTime(Button.CYCLE_FORM); + } else if (this.buttonJustPressed(Button.CYCLE_GENDER)) { + inputSuccess = this.ui.processInput(Button.CYCLE_GENDER); + this.setLastProcessedMovementTime(Button.CYCLE_GENDER); + } else if (this.buttonJustPressed(Button.CYCLE_ABILITY)) { + inputSuccess = this.ui.processInput(Button.CYCLE_ABILITY); + this.setLastProcessedMovementTime(Button.CYCLE_ABILITY); + } else if (this.buttonJustPressed(Button.CYCLE_NATURE)) { + inputSuccess = this.ui.processInput(Button.CYCLE_NATURE); + this.setLastProcessedMovementTime(Button.CYCLE_NATURE); + } else if (this.buttonJustPressed(Button.CYCLE_VARIANT)) { + inputSuccess = this.ui.processInput(Button.CYCLE_VARIANT); + this.setLastProcessedMovementTime(Button.CYCLE_VARIANT); + } else + return; + } else if (this.buttonJustPressed(Button.SPEED_UP)) { + if (this.gameSpeed < 5) { + this.gameData.saveSetting(Setting.Game_Speed, settingOptions[Setting.Game_Speed].indexOf(`${this.gameSpeed}x`) + 1); + if (this.ui?.getMode() === Mode.SETTINGS) + (this.ui.getHandler() as SettingsUiHandler).show([]); + } + } else if (this.buttonJustPressed(Button.SLOW_DOWN)) { + if (this.gameSpeed > 1) { + this.gameData.saveSetting(Setting.Game_Speed, Math.max(settingOptions[Setting.Game_Speed].indexOf(`${this.gameSpeed}x`) - 1, 0)); + if (this.ui?.getMode() === Mode.SETTINGS) + (this.ui.getHandler() as SettingsUiHandler).show([]); + } + } else { + let pressed = false; + if (this.ui && (this.buttonJustReleased(Button.STATS) || (pressed = this.buttonJustPressed(Button.STATS)))) { + for (let p of this.getField().filter(p => p?.isActive(true))) + p.toggleStats(pressed); + if (pressed) + this.setLastProcessedMovementTime(Button.STATS); + } else + return; + } + if (inputSuccess && this.enableVibration && typeof navigator.vibrate !== 'undefined') + navigator.vibrate(vibrationLength || 10); + } + + /** + * gamepadButtonJustDown returns true if @param button has just been pressed down + * or not. It will only return true once, until the key is released and pressed down + * again. + */ + gamepadButtonJustDown(button: Phaser.Input.Gamepad.Button): boolean { + if (!button || !this.gamepadSupport) + return false; + + let ret = false; + if (button.pressed) { + if (!this.gamepadButtonStates[button.index]) + ret = true; + this.gamepadButtonStates[button.index] = true; + } else + this.gamepadButtonStates[button.index] = false; + + return ret; + } + + buttonJustPressed(button: Button): boolean { + const gamepad = this.input.gamepad?.gamepads[0]; + return this.buttonKeys[button].some(k => Phaser.Input.Keyboard.JustDown(k)) || this.gamepadButtonJustDown(gamepad?.buttons[this.gamepadKeyConfig[button]]); + } + + /** + * gamepadButtonJustUp returns true if @param button has just been released + * or not. It will only return true once, until the key is released and pressed down + * again. + */ + gamepadButtonJustUp(button: Phaser.Input.Gamepad.Button): boolean { + if (!button || !this.gamepadSupport) + return false; + + return !this.gamepadButtonStates[button.index]; + } + + buttonJustReleased(button: Button): boolean { + const gamepad = this.input.gamepad?.gamepads[0]; + return this.buttonKeys[button].some(k => Phaser.Input.Keyboard.JustUp(k)) || this.gamepadButtonJustUp(gamepad?.buttons[this.gamepadKeyConfig[button]]); + } + + /** + * repeatInputDurationJustPassed returns true if @param button has been held down long + * enough to fire a repeated input. A button must claim the movementButtonLock before + * firing a repeated input - this is to prevent multiple buttons from firing repeatedly. + */ + repeatInputDurationJustPassed(button: Button): boolean { + if (this.movementButtonLock !== null && this.movementButtonLock !== button) { + return false; + } + if (this.buttonKeys[button].every(k => k.isUp) && this.gamepadButtonStates.every(b => b == false)) { + this.movementButtonLock = null; + return false; + } + if (this.time.now - this.lastProcessedButtonPressTimes.get(button) >= repeatInputDelayMillis) { + return true; + } + } + + setLastProcessedMovementTime(button: Button) { + this.lastProcessedButtonPressTimes.set(button, this.time.now); + this.movementButtonLock = button; + } + isBgmPlaying(): boolean { return this.bgm && this.bgm.isPlaying; } diff --git a/src/configs/pad_dualshock.ts b/src/configs/pad_dualshock.ts deleted file mode 100644 index 4f66ff8c00a..00000000000 --- a/src/configs/pad_dualshock.ts +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Dualshock mapping - */ -const pad_dualshock = { - padID: 'Dualshock', - padType: 'Sony', - gamepadMapping: { - RC_S: 0, - RC_E: 1, - RC_W: 2, - RC_N: 3, - START: 9, // Options - SELECT: 8, // Share - LB: 4, - RB: 5, - LT: 6, - RT: 7, - LS: 10, - RS: 11, - LC_N: 12, - LC_S: 13, - LC_W: 14, - LC_E: 15, - MENU: 16, - TOUCH: 17 - }, -}; - -export default pad_dualshock; diff --git a/src/configs/pad_generic.ts b/src/configs/pad_generic.ts deleted file mode 100644 index 19b5d3df16e..00000000000 --- a/src/configs/pad_generic.ts +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Generic pad mapping - */ -const pad_generic = { - padID: 'Generic', - padType: 'generic', - gamepadMapping: { - RC_S: 0, - RC_E: 1, - RC_W: 2, - RC_N: 3, - START: 9, - SELECT: 8, - LB: 4, - RB: 5, - LT: 6, - RT: 7, - LS: 10, - RS: 11, - LC_N: 12, - LC_S: 13, - LC_W: 14, - LC_E: 15 - }, -}; - -export default pad_generic; diff --git a/src/configs/pad_unlicensedSNES.ts b/src/configs/pad_unlicensedSNES.ts deleted file mode 100644 index ba8ee538d30..00000000000 --- a/src/configs/pad_unlicensedSNES.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * 081f-e401 - UnlicensedSNES - */ -const pad_unlicensedSNES = { - padID: '081f-e401', - padType: 'snes', - gamepadMapping : { - RC_S: 2, - RC_E: 1, - RC_W: 3, - RC_N: 0, - START: 9, - SELECT: 8, - LB: 4, - RB: 5, - LC_N: 12, - LC_S: 13, - LC_W: 14, - LC_E: 15 - } -}; - -export default pad_unlicensedSNES; diff --git a/src/configs/pad_xbox360.ts b/src/configs/pad_xbox360.ts deleted file mode 100644 index e44ebb54b64..00000000000 --- a/src/configs/pad_xbox360.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Generic pad mapping - */ -const pad_xbox360 = { - padID: 'Xbox 360 controller (XInput STANDARD GAMEPAD)', - padType: 'xbox', - gamepadMapping: { - RC_S: 0, - RC_E: 1, - RC_W: 2, - RC_N: 3, - START: 9, - SELECT: 8, - LB: 4, - RB: 5, - LT: 6, - RT: 7, - LS: 10, - RS: 11, - LC_N: 12, - LC_S: 13, - LC_W: 14, - LC_E: 15, - MENU: 16 - }, -}; - -export default pad_xbox360; diff --git a/src/inputs-controller.ts b/src/inputs-controller.ts deleted file mode 100644 index 441649a5199..00000000000 --- a/src/inputs-controller.ts +++ /dev/null @@ -1,266 +0,0 @@ -import Phaser, {Time} from "phaser"; -import * as Utils from "./utils"; -import {initTouchControls} from './touch-controls'; -import pad_generic from "#app/configs/pad_generic"; -import pad_unlicensedSNES from "#app/configs/pad_unlicensedSNES"; -import pad_xbox360 from "#app/configs/pad_xbox360"; -import pad_dualshock from "#app/configs/pad_dualshock"; - - -export enum Button { - UP, - DOWN, - LEFT, - RIGHT, - SUBMIT, - ACTION, - CANCEL, - MENU, - STATS, - CYCLE_SHINY, - CYCLE_FORM, - CYCLE_GENDER, - CYCLE_ABILITY, - CYCLE_NATURE, - CYCLE_VARIANT, - SPEED_UP, - SLOW_DOWN -} - -const repeatInputDelayMillis = 250; - -export class InputsController extends Phaser.Plugins.ScenePlugin { - private game: Phaser.Game; - private buttonKeys: Phaser.Input.Keyboard.Key[][]; - private gamepads: Array = new Array(); - private scene: Phaser.Scene; - - // buttonLock ensures only a single movement key is firing repeated inputs - // (i.e. by holding down a button) at a time - private buttonLock: Button; - private interactions: Map> = new Map(); - private time: Time; - - constructor(scene: Phaser.Scene, pluginManager: Phaser.Plugins.PluginManager, pluginKey: string) { - super(scene, pluginManager, pluginKey); - this.game = pluginManager.game; - this.scene = scene; - this.time = this.scene.time; - this.buttonKeys = []; - - for (const b of Utils.getEnumValues(Button)) { - this.interactions[b] = { - pressTime: false, - isPressed: false, - } - } - // We don't want the menu key to be repeated - delete this.interactions[Button.MENU]; - } - - boot() { - this.eventEmitter = this.systems.events; - this.events = new Phaser.Events.EventEmitter(); - this.game.events.on(Phaser.Core.Events.STEP, this.update, this); - - if (typeof this.systems.input.gamepad !== 'undefined') { - this.systems.input.gamepad.on('connected', function (thisGamepad) { - this.refreshGamepads(); - this.setupGamepad(thisGamepad); - }, this); - - // Check to see if the gamepad has already been setup by the browser - this.systems.input.gamepad.refreshPads(); - if (this.systems.input.gamepad.total) { - this.refreshGamepads(); - for (const thisGamepad of this.gamepads) { - this.systems.input.gamepad.emit('connected', thisGamepad); - } - } - - this.systems.input.gamepad.on('down', this.gamepadButtonDown, this); - this.systems.input.gamepad.on('up', this.gamepadButtonUp, this); - } - - // Keyboard - this.setupKeyboardControls(); - } - - update() { - for (const b of Utils.getEnumValues(Button)) { - if (!this.interactions.hasOwnProperty(b)) continue; - if (this.repeatInputDurationJustPassed(b)) { - this.events.emit('input_down', { - controller_type: 'keyboard', - button: b, - }); - this.setLastProcessedMovementTime(b); - } - } - } - - setupGamepad(thisGamepad): void { - let gamepadID = thisGamepad.id.toLowerCase(); - const mappedPad = this.mapGamepad(gamepadID); - this.player = { - 'mapping': mappedPad.gamepadMapping, - } - } - - refreshGamepads(): void { - // Sometimes, gamepads are undefined. For some reason. - this.gamepads = this.systems.input.gamepad.gamepads.filter(function (el) { - return el != null; - }); - - for (const [index, thisGamepad] of this.gamepads.entries()) { - thisGamepad.index = index; // Overwrite the gamepad index, in case we had undefined gamepads earlier - } - } - - getActionGamepadMapping() { - const gamepadMapping = {}; - gamepadMapping[this.player.mapping.LC_N] = Button.UP; - gamepadMapping[this.player.mapping.LC_S] = Button.DOWN; - gamepadMapping[this.player.mapping.LC_W] = Button.LEFT; - gamepadMapping[this.player.mapping.LC_E] = Button.RIGHT; - gamepadMapping[this.player.mapping.TOUCH] = Button.SUBMIT; - gamepadMapping[this.player.mapping.RC_S] = Button.ACTION; - gamepadMapping[this.player.mapping.RC_E] = Button.CANCEL; - gamepadMapping[this.player.mapping.SELECT] = Button.STATS; - gamepadMapping[this.player.mapping.START] = Button.MENU; - gamepadMapping[this.player.mapping.RB] = Button.CYCLE_SHINY; - gamepadMapping[this.player.mapping.LB] = Button.CYCLE_FORM; - gamepadMapping[this.player.mapping.LT] = Button.CYCLE_GENDER; - gamepadMapping[this.player.mapping.RT] = Button.CYCLE_ABILITY; - gamepadMapping[this.player.mapping.RC_W] = Button.CYCLE_NATURE; - gamepadMapping[this.player.mapping.RC_N] = Button.CYCLE_VARIANT; - gamepadMapping[this.player.mapping.LS] = Button.SPEED_UP; - gamepadMapping[this.player.mapping.RS] = Button.SLOW_DOWN; - - return gamepadMapping; - } - - gamepadButtonDown(pad, button, value): void { - const actionMapping = this.getActionGamepadMapping(); - const buttonDown = actionMapping.hasOwnProperty(button.index) && actionMapping[button.index]; - if (buttonDown !== undefined) { - this.events.emit('input_down', { - controller_type: 'gamepad', - button: buttonDown, - }); - this.setLastProcessedMovementTime(buttonDown); - } - } - - gamepadButtonUp(pad, button, value): void { - const actionMapping = this.getActionGamepadMapping(); - const buttonUp = actionMapping.hasOwnProperty(button.index) && actionMapping[button.index]; - if (buttonUp !== undefined) { - this.events.emit('input_up', { - controller_type: 'gamepad', - button: buttonUp, - }); - this.delLastProcessedMovementTime(buttonUp); - } - } - - setupKeyboardControls(): void { - const keyCodes = Phaser.Input.Keyboard.KeyCodes; - const keyConfig = { - [Button.UP]: [keyCodes.UP, keyCodes.W], - [Button.DOWN]: [keyCodes.DOWN, keyCodes.S], - [Button.LEFT]: [keyCodes.LEFT, keyCodes.A], - [Button.RIGHT]: [keyCodes.RIGHT, keyCodes.D], - [Button.SUBMIT]: [keyCodes.ENTER], - [Button.ACTION]: [keyCodes.SPACE, keyCodes.Z], - [Button.CANCEL]: [keyCodes.BACKSPACE, keyCodes.X], - [Button.MENU]: [keyCodes.ESC, keyCodes.M], - [Button.STATS]: [keyCodes.SHIFT, keyCodes.C], - [Button.CYCLE_SHINY]: [keyCodes.R], - [Button.CYCLE_FORM]: [keyCodes.F], - [Button.CYCLE_GENDER]: [keyCodes.G], - [Button.CYCLE_ABILITY]: [keyCodes.E], - [Button.CYCLE_NATURE]: [keyCodes.N], - [Button.CYCLE_VARIANT]: [keyCodes.V], - [Button.SPEED_UP]: [keyCodes.PLUS], - [Button.SLOW_DOWN]: [keyCodes.MINUS] - }; - const mobileKeyConfig = {}; - for (const b of Utils.getEnumValues(Button)) { - const keys: Phaser.Input.Keyboard.Key[] = []; - if (keyConfig.hasOwnProperty(b)) { - for (let k of keyConfig[b]) - keys.push(this.systems.input.keyboard.addKey(k, false)); - mobileKeyConfig[Button[b]] = keys[0]; - } - this.buttonKeys[b] = keys; - } - - initTouchControls(mobileKeyConfig); - this.listenInputKeyboard(); - } - - listenInputKeyboard(): void { - this.buttonKeys.forEach((row, index) => { - for (const key of row) { - key.on('down', () => { - this.events.emit('input_down', { - controller_type: 'keyboard', - button: index, - }); - this.setLastProcessedMovementTime(index); - }); - key.on('up', () => { - this.events.emit('input_up', { - controller_type: 'keyboard', - button: index, - }); - this.delLastProcessedMovementTime(index); - }); - } - }); - } - - mapGamepad(id) { - id = id.toLowerCase(); - let padConfig = pad_generic; - - if (id.includes('081f') && id.includes('e401')) { - padConfig = pad_unlicensedSNES; - } else if (id.includes('xbox') && id.includes('360')) { - padConfig = pad_xbox360; - } else if (id.includes('054c')) { - padConfig = pad_dualshock; - } - - return padConfig; - } - - /** - * repeatInputDurationJustPassed returns true if @param button has been held down long - * enough to fire a repeated input. A button must claim the buttonLock before - * firing a repeated input - this is to prevent multiple buttons from firing repeatedly. - */ - repeatInputDurationJustPassed(button: Button): boolean { - if (this.buttonLock === null || this.buttonLock !== button) { - return false; - } - if (this.time.now - this.interactions[button].pressTime >= repeatInputDelayMillis) { - this.buttonLock = null; - return true; - } - } - - setLastProcessedMovementTime(button: Button): void { - if (!this.interactions.hasOwnProperty(button)) return; - this.buttonLock = button; - this.interactions[button].pressTime = this.time.now; - } - - delLastProcessedMovementTime(button: Button): void { - if (!this.interactions.hasOwnProperty(button)) return; - this.buttonLock = null; - this.interactions[button].pressTime = null; - } -} \ No newline at end of file diff --git a/src/ui-inputs.ts b/src/ui-inputs.ts deleted file mode 100644 index bcdcc34b1fa..00000000000 --- a/src/ui-inputs.ts +++ /dev/null @@ -1,159 +0,0 @@ -import Phaser from "phaser"; -import UI, {Mode} from "./ui/ui"; -import {Button} from "#app/inputs-controller"; -import MessageUiHandler from "#app/ui/message-ui-handler"; -import StarterSelectUiHandler from "#app/ui/starter-select-ui-handler"; -import {Setting, settingOptions} from "#app/system/settings"; -import SettingsUiHandler from "#app/ui/settings-ui-handler"; - - -export class UiInputs extends Phaser.Plugins.ScenePlugin { - private game: Phaser.Game; - private scene: Phaser.Scene; - private events; - - constructor(scene: Phaser.Scene, pluginManager: Phaser.Plugins.PluginManager, pluginKey: string) { - super(scene, pluginManager, pluginKey); - this.game = pluginManager.game; - this.scene = scene; - this.events = this.scene.inputController.events - } - - boot() { - this.listenInputs(); - } - - listenInputs(): void { - this.events.on('input_down', (event) => { - const actions = this.getActionsKeyDown(); - if (!actions.hasOwnProperty(event.button)) return; - const [inputSuccess, vibrationLength] = actions[event.button](); - if (inputSuccess && this.scene.enableVibration && typeof navigator.vibrate !== 'undefined') - navigator.vibrate(vibrationLength); - }, this); - - this.events.on('input_up', (event) => { - const actions = this.getActionsKeyUp(); - if (!actions.hasOwnProperty(event.button)) return; - const [inputSuccess, vibrationLength] = actions[event.button](); - if (inputSuccess && this.scene.enableVibration && typeof navigator.vibrate !== 'undefined') - navigator.vibrate(vibrationLength); - }, this); - } - - getActionsKeyDown() { - const actions = {}; - actions[Button.UP] = () => this.buttonDirection(Button.UP); - actions[Button.DOWN] = () => this.buttonDirection(Button.DOWN); - actions[Button.LEFT] = () => this.buttonDirection(Button.LEFT); - actions[Button.RIGHT] = () => this.buttonDirection(Button.RIGHT); - actions[Button.SUBMIT] = () => this.buttonTouch(); - actions[Button.ACTION] = () => this.buttonAb(Button.ACTION); - actions[Button.CANCEL] = () => this.buttonAb(Button.CANCEL); - actions[Button.MENU] = () => this.buttonMenu(); - actions[Button.STATS] = () => this.buttonStats(true); - actions[Button.CYCLE_SHINY] = () => this.buttonCycleOption(Button.CYCLE_SHINY); - actions[Button.CYCLE_FORM] = () => this.buttonCycleOption(Button.CYCLE_FORM); - actions[Button.CYCLE_GENDER] = () => this.buttonCycleOption(Button.CYCLE_GENDER); - actions[Button.CYCLE_ABILITY] = () => this.buttonCycleOption(Button.CYCLE_ABILITY); - actions[Button.CYCLE_NATURE] = () => this.buttonCycleOption(Button.CYCLE_NATURE); - actions[Button.CYCLE_VARIANT] = () => this.buttonCycleOption(Button.CYCLE_VARIANT); - actions[Button.SPEED_UP] = () => this.buttonSpeedChange(); - actions[Button.SLOW_DOWN] = () => this.buttonSpeedChange(false); - return actions; - } - - getActionsKeyUp() { - const actions = {}; - actions[Button.STATS] = () => this.buttonStats(false); - return actions; - } - - buttonDirection(direction): Array { - const inputSuccess = this.scene.ui.processInput(direction); - const vibrationLength = 5; - return [inputSuccess, vibrationLength]; - } - - buttonAb(button): Array { - const inputSuccess = this.scene.ui.processInput(button); - return [inputSuccess, 0]; - } - - buttonTouch(): Array { - const inputSuccess = this.scene.ui.processInput(Button.SUBMIT) || this.scene.ui.processInput(Button.ACTION); - return [inputSuccess, 0]; - } - - buttonStats(pressed = true): Array { - if (pressed) { - for (let p of this.scene.getField().filter(p => p?.isActive(true))) - p.toggleStats(true); - } else { - for (let p of this.scene.getField().filter(p => p?.isActive(true))) - p.toggleStats(false); - } - return [true, 0]; - } - - buttonMenu(): Array { - let inputSuccess; - if (this.scene.disableMenu) - return [true, 0]; - switch (this.scene.ui?.getMode()) { - case Mode.MESSAGE: - if (!(this.scene.ui.getHandler() as MessageUiHandler).pendingPrompt) - return [true, 0]; - case Mode.TITLE: - case Mode.COMMAND: - case Mode.FIGHT: - case Mode.BALL: - case Mode.TARGET_SELECT: - case Mode.SAVE_SLOT: - case Mode.PARTY: - case Mode.SUMMARY: - case Mode.STARTER_SELECT: - case Mode.CONFIRM: - case Mode.OPTION_SELECT: - this.scene.ui.setOverlayMode(Mode.MENU); - inputSuccess = true; - break; - case Mode.MENU: - case Mode.SETTINGS: - case Mode.ACHIEVEMENTS: - this.scene.ui.revertMode(); - this.scene.playSound('select'); - inputSuccess = true; - break; - default: - return [true, 0]; - } - return [inputSuccess, 0]; - } - - buttonCycleOption(button): Array { - let inputSuccess; - if (this.scene.ui?.getHandler() instanceof StarterSelectUiHandler) { - inputSuccess = this.scene.ui.processInput(button); - } - return [inputSuccess, 0]; - } - - buttonSpeedChange(up = true): Array { - if (up) { - if (this.scene.gameSpeed < 5) { - this.scene.gameData.saveSetting(Setting.Game_Speed, settingOptions[Setting.Game_Speed].indexOf(`${this.scene.gameSpeed}x`) + 1); - if (this.scene.ui?.getMode() === Mode.SETTINGS) - (this.scene.ui.getHandler() as SettingsUiHandler).show([]); - } - return [0, 0]; - } - if (this.scene.gameSpeed > 1) { - this.scene.gameData.saveSetting(Setting.Game_Speed, Math.max(settingOptions[Setting.Game_Speed].indexOf(`${this.scene.gameSpeed}x`) - 1, 0)); - if (this.scene.ui?.getMode() === Mode.SETTINGS) - (this.scene.ui.getHandler() as SettingsUiHandler).show([]); - } - return [0, 0]; - } - -} \ No newline at end of file diff --git a/src/ui/abstact-option-select-ui-handler.ts b/src/ui/abstact-option-select-ui-handler.ts index ac2dca03ed3..2f2c4face89 100644 --- a/src/ui/abstact-option-select-ui-handler.ts +++ b/src/ui/abstact-option-select-ui-handler.ts @@ -1,11 +1,10 @@ -import BattleScene from "../battle-scene"; +import BattleScene, { Button } from "../battle-scene"; import { TextStyle, addTextObject } from "./text"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import { addWindow } from "./ui-theme"; import * as Utils from "../utils"; import { argbFromRgba } from "@material/material-color-utilities"; -import {Button} from "#app/inputs-controller"; export interface OptionSelectConfig { xOffset?: number; diff --git a/src/ui/achvs-ui-handler.ts b/src/ui/achvs-ui-handler.ts index 778a5d5f131..cadda64e032 100644 --- a/src/ui/achvs-ui-handler.ts +++ b/src/ui/achvs-ui-handler.ts @@ -1,10 +1,9 @@ -import BattleScene from "../battle-scene"; +import BattleScene, { Button } from "../battle-scene"; import { Achv, achvs } from "../system/achv"; import MessageUiHandler from "./message-ui-handler"; import { TextStyle, addTextObject } from "./text"; import { Mode } from "./ui"; import { addWindow } from "./ui-theme"; -import {Button} from "#app/inputs-controller"; export default class AchvsUiHandler extends MessageUiHandler { private achvsContainer: Phaser.GameObjects.Container; diff --git a/src/ui/awaitable-ui-handler.ts b/src/ui/awaitable-ui-handler.ts index 5d5f0b7a094..e8cc979e423 100644 --- a/src/ui/awaitable-ui-handler.ts +++ b/src/ui/awaitable-ui-handler.ts @@ -1,7 +1,6 @@ -import BattleScene from "../battle-scene"; +import BattleScene, { Button } from "../battle-scene"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; -import {Button} from "#app/inputs-controller"; export default abstract class AwaitableUiHandler extends UiHandler { protected awaitingActionInput: boolean; diff --git a/src/ui/ball-ui-handler.ts b/src/ui/ball-ui-handler.ts index a4ee6c99d46..f2ebdc342a4 100644 --- a/src/ui/ball-ui-handler.ts +++ b/src/ui/ball-ui-handler.ts @@ -1,12 +1,11 @@ import { CommandPhase } from "../phases"; -import BattleScene from "../battle-scene"; +import BattleScene, { Button } from "../battle-scene"; import { getPokeballName } from "../data/pokeball"; import { addTextObject, TextStyle } from "./text"; import { Command } from "./command-ui-handler"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import { addWindow } from "./ui-theme"; -import {Button} from "#app/inputs-controller"; export default class BallUiHandler extends UiHandler { private pokeballSelectContainer: Phaser.GameObjects.Container; diff --git a/src/ui/battle-message-ui-handler.ts b/src/ui/battle-message-ui-handler.ts index 7bba9657cd9..5e2cb56518f 100644 --- a/src/ui/battle-message-ui-handler.ts +++ b/src/ui/battle-message-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene from "../battle-scene"; +import BattleScene, { Button } from "../battle-scene"; import { addBBCodeTextObject, addTextObject, getTextColor, TextStyle } from "./text"; import { Mode } from "./ui"; import * as Utils from "../utils"; @@ -6,7 +6,6 @@ import MessageUiHandler from "./message-ui-handler"; import { getStatName, Stat } from "../data/pokemon-stat"; import { addWindow } from "./ui-theme"; import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext"; -import {Button} from "#app/inputs-controller"; export default class BattleMessageUiHandler extends MessageUiHandler { private levelUpStatsContainer: Phaser.GameObjects.Container; diff --git a/src/ui/command-ui-handler.ts b/src/ui/command-ui-handler.ts index 4c49246ebb6..b8223694b4c 100644 --- a/src/ui/command-ui-handler.ts +++ b/src/ui/command-ui-handler.ts @@ -1,11 +1,10 @@ import { CommandPhase } from "../phases"; -import BattleScene from "../battle-scene"; +import BattleScene, { Button } from "../battle-scene"; import { addTextObject, TextStyle } from "./text"; import PartyUiHandler, { PartyUiMode } from "./party-ui-handler"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import i18next from '../plugins/i18n'; -import {Button} from "#app/inputs-controller"; export enum Command { FIGHT = 0, diff --git a/src/ui/confirm-ui-handler.ts b/src/ui/confirm-ui-handler.ts index 600a84e614d..d9e7726d826 100644 --- a/src/ui/confirm-ui-handler.ts +++ b/src/ui/confirm-ui-handler.ts @@ -1,7 +1,6 @@ -import BattleScene from "../battle-scene"; +import BattleScene, { Button } from "../battle-scene"; import AbstractOptionSelectUiHandler, { OptionSelectConfig } from "./abstact-option-select-ui-handler"; import { Mode } from "./ui"; -import {Button} from "#app/inputs-controller"; export default class ConfirmUiHandler extends AbstractOptionSelectUiHandler { private switchCheck: boolean; diff --git a/src/ui/egg-gacha-ui-handler.ts b/src/ui/egg-gacha-ui-handler.ts index 0f8b999ba59..f0e32dbc2e9 100644 --- a/src/ui/egg-gacha-ui-handler.ts +++ b/src/ui/egg-gacha-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene from "../battle-scene"; +import BattleScene, { Button } from "../battle-scene"; import { Mode } from "./ui"; import { TextStyle, addTextObject, getEggTierTextTint } from "./text"; import MessageUiHandler from "./message-ui-handler"; @@ -9,7 +9,6 @@ import { getPokemonSpecies } from "../data/pokemon-species"; import { addWindow } from "./ui-theme"; import { Tutorial, handleTutorial } from "../tutorial"; import { EggTier } from "../data/enums/egg-type"; -import {Button} from "#app/inputs-controller"; const defaultText = 'Select a machine.'; diff --git a/src/ui/egg-hatch-scene-handler.ts b/src/ui/egg-hatch-scene-handler.ts index fefd5197be2..f841bafc268 100644 --- a/src/ui/egg-hatch-scene-handler.ts +++ b/src/ui/egg-hatch-scene-handler.ts @@ -1,8 +1,7 @@ -import BattleScene from "../battle-scene"; +import BattleScene, { Button } from "../battle-scene"; import { EggHatchPhase } from "../egg-hatch-phase"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; -import {Button} from "#app/inputs-controller"; export default class EggHatchSceneHandler extends UiHandler { public eggHatchContainer: Phaser.GameObjects.Container; diff --git a/src/ui/egg-list-ui-handler.ts b/src/ui/egg-list-ui-handler.ts index 8271ee00788..7537b8deeb0 100644 --- a/src/ui/egg-list-ui-handler.ts +++ b/src/ui/egg-list-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene from "../battle-scene"; +import BattleScene, { Button } from "../battle-scene"; import { Mode } from "./ui"; import PokemonIconAnimHandler, { PokemonIconAnimMode } from "./pokemon-icon-anim-handler"; import { TextStyle, addTextObject } from "./text"; @@ -6,7 +6,6 @@ import MessageUiHandler from "./message-ui-handler"; import { EGG_SEED, Egg, GachaType, getEggGachaTypeDescriptor, getEggHatchWavesMessage, getEggDescriptor } from "../data/egg"; import * as Utils from "../utils"; import { addWindow } from "./ui-theme"; -import {Button} from "#app/inputs-controller"; export default class EggListUiHandler extends MessageUiHandler { private eggListContainer: Phaser.GameObjects.Container; diff --git a/src/ui/evolution-scene-handler.ts b/src/ui/evolution-scene-handler.ts index 21b39b593cf..7e0ef063ea0 100644 --- a/src/ui/evolution-scene-handler.ts +++ b/src/ui/evolution-scene-handler.ts @@ -1,8 +1,7 @@ -import BattleScene from "../battle-scene"; +import BattleScene, { Button } from "../battle-scene"; import MessageUiHandler from "./message-ui-handler"; import { TextStyle, addTextObject } from "./text"; import { Mode } from "./ui"; -import {Button} from "#app/inputs-controller"; export default class EvolutionSceneHandler extends MessageUiHandler { public evolutionContainer: Phaser.GameObjects.Container; diff --git a/src/ui/fight-ui-handler.ts b/src/ui/fight-ui-handler.ts index b35292ebd45..1a7a8bef597 100644 --- a/src/ui/fight-ui-handler.ts +++ b/src/ui/fight-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene from "../battle-scene"; +import BattleScene, { Button } from "../battle-scene"; import { addTextObject, TextStyle } from "./text"; import { Type } from "../data/type"; import { Command } from "./command-ui-handler"; @@ -8,7 +8,6 @@ import * as Utils from "../utils"; import { CommandPhase } from "../phases"; import { MoveCategory } from "#app/data/move.js"; import i18next from '../plugins/i18n'; -import {Button} from "#app/inputs-controller"; export default class FightUiHandler extends UiHandler { private movesContainer: Phaser.GameObjects.Container; diff --git a/src/ui/form-modal-ui-handler.ts b/src/ui/form-modal-ui-handler.ts index 4830bd191f9..ec5f4147c58 100644 --- a/src/ui/form-modal-ui-handler.ts +++ b/src/ui/form-modal-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene from "../battle-scene"; +import BattleScene, { Button } from "../battle-scene"; import { ModalConfig, ModalUiHandler } from "./modal-ui-handler"; import { Mode } from "./ui"; import { TextStyle, addTextInputObject, addTextObject } from "./text"; @@ -6,7 +6,6 @@ import { WindowVariant, addWindow } from "./ui-theme"; import InputText from "phaser3-rex-plugins/plugins/inputtext"; import * as Utils from "../utils"; import i18next from '../plugins/i18n'; -import {Button} from "#app/inputs-controller"; export interface FormModalConfig extends ModalConfig { errorMessage?: string; diff --git a/src/ui/game-stats-ui-handler.ts b/src/ui/game-stats-ui-handler.ts index 5b271159f4a..00e358ff8e4 100644 --- a/src/ui/game-stats-ui-handler.ts +++ b/src/ui/game-stats-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene from "../battle-scene"; +import BattleScene, { Button } from "../battle-scene"; import { TextStyle, addTextObject, getTextColor } from "./text"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; @@ -6,7 +6,6 @@ import { addWindow } from "./ui-theme"; import * as Utils from "../utils"; import { DexAttr, GameData } from "../system/game-data"; import { speciesStarters } from "../data/pokemon-species"; -import {Button} from "#app/inputs-controller"; interface DisplayStat { label?: string; diff --git a/src/ui/menu-ui-handler.ts b/src/ui/menu-ui-handler.ts index 7ce5302aa0e..03d93699e75 100644 --- a/src/ui/menu-ui-handler.ts +++ b/src/ui/menu-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene, { bypassLogin } from "../battle-scene"; +import BattleScene, { Button, bypassLogin } from "../battle-scene"; import { TextStyle, addTextObject } from "./text"; import { Mode } from "./ui"; import * as Utils from "../utils"; @@ -9,7 +9,6 @@ import { OptionSelectConfig, OptionSelectItem } from "./abstact-option-select-ui import { Tutorial, handleTutorial } from "../tutorial"; import { updateUserInfo } from "../account"; import i18next from '../plugins/i18n'; -import {Button} from "#app/inputs-controller"; export enum MenuOptions { GAME_SETTINGS, diff --git a/src/ui/modal-ui-handler.ts b/src/ui/modal-ui-handler.ts index 507e3292fb9..f193a3db54f 100644 --- a/src/ui/modal-ui-handler.ts +++ b/src/ui/modal-ui-handler.ts @@ -1,9 +1,8 @@ -import BattleScene from "../battle-scene"; +import BattleScene, { Button } from "../battle-scene"; import { TextStyle, addTextObject } from "./text"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import { WindowVariant, addWindow } from "./ui-theme"; -import {Button} from "#app/inputs-controller"; export interface ModalConfig { buttonActions: Function[]; diff --git a/src/ui/modifier-select-ui-handler.ts b/src/ui/modifier-select-ui-handler.ts index 7597503d645..e5252e02a8f 100644 --- a/src/ui/modifier-select-ui-handler.ts +++ b/src/ui/modifier-select-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene from "../battle-scene"; +import BattleScene, { Button } from "../battle-scene"; import { getPlayerShopModifierTypeOptionsForWave, ModifierTypeOption } from "../modifier/modifier-type"; import { getPokeballAtlasKey, PokeballType } from "../data/pokeball"; import { addTextObject, getModifierTierTextTint, getTextColor, TextStyle } from "./text"; @@ -6,7 +6,6 @@ import AwaitableUiHandler from "./awaitable-ui-handler"; import { Mode } from "./ui"; import { LockModifierTiersModifier, PokemonHeldItemModifier } from "../modifier/modifier"; import { handleTutorial, Tutorial } from "../tutorial"; -import {Button} from "#app/inputs-controller"; export const SHOP_OPTIONS_ROW_LIMIT = 6; diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts index 29b0bb85011..35014fa7027 100644 --- a/src/ui/party-ui-handler.ts +++ b/src/ui/party-ui-handler.ts @@ -1,5 +1,5 @@ import { CommandPhase } from "../phases"; -import BattleScene from "../battle-scene"; +import BattleScene, { Button } from "../battle-scene"; import { PlayerPokemon, PokemonMove } from "../field/pokemon"; import { addTextObject, TextStyle } from "./text"; import { Command } from "./command-ui-handler"; @@ -16,7 +16,6 @@ import { pokemonEvolutions } from "../data/pokemon-evolutions"; import { addWindow } from "./ui-theme"; import { SpeciesFormChangeItemTrigger } from "../data/pokemon-forms"; import { getVariantTint } from "#app/data/variant"; -import {Button} from "#app/inputs-controller"; const defaultMessage = 'Choose a Pokémon.'; diff --git a/src/ui/save-slot-select-ui-handler.ts b/src/ui/save-slot-select-ui-handler.ts index 07a9283f7e8..181b0643cb9 100644 --- a/src/ui/save-slot-select-ui-handler.ts +++ b/src/ui/save-slot-select-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene from "../battle-scene"; +import BattleScene, { Button } from "../battle-scene"; import { gameModes } from "../game-mode"; import { SessionSaveData } from "../system/game-data"; import { TextStyle, addTextObject } from "./text"; @@ -8,7 +8,6 @@ import * as Utils from "../utils"; import PokemonData from "../system/pokemon-data"; import { PokemonHeldItemModifier } from "../modifier/modifier"; import MessageUiHandler from "./message-ui-handler"; -import {Button} from "#app/inputs-controller"; const sessionSlotCount = 5; diff --git a/src/ui/settings-ui-handler.ts b/src/ui/settings-ui-handler.ts index 6b1b7467d67..8f43b377d21 100644 --- a/src/ui/settings-ui-handler.ts +++ b/src/ui/settings-ui-handler.ts @@ -1,11 +1,10 @@ -import BattleScene from "../battle-scene"; +import BattleScene, { Button } from "../battle-scene"; import { Setting, reloadSettings, settingDefaults, settingOptions } from "../system/settings"; import { hasTouchscreen, isMobile } from "../touch-controls"; import { TextStyle, addTextObject } from "./text"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import { addWindow } from "./ui-theme"; -import {Button} from "#app/inputs-controller"; export default class SettingsUiHandler extends UiHandler { private settingsContainer: Phaser.GameObjects.Container; diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index ad3e51d24a2..f1e058b12cf 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene, { starterColors } from "../battle-scene"; +import BattleScene, { Button, starterColors } from "../battle-scene"; import PokemonSpecies, { allSpecies, getPokemonSpecies, getPokemonSpeciesForm, speciesStarters, starterPassiveAbilities } from "../data/pokemon-species"; import { Species } from "../data/enums/species"; import { TextStyle, addBBCodeTextObject, addTextObject } from "./text"; @@ -27,7 +27,6 @@ import { argbFromRgba } from "@material/material-color-utilities"; import { OptionSelectItem } from "./abstact-option-select-ui-handler"; import { pokemonPrevolutions } from "#app/data/pokemon-evolutions"; import { Variant, getVariantTint } from "#app/data/variant"; -import {Button} from "#app/inputs-controller"; export type StarterSelectCallback = (starters: Starter[]) => void; diff --git a/src/ui/summary-ui-handler.ts b/src/ui/summary-ui-handler.ts index 4b014b83778..cf5eb3639fd 100644 --- a/src/ui/summary-ui-handler.ts +++ b/src/ui/summary-ui-handler.ts @@ -1,4 +1,4 @@ -import BattleScene from "../battle-scene"; +import BattleScene, { Button } from "../battle-scene"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import * as Utils from "../utils"; @@ -17,7 +17,6 @@ import { Nature, getNatureStatMultiplier } from "../data/nature"; import { loggedInUser } from "../account"; import { PlayerGender } from "../system/game-data"; import { Variant, getVariantTint } from "#app/data/variant"; -import {Button} from "#app/inputs-controller"; enum Page { PROFILE, diff --git a/src/ui/target-select-ui-handler.ts b/src/ui/target-select-ui-handler.ts index b5242e713d7..f8a7c9d28a3 100644 --- a/src/ui/target-select-ui-handler.ts +++ b/src/ui/target-select-ui-handler.ts @@ -1,11 +1,10 @@ import { BattlerIndex } from "../battle"; -import BattleScene from "../battle-scene"; +import BattleScene, { Button } from "../battle-scene"; import { Moves } from "../data/enums/moves"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import * as Utils from "../utils"; import { getMoveTargets } from "../data/move"; -import {Button} from "#app/inputs-controller"; export type TargetSelectCallback = (cursor: integer) => void; diff --git a/src/ui/ui-handler.ts b/src/ui/ui-handler.ts index 20f34a33388..e3c94b76467 100644 --- a/src/ui/ui-handler.ts +++ b/src/ui/ui-handler.ts @@ -1,7 +1,6 @@ -import BattleScene from "../battle-scene"; +import BattleScene, { Button } from "../battle-scene"; import { TextStyle, getTextColor } from "./text"; import UI, { Mode } from "./ui"; -import {Button} from "#app/inputs-controller"; export default abstract class UiHandler { protected scene: BattleScene; diff --git a/src/ui/ui.ts b/src/ui/ui.ts index 0555c54193d..6e20b2cb8b8 100644 --- a/src/ui/ui.ts +++ b/src/ui/ui.ts @@ -1,4 +1,4 @@ -import { default as BattleScene } from '../battle-scene'; +import { Button, default as BattleScene } from '../battle-scene'; import UiHandler from './ui-handler'; import BattleMessageUiHandler from './battle-message-ui-handler'; import CommandUiHandler from './command-ui-handler'; @@ -35,7 +35,6 @@ import SavingIconHandler from './saving-icon-handler'; import UnavailableModalUiHandler from './unavailable-modal-ui-handler'; import OutdatedModalUiHandler from './outdated-modal-ui-handler'; import SessionReloadModalUiHandler from './session-reload-modal-ui-handler'; -import {Button} from "#app/inputs-controller"; export enum Mode { MESSAGE, diff --git a/src/ui/vouchers-ui-handler.ts b/src/ui/vouchers-ui-handler.ts index 36926c6fa71..3f41cf9ae74 100644 --- a/src/ui/vouchers-ui-handler.ts +++ b/src/ui/vouchers-ui-handler.ts @@ -1,10 +1,9 @@ -import BattleScene from "../battle-scene"; +import BattleScene, { Button } from "../battle-scene"; import { Voucher, getVoucherTypeIcon, getVoucherTypeName, vouchers } from "../system/voucher"; import MessageUiHandler from "./message-ui-handler"; import { TextStyle, addTextObject } from "./text"; import { Mode } from "./ui"; import { addWindow } from "./ui-theme"; -import {Button} from "#app/inputs-controller"; const itemRows = 4; const itemCols = 17; From 71705dd6d40c67f6df64b80e68f0e144b4438888 Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Fri, 3 May 2024 15:03:11 -0400 Subject: [PATCH 54/72] Add candy popup sound --- public/audio/se/shing.wav | Bin 0 -> 124500 bytes src/loading-scene.ts | 1 + src/ui/candy-bar.ts | 2 ++ src/ui/save-slot-select-ui-handler.ts | 2 +- 4 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 public/audio/se/shing.wav diff --git a/public/audio/se/shing.wav b/public/audio/se/shing.wav new file mode 100644 index 0000000000000000000000000000000000000000..e693cb207fca07ca996378bc42c1492516988a25 GIT binary patch literal 124500 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 literal 0 HcmV?d00001 diff --git a/src/loading-scene.ts b/src/loading-scene.ts index d0751e9a2da..05b6c9f50b1 100644 --- a/src/loading-scene.ts +++ b/src/loading-scene.ts @@ -223,6 +223,7 @@ export class LoadingScene extends SceneBase { this.loadSe('sparkle'); this.loadSe('restore'); this.loadSe('shine'); + this.loadSe('shing'); this.loadSe('charge'); this.loadSe('beam'); this.loadSe('upgrade'); diff --git a/src/ui/candy-bar.ts b/src/ui/candy-bar.ts index 2219e07479d..a4cc1295028 100644 --- a/src/ui/candy-bar.ts +++ b/src/ui/candy-bar.ts @@ -69,6 +69,8 @@ export default class CandyBar extends Phaser.GameObjects.Container { if (this.tween) this.tween.stop(); + (this.scene as BattleScene).playSound('shing'); + this.tween = this.scene.tweens.add({ targets: this, x: (this.scene.game.canvas.width / 6) - (this.bg.width - 5), diff --git a/src/ui/save-slot-select-ui-handler.ts b/src/ui/save-slot-select-ui-handler.ts index 181b0643cb9..11680cd3952 100644 --- a/src/ui/save-slot-select-ui-handler.ts +++ b/src/ui/save-slot-select-ui-handler.ts @@ -258,7 +258,7 @@ class SessionSlot extends Phaser.GameObjects.Container { async setupWithData(data: SessionSaveData) { this.remove(this.loadingLabel, true); - const gameModeLabel = addTextObject(this.scene, 8, 5, `${gameModes[data.gameMode].getName()} - Wave ${data.waveIndex}`, TextStyle.WINDOW); + const gameModeLabel = addTextObject(this.scene, 8, 5, `${gameModes[data.gameMode]?.getName() || 'Unknown'} - Wave ${data.waveIndex}`, TextStyle.WINDOW); this.add(gameModeLabel); const timestampLabel = addTextObject(this.scene, 8, 19, new Date(data.timestamp).toLocaleString(), TextStyle.WINDOW); From 9a559c8d6ac8e24009a0df5e0a7c1d6fb9a7e28a Mon Sep 17 00:00:00 2001 From: Madmadness65 Date: Fri, 3 May 2024 14:04:43 -0500 Subject: [PATCH 55/72] Update passive abilities for legendaries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the first batch of passive ability revisions, this one directed at legendary and mythical Pokémon. --- src/data/pokemon-species.ts | 112 ++++++++++++++++++------------------ 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index c67f0c14b47..57bb9230c5e 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -3300,7 +3300,7 @@ export const starterPassiveAbilities = { [Species.ENTEI]: Abilities.MOXIE, [Species.SUICUNE]: Abilities.UNAWARE, [Species.LARVITAR]: Abilities.SAND_FORCE, - [Species.LUGIA]: Abilities.STORM_DRAIN, + [Species.LUGIA]: Abilities.DELTA_STREAM, [Species.HO_OH]: Abilities.MAGIC_GUARD, [Species.CELEBI]: Abilities.GRASSY_SURGE, [Species.TREECKO]: Abilities.GRASSY_SURGE, @@ -3366,13 +3366,13 @@ export const starterPassiveAbilities = { [Species.LUVDISC]: Abilities.PICKUP, [Species.BAGON]: Abilities.GALE_WINGS, [Species.BELDUM]: Abilities.IRON_FIST, - [Species.REGIROCK]: Abilities.REGENERATOR, - [Species.REGICE]: Abilities.ICE_SCALES, - [Species.REGISTEEL]: Abilities.STEELY_SPIRIT, - [Species.LATIAS]: Abilities.SERENE_GRACE, - [Species.LATIOS]: Abilities.SERENE_GRACE, + [Species.REGIROCK]: Abilities.SAND_STREAM, + [Species.REGICE]: Abilities.SNOW_WARNING, + [Species.REGISTEEL]: Abilities.FILTER, + [Species.LATIAS]: Abilities.SOUL_HEART, + [Species.LATIOS]: Abilities.TINTED_LENS, [Species.KYOGRE]: Abilities.HYDRATION, - [Species.GROUDON]: Abilities.EARTH_EATER, + [Species.GROUDON]: Abilities.FLAME_BODY, [Species.RAYQUAZA]: Abilities.UNNERVE, [Species.JIRACHI]: Abilities.COMATOSE, [Species.DEOXYS]: Abilities.PROTEAN, @@ -3414,16 +3414,16 @@ export const starterPassiveAbilities = { [Species.MANTYKE]: Abilities.STORM_DRAIN, [Species.SNOVER]: Abilities.SNOW_CLOAK, [Species.ROTOM]: Abilities.HADRON_ENGINE, - [Species.UXIE]: Abilities.ILLUSION, + [Species.UXIE]: Abilities.UNAWARE, [Species.MESPRIT]: Abilities.MOODY, [Species.AZELF]: Abilities.NEUROFORCE, [Species.DIALGA]: Abilities.SPEED_BOOST, - [Species.PALKIA]: Abilities.MAGIC_BOUNCE, - [Species.HEATRAN]: Abilities.ROUGH_SKIN, + [Species.PALKIA]: Abilities.MULTISCALE, + [Species.HEATRAN]: Abilities.FILTER, [Species.REGIGIGAS]: Abilities.MINDS_EYE, - [Species.GIRATINA]: Abilities.SHADOW_TAG, + [Species.GIRATINA]: Abilities.SHADOW_SHIELD, [Species.CRESSELIA]: Abilities.MAGIC_BOUNCE, - [Species.PHIONE]: Abilities.SWIFT_SWIM, + [Species.PHIONE]: Abilities.SIMPLE, [Species.MANAPHY]: Abilities.SIMPLE, [Species.DARKRAI]: Abilities.UNNERVE, [Species.SHAYMIN]: Abilities.FLOWER_VEIL, @@ -3500,16 +3500,16 @@ export const starterPassiveAbilities = { [Species.LARVESTA]: Abilities.DROUGHT, [Species.COBALION]: Abilities.INTREPID_SWORD, [Species.TERRAKION]: Abilities.ROCKY_PAYLOAD, - [Species.VIRIZION]: Abilities.SYMBIOSIS, - [Species.TORNADUS]: Abilities.DELTA_STREAM, + [Species.VIRIZION]: Abilities.SHARPNESS, + [Species.TORNADUS]: Abilities.DRIZZLE, [Species.THUNDURUS]: Abilities.DRIZZLE, [Species.RESHIRAM]: Abilities.ORICHALCUM_PULSE, [Species.ZEKROM]: Abilities.HADRON_ENGINE, - [Species.LANDORUS]: Abilities.PRANKSTER, + [Species.LANDORUS]: Abilities.STORM_DRAIN, [Species.KYUREM]: Abilities.SNOW_WARNING, - [Species.KELDEO]: Abilities.SHARPNESS, - [Species.MELOETTA]: Abilities.PUNK_ROCK, - [Species.GENESECT]: Abilities.MEGA_LAUNCHER, + [Species.KELDEO]: Abilities.GRIM_NEIGH, + [Species.MELOETTA]: Abilities.MINDS_EYE, + [Species.GENESECT]: Abilities.REGENERATOR, [Species.CHESPIN]: Abilities.IRON_BARBS, [Species.FENNEKIN]: Abilities.MAGIC_BOUNCE, [Species.FROAKIE]: Abilities.ADAPTABILITY, @@ -3541,11 +3541,11 @@ export const starterPassiveAbilities = { [Species.PUMPKABOO]: Abilities.FLASH_FIRE, [Species.BERGMITE]: Abilities.MIRROR_ARMOR, [Species.NOIBAT]: Abilities.PUNK_ROCK, - [Species.XERNEAS]: Abilities.COMPETITIVE, - [Species.YVELTAL]: Abilities.DEFIANT, - [Species.ZYGARDE]: Abilities.REGENERATOR, - [Species.DIANCIE]: Abilities.QUEENLY_MAJESTY, - [Species.HOOPA]: Abilities.TRACE, + [Species.XERNEAS]: Abilities.MISTY_SURGE, + [Species.YVELTAL]: Abilities.SOUL_HEART, + [Species.ZYGARDE]: Abilities.HUGE_POWER, + [Species.DIANCIE]: Abilities.LEVITATE, + [Species.HOOPA]: Abilities.OPPORTUNIST, [Species.VOLCANION]: Abilities.FILTER, [Species.ROWLET]: Abilities.SNIPER, [Species.LITTEN]: Abilities.PRANKSTER, @@ -3582,26 +3582,26 @@ export const starterPassiveAbilities = { [Species.DRAMPA]: Abilities.FLASH_FIRE, [Species.DHELMISE]: Abilities.INFILTRATOR, [Species.JANGMO_O]: Abilities.DANCER, - [Species.TAPU_KOKO]: Abilities.GALVANIZE, - [Species.TAPU_LELE]: Abilities.BERSERK, - [Species.TAPU_BULU]: Abilities.FLOWER_VEIL, + [Species.TAPU_KOKO]: Abilities.TRANSISTOR, + [Species.TAPU_LELE]: Abilities.SHEER_FORCE, + [Species.TAPU_BULU]: Abilities.GRASS_PELT, [Species.TAPU_FINI]: Abilities.FAIRY_AURA, [Species.COSMOG]: Abilities.BEAST_BOOST, - [Species.NIHILEGO]: Abilities.POISON_PUPPETEER, + [Species.NIHILEGO]: Abilities.LEVITATE, [Species.BUZZWOLE]: Abilities.MOXIE, - [Species.PHEROMOSA]: Abilities.MOXIE, - [Species.XURKITREE]: Abilities.LIGHTNING_ROD, - [Species.CELESTEELA]: Abilities.CHLOROPHYLL, + [Species.PHEROMOSA]: Abilities.TINTED_LENS, + [Species.XURKITREE]: Abilities.TRANSISTOR, + [Species.CELESTEELA]: Abilities.HEATPROOF, [Species.KARTANA]: Abilities.SHARPNESS, - [Species.GUZZLORD]: Abilities.GLUTTONY, + [Species.GUZZLORD]: Abilities.INNARDS_OUT, [Species.NECROZMA]: Abilities.BEAST_BOOST, [Species.MAGEARNA]: Abilities.STEELY_SPIRIT, [Species.MARSHADOW]: Abilities.IRON_FIST, - [Species.POIPOLE]: Abilities.MERCILESS, - [Species.STAKATAKA]: Abilities.DAUNTLESS_SHIELD, + [Species.POIPOLE]: Abilities.SHEER_FORCE, + [Species.STAKATAKA]: Abilities.SOLID_ROCK, [Species.BLACEPHALON]: Abilities.MAGIC_GUARD, - [Species.ZERAORA]: Abilities.MOTOR_DRIVE, - [Species.MELTAN]: Abilities.FULL_METAL_BODY, + [Species.ZERAORA]: Abilities.TOUGH_CLAWS, + [Species.MELTAN]: Abilities.STEELY_SPIRIT, [Species.GROOKEY]: Abilities.GRASS_PELT, [Species.SCORBUNNY]: Abilities.RECKLESS, [Species.SOBBLE]: Abilities.SUPER_LUCK, @@ -3639,17 +3639,17 @@ export const starterPassiveAbilities = { [Species.ARCTOVISH]: Abilities.STRONG_JAW, [Species.DURALUDON]: Abilities.MEGA_LAUNCHER, [Species.DREEPY]: Abilities.PARENTAL_BOND, - [Species.ZACIAN]: Abilities.GUARD_DOG, - [Species.ZAMAZENTA]: Abilities.GUARD_DOG, + [Species.ZACIAN]: Abilities.UNNERVE, + [Species.ZAMAZENTA]: Abilities.STAMINA, [Species.ETERNATUS]: Abilities.SUPREME_OVERLORD, [Species.KUBFU]: Abilities.IRON_FIST, - [Species.ZARUDE]: Abilities.PRANKSTER, - [Species.REGIELEKI]: Abilities.LEVITATE, - [Species.REGIDRAGO]: Abilities.INTIMIDATE, + [Species.ZARUDE]: Abilities.GRASSY_SURGE, + [Species.REGIELEKI]: Abilities.ELECTRIC_SURGE, + [Species.REGIDRAGO]: Abilities.MULTISCALE, [Species.GLASTRIER]: Abilities.FILTER, - [Species.SPECTRIER]: Abilities.PERISH_BODY, + [Species.SPECTRIER]: Abilities.SHADOW_SHIELD, [Species.CALYREX]: Abilities.HARVEST, - [Species.ENAMORUS]: Abilities.PRANKSTER, + [Species.ENAMORUS]: Abilities.FAIRY_AURA, [Species.SPRIGATITO]: Abilities.MAGICIAN, [Species.FUECOCO]: Abilities.EARTH_EATER, [Species.QUAXLY]: Abilities.DANCER, @@ -3688,40 +3688,40 @@ export const starterPassiveAbilities = { [Species.DONDOZO]: Abilities.GLUTTONY, [Species.TATSUGIRI]: Abilities.WATER_BUBBLE, [Species.GREAT_TUSK]: Abilities.INTIMIDATE, - [Species.SCREAM_TAIL]: Abilities.PIXILATE, + [Species.SCREAM_TAIL]: Abilities.UNAWARE, [Species.BRUTE_BONNET]: Abilities.BEAST_BOOST, [Species.FLUTTER_MANE]: Abilities.DAZZLING, - [Species.SLITHER_WING]: Abilities.MOXIE, + [Species.SLITHER_WING]: Abilities.SCRAPPY, [Species.SANDY_SHOCKS]: Abilities.EARTH_EATER, - [Species.IRON_TREADS]: Abilities.BULLETPROOF, + [Species.IRON_TREADS]: Abilities.STEELY_SPIRIT, [Species.IRON_BUNDLE]: Abilities.SNOW_WARNING, [Species.IRON_HANDS]: Abilities.IRON_FIST, - [Species.IRON_JUGULIS]: Abilities.NO_GUARD, + [Species.IRON_JUGULIS]: Abilities.AERILATE, [Species.IRON_MOTH]: Abilities.LEVITATE, [Species.IRON_THORNS]: Abilities.SAND_STREAM, [Species.FRIGIBAX]: Abilities.THICK_FAT, [Species.GIMMIGHOUL]: Abilities.SUPER_LUCK, - [Species.WO_CHIEN]: Abilities.TRIAGE, - [Species.CHIEN_PAO]: Abilities.REFRIGERATE, + [Species.WO_CHIEN]: Abilities.GRASSY_SURGE, + [Species.CHIEN_PAO]: Abilities.INTREPID_SWORD, [Species.TING_LU]: Abilities.STAMINA, - [Species.CHI_YU]: Abilities.BLAZE, - [Species.ROARING_MOON]: Abilities.AERILATE, + [Species.CHI_YU]: Abilities.DROUGHT, + [Species.ROARING_MOON]: Abilities.TOUGH_CLAWS, [Species.IRON_VALIANT]: Abilities.DOWNLOAD, [Species.KORAIDON]: Abilities.PROTOSYNTHESIS, [Species.MIRAIDON]: Abilities.QUARK_DRIVE, [Species.WALKING_WAKE]: Abilities.BEAST_BOOST, [Species.IRON_LEAVES]: Abilities.SHARPNESS, [Species.POLTCHAGEIST]: Abilities.FLAME_BODY, - [Species.OKIDOGI]: Abilities.INTIMIDATE, - [Species.MUNKIDORI]: Abilities.PRANKSTER, - [Species.FEZANDIPITI]: Abilities.DAZZLING, + [Species.OKIDOGI]: Abilities.FUR_COAT, + [Species.MUNKIDORI]: Abilities.NEUROFORCE, + [Species.FEZANDIPITI]: Abilities.LEVITATE, [Species.OGERPON]: Abilities.OPPORTUNIST, [Species.GOUGING_FIRE]: Abilities.BEAST_BOOST, [Species.RAGING_BOLT]: Abilities.BEAST_BOOST, [Species.IRON_BOULDER]: Abilities.SHARPNESS, [Species.IRON_CROWN]: Abilities.SHARPNESS, - [Species.TERAPAGOS]: Abilities.PROTEAN, - [Species.PECHARUNT]: Abilities.CORROSION, + [Species.TERAPAGOS]: Abilities.REGENERATOR, + [Species.PECHARUNT]: Abilities.TOXIC_CHAIN, [Species.ALOLA_RATTATA]: Abilities.CHEEK_POUCH, [Species.ALOLA_SANDSHREW]: Abilities.ICE_BODY, [Species.ALOLA_VULPIX]: Abilities.ICE_BODY, @@ -3736,7 +3736,7 @@ export const starterPassiveAbilities = { [Species.GALAR_FARFETCHD]: Abilities.SUPER_LUCK, [Species.GALAR_ARTICUNO]: Abilities.SERENE_GRACE, [Species.GALAR_ZAPDOS]: Abilities.TOUGH_CLAWS, - [Species.GALAR_MOLTRES]: Abilities.REGENERATOR, + [Species.GALAR_MOLTRES]: Abilities.DARK_AURA, [Species.GALAR_CORSOLA]: Abilities.SHADOW_TAG, [Species.GALAR_ZIGZAGOON]: Abilities.PICKPOCKET, [Species.GALAR_DARUMAKA]: Abilities.FLASH_FIRE, From cbf06ffa2ca647dc9ee8a89028cc044431c8b89d Mon Sep 17 00:00:00 2001 From: Madi Simpson Date: Fri, 3 May 2024 12:06:43 -0700 Subject: [PATCH 56/72] bugfix: ensure direct stat modifying moves update both pokemon's stat info --- src/data/move.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/data/move.ts b/src/data/move.ts index 21f376254f7..264f5576ea5 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -1573,7 +1573,7 @@ export class CopyStatsAttr extends MoveEffectAttr { user.addTag(BattlerTagType.CRIT_BOOST, 0, move.id); else user.removeTag(BattlerTagType.CRIT_BOOST); - + target.updateInfo(); user.updateInfo(); target.scene.queueMessage(getPokemonMessage(user, 'copied\n') + getPokemonMessage(target, `'s stat changes!`)); @@ -1589,7 +1589,7 @@ export class InvertStatsAttr extends MoveEffectAttr { for (let s = 0; s < target.summonData.battleStats.length; s++) target.summonData.battleStats[s] *= -1; - + target.updateInfo(); user.updateInfo(); target.scene.queueMessage(getPokemonMessage(target, `'s stat changes\nwere all reversed!`)); @@ -1605,7 +1605,7 @@ export class ResetStatsAttr extends MoveEffectAttr { for (let s = 0; s < target.summonData.battleStats.length; s++) target.summonData.battleStats[s] = 0; - + target.updateInfo(); user.updateInfo(); target.scene.queueMessage(getPokemonMessage(target, `'s stat changes\nwere eliminated!`)); From 1484a52fd70adbce0e8ac5f7ce07fadae998465c Mon Sep 17 00:00:00 2001 From: Matt Ross <13306707+mattrossdev@users.noreply.github.com> Date: Fri, 3 May 2024 12:54:21 -0700 Subject: [PATCH 57/72] Add variable power attribute for knock off (#426) * feature/add-variable-power-knock-off * Remove console logs --- src/data/move.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/data/move.ts b/src/data/move.ts index 264f5576ea5..5f86911aebb 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -2021,6 +2021,17 @@ export class PresentPowerAttr extends VariablePowerAttr { } } +export class KnockOffPowerAttr extends VariablePowerAttr { + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + if(target.getHeldItems().length > 0){ + (args[0] as Utils.NumberHolder).value *= 1.5; + return true; + } + + return false; + } +} + export class VariableAtkAttr extends MoveAttr { constructor() { super(); @@ -4583,6 +4594,7 @@ export function initMoves() { .attr(AddBattlerTagAttr, BattlerTagType.DROWSY, false, true) .condition((user, target, move) => !target.status), new AttackMove(Moves.KNOCK_OFF, Type.DARK, MoveCategory.PHYSICAL, 65, 100, 20, -1, 0, 3) + .attr(KnockOffPowerAttr) .partial(), new AttackMove(Moves.ENDEAVOR, Type.NORMAL, MoveCategory.PHYSICAL, -1, 100, 5, -1, 0, 3) .attr(MatchHpAttr) From 3b61662bba9927115b385abb2893804f5cc5e564 Mon Sep 17 00:00:00 2001 From: Benjamin Odom Date: Fri, 3 May 2024 15:17:37 -0500 Subject: [PATCH 58/72] Fixed Mighty Cleave not being a Slicing Move --- src/data/move.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/data/move.ts b/src/data/move.ts index 5f86911aebb..5c29b6a5758 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -6428,6 +6428,7 @@ export function initMoves() { new AttackMove(Moves.THUNDERCLAP, Type.ELECTRIC, MoveCategory.SPECIAL, 70, 100, 5, -1, 1, 9) .condition((user, target, move) => user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.FIGHT && !target.turnData.acted && allMoves[user.scene.currentBattle.turnCommands[target.getBattlerIndex()].move.move].category !== MoveCategory.STATUS), new AttackMove(Moves.MIGHTY_CLEAVE, Type.ROCK, MoveCategory.PHYSICAL, 95, 100, 5, -1, 0, 9) + .slicingMove() .ignoresProtect(), new AttackMove(Moves.TACHYON_CUTTER, Type.STEEL, MoveCategory.SPECIAL, 50, -1, 10, -1, 0, 9) .attr(MultiHitAttr, MultiHitType._2) From 313fdc0e4222202e28878496cd3e2101e35759e9 Mon Sep 17 00:00:00 2001 From: Benjamin Odom Date: Fri, 3 May 2024 15:38:32 -0500 Subject: [PATCH 59/72] Fix Venom Drench not working on Toxic Status --- src/data/move.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/move.ts b/src/data/move.ts index 5c29b6a5758..dd149940fee 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -5444,7 +5444,7 @@ export function initMoves() { new StatusMove(Moves.EERIE_IMPULSE, Type.ELECTRIC, 100, 15, -1, 0, 6) .attr(StatChangeAttr, BattleStat.SPATK, -2), new StatusMove(Moves.VENOM_DRENCH, Type.POISON, 100, 20, 100, 0, 6) - .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK, BattleStat.SPD ], -1, false, (user, target, move) => target.status?.effect === StatusEffect.POISON) + .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK, BattleStat.SPD ], -1, false, (user, target, move) => target.status?.effect === StatusEffect.POISON || target.status?.effect === StatusEffect.TOXIC) .target(MoveTarget.ALL_NEAR_ENEMIES), new StatusMove(Moves.POWDER, Type.BUG, 100, 20, -1, 1, 6) .powderMove() From d48f0aa97d7438ceb41f6b69d0af7076d21294f8 Mon Sep 17 00:00:00 2001 From: Madi Simpson Date: Fri, 3 May 2024 13:55:46 -0700 Subject: [PATCH 60/72] Implement Anger Shell and Berserk (#421) * abilities: implement anger shell and berserk * abilities: fix small typo causing berserk to raise speed instead of spatk * abilities: condense battlestats into an array instead of multiple attrs --- src/data/ability.ts | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index a0f85e2fd5e..7ac3e721837 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -580,6 +580,35 @@ export class PostDefendStatChangeAbAttr extends PostDefendAbAttr { } } +export class PostDefendHpGatedStatChangeAbAttr extends PostDefendAbAttr { + private condition: PokemonDefendCondition; + private hpGate: number; + private stats: BattleStat[]; + private levels: integer; + private selfTarget: boolean; + + constructor(condition: PokemonDefendCondition, hpGate: number, stats: BattleStat[], levels: integer, selfTarget: boolean = true) { + super(true); + + this.condition = condition; + this.hpGate = hpGate; + this.stats = stats; + this.levels = levels; + this.selfTarget = selfTarget; + } + + applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { + const hpGateFlat: integer = Math.ceil(pokemon.getMaxHp() * this.hpGate) + const lastAttackReceived = pokemon.turnData.attacksReceived[pokemon.turnData.attacksReceived.length - 1] + if (this.condition(pokemon, attacker, move.getMove()) && (pokemon.hp <= hpGateFlat && (pokemon.hp + lastAttackReceived.damage) > hpGateFlat)) { + pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, (this.selfTarget ? pokemon : attacker).getBattlerIndex(), true, this.stats, this.levels)); + return true; + } + + return false; + } +} + export class PostDefendApplyArenaTrapTagAbAttr extends PostDefendAbAttr { private condition: PokemonDefendCondition; private tagType: ArenaTagType; @@ -3091,7 +3120,7 @@ export function initAbilities() { new Ability(Abilities.STEELWORKER, 7) .attr(MoveTypePowerBoostAbAttr, Type.STEEL), new Ability(Abilities.BERSERK, 7) - .unimplemented(), + .attr(PostDefendHpGatedStatChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, 0.5, [BattleStat.SPATK], 1), new Ability(Abilities.SLUSH_RUSH, 7) .attr(BattleStatMultiplierAbAttr, BattleStat.SPD, 2) .condition(getWeatherCondition(WeatherType.HAIL, WeatherType.SNOW)), @@ -3327,7 +3356,8 @@ export function initAbilities() { .attr(StatusEffectImmunityAbAttr, StatusEffect.BURN) .ignorable(), new Ability(Abilities.ANGER_SHELL, 9) - .unimplemented(), + .attr(PostDefendHpGatedStatChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, 0.5, [ BattleStat.ATK, BattleStat.SPATK, BattleStat.SPD ], 1) + .attr(PostDefendHpGatedStatChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, 0.5, [ BattleStat.DEF, BattleStat.SPDEF ], -1), new Ability(Abilities.PURIFYING_SALT, 9) .attr(StatusEffectImmunityAbAttr) .attr(ReceivedTypeDamageMultiplierAbAttr, Type.GHOST, 0.5) From 06ae04abaded1c0f994b4c0e0d419b118807aba3 Mon Sep 17 00:00:00 2001 From: Madi Simpson Date: Fri, 3 May 2024 14:06:50 -0700 Subject: [PATCH 61/72] bugfix: ensure hit recoil moves always do at least 1hp in recoil --- src/data/move.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/move.ts b/src/data/move.ts index dd149940fee..958588f7af4 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -685,7 +685,7 @@ export class RecoilAttr extends MoveEffectAttr { return false; const recoilDamage = Math.max(Math.floor((!this.useHp ? user.turnData.damageDealt : user.getMaxHp()) * this.damageRatio), - !this.useHp && user.turnData.damageDealt ? 1 : 0); + user.turnData.damageDealt ? 1 : 0); if (!recoilDamage) return false; From 6f446324db639905133de5ed106811534bf3c85c Mon Sep 17 00:00:00 2001 From: gericocross <32669590+gericocross@users.noreply.github.com> Date: Fri, 3 May 2024 23:38:34 +0200 Subject: [PATCH 62/72] Longer descriptions don't stuck shorter ones anymore --- src/ui/summary-ui-handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/summary-ui-handler.ts b/src/ui/summary-ui-handler.ts index cf5eb3639fd..7776e21782f 100644 --- a/src/ui/summary-ui-handler.ts +++ b/src/ui/summary-ui-handler.ts @@ -441,6 +441,7 @@ export default class SummaryUiHandler extends UiHandler { const selectedMove = this.getSelectedMove(); if (selectedMove) { + this.moveDescriptionText.setY(84); this.movePowerText.setText(selectedMove.power >= 0 ? selectedMove.power.toString() : '---'); this.moveAccuracyText.setText(selectedMove.accuracy >= 0 ? selectedMove.accuracy.toString() : '---'); this.moveCategoryIcon.setFrame(MoveCategory[selectedMove.category].toLowerCase()); @@ -457,7 +458,6 @@ export default class SummaryUiHandler extends UiHandler { } if (moveDescriptionLineCount > 3) { - this.moveDescriptionText.setY(84); this.descriptionScrollTween = this.scene.tweens.add({ targets: this.moveDescriptionText, delay: Utils.fixedInt(2000), From 19e434929c19f00342fa2529a3e8575adc584c72 Mon Sep 17 00:00:00 2001 From: ArceUseless <36188730+ArceUseless@users.noreply.github.com> Date: Fri, 3 May 2024 23:52:09 +0200 Subject: [PATCH 63/72] Spanish translations (#422) * Spanish translations for intro messages and some menus. Added Empty (save file) to lang files * Spanish translations + new literals in all langs --------- Co-authored-by: rnicar --- src/locales/de/menu.ts | 6 ++- src/locales/en/menu.ts | 6 ++- src/locales/es/command-ui-handler.ts | 2 +- src/locales/es/menu.ts | 14 ++++-- src/locales/es/tutorial.ts | 69 +++++++++++++++------------ src/locales/fr/menu.ts | 6 ++- src/locales/it/menu.ts | 6 ++- src/ui/confirm-ui-handler.ts | 5 +- src/ui/save-slot-select-ui-handler.ts | 3 +- src/ui/starter-select-ui-handler.ts | 3 +- 10 files changed, 75 insertions(+), 45 deletions(-) diff --git a/src/locales/de/menu.ts b/src/locales/de/menu.ts index c648b15bfe8..3f86ae41a7e 100644 --- a/src/locales/de/menu.ts +++ b/src/locales/de/menu.ts @@ -39,5 +39,9 @@ export const menu: SimpleTranslationEntries = { "weeklyRankings": "Weekly Rankings", "noRankings": "No Rankings", "loading": "Loading…", - "playersOnline": "Players Online" + "playersOnline": "Players Online", + "empty":"Empty", + "yes":"Yes", + "no":"No", + "confirmStartTeam":'Begin with these Pokémon?', } as const; \ No newline at end of file diff --git a/src/locales/en/menu.ts b/src/locales/en/menu.ts index 42888b17337..887f3d87834 100644 --- a/src/locales/en/menu.ts +++ b/src/locales/en/menu.ts @@ -39,5 +39,9 @@ export const menu: SimpleTranslationEntries = { "weeklyRankings": "Weekly Rankings", "noRankings": "No Rankings", "loading": "Loading…", - "playersOnline": "Players Online" + "playersOnline": "Players Online", + "empty":"Empty", + "yes":"Yes", + "no":"No", + "confirmStartTeam":'Begin with these Pokémon?', } as const; \ No newline at end of file diff --git a/src/locales/es/command-ui-handler.ts b/src/locales/es/command-ui-handler.ts index 237e779db03..66a892f8fd3 100644 --- a/src/locales/es/command-ui-handler.ts +++ b/src/locales/es/command-ui-handler.ts @@ -2,7 +2,7 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const commandUiHandler: SimpleTranslationEntries = { "fight": "Luchar", - "ball": "Ball", + "ball": "Balls", "pokemon": "Pokémon", "run": "Huir", "actionMessage": "¿Qué debería\nhacer {{pokemonName}}?", diff --git a/src/locales/es/menu.ts b/src/locales/es/menu.ts index c67287ae0cc..5569c1e1668 100644 --- a/src/locales/es/menu.ts +++ b/src/locales/es/menu.ts @@ -19,9 +19,13 @@ export const menu: SimpleTranslationEntries = { "boyOrGirl": "¿Eres un chico o una chica?", "boy": "Chico", "girl": "Chica", - "dailyRankings": "Daily Rankings", - "weeklyRankings": "Weekly Rankings", - "noRankings": "No Rankings", - "loading": "Loading…", - "playersOnline": "Players Online" + "dailyRankings": "Rankings Diarios", + "weeklyRankings": "Rankings Semanales", + "noRankings": "Sin Rankings", + "loading": "Cargando…", + "playersOnline": "Jugadores en Línea", + "empty":"Vacío", + "yes":"Sí", + "no":"No", + "confirmStartTeam":'¿Comenzar con estos Pokémon?', } as const; \ No newline at end of file diff --git a/src/locales/es/tutorial.ts b/src/locales/es/tutorial.ts index 2773b6710ba..e179ca55cee 100644 --- a/src/locales/es/tutorial.ts +++ b/src/locales/es/tutorial.ts @@ -1,42 +1,49 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const tutorial: SimpleTranslationEntries = { - "intro": `Welcome to PokéRogue! This is a battle-focused Pokémon fangame with roguelite elements. - $This game is not monetized and we claim no ownership of Pokémon nor of the copyrighted assets used. - $The game is a work in progress, but fully playable.\nFor bug reports, please use the Discord community. - $If the game runs slowly, please ensure 'Hardware Acceleration' is turned on in your browser settings.`, + "intro": `¡Bienvenido/a a PokéRogue! Este es un fangame de Pokémon centrado en el combate con elementos roguelite. + $Este juego no está monetizado y no reclamamos ningún derecho de propiedad sobre Pokémon ni sobre ninguno de + $los recursos con copyright utilizados. + $El juego está en proceso, pero es completamente jugable.\nPara reportar bugs, por favor, hazlo en nuestra + $comunidad de Discord. + $Si el juego va lento, por favor, asegúrate de que tengas activada la opción 'Aceleración de gráficos' en los + $ajustes de tu navegador.`, - "accessMenu": `To access the menu, press M or Escape while awaiting input.\nThe menu contains settings and various features.`, + "accessMenu": `Para acceder al menú, pulsa M o Escape cuando\ntengas el control. + $El menú contiene la configuración y otras funciones.`, - "menu": `From this menu you can access the settings. - $From the settings you can change game speed, window style, and other options. - $There are also various other features here, so be sure to check them all!`, + "menu": `Desde este menú podrás acceder a la configuración. + $Podrás cambiar la velocidad del juego, el estilo de la ventana y demás. + $Hay más opciones, ¡así que pruébalas todas!`, - "starterSelect": `From this screen, you can select your starters.\nThese are your initial party members. - $Each starter has a value. Your party can have up to\n6 members as long as the total does not exceed 10. - $You can also select gender, ability, and form depending on\nthe variants you've caught or hatched. - $The IVs for a species are also the best of every one you've\ncaught or hatched, so try to get lots of the same species!`, + "starterSelect": `En esta pantalla podrás elegir tus iniciales. Estos serán tus\nmiembros de equipo al comenzar la partida. + $Cada inicial tiene un valor. Tu equipo puede contener hasta 6\nmiembros mientras el valor total no pase de 10. + $También puedes elegir su género, habilidad y forma\ndependiendo de las variantes que hayas conseguido. + $Los IVs de los iniciales corresponderán al valor más alto de\nlos Pokémon de la misma especie que hayas obtenido. + $¡Así que intenta conseguir muchos Pokémon de la misma\nespecie!`, - "pokerus": `A daily random 3 selectable starters have a purple border. - $If you see a starter you own with one of these,\ntry adding it to your party. Be sure to check its summary!`, + "pokerus": `Cada día, 3 iniciales aleatorios tendrán un borde morado. + $Si ves un inicial que tengas con este borde, prueba a\nañadirlo a tu equipo. ¡No olvides revisar sus datos!`, - "statChange": `Stat changes persist across battles as long as your Pokémon aren't recalled. - $Your Pokémon are recalled before a trainer battle and before entering a new biome. - $You can also view the stat changes for the Pokémon on the field by holding C or Shift.`, + "statChange": `Los cambios de estadísticas se mantienen entre combates\nmientras que el Pokémon no vuelva a la Poké Ball. + $Tus Pokémon vuelven a sus Poké Balls antes de combates contra entrenadores y de entrar a un nuevo bioma. + $También puedes ver los cambios de estadísticas del Pokémon en campo manteniendo pulsado C o Shift.`, - "selectItem": `After every battle, you are given a choice of 3 random items.\nYou may only pick one. - $These range from consumables, to Pokémon held items, to passive permanent items. - $Most non-consumable item effects will stack in various ways. - $Some items will only show up if they can be used, such as evolution items. - $You can also transfer held items between Pokémon using the transfer option. - $The transfer option will appear in the bottom right once you have obtained a held item. - $You may purchase consumable items with money, and a larger variety will be available the further you get. - $Be sure to buy these before you pick your random item, as it will progress to the next battle once you do.`, + "selectItem": `Tras cada combate, tendrás la opción de elegir entre tres objetos aleatorios. Solo podrás escoger uno. + $Estos objetos pueden ser consumibles, objetos equipables u objetos pasivos permanentes (hasta acabar la partida). + $La mayoría de los efectos de objetos no consumibles se acumularán de varias maneras. + $Algunos objetos solo aparecerán si pueden ser utilizados, como las piedras evolutivas. + $También puedes transferir objetos equipados entre Pokémon utilizando la opción de transferir. + $La opción de transferir aparecerá en la parte inferior derecha una vez hayas obtenido un objeto equipable. + $También puedes comprar objetos consumibles con dinero y su variedad irá aumentando según tu avance. + $Asegúrate de comprar antes de escoger un objeto aleatorio, ya que se avanzará al siguiente combate.`, - "eggGacha": `From this screen, you can redeem your vouchers for\nPokémon eggs. - $Eggs have to be hatched and get closer to hatching after\nevery battle. Rarer eggs take longer to hatch. - $Hatched Pokémon also won't be added to your party, they will\nbe added to your starters. - $Pokémon hatched from eggs generally have better IVs than\nwild Pokémon. - $Some Pokémon can only even be obtained from eggs. - $There are 3 different machines to pull from with different\nbonuses, so pick the one that suits you best!`, + "eggGacha": `En esta pantalla podrás canjear tus vales por huevos\nde Pokémon. + $Los huevos deben eclosionar y estarán más cerca de\nhacerlo tras cada combate. + $Los huevos más raros tardarán más en eclosionar. + $Los Pokémon que hayan salido del huevo no se\nañadirán a tu equipo, pero sí a tus iniciales. + $Los Pokémon salidos de un huevo suelen tener mejores\nIVs que los Pokémon salvajes. + $Algunos Pokémon solo pueden ser obtenidos de huevos. + $Hay 3 máquinas diferentes entre las que elegir, cada\nuna con zdiferentes bonificaciones. + $¡Así que escoge la que más te interese!`, } as const; \ No newline at end of file diff --git a/src/locales/fr/menu.ts b/src/locales/fr/menu.ts index 1744297089c..7de214271eb 100644 --- a/src/locales/fr/menu.ts +++ b/src/locales/fr/menu.ts @@ -34,5 +34,9 @@ export const menu: SimpleTranslationEntries = { "weeklyRankings": "Classement de la Semaine", "noRankings": "Pas de Classement", "loading": "Chargement…", - "playersOnline": "Joueurs Connectés" + "playersOnline": "Joueurs Connectés", + "empty":"Empty", + "yes":"Yes", + "no":"No", + "confirmStartTeam":'Begin with these Pokémon?', } as const; diff --git a/src/locales/it/menu.ts b/src/locales/it/menu.ts index 9812236b7f0..33c128c137e 100644 --- a/src/locales/it/menu.ts +++ b/src/locales/it/menu.ts @@ -39,5 +39,9 @@ export const menu: SimpleTranslationEntries = { "weeklyRankings": "Weekly Rankings", "noRankings": "No Rankings", "loading": "Loading…", - "playersOnline": "Players Online" + "playersOnline": "Players Online", + "empty":"Empty", + "yes":"Yes", + "no":"No", + "confirmStartTeam":'Begin with these Pokémon?', } as const; \ No newline at end of file diff --git a/src/ui/confirm-ui-handler.ts b/src/ui/confirm-ui-handler.ts index d9e7726d826..a220b6f3a3d 100644 --- a/src/ui/confirm-ui-handler.ts +++ b/src/ui/confirm-ui-handler.ts @@ -1,6 +1,7 @@ import BattleScene, { Button } from "../battle-scene"; import AbstractOptionSelectUiHandler, { OptionSelectConfig } from "./abstact-option-select-ui-handler"; import { Mode } from "./ui"; +import i18next from "i18next"; export default class ConfirmUiHandler extends AbstractOptionSelectUiHandler { private switchCheck: boolean; @@ -19,14 +20,14 @@ export default class ConfirmUiHandler extends AbstractOptionSelectUiHandler { const config: OptionSelectConfig = { options: [ { - label: 'Yes', + label: i18next.t("menu:yes"), handler: () => { args[0](); return true; } }, { - label: 'No', + label: i18next.t("menu:no"), handler: () => { args[1](); return true; diff --git a/src/ui/save-slot-select-ui-handler.ts b/src/ui/save-slot-select-ui-handler.ts index 11680cd3952..69ac94d99ba 100644 --- a/src/ui/save-slot-select-ui-handler.ts +++ b/src/ui/save-slot-select-ui-handler.ts @@ -8,6 +8,7 @@ import * as Utils from "../utils"; import PokemonData from "../system/pokemon-data"; import { PokemonHeldItemModifier } from "../modifier/modifier"; import MessageUiHandler from "./message-ui-handler"; +import i18next from "i18next"; const sessionSlotCount = 5; @@ -314,7 +315,7 @@ class SessionSlot extends Phaser.GameObjects.Container { this.scene.gameData.getSession(this.slotId).then(async sessionData => { if (!sessionData) { this.hasData = false; - this.loadingLabel.setText('Empty'); + this.loadingLabel.setText(i18next.t("menu:empty")); resolve(false); return; } diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index f1e058b12cf..7cc99d81fb7 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -27,6 +27,7 @@ import { argbFromRgba } from "@material/material-color-utilities"; import { OptionSelectItem } from "./abstact-option-select-ui-handler"; import { pokemonPrevolutions } from "#app/data/pokemon-evolutions"; import { Variant, getVariantTint } from "#app/data/variant"; +import i18next from "i18next"; export type StarterSelectCallback = (starters: Starter[]) => void; @@ -1653,7 +1654,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.clearText(); }; - ui.showText('Begin with these Pokémon?', null, () => { + ui.showText(i18next.t("menu:confirmStartTeam"), null, () => { ui.setModeWithoutClear(Mode.CONFIRM, () => { const startRun = (gameMode: GameModes) => { this.scene.gameMode = gameModes[gameMode]; From 2eec545c496decd9c4a8e61ebca5ac259af27287 Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Fri, 3 May 2024 17:54:56 -0400 Subject: [PATCH 64/72] Fix stat number keys in legacy battle stats view --- public/images/ui/legacy/pbinfo_stat_numbers.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/public/images/ui/legacy/pbinfo_stat_numbers.json b/public/images/ui/legacy/pbinfo_stat_numbers.json index 9c74ee86dbc..fa7d757990f 100644 --- a/public/images/ui/legacy/pbinfo_stat_numbers.json +++ b/public/images/ui/legacy/pbinfo_stat_numbers.json @@ -10,7 +10,7 @@ "scale": 1, "frames": [ { - "filename": "+1", + "filename": "1", "rotated": false, "trimmed": false, "sourceSize": { @@ -31,7 +31,7 @@ } }, { - "filename": "+2", + "filename": "2", "rotated": false, "trimmed": false, "sourceSize": { @@ -52,7 +52,7 @@ } }, { - "filename": "+3", + "filename": "3", "rotated": false, "trimmed": false, "sourceSize": { @@ -73,7 +73,7 @@ } }, { - "filename": "+4", + "filename": "4", "rotated": false, "trimmed": false, "sourceSize": { @@ -94,7 +94,7 @@ } }, { - "filename": "+5", + "filename": "5", "rotated": false, "trimmed": false, "sourceSize": { @@ -115,7 +115,7 @@ } }, { - "filename": "+6", + "filename": "6", "rotated": false, "trimmed": false, "sourceSize": { From 754fe434e67783e16ec9f629d04a073ea1032931 Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Fri, 3 May 2024 18:37:46 -0400 Subject: [PATCH 65/72] Update biome pools for various legendaries and regionals --- src/data/biomes.ts | 162 ++++++++++++++++++++++++--------------------- 1 file changed, 85 insertions(+), 77 deletions(-) diff --git a/src/data/biomes.ts b/src/data/biomes.ts index c6a3c95b631..3dc12491816 100644 --- a/src/data/biomes.ts +++ b/src/data/biomes.ts @@ -241,10 +241,10 @@ export const biomePokemonPools: BiomePokemonPools = { [TimeOfDay.ALL]: [ { 1: [ Species.BULBASAUR ], 16: [ Species.IVYSAUR ], 32: [ Species.VENUSAUR ] }, Species.GROWLITHE, { 1: [ Species.TURTWIG ], 18: [ Species.GROTLE ], 32: [ Species.TORTERRA ] } ] }, [BiomePoolTier.SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.SUDOWOODO ] }, - [BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] }, + [BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.VIRIZION ] }, [BiomePoolTier.BOSS]: { [TimeOfDay.DAWN]: [ Species.JUMPLUFF, Species.SUNFLORA, Species.WHIMSICOTT ], [TimeOfDay.DAY]: [ Species.JUMPLUFF, Species.SUNFLORA, Species.WHIMSICOTT ], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] }, [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.VENUSAUR, Species.SUDOWOODO, Species.TORTERRA ] }, - [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] }, + [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.VIRIZION ] }, [BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] } }, [Biome.TALL_GRASS]: { @@ -487,14 +487,14 @@ export const biomePokemonPools: BiomePokemonPools = { [TimeOfDay.NIGHT]: [ Species.ARBOK, Species.CLODSIRE ], [TimeOfDay.ALL]: [ Species.POLIWRATH, Species.SWALOT, Species.WHISCASH, Species.GASTRODON, Species.SEISMITOAD, Species.STUNFISK, Species.TOXAPEX ] }, - [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.FERALIGATR, Species.POLITOED, Species.SWAMPERT ] }, - [BiomePoolTier.BOSS_SUPER_RARE]: { + [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [ Species.GALAR_SLOWBRO, Species.GALAR_SLOWKING, Species.HISUI_GOODRA ], [TimeOfDay.DAY]: [ Species.GALAR_SLOWBRO, Species.GALAR_SLOWKING, Species.HISUI_GOODRA ], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], - [TimeOfDay.ALL]: [ Species.AZELF, Species.NAGANADEL, Species.GALAR_STUNFISK ] + [TimeOfDay.ALL]: [ Species.FERALIGATR, Species.POLITOED, Species.SWAMPERT, Species.GALAR_STUNFISK ] }, + [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.AZELF, Species.NAGANADEL ] }, [BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] } }, [Biome.BEACH]: { @@ -521,7 +521,7 @@ export const biomePokemonPools: BiomePokemonPools = { }, [BiomePoolTier.RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ { 1: [ Species.QUAXLY ], 16: [ Species.QUAXWELL ], 36: [ Species.QUAQUAVAL ] }, Species.TATSUGIRI ] }, [BiomePoolTier.SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ { 1: [ Species.TIRTOUGA ], 37: [ Species.CARRACOSTA ] } ] }, - [BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.KELDEO ] }, + [BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.CRESSELIA, Species.KELDEO, Species.TAPU_FINI ] }, [BiomePoolTier.BOSS]: { [TimeOfDay.DAWN]: [ Species.STARMIE ], [TimeOfDay.DAY]: [ Species.STARMIE ], @@ -530,7 +530,7 @@ export const biomePokemonPools: BiomePokemonPools = { [TimeOfDay.ALL]: [ Species.KINGLER, Species.CRAWDAUNT, Species.WORMADAM, Species.CRUSTLE, Species.BARBARACLE, Species.CLAWITZER, Species.TOXAPEX, Species.PALOSSAND ] }, [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.CARRACOSTA, Species.QUAQUAVAL ] }, - [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.KELDEO ] }, + [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.CRESSELIA, Species.KELDEO, Species.TAPU_FINI ] }, [BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] } }, [Biome.LAKE]: { @@ -640,8 +640,14 @@ export const biomePokemonPools: BiomePokemonPools = { [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.LANTURN, Species.QWILFISH, Species.CORSOLA, Species.OCTILLERY, Species.MANTINE, Species.WAILORD, Species.HUNTAIL, Species.GOREBYSS, Species.LUVDISC, Species.JELLICENT, Species.ALOMOMOLA, Species.DRAGALGE, Species.BARRASKEWDA, Species.DONDOZO ] }, - [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.OMASTAR, Species.KABUTOPS, Species.RELICANTH, Species.EELEKTROSS, Species.PYUKUMUKU, Species.DHELMISE, Species.ARCTOVISH, Species.BASCULEGION ] }, - [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.MILOTIC, Species.NIHILEGO, Species.CURSOLA, Species.OVERQWIL ] }, + [BiomePoolTier.BOSS_RARE]: { + [TimeOfDay.DAWN]: [], + [TimeOfDay.DAY]: [], + [TimeOfDay.DUSK]: [], + [TimeOfDay.NIGHT]: [], + [TimeOfDay.ALL]: [ Species.OMASTAR, Species.KABUTOPS, Species.RELICANTH, Species.EELEKTROSS, Species.PYUKUMUKU, Species.DHELMISE, Species.CURSOLA, Species.ARCTOVISH, Species.BASCULEGION, Species.OVERQWIL ] + }, + [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.MILOTIC, Species.NIHILEGO ] }, [BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.KYOGRE ] } }, [Biome.MOUNTAIN]: { @@ -840,7 +846,7 @@ export const biomePokemonPools: BiomePokemonPools = { [TimeOfDay.ALL]: [ { 1: [ Species.DARUMAKA ], 35: [ Species.DARMANITAN ] } ] }, [BiomePoolTier.SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ { 1: [ Species.LILEEP ], 40: [ Species.CRADILY ] }, { 1: [ Species.ANORITH ], 40: [ Species.ARMALDO ] } ] }, - [BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.REGIROCK, Species.PHEROMOSA ] }, + [BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.REGIROCK, Species.TAPU_BULU, Species.PHEROMOSA ] }, [BiomePoolTier.BOSS]: { [TimeOfDay.DAWN]: [ Species.HIPPOWDON, Species.HELIOLISK, Species.RABSCA ], [TimeOfDay.DAY]: [ Species.HIPPOWDON, Species.HELIOLISK, Species.RABSCA ], @@ -849,7 +855,7 @@ export const biomePokemonPools: BiomePokemonPools = { [TimeOfDay.ALL]: [ Species.SANDSLASH, Species.DRAPION, Species.DARMANITAN, Species.MARACTUS, Species.SANDACONDA, Species.BRAMBLEGHAST ] }, [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.CRADILY, Species.ARMALDO ] }, - [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.REGIROCK, Species.PHEROMOSA ] }, + [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.REGIROCK, Species.TAPU_BULU, Species.PHEROMOSA ] }, [BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] } }, [Biome.ICE_CAVE]: { @@ -951,9 +957,9 @@ export const biomePokemonPools: BiomePokemonPools = { [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.TAUROS, Species.MILTANK, Species.GARDEVOIR, Species.PURUGLY, Species.ZEBSTRIKA, Species.FLORGES, Species.RIBOMBEE, Species.DUBWOOL ] }, - [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.BLISSEY, Species.SYLVEON, Species.FLAPPLE, Species.APPLETUN, Species.MEOWSCARADA, Species.HYDRAPPLE ] }, - [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [ Species.HISUI_LILLIGANT ], [TimeOfDay.DAY]: [ Species.HISUI_LILLIGANT ], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.MELOETTA ] }, - [BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] } + [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [ Species.HISUI_LILLIGANT ], [TimeOfDay.DAY]: [ Species.HISUI_LILLIGANT ], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.BLISSEY, Species.SYLVEON, Species.FLAPPLE, Species.APPLETUN, Species.MEOWSCARADA, Species.HYDRAPPLE ] }, + [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.MELOETTA ] }, + [BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.SHAYMIN ] } }, [Biome.POWER_PLANT]: { [BiomePoolTier.COMMON]: { @@ -984,8 +990,8 @@ export const biomePokemonPools: BiomePokemonPools = { [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.RAICHU, Species.MANECTRIC, Species.LUXRAY, Species.MAGNEZONE, Species.ELECTIVIRE, Species.DEDENNE, Species.VIKAVOLT, Species.TOGEDEMARU, Species.PAWMOT, Species.BELLIBOLT ] }, - [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.JOLTEON, Species.AMPHAROS ] }, - [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.ZAPDOS, Species.RAIKOU, Species.THUNDURUS, Species.XURKITREE, Species.ZERAORA, Species.REGIELEKI, Species.HISUI_ELECTRODE ] }, + [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.JOLTEON, Species.AMPHAROS, Species.HISUI_ELECTRODE ] }, + [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.ZAPDOS, Species.RAIKOU, Species.THUNDURUS, Species.XURKITREE, Species.ZERAORA, Species.REGIELEKI ] }, [BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.ZEKROM ] } }, [Biome.VOLCANO]: { @@ -1035,9 +1041,9 @@ export const biomePokemonPools: BiomePokemonPools = { [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], - [TimeOfDay.ALL]: [ Species.CHARIZARD, Species.FLAREON, Species.TYPHLOSION, Species.INFERNAPE, Species.EMBOAR, Species.VOLCARONA, Species.DELPHOX, Species.INCINEROAR, Species.CINDERACE, Species.ARMAROUGE ] + [TimeOfDay.ALL]: [ Species.CHARIZARD, Species.FLAREON, Species.TYPHLOSION, Species.INFERNAPE, Species.EMBOAR, Species.VOLCARONA, Species.DELPHOX, Species.INCINEROAR, Species.CINDERACE, Species.ARMAROUGE, Species.HISUI_ARCANINE ] }, - [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.MOLTRES, Species.ENTEI, Species.ROTOM, Species.HEATRAN, Species.VOLCANION, Species.CHI_YU, Species.HISUI_ARCANINE ] }, + [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.MOLTRES, Species.ENTEI, Species.ROTOM, Species.HEATRAN, Species.VOLCANION, Species.CHI_YU ] }, [BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.RESHIRAM ] } }, [Biome.GRAVEYARD]: { @@ -1074,8 +1080,8 @@ export const biomePokemonPools: BiomePokemonPools = { [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.GENGAR, Species.BANETTE, Species.DRIFBLIM, Species.MISMAGIUS, Species.DUSKNOIR, Species.CHANDELURE, Species.TREVENANT, Species.GOURGEIST, Species.MIMIKYU, Species.POLTEAGEIST, Species.HOUNDSTONE ] }, - [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.SKELEDIRGE, Species.CERULEDGE ] }, - [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.MARSHADOW, Species.SPECTRIER, Species.HISUI_TYPHLOSION ] }, + [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.SKELEDIRGE, Species.CERULEDGE, Species.HISUI_TYPHLOSION ] }, + [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.MARSHADOW, Species.SPECTRIER ] }, [BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.GIRATINA ] } }, [Biome.DOJO]: { @@ -1109,8 +1115,8 @@ export const biomePokemonPools: BiomePokemonPools = { [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.HITMONLEE, Species.HITMONCHAN, Species.HARIYAMA, Species.MEDICHAM, Species.LUCARIO, Species.TOXICROAK, Species.THROH, Species.SAWK, Species.SCRAFTY, Species.MIENSHAO, Species.BEWEAR, Species.GRAPPLOCT, Species.ANNIHILAPE ] }, - [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.HITMONTOP, Species.GALLADE, Species.PANGORO ] }, - [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.TERRAKION, Species.SIRFETCHD, Species.URSHIFU, Species.HISUI_DECIDUEYE ] }, + [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.HITMONTOP, Species.GALLADE, Species.PANGORO, Species.SIRFETCHD, Species.HISUI_DECIDUEYE ] }, + [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.TERRAKION, Species.URSHIFU ] }, [BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.ZAMAZENTA, Species.GALAR_ZAPDOS ] } }, [Biome.FACTORY]: { @@ -1168,8 +1174,8 @@ export const biomePokemonPools: BiomePokemonPools = { }, [BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.REGISTEEL, Species.FEZANDIPITI ] }, [BiomePoolTier.BOSS]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.ALAKAZAM, Species.HYPNO, Species.XATU, Species.GRUMPIG, Species.CLAYDOL, Species.SIGILYPH, Species.GOTHITELLE, Species.BEHEEYEM, Species.TINKATON ] }, - [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [ Species.ESPEON ], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.MR_MIME, Species.WOBBUFFET, Species.ARCHEOPS ] }, - [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [ Species.RUNERIGUS ], [TimeOfDay.NIGHT]: [ Species.RUNERIGUS ], [TimeOfDay.ALL]: [ Species.REGISTEEL, Species.FEZANDIPITI ] }, + [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [ Species.ESPEON ], [TimeOfDay.DUSK]: [ Species.RUNERIGUS ], [TimeOfDay.NIGHT]: [ Species.RUNERIGUS ], [TimeOfDay.ALL]: [ Species.MR_MIME, Species.WOBBUFFET, Species.ARCHEOPS ] }, + [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.REGISTEEL, Species.FEZANDIPITI ] }, [BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.KORAIDON ] } }, [Biome.WASTELAND]: { @@ -1245,7 +1251,7 @@ export const biomePokemonPools: BiomePokemonPools = { [TimeOfDay.ALL]: [ Species.ABSOL, Species.SPIRITOMB, { 1: [ Species.ZORUA ], 30: [ Species.ZOROARK ] }, { 1: [ Species.DEINO ], 50: [ Species.ZWEILOUS ], 64: [ Species.HYDREIGON ] } ] }, [BiomePoolTier.SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.UMBREON ] }, - [BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.DARKRAI, Species.GUZZLORD, Species.GALAR_MOLTRES ] }, + [BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.DARKRAI, Species.GALAR_MOLTRES ] }, [BiomePoolTier.BOSS]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], @@ -1253,8 +1259,8 @@ export const biomePokemonPools: BiomePokemonPools = { [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.HOUNDOOM, Species.SABLEYE, Species.ABSOL, Species.HONCHKROW, Species.SPIRITOMB, Species.LIEPARD, Species.ZOROARK, Species.HYDREIGON, Species.THIEVUL, Species.GRIMMSNARL, Species.MABOSSTIFF, Species.KINGAMBIT ] }, - [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.UMBREON ] }, - [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.DARKRAI, Species.GUZZLORD, Species.HISUI_SAMUROTT ] }, + [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.UMBREON, Species.HISUI_SAMUROTT ] }, + [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.DARKRAI ] }, [BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.PALKIA, Species.YVELTAL, Species.GALAR_MOLTRES ] } }, [Biome.SPACE]: { @@ -1274,10 +1280,10 @@ export const biomePokemonPools: BiomePokemonPools = { [TimeOfDay.ALL]: [ { 1: [ Species.BELDUM ], 20: [ Species.METANG ], 45: [ Species.METAGROSS ] }, Species.SIGILYPH, { 1: [ Species.SOLOSIS ], 32: [ Species.DUOSION ], 41: [ Species.REUNICLUS ] } ] }, [BiomePoolTier.SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ { 1: [ Species.PORYGON ], 30: [ Species.PORYGON2 ] } ] }, - [BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.CRESSELIA, { 1: [ Species.COSMOG ], 43: [ Species.COSMOEM ] }, Species.CELESTEELA ] }, + [BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ { 1: [ Species.COSMOG ], 43: [ Species.COSMOEM ] }, Species.CELESTEELA ] }, [BiomePoolTier.BOSS]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [ Species.SOLROCK ], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [ Species.LUNATONE ], [TimeOfDay.ALL]: [ Species.CLEFABLE, Species.BRONZONG, Species.MUSHARNA, Species.REUNICLUS, Species.MINIOR ] }, [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.METAGROSS, Species.PORYGON_Z ] }, - [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.CRESSELIA, Species.CELESTEELA ] }, + [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.CELESTEELA ] }, [BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [ Species.SOLGALEO ], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [ Species.LUNALA ], [TimeOfDay.ALL]: [ Species.RAYQUAZA, Species.NECROZMA ] } }, [Biome.CONSTRUCTION_SITE]: { @@ -1307,10 +1313,10 @@ export const biomePokemonPools: BiomePokemonPools = { }, [BiomePoolTier.RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [ { 1: [ Species.GALAR_MEOWTH ], 28: [ Species.PERRSERKER ] } ], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.ONIX, Species.HITMONLEE, Species.HITMONCHAN, Species.DURALUDON ] }, [BiomePoolTier.SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.DITTO, Species.HITMONTOP ] }, - [BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.COBALION ] }, + [BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.COBALION, Species.STAKATAKA ] }, [BiomePoolTier.BOSS]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.MACHAMP, Species.CONKELDURR ] }, [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [ Species.PERRSERKER ], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.ARCHALUDON ] }, - [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.COBALION ] }, + [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.COBALION, Species.STAKATAKA ] }, [BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] } }, [Biome.JUNGLE]: { @@ -1352,7 +1358,7 @@ export const biomePokemonPools: BiomePokemonPools = { ] }, [BiomePoolTier.SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.KANGASKHAN, Species.CHATOT, Species.KLEAVOR ] }, - [BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.VIRIZION, Species.BUZZWOLE, Species.ZARUDE, Species.MUNKIDORI ] }, + [BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.TAPU_LELE, Species.BUZZWOLE, Species.ZARUDE, Species.MUNKIDORI ] }, [BiomePoolTier.BOSS]: { [TimeOfDay.DAWN]: [ Species.EXEGGUTOR, Species.TROPIUS, Species.CHERRIM, Species.LEAVANNY, Species.KOMALA ], [TimeOfDay.DAY]: [ Species.EXEGGUTOR, Species.TROPIUS, Species.CHERRIM, Species.LEAVANNY, Species.KOMALA ], @@ -1367,7 +1373,7 @@ export const biomePokemonPools: BiomePokemonPools = { [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.KANGASKHAN, Species.SCIZOR, Species.SLAKING, Species.LEAFEON, Species.SERPERIOR, Species.RILLABOOM ] }, - [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.VIRIZION, Species.BUZZWOLE, Species.ZARUDE, Species.MUNKIDORI ] }, + [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.TAPU_LELE, Species.BUZZWOLE, Species.ZARUDE, Species.MUNKIDORI ] }, [BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.KLEAVOR ] } }, [Biome.FAIRY_CAVE]: { @@ -1445,10 +1451,10 @@ export const biomePokemonPools: BiomePokemonPools = { }, [BiomePoolTier.RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ { 1: [ Species.GIMMIGHOUL ], 40: [ Species.GHOLDENGO ] } ] }, [BiomePoolTier.SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] }, - [BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.HOOPA, Species.TAPU_KOKO, Species.TAPU_LELE, Species.TAPU_BULU, Species.TAPU_FINI ] }, + [BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.HOOPA, Species.TAPU_KOKO ] }, [BiomePoolTier.BOSS]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.CHIMECHO, Species.COFAGRIGUS, Species.GOLURK, Species.AEGISLASH ] }, [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.GHOLDENGO ] }, - [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.HOOPA, Species.TAPU_KOKO, Species.TAPU_LELE, Species.TAPU_BULU, Species.TAPU_FINI ] }, + [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.HOOPA, Species.TAPU_KOKO ] }, [BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.REGIGIGAS ] } }, [Biome.SLUM]: { @@ -1479,10 +1485,10 @@ export const biomePokemonPools: BiomePokemonPools = { [TimeOfDay.ALL]: [ { 1: [ Species.VAROOM ], 40: [ Species.REVAVROOM ] } ] }, [BiomePoolTier.SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] }, - [BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] }, + [BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.GUZZLORD ] }, [BiomePoolTier.BOSS]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [ Species.SKUNTANK, Species.WATCHOG ], [TimeOfDay.NIGHT]: [ Species.SKUNTANK, Species.WATCHOG ], [TimeOfDay.ALL]: [ Species.MUK, Species.WEEZING, Species.WORMADAM, Species.GARBODOR ] }, - [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [ Species.TOXTRICITY, Species.OBSTAGOON ], [TimeOfDay.NIGHT]: [ Species.TOXTRICITY, Species.OBSTAGOON ], [TimeOfDay.ALL]: [ Species.REVAVROOM ] }, - [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.GALAR_WEEZING ] }, + [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [ Species.TOXTRICITY, Species.OBSTAGOON ], [TimeOfDay.NIGHT]: [ Species.TOXTRICITY, Species.OBSTAGOON ], [TimeOfDay.ALL]: [ Species.REVAVROOM, Species.GALAR_WEEZING ] }, + [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.GUZZLORD ] }, [BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] } }, [Biome.SNOWY_FOREST]: { @@ -1516,14 +1522,14 @@ export const biomePokemonPools: BiomePokemonPools = { }, [BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.GLASTRIER, Species.CHIEN_PAO, Species.GALAR_ARTICUNO ] }, [BiomePoolTier.BOSS]: { [TimeOfDay.DAWN]: [ Species.WYRDEER ], [TimeOfDay.DAY]: [ Species.WYRDEER ], [TimeOfDay.DUSK]: [ Species.FROSMOTH ], [TimeOfDay.NIGHT]: [ Species.FROSMOTH ], [TimeOfDay.ALL]: [ Species.ABOMASNOW, Species.URSALUNA ] }, - [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.ARCTOZOLT, Species.ALOLA_SANDSLASH, Species.ALOLA_NINETALES ] }, - [BiomePoolTier.BOSS_SUPER_RARE]: { + [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [ Species.SNEASLER, Species.GALAR_DARMANITAN ], [TimeOfDay.DAY]: [ Species.SNEASLER, Species.GALAR_DARMANITAN ], [TimeOfDay.DUSK]: [ Species.HISUI_ZOROARK ], [TimeOfDay.NIGHT]: [ Species.HISUI_ZOROARK ], - [TimeOfDay.ALL]: [ Species.MR_RIME, Species.GLASTRIER, Species.CHIEN_PAO ] + [TimeOfDay.ALL]: [ Species.MR_RIME, Species.ARCTOZOLT, Species.ALOLA_SANDSLASH, Species.ALOLA_NINETALES ] }, + [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.GLASTRIER, Species.CHIEN_PAO ] }, [BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.ZACIAN, Species.GALAR_ARTICUNO ] } }, [Biome.ISLAND]: { @@ -1550,7 +1556,7 @@ export const biomePokemonPools: BiomePokemonPools = { }, [BiomePoolTier.RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] }, [BiomePoolTier.SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] }, - [BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.STAKATAKA, Species.BLACEPHALON ] }, + [BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.BLACEPHALON ] }, [BiomePoolTier.BOSS]: { [TimeOfDay.DAWN]: [ Species.ALOLA_RAICHU, Species.ALOLA_EXEGGUTOR ], [TimeOfDay.DAY]: [ Species.ALOLA_RAICHU, Species.ALOLA_EXEGGUTOR ], @@ -1559,7 +1565,7 @@ export const biomePokemonPools: BiomePokemonPools = { [TimeOfDay.ALL]: [ Species.ORICORIO, Species.BRUXISH, Species.ALOLA_SANDSLASH, Species.ALOLA_NINETALES, Species.ALOLA_DUGTRIO, Species.ALOLA_GOLEM, Species.ALOLA_MUK ] }, [BiomePoolTier.BOSS_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] }, - [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.STAKATAKA, Species.BLACEPHALON ] }, + [BiomePoolTier.BOSS_SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.BLACEPHALON ] }, [BiomePoolTier.BOSS_ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] } }, [Biome.LABORATORY]: { @@ -4371,8 +4377,8 @@ export const biomeTrainerPools: BiomeTrainerPools = { ] ], [ Species.CRESSELIA, Type.PSYCHIC, -1, [ - [ Biome.SPACE, BiomePoolTier.ULTRA_RARE ], - [ Biome.SPACE, BiomePoolTier.BOSS_SUPER_RARE ] + [ Biome.BEACH, BiomePoolTier.ULTRA_RARE ], + [ Biome.BEACH, BiomePoolTier.BOSS_SUPER_RARE ] ] ], [ Species.PHIONE, Type.WATER, -1, [ ] @@ -4384,7 +4390,9 @@ export const biomeTrainerPools: BiomeTrainerPools = { [ Biome.ABYSS, BiomePoolTier.BOSS_SUPER_RARE ] ] ], - [ Species.SHAYMIN, Type.GRASS, -1, [ ] + [ Species.SHAYMIN, Type.GRASS, -1, [ + [ Biome.MEADOW, BiomePoolTier.BOSS_ULTRA_RARE ] + ] ], [ Species.ARCEUS, Type.NORMAL, -1, [ ] ], @@ -5103,8 +5111,8 @@ export const biomeTrainerPools: BiomeTrainerPools = { ] ], [ Species.VIRIZION, Type.GRASS, Type.FIGHTING, [ - [ Biome.JUNGLE, BiomePoolTier.ULTRA_RARE ], - [ Biome.JUNGLE, BiomePoolTier.BOSS_SUPER_RARE ] + [ Biome.GRASS, BiomePoolTier.ULTRA_RARE ], + [ Biome.GRASS, BiomePoolTier.BOSS_SUPER_RARE ] ] ], [ Species.TORNADUS, Type.FLYING, -1, [ @@ -5779,18 +5787,18 @@ export const biomeTrainerPools: BiomeTrainerPools = { ] ], [ Species.TAPU_LELE, Type.PSYCHIC, Type.FAIRY, [ - [ Biome.TEMPLE, BiomePoolTier.ULTRA_RARE ], - [ Biome.TEMPLE, BiomePoolTier.BOSS_SUPER_RARE ] + [ Biome.JUNGLE, BiomePoolTier.ULTRA_RARE ], + [ Biome.JUNGLE, BiomePoolTier.BOSS_SUPER_RARE ] ] ], [ Species.TAPU_BULU, Type.GRASS, Type.FAIRY, [ - [ Biome.TEMPLE, BiomePoolTier.ULTRA_RARE ], - [ Biome.TEMPLE, BiomePoolTier.BOSS_SUPER_RARE ] + [ Biome.DESERT, BiomePoolTier.ULTRA_RARE ], + [ Biome.DESERT, BiomePoolTier.BOSS_SUPER_RARE ] ] ], [ Species.TAPU_FINI, Type.WATER, Type.FAIRY, [ - [ Biome.TEMPLE, BiomePoolTier.ULTRA_RARE ], - [ Biome.TEMPLE, BiomePoolTier.BOSS_SUPER_RARE ] + [ Biome.BEACH, BiomePoolTier.ULTRA_RARE ], + [ Biome.BEACH, BiomePoolTier.BOSS_SUPER_RARE ] ] ], [ Species.COSMOG, Type.PSYCHIC, -1, [ @@ -5840,8 +5848,8 @@ export const biomeTrainerPools: BiomeTrainerPools = { ] ], [ Species.GUZZLORD, Type.DARK, Type.DRAGON, [ - [ Biome.ABYSS, BiomePoolTier.ULTRA_RARE ], - [ Biome.ABYSS, BiomePoolTier.BOSS_SUPER_RARE ] + [ Biome.SLUM, BiomePoolTier.ULTRA_RARE ], + [ Biome.SLUM, BiomePoolTier.BOSS_SUPER_RARE ] ] ], [ Species.NECROZMA, Type.PSYCHIC, -1, [ @@ -5867,8 +5875,8 @@ export const biomeTrainerPools: BiomeTrainerPools = { ] ], [ Species.STAKATAKA, Type.ROCK, Type.STEEL, [ - [ Biome.ISLAND, BiomePoolTier.ULTRA_RARE ], - [ Biome.ISLAND, BiomePoolTier.BOSS_SUPER_RARE ] + [ Biome.CONSTRUCTION_SITE, BiomePoolTier.ULTRA_RARE ], + [ Biome.CONSTRUCTION_SITE, BiomePoolTier.BOSS_SUPER_RARE ] ] ], [ Species.BLACEPHALON, Type.FIRE, Type.GHOST, [ @@ -6129,21 +6137,21 @@ export const biomeTrainerPools: BiomeTrainerPools = { ], [ Species.CURSOLA, Type.GHOST, -1, [ [ Biome.SEABED, BiomePoolTier.SUPER_RARE ], - [ Biome.SEABED, BiomePoolTier.BOSS_SUPER_RARE ] + [ Biome.SEABED, BiomePoolTier.BOSS_RARE ] ] ], [ Species.SIRFETCHD, Type.FIGHTING, -1, [ - [ Biome.DOJO, BiomePoolTier.BOSS_SUPER_RARE ] + [ Biome.DOJO, BiomePoolTier.BOSS_RARE ] ] ], [ Species.MR_RIME, Type.ICE, Type.PSYCHIC, [ [ Biome.SNOWY_FOREST, BiomePoolTier.SUPER_RARE ], - [ Biome.SNOWY_FOREST, BiomePoolTier.BOSS_SUPER_RARE ] + [ Biome.SNOWY_FOREST, BiomePoolTier.BOSS_RARE ] ] ], [ Species.RUNERIGUS, Type.GROUND, Type.GHOST, [ [ Biome.RUINS, BiomePoolTier.SUPER_RARE, [ TimeOfDay.DUSK, TimeOfDay.NIGHT ] ], - [ Biome.RUINS, BiomePoolTier.BOSS_SUPER_RARE, [ TimeOfDay.DUSK, TimeOfDay.NIGHT ] ] + [ Biome.RUINS, BiomePoolTier.BOSS_RARE, [ TimeOfDay.DUSK, TimeOfDay.NIGHT ] ] ] ], [ Species.MILCERY, Type.FAIRY, -1, [ @@ -6305,11 +6313,11 @@ export const biomeTrainerPools: BiomeTrainerPools = { ] ], [ Species.SNEASLER, Type.FIGHTING, Type.POISON, [ - [ Biome.SNOWY_FOREST, BiomePoolTier.BOSS_SUPER_RARE, [ TimeOfDay.DAWN, TimeOfDay.DAY ] ] + [ Biome.SNOWY_FOREST, BiomePoolTier.BOSS_RARE, [ TimeOfDay.DAWN, TimeOfDay.DAY ] ] ] ], [ Species.OVERQWIL, Type.DARK, Type.POISON, [ - [ Biome.SEABED, BiomePoolTier.BOSS_SUPER_RARE ] + [ Biome.SEABED, BiomePoolTier.BOSS_RARE ] ] ], [ Species.ENAMORUS, Type.FAIRY, Type.FLYING, [ @@ -6972,7 +6980,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { ], [ Species.GALAR_SLOWBRO, Type.POISON, Type.PSYCHIC, [ [ Biome.SWAMP, BiomePoolTier.SUPER_RARE, [ TimeOfDay.DAWN, TimeOfDay.DAY ] ], - [ Biome.SWAMP, BiomePoolTier.BOSS_SUPER_RARE, [ TimeOfDay.DAWN, TimeOfDay.DAY ] ] + [ Biome.SWAMP, BiomePoolTier.BOSS_RARE, [ TimeOfDay.DAWN, TimeOfDay.DAY ] ] ] ], [ Species.GALAR_FARFETCHD, Type.FIGHTING, -1, [ @@ -6980,7 +6988,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { ] ], [ Species.GALAR_WEEZING, Type.POISON, Type.FAIRY, [ - [ Biome.SLUM, BiomePoolTier.BOSS_SUPER_RARE ] + [ Biome.SLUM, BiomePoolTier.BOSS_RARE ] ] ], [ Species.GALAR_MR_MIME, Type.ICE, Type.PSYCHIC, [ @@ -7003,7 +7011,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { ] ], [ Species.GALAR_SLOWKING, Type.POISON, Type.PSYCHIC, [ - [ Biome.SWAMP, BiomePoolTier.BOSS_SUPER_RARE, [ TimeOfDay.DAWN, TimeOfDay.DAY ] ] + [ Biome.SWAMP, BiomePoolTier.BOSS_RARE, [ TimeOfDay.DAWN, TimeOfDay.DAY ] ] ] ], [ Species.GALAR_CORSOLA, Type.GHOST, -1, [ @@ -7024,7 +7032,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { ], [ Species.GALAR_DARMANITAN, Type.ICE, -1, [ [ Biome.SNOWY_FOREST, BiomePoolTier.RARE, [ TimeOfDay.DAWN, TimeOfDay.DAY ] ], - [ Biome.SNOWY_FOREST, BiomePoolTier.BOSS_SUPER_RARE, [ TimeOfDay.DAWN, TimeOfDay.DAY ] ] + [ Biome.SNOWY_FOREST, BiomePoolTier.BOSS_RARE, [ TimeOfDay.DAWN, TimeOfDay.DAY ] ] ] ], [ Species.GALAR_YAMASK, Type.GROUND, Type.GHOST, [ @@ -7033,7 +7041,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { ], [ Species.GALAR_STUNFISK, Type.GROUND, Type.STEEL, [ [ Biome.SWAMP, BiomePoolTier.SUPER_RARE ], - [ Biome.SWAMP, BiomePoolTier.BOSS_SUPER_RARE ] + [ Biome.SWAMP, BiomePoolTier.BOSS_RARE ] ] ], [ Species.HISUI_GROWLITHE, Type.FIRE, Type.ROCK, [ @@ -7041,7 +7049,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { ] ], [ Species.HISUI_ARCANINE, Type.FIRE, Type.ROCK, [ - [ Biome.VOLCANO, BiomePoolTier.BOSS_SUPER_RARE ] + [ Biome.VOLCANO, BiomePoolTier.BOSS_RARE ] ] ], [ Species.HISUI_VOLTORB, Type.ELECTRIC, Type.GRASS, [ @@ -7049,11 +7057,11 @@ export const biomeTrainerPools: BiomeTrainerPools = { ] ], [ Species.HISUI_ELECTRODE, Type.ELECTRIC, Type.GRASS, [ - [ Biome.POWER_PLANT, BiomePoolTier.BOSS_SUPER_RARE ] + [ Biome.POWER_PLANT, BiomePoolTier.BOSS_RARE ] ] ], [ Species.HISUI_TYPHLOSION, Type.FIRE, Type.GHOST, [ - [ Biome.GRAVEYARD, BiomePoolTier.BOSS_SUPER_RARE ] + [ Biome.GRAVEYARD, BiomePoolTier.BOSS_RARE ] ] ], [ Species.HISUI_QWILFISH, Type.DARK, Type.POISON, [ @@ -7065,11 +7073,11 @@ export const biomeTrainerPools: BiomeTrainerPools = { ] ], [ Species.HISUI_SAMUROTT, Type.WATER, Type.DARK, [ - [ Biome.ABYSS, BiomePoolTier.BOSS_SUPER_RARE ] + [ Biome.ABYSS, BiomePoolTier.BOSS_RARE ] ] ], [ Species.HISUI_LILLIGANT, Type.GRASS, Type.FIGHTING, [ - [ Biome.MEADOW, BiomePoolTier.BOSS_SUPER_RARE, [ TimeOfDay.DAWN, TimeOfDay.DAY ] ] + [ Biome.MEADOW, BiomePoolTier.BOSS_RARE, [ TimeOfDay.DAWN, TimeOfDay.DAY ] ] ] ], [ Species.HISUI_ZORUA, Type.NORMAL, Type.GHOST, [ @@ -7078,7 +7086,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { ], [ Species.HISUI_ZOROARK, Type.NORMAL, Type.GHOST, [ [ Biome.SNOWY_FOREST, BiomePoolTier.SUPER_RARE, [ TimeOfDay.DUSK, TimeOfDay.NIGHT ] ], - [ Biome.SNOWY_FOREST, BiomePoolTier.BOSS_SUPER_RARE, [ TimeOfDay.DUSK, TimeOfDay.NIGHT ] ] + [ Biome.SNOWY_FOREST, BiomePoolTier.BOSS_RARE, [ TimeOfDay.DUSK, TimeOfDay.NIGHT ] ] ] ], [ Species.HISUI_BRAVIARY, Type.PSYCHIC, Type.FLYING, [ @@ -7091,7 +7099,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { ], [ Species.HISUI_GOODRA, Type.STEEL, Type.DRAGON, [ [ Biome.SWAMP, BiomePoolTier.SUPER_RARE, [ TimeOfDay.DAWN, TimeOfDay.DAY ] ], - [ Biome.SWAMP, BiomePoolTier.BOSS_SUPER_RARE, [ TimeOfDay.DAWN, TimeOfDay.DAY ] ] + [ Biome.SWAMP, BiomePoolTier.BOSS_RARE, [ TimeOfDay.DAWN, TimeOfDay.DAY ] ] ] ], [ Species.HISUI_AVALUGG, Type.ICE, Type.ROCK, [ @@ -7099,7 +7107,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { ] ], [ Species.HISUI_DECIDUEYE, Type.GRASS, Type.FIGHTING, [ - [ Biome.DOJO, BiomePoolTier.BOSS_SUPER_RARE ] + [ Biome.DOJO, BiomePoolTier.BOSS_RARE ] ] ], [ Species.PALDEA_TAUROS, Type.FIGHTING, -1, [ From 75cbe4fe2cd492e36f51e937ca200b29f7734f54 Mon Sep 17 00:00:00 2001 From: Lugiad Date: Sat, 4 May 2024 00:43:32 +0200 Subject: [PATCH 66/72] French Update to menu.ts (#436) --- src/locales/fr/menu.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/locales/fr/menu.ts b/src/locales/fr/menu.ts index 7de214271eb..7cea2c6d306 100644 --- a/src/locales/fr/menu.ts +++ b/src/locales/fr/menu.ts @@ -35,8 +35,8 @@ export const menu: SimpleTranslationEntries = { "noRankings": "Pas de Classement", "loading": "Chargement…", "playersOnline": "Joueurs Connectés", - "empty":"Empty", - "yes":"Yes", - "no":"No", - "confirmStartTeam":'Begin with these Pokémon?', + "empty":"Vide", + "yes":"Oui", + "no":"Non", + "confirmStartTeam":'Commencer avec ces Pokémon ?', } as const; From 0c9402a649c94cc06fa04927519d606cb1624a03 Mon Sep 17 00:00:00 2001 From: Lugiad Date: Sat, 4 May 2024 01:07:06 +0200 Subject: [PATCH 67/72] Update French tutorial.ts (#437) Changes made after in game test --- src/locales/fr/tutorial.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/locales/fr/tutorial.ts b/src/locales/fr/tutorial.ts index 1502b285356..bcd76d61da2 100644 --- a/src/locales/fr/tutorial.ts +++ b/src/locales/fr/tutorial.ts @@ -25,12 +25,9 @@ export const tutorial: SimpleTranslationEntries = { $violet. Si un starter que vous possédez l’a, essayez de $l’ajouter à votre équipe. Vérifiez bien son résumé !`, - "statChange": `Les changements de stats restent à travers les combats tant que le Pokémon - $n’est pas rappelé. - $Vos Pokémon sont rappelés avant un combat de Dresseur et avant d’entrer - $dans un nouveau biome. - $Vous pouvez également voir en combat les changements de stats d’un Pokémon - $en maintenant C ou Maj.`, + "statChange": `Les changements de stats restent à travers les combats tant que le Pokémon n’est pas rappelé. + $Vos Pokémon sont rappelés avant un combat de Dresseur et avant d’entrer dans un nouveau biome. + $Vous pouvez également voir en combat les changements de stats d’un Pokémon en maintenant C ou Maj.`, "selectItem": `Après chaque combat, vous avez le choix entre 3 objets\ntirés au sort. Vous ne pouvez en prendre qu’un. $Cela peut être des objets consommables, des objets à\nfaire tenir, ou des objets passifs aux effets permanents. From 77c3a5ad78271b8390e3d7cfcd48ec192013dc2c Mon Sep 17 00:00:00 2001 From: Lugiad Date: Sat, 4 May 2024 01:07:51 +0200 Subject: [PATCH 68/72] Minor update to French battle.ts (#438) * Minor update to French battle.ts Added missing spaces before some exclamation marks * Minor Update to French battle.ts --- src/locales/fr/battle.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/locales/fr/battle.ts b/src/locales/fr/battle.ts index 8768c30155a..742a8f63d77 100644 --- a/src/locales/fr/battle.ts +++ b/src/locales/fr/battle.ts @@ -14,11 +14,11 @@ export const battle: SimpleTranslationEntries = { "pokemonCaught": "Vous avez attrapé {{pokemonName}} !", "pokemon": "Pokémon", "sendOutPokemon": "{{pokemonName}} ! Go !", - "hitResultCriticalHit": "Coup critique!", - "hitResultSuperEffective": "C’est super efficace!", + "hitResultCriticalHit": "Coup critique !", + "hitResultSuperEffective": "C’est super efficace !", "hitResultNotVeryEffective": "Ce n’est pas très efficace…", "hitResultNoEffect": "Ça n’affecte pas {{pokemonName}}…", - "hitResultOneHitKO": "K.O. en un coup!", + "hitResultOneHitKO": "K.O. en un coup !", "attackFailed": "Mais cela échoue !", "attackHitsCount": `Touché {{count}} fois !`, "expGain": "{{pokemonName}} gagne\n{{exp}} Points d’Exp !", @@ -36,7 +36,7 @@ export const battle: SimpleTranslationEntries = { "moveDisabled": "{{moveName}} est sous entrave !", "noPokeballForce": "Une force mystérieuse\nempêche l’utilisation des Poké Balls.", "noPokeballTrainer": "Le Dresseur détourne la Ball\nVoler, c’est mal !", - "noPokeballMulti": "Impossible ! On ne peut pas viser\nquand il y a deux Pokémon!", + "noPokeballMulti": "Impossible ! On ne peut pas viser\nquand il y a deux Pokémon !", "noPokeballStrong": "Le Pokémon est trop fort pour être capturé !\nVous devez d’abord l’affaiblir !", "noEscapeForce": "Une force mystérieuse\nempêche la fuite.", "noEscapeTrainer": "On ne s’enfuit pas d’un\ncombat de Dresseurs !", @@ -49,4 +49,4 @@ export const battle: SimpleTranslationEntries = { "skipItemQuestion": "Êtes-vous sûr·e de ne pas vouloir prendre d’objet ?", "eggHatching": "Oh ?", "ivScannerUseQuestion": "Utiliser le Scanner d’IV sur {{pokemonName}} ?" -} as const; \ No newline at end of file +} as const; From cfee310350f65533b3c9fe44e9750cbd6867b74f Mon Sep 17 00:00:00 2001 From: Madmadness65 Date: Fri, 3 May 2024 19:21:02 -0500 Subject: [PATCH 69/72] Adjust more passive abilities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes some of the more problematic passives some Pokémon had. As usual, if there's any that you may have a problem with, we are always up for suggestions. --- src/data/biomes.ts | 4 ++-- src/data/pokemon-species.ts | 48 ++++++++++++++++++------------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/data/biomes.ts b/src/data/biomes.ts index 3dc12491816..61da0410dcf 100644 --- a/src/data/biomes.ts +++ b/src/data/biomes.ts @@ -4391,8 +4391,8 @@ export const biomeTrainerPools: BiomeTrainerPools = { ] ], [ Species.SHAYMIN, Type.GRASS, -1, [ - [ Biome.MEADOW, BiomePoolTier.BOSS_ULTRA_RARE ] - ] + [ Biome.MEADOW, BiomePoolTier.BOSS_ULTRA_RARE ] + ] ], [ Species.ARCEUS, Type.NORMAL, -1, [ ] ], diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index 57bb9230c5e..a045fe2292f 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -3209,7 +3209,7 @@ export const starterPassiveAbilities = { [Species.BELLSPROUT]: Abilities.CORROSION, [Species.TENTACOOL]: Abilities.INNARDS_OUT, [Species.GEODUDE]: Abilities.ROCKY_PAYLOAD, - [Species.PONYTA]: Abilities.PIXILATE, + [Species.PONYTA]: Abilities.MAGIC_GUARD, [Species.SLOWPOKE]: Abilities.UNAWARE, [Species.MAGNEMITE]: Abilities.MOTOR_DRIVE, [Species.FARFETCHD]: Abilities.PURE_POWER, @@ -3235,7 +3235,7 @@ export const starterPassiveAbilities = { [Species.SCYTHER]: Abilities.SPEED_BOOST, [Species.PINSIR]: Abilities.SAP_SIPPER, [Species.TAUROS]: Abilities.ROCK_HEAD, - [Species.MAGIKARP]: Abilities.BERSERK, + [Species.MAGIKARP]: Abilities.MULTISCALE, [Species.LAPRAS]: Abilities.LIQUID_VOICE, [Species.DITTO]: Abilities.GOOEY, [Species.EEVEE]: Abilities.PROTEAN, @@ -3249,16 +3249,16 @@ export const starterPassiveAbilities = { [Species.DRATINI]: Abilities.DELTA_STREAM, [Species.MEWTWO]: Abilities.NEUROFORCE, [Species.MEW]: Abilities.PROTEAN, - [Species.CHIKORITA]: Abilities.RIPEN, + [Species.CHIKORITA]: Abilities.THICK_FAT, [Species.CYNDAQUIL]: Abilities.TURBOBLAZE, [Species.TOTODILE]: Abilities.TOUGH_CLAWS, [Species.SENTRET]: Abilities.FLUFFY, [Species.HOOTHOOT]: Abilities.CURSED_BODY, - [Species.LEDYBA]: Abilities.SCREEN_CLEANER, + [Species.LEDYBA]: Abilities.PRANKSTER, [Species.SPINARAK]: Abilities.PRANKSTER, [Species.CHINCHOU]: Abilities.REGENERATOR, [Species.PICHU]: Abilities.TRANSISTOR, - [Species.CLEFFA]: Abilities.MISTY_SURGE, + [Species.CLEFFA]: Abilities.MAGIC_BOUNCE, [Species.IGGLYBUFF]: Abilities.SERENE_GRACE, [Species.TOGEPI]: Abilities.OPPORTUNIST, [Species.NATU]: Abilities.TINTED_LENS, @@ -3276,7 +3276,7 @@ export const starterPassiveAbilities = { [Species.DUNSPARCE]: Abilities.MARVEL_SCALE, [Species.GLIGAR]: Abilities.MERCILESS, [Species.SNUBBULL]: Abilities.BALL_FETCH, - [Species.QWILFISH]: Abilities.LIQUID_OOZE, + [Species.QWILFISH]: Abilities.TOXIC_DEBRIS, [Species.SHUCKLE]: Abilities.WELL_BAKED_BODY, [Species.HERACROSS]: Abilities.QUICK_FEET, [Species.SNEASEL]: Abilities.MOXIE, @@ -3292,7 +3292,7 @@ export const starterPassiveAbilities = { [Species.STANTLER]: Abilities.MAGIC_GUARD, [Species.SMEARGLE]: Abilities.QUICK_DRAW, [Species.TYROGUE]: Abilities.STAMINA, - [Species.SMOOCHUM]: Abilities.CUTE_CHARM, + [Species.SMOOCHUM]: Abilities.DAZZLING, [Species.ELEKID]: Abilities.IRON_FIST, [Species.MAGBY]: Abilities.CONTRARY, [Species.MILTANK]: Abilities.GLUTTONY, @@ -3303,7 +3303,7 @@ export const starterPassiveAbilities = { [Species.LUGIA]: Abilities.DELTA_STREAM, [Species.HO_OH]: Abilities.MAGIC_GUARD, [Species.CELEBI]: Abilities.GRASSY_SURGE, - [Species.TREECKO]: Abilities.GRASSY_SURGE, + [Species.TREECKO]: Abilities.TINTED_LENS, [Species.TORCHIC]: Abilities.RECKLESS, [Species.MUDKIP]: Abilities.REGENERATOR, [Species.POOCHYENA]: Abilities.STRONG_JAW, @@ -3320,7 +3320,7 @@ export const starterPassiveAbilities = { [Species.NINCADA]: Abilities.OVERCOAT, [Species.WHISMUR]: Abilities.PUNK_ROCK, [Species.MAKUHITA]: Abilities.STAMINA, - [Species.AZURILL]: Abilities.UNNERVE, + [Species.AZURILL]: Abilities.MISTY_SURGE, [Species.NOSEPASS]: Abilities.LEVITATE, [Species.SKITTY]: Abilities.SCRAPPY, [Species.SABLEYE]: Abilities.UNNERVE, @@ -3351,7 +3351,7 @@ export const starterPassiveAbilities = { [Species.BALTOY]: Abilities.OWN_TEMPO, [Species.LILEEP]: Abilities.WATER_ABSORB, [Species.ANORITH]: Abilities.WATER_ABSORB, - [Species.FEEBAS]: Abilities.PASTEL_VEIL, + [Species.FEEBAS]: Abilities.MAGIC_GUARD, [Species.CASTFORM]: Abilities.ADAPTABILITY, [Species.KECLEON]: Abilities.ADAPTABILITY, [Species.SHUPPET]: Abilities.MUMMY, @@ -3431,7 +3431,7 @@ export const starterPassiveAbilities = { [Species.VICTINI]: Abilities.SUPER_LUCK, [Species.SNIVY]: Abilities.MULTISCALE, [Species.TEPIG]: Abilities.ROCK_HEAD, - [Species.OSHAWOTT]: Abilities.MOLD_BREAKER, + [Species.OSHAWOTT]: Abilities.QUICK_DRAW, [Species.PATRAT]: Abilities.STAKEOUT, [Species.LILLIPUP]: Abilities.BALL_FETCH, [Species.PURRLOIN]: Abilities.DEFIANT, @@ -3444,14 +3444,14 @@ export const starterPassiveAbilities = { [Species.ROGGENROLA]: Abilities.SOLID_ROCK, [Species.WOOBAT]: Abilities.SOUL_HEART, [Species.DRILBUR]: Abilities.SAND_STREAM, - [Species.AUDINO]: Abilities.SERENE_GRACE, + [Species.AUDINO]: Abilities.FRIEND_GUARD, [Species.TIMBURR]: Abilities.STAMINA, [Species.TYMPOLE]: Abilities.MOODY, [Species.THROH]: Abilities.SIMPLE, [Species.SAWK]: Abilities.DEFIANT, [Species.SEWADDLE]: Abilities.SHARPNESS, [Species.VENIPEDE]: Abilities.INTIMIDATE, - [Species.COTTONEE]: Abilities.MISTY_SURGE, + [Species.COTTONEE]: Abilities.FLUFFY, [Species.PETILIL]: Abilities.DANCER, [Species.BASCULIN]: Abilities.OPPORTUNIST, [Species.SANDILE]: Abilities.STRONG_JAW, @@ -3460,7 +3460,7 @@ export const starterPassiveAbilities = { [Species.DWEBBLE]: Abilities.STAMINA, [Species.SCRAGGY]: Abilities.ROCK_HEAD, [Species.SIGILYPH]: Abilities.MAGICIAN, - [Species.YAMASK]: Abilities.GOOD_AS_GOLD, + [Species.YAMASK]: Abilities.PURIFYING_SALT, [Species.TIRTOUGA]: Abilities.SHELL_ARMOR, [Species.ARCHEN]: Abilities.ROCKY_PAYLOAD, [Species.TRUBBISH]: Abilities.GOOEY, @@ -3521,7 +3521,7 @@ export const starterPassiveAbilities = { [Species.SKIDDO]: Abilities.GRASSY_SURGE, [Species.PANCHAM]: Abilities.FLUFFY, [Species.FURFROU]: Abilities.BALL_FETCH, - [Species.ESPURR]: Abilities.PSYCHIC_SURGE, + [Species.ESPURR]: Abilities.FUR_COAT, [Species.HONEDGE]: Abilities.SHARPNESS, [Species.SPRITZEE]: Abilities.MISTY_SURGE, [Species.SWIRLIX]: Abilities.WELL_BAKED_BODY, @@ -3548,7 +3548,7 @@ export const starterPassiveAbilities = { [Species.HOOPA]: Abilities.OPPORTUNIST, [Species.VOLCANION]: Abilities.FILTER, [Species.ROWLET]: Abilities.SNIPER, - [Species.LITTEN]: Abilities.PRANKSTER, + [Species.LITTEN]: Abilities.FLAME_BODY, [Species.POPPLIO]: Abilities.PUNK_ROCK, [Species.PIKIPEK]: Abilities.ANGER_POINT, [Species.YUNGOOS]: Abilities.HUGE_POWER, @@ -3577,7 +3577,7 @@ export const starterPassiveAbilities = { [Species.KOMALA]: Abilities.GUTS, [Species.TURTONATOR]: Abilities.ANGER_SHELL, [Species.TOGEDEMARU]: Abilities.STATIC, - [Species.MIMIKYU]: Abilities.CURSED_BODY, + [Species.MIMIKYU]: Abilities.TOUGH_CLAWS, [Species.BRUXISH]: Abilities.MULTISCALE, [Species.DRAMPA]: Abilities.FLASH_FIRE, [Species.DHELMISE]: Abilities.INFILTRATOR, @@ -3607,9 +3607,9 @@ export const starterPassiveAbilities = { [Species.SOBBLE]: Abilities.SUPER_LUCK, [Species.SKWOVET]: Abilities.HONEY_GATHER, [Species.ROOKIDEE]: Abilities.IRON_BARBS, - [Species.BLIPBUG]: Abilities.TINTED_LENS, + [Species.BLIPBUG]: Abilities.PSYCHIC_SURGE, [Species.NICKIT]: Abilities.INTIMIDATE, - [Species.GOSSIFLEUR]: Abilities.STORM_DRAIN, + [Species.GOSSIFLEUR]: Abilities.GRASSY_SURGE, [Species.WOOLOO]: Abilities.ROCK_HEAD, [Species.CHEWTLE]: Abilities.ROCK_HEAD, [Species.YAMPER]: Abilities.STAKEOUT, @@ -3624,7 +3624,7 @@ export const starterPassiveAbilities = { [Species.SINISTEA]: Abilities.WATER_ABSORB, [Species.HATENNA]: Abilities.MAGIC_GUARD, [Species.IMPIDIMP]: Abilities.TANGLING_HAIR, - [Species.MILCERY]: Abilities.WELL_BAKED_BODY, + [Species.MILCERY]: Abilities.MISTY_SURGE, [Species.FALINKS]: Abilities.MOXIE, [Species.PINCURCHIN]: Abilities.IRON_BARBS, [Species.SNOM]: Abilities.SNOW_WARNING, @@ -3674,9 +3674,9 @@ export const starterPassiveAbilities = { [Species.RELLOR]: Abilities.MAGIC_GUARD, [Species.FLITTLE]: Abilities.COMPETITIVE, [Species.TINKATINK]: Abilities.HUGE_POWER, - [Species.WIGLETT]: Abilities.STORM_DRAIN, + [Species.WIGLETT]: Abilities.STURDY, [Species.BOMBIRDIER]: Abilities.UNAWARE, - [Species.FINIZEN]: Abilities.LIQUID_VOICE, + [Species.FINIZEN]: Abilities.IRON_FIST, [Species.VAROOM]: Abilities.SPEED_BOOST, [Species.CYCLIZAR]: Abilities.PROTEAN, [Species.ORTHWORM]: Abilities.HEATPROOF, @@ -3725,13 +3725,13 @@ export const starterPassiveAbilities = { [Species.ALOLA_RATTATA]: Abilities.CHEEK_POUCH, [Species.ALOLA_SANDSHREW]: Abilities.ICE_BODY, [Species.ALOLA_VULPIX]: Abilities.ICE_BODY, - [Species.ALOLA_DIGLETT]: Abilities.CUTE_CHARM, + [Species.ALOLA_DIGLETT]: Abilities.STURDY, [Species.ALOLA_MEOWTH]: Abilities.UNNERVE, [Species.ALOLA_GEODUDE]: Abilities.ELECTROMORPHOSIS, [Species.ALOLA_GRIMER]: Abilities.MERCILESS, [Species.ETERNAL_FLOETTE]: Abilities.MAGIC_GUARD, [Species.GALAR_MEOWTH]: Abilities.SUPER_LUCK, - [Species.GALAR_PONYTA]: Abilities.MAGIC_GUARD, + [Species.GALAR_PONYTA]: Abilities.PIXILATE, [Species.GALAR_SLOWPOKE]: Abilities.POISON_TOUCH, [Species.GALAR_FARFETCHD]: Abilities.SUPER_LUCK, [Species.GALAR_ARTICUNO]: Abilities.SERENE_GRACE, From ed24e03a6f79c3641295d4dc2c2d769a628c63f8 Mon Sep 17 00:00:00 2001 From: Madmadness65 Date: Fri, 3 May 2024 19:35:07 -0500 Subject: [PATCH 70/72] Fix Groudon's passive Changed from Flame Body to Protosynthesis, the original change wasn't discussed enough. --- src/data/pokemon-species.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index a045fe2292f..d118adc0fd8 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -3372,7 +3372,7 @@ export const starterPassiveAbilities = { [Species.LATIAS]: Abilities.SOUL_HEART, [Species.LATIOS]: Abilities.TINTED_LENS, [Species.KYOGRE]: Abilities.HYDRATION, - [Species.GROUDON]: Abilities.FLAME_BODY, + [Species.GROUDON]: Abilities.PROTOSYNTHESIS, [Species.RAYQUAZA]: Abilities.UNNERVE, [Species.JIRACHI]: Abilities.COMATOSE, [Species.DEOXYS]: Abilities.PROTEAN, From e02b85629f833f4a0c408d1d82c3c22cb478c807 Mon Sep 17 00:00:00 2001 From: Benjamin Odom Date: Fri, 3 May 2024 19:47:28 -0500 Subject: [PATCH 71/72] Fix Enemy Counter Moves The AI couldn't decide who to target with CounterDamageAttr moves which don't need a target. This change makes an exception. Now functions the same as when the player selects one of these moves. --- src/field/pokemon.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 909d255eef8..27728680c5f 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -4,7 +4,7 @@ import { Variant, VariantSet, variantColorCache } from '#app/data/variant'; import { variantData } from '#app/data/variant'; import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from '../ui/battle-info'; import { Moves } from "../data/enums/moves"; -import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, VariablePowerAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, MultiHitAttr, StatusMoveTypeImmunityAttr, MoveTarget, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatChangesAttr, SacrificialAttr, VariableMoveTypeAttr, VariableMoveCategoryAttr } from "../data/move"; +import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, VariablePowerAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, MultiHitAttr, StatusMoveTypeImmunityAttr, MoveTarget, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatChangesAttr, SacrificialAttr, VariableMoveTypeAttr, VariableMoveCategoryAttr, CounterDamageAttr } from "../data/move"; import { default as PokemonSpecies, PokemonSpeciesForm, SpeciesFormKey, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm, getStarterValueFriendshipCap, speciesStarters, starterPassiveAbilities } from '../data/pokemon-species'; import * as Utils from '../utils'; import { Type, TypeDamageMultiplier, getTypeDamageMultiplier, getTypeRgb } from '../data/type'; @@ -2731,6 +2731,10 @@ export class EnemyPokemon extends Pokemon { let targetScores: integer[] = []; for (let mt of moveTargets[move.id]) { + // Prevent a target score from being calculated when there isn't a target + if (mt === -1) + break; + const target = this.scene.getField()[mt]; let targetScore = move.getUserBenefitScore(this, target, move) + move.getTargetBenefitScore(this, target, move) * (mt < BattlerIndex.ENEMY === this.isPlayer() ? 1 : -1); if (move.name.endsWith(' (N)') || !move.applyConditions(this, target, move)) @@ -2801,8 +2805,14 @@ export class EnemyPokemon extends Pokemon { return scoreA < scoreB ? 1 : scoreA > scoreB ? -1 : 0; }); - if (!sortedBenefitScores.length) + if (!sortedBenefitScores.length) { + // Set target to -1 when using a counter move + // This is the same as when the player does so + if (!!move.findAttr(attr => attr instanceof CounterDamageAttr)) + return [-1]; + return []; + } let targetWeights = sortedBenefitScores.map(s => s[1]); const lowestWeight = targetWeights[targetWeights.length - 1]; From 4163005f122e886feef1168df73c0aa6c58b0393 Mon Sep 17 00:00:00 2001 From: Tempoanon <163687446+TempsRay@users.noreply.github.com> Date: Fri, 3 May 2024 22:10:40 -0400 Subject: [PATCH 72/72] Implement Forewarn, Frisk, and BattlerTags for Magnet Rise (WIP) (#241) * Implement Forewarn, Frisk, and BattlerTags for Magnet Rise (WIP) --- src/data/ability.ts | 51 ++++++++++++++++++++++++++++-- src/data/battler-tags.ts | 15 +++++++++ src/data/enums/battler-tag-type.ts | 3 +- src/data/move.ts | 4 +++ 4 files changed, 70 insertions(+), 3 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index 7ac3e721837..88695e23f3f 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -1785,6 +1785,53 @@ function getAnticipationCondition(): AbAttrCondition { }; } +export class ForewarnAbAttr extends PostSummonAbAttr { + constructor() { + super(true); + } + + applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + let maxPowerSeen = 0; + let maxMove = ""; + let movePower = 0; + for (let opponent of pokemon.getOpponents()) { + for (let move of opponent.moveset) { + if (move.getMove() instanceof StatusMove) { + movePower = 1; + } else if (move.getMove().findAttr(attr => attr instanceof OneHitKOAttr)) { + movePower = 150; + } else if (move.getMove().id === Moves.COUNTER || move.getMove().id === Moves.MIRROR_COAT || move.getMove().id === Moves.METAL_BURST) { + movePower = 120; + } else if (move.getMove().power === -1) { + movePower = 80; + } else { + movePower = move.getMove().power; + } + + if (movePower > maxPowerSeen) { + maxPowerSeen = movePower; + maxMove = move.getName(); + } + } + } + pokemon.scene.queueMessage(getPokemonMessage(pokemon, " was forewarned about " + maxMove + "!")); + return true; + } +} + +export class FriskAbAttr extends PostSummonAbAttr { + constructor() { + super(true); + } + + applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + for (let opponent of pokemon.getOpponents()) { + pokemon.scene.queueMessage(getPokemonMessage(pokemon, " frisked " + opponent.name + "\'s " + opponent.getAbility().name + "!")); + } + return true; + } +} + export class PostWeatherChangeAbAttr extends AbAttr { applyPostWeatherChange(pokemon: Pokemon, passive: boolean, weather: WeatherType, args: any[]): boolean { return false; @@ -2854,7 +2901,7 @@ export function initAbilities() { new Ability(Abilities.ANTICIPATION, 4) .conditionalAttr(getAnticipationCondition(), PostSummonMessageAbAttr, (pokemon: Pokemon) => getPokemonMessage(pokemon, ' shuddered!')), new Ability(Abilities.FOREWARN, 4) - .unimplemented(), + .attr(ForewarnAbAttr), new Ability(Abilities.UNAWARE, 4) .attr(IgnoreOpponentStatChangesAbAttr) .ignorable(), @@ -2883,7 +2930,7 @@ export function initAbilities() { new Ability(Abilities.HONEY_GATHER, 4) .unimplemented(), new Ability(Abilities.FRISK, 4) - .unimplemented(), + .attr(FriskAbAttr), new Ability(Abilities.RECKLESS, 4) .attr(MovePowerBoostAbAttr, (user, target, move) => move.getAttrs(RecoilAttr).length && move.id !== Moves.STRUGGLE, 1.2), new Ability(Abilities.MULTITYPE, 4) diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 8ff684394ec..183306d5066 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -984,6 +984,19 @@ export class HideSpriteTag extends BattlerTag { } } +export class TypeImmuneTag extends BattlerTag { + public immuneType: Type; + constructor(tagType: BattlerTagType, sourceMove: Moves, immuneType: Type, length: number) { + super(tagType, BattlerTagLapseType.TURN_END, 1, sourceMove); + } +} + +export class MagnetRisenTag extends TypeImmuneTag { + constructor(tagType: BattlerTagType, sourceMove: Moves) { + super(tagType, sourceMove, Type.GROUND, 5); + } +} + export class TypeBoostTag extends BattlerTag { public boostedType: Type; public boostValue: number; @@ -1211,6 +1224,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc return new CursedTag(sourceId); case BattlerTagType.CHARGED: return new TypeBoostTag(tagType, sourceMove, Type.ELECTRIC, 2, true); + case BattlerTagType.MAGNET_RISEN: + return new MagnetRisenTag(tagType, sourceMove); case BattlerTagType.NONE: default: return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId); diff --git a/src/data/enums/battler-tag-type.ts b/src/data/enums/battler-tag-type.ts index 7a9f6ba8bb2..d18ccf1c52f 100644 --- a/src/data/enums/battler-tag-type.ts +++ b/src/data/enums/battler-tag-type.ts @@ -54,5 +54,6 @@ export enum BattlerTagType { SALT_CURED = "SALT_CURED", CURSED = "CURSED", CHARGED = "CHARGED", - GROUNDED = "GROUNDED" + GROUNDED = "GROUNDED", + MAGNET_RISEN = "MAGNET_RISEN" } diff --git a/src/data/move.ts b/src/data/move.ts index 958588f7af4..0fedea1ec0e 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -4895,6 +4895,10 @@ export function initMoves() { new SelfStatusMove(Moves.AQUA_RING, Type.WATER, -1, 20, -1, 0, 4) .attr(AddBattlerTagAttr, BattlerTagType.AQUA_RING, true, true), new SelfStatusMove(Moves.MAGNET_RISE, Type.ELECTRIC, -1, 10, -1, 0, 4) + .attr(AddBattlerTagAttr, BattlerTagType.MAGNET_RISEN, true, true) + .condition((user, target, move) => !user.scene.arena.getTag(ArenaTagType.GRAVITY) && + !user.getTag(BattlerTagType.IGNORE_FLYING) && !user.getTag(BattlerTagType.INGRAIN) && + !user.getTag(BattlerTagType.MAGNET_RISEN)) .unimplemented(), new AttackMove(Moves.FLARE_BLITZ, Type.FIRE, MoveCategory.PHYSICAL, 120, 100, 15, 10, 0, 4) .attr(RecoilAttr, false, 0.33)