diff --git a/index.css b/index.css
index 9a507ad67..dd47387ad 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 bd316330a..506fa4f1e 100644
--- a/index.html
+++ b/index.html
@@ -74,6 +74,9 @@
V
+
+ Shift
+
diff --git a/public/images/pbinfo_stat_numbers.json b/public/images/pbinfo_stat_numbers.json
new file mode 100644
index 000000000..32170690a
--- /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 000000000..94c9f2a18
Binary files /dev/null and b/public/images/ui/legacy/pbinfo_enemy_boss_stats.png differ
diff --git a/public/images/ui/legacy/pbinfo_enemy_mini_stats.png b/public/images/ui/legacy/pbinfo_enemy_mini_stats.png
new file mode 100644
index 000000000..eb32e6941
Binary files /dev/null and b/public/images/ui/legacy/pbinfo_enemy_mini_stats.png differ
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 000000000..dd2b7e65b
Binary files /dev/null and b/public/images/ui/legacy/pbinfo_player_mini_stats.png differ
diff --git a/public/images/ui/legacy/pbinfo_player_stats.png b/public/images/ui/legacy/pbinfo_player_stats.png
new file mode 100644
index 000000000..078248624
Binary files /dev/null and b/public/images/ui/legacy/pbinfo_player_stats.png differ
diff --git a/public/images/ui/legacy/pbinfo_stat.json b/public/images/ui/legacy/pbinfo_stat.json
new file mode 100644
index 000000000..b7da47fc1
--- /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 000000000..62ec37587
Binary files /dev/null and b/public/images/ui/legacy/pbinfo_stat.png differ
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 000000000..9c74ee86d
--- /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 000000000..ee1453b21
Binary files /dev/null and b/public/images/ui/legacy/pbinfo_stat_numbers.png differ
diff --git a/public/images/ui/pbinfo_enemy_boss.png b/public/images/ui/pbinfo_enemy_boss.png
index 58edefa16..ff5ba6614 100644
Binary files a/public/images/ui/pbinfo_enemy_boss.png and b/public/images/ui/pbinfo_enemy_boss.png differ
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 000000000..7148a7af4
Binary files /dev/null and b/public/images/ui/pbinfo_enemy_boss_stats.png differ
diff --git a/public/images/ui/pbinfo_enemy_mini.png b/public/images/ui/pbinfo_enemy_mini.png
index 5250cb6f0..a7ff3cb9b 100644
Binary files a/public/images/ui/pbinfo_enemy_mini.png and b/public/images/ui/pbinfo_enemy_mini.png differ
diff --git a/public/images/ui/pbinfo_enemy_mini_stats.png b/public/images/ui/pbinfo_enemy_mini_stats.png
new file mode 100644
index 000000000..69ac5d494
Binary files /dev/null and b/public/images/ui/pbinfo_enemy_mini_stats.png differ
diff --git a/public/images/ui/pbinfo_enemy_type.png b/public/images/ui/pbinfo_enemy_type.png
index 021a12007..9bac63e5e 100644
Binary files a/public/images/ui/pbinfo_enemy_type.png and b/public/images/ui/pbinfo_enemy_type.png differ
diff --git a/public/images/ui/pbinfo_enemy_type1.png b/public/images/ui/pbinfo_enemy_type1.png
index 89b84d7f6..6d94871e8 100644
Binary files a/public/images/ui/pbinfo_enemy_type1.png and b/public/images/ui/pbinfo_enemy_type1.png differ
diff --git a/public/images/ui/pbinfo_enemy_type2.png b/public/images/ui/pbinfo_enemy_type2.png
index d1f9818d7..56a1989f2 100644
Binary files a/public/images/ui/pbinfo_enemy_type2.png and b/public/images/ui/pbinfo_enemy_type2.png differ
diff --git a/public/images/ui/pbinfo_player.png b/public/images/ui/pbinfo_player.png
index 9d3e03bd6..fee08f710 100644
Binary files a/public/images/ui/pbinfo_player.png and b/public/images/ui/pbinfo_player.png differ
diff --git a/public/images/ui/pbinfo_player_mini.png b/public/images/ui/pbinfo_player_mini.png
index db2762272..f12d46bb4 100644
Binary files a/public/images/ui/pbinfo_player_mini.png and b/public/images/ui/pbinfo_player_mini.png differ
diff --git a/public/images/ui/pbinfo_player_mini_stats.png b/public/images/ui/pbinfo_player_mini_stats.png
new file mode 100644
index 000000000..7ce3bd1af
Binary files /dev/null and b/public/images/ui/pbinfo_player_mini_stats.png differ
diff --git a/public/images/ui/pbinfo_player_stats.png b/public/images/ui/pbinfo_player_stats.png
new file mode 100644
index 000000000..cda978979
Binary files /dev/null and b/public/images/ui/pbinfo_player_stats.png differ
diff --git a/public/images/ui/pbinfo_player_type1.png b/public/images/ui/pbinfo_player_type1.png
index d1f9818d7..56a1989f2 100644
Binary files a/public/images/ui/pbinfo_player_type1.png and b/public/images/ui/pbinfo_player_type1.png differ
diff --git a/public/images/ui/pbinfo_player_type2.png b/public/images/ui/pbinfo_player_type2.png
index 89b84d7f6..6d94871e8 100644
Binary files a/public/images/ui/pbinfo_player_type2.png and b/public/images/ui/pbinfo_player_type2.png differ
diff --git a/public/images/ui/pbinfo_stat.json b/public/images/ui/pbinfo_stat.json
new file mode 100644
index 000000000..f431e5afa
--- /dev/null
+++ b/public/images/ui/pbinfo_stat.json
@@ -0,0 +1,188 @@
+{
+ "textures": [
+ {
+ "image": "pbinfo_stat.png",
+ "format": "RGBA8888",
+ "size": {
+ "w": 120,
+ "h": 7
+ },
+ "scale": 1,
+ "frames": [
+ {
+ "filename": "SPATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 19,
+ "h": 7
+ },
+ "frame": {
+ "x": 0,
+ "y": 0,
+ "w": 19,
+ "h": 7
+ }
+ },
+ {
+ "filename": "SPDEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 19,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 19,
+ "h": 7
+ },
+ "frame": {
+ "x": 19,
+ "y": 0,
+ "w": 19,
+ "h": 7
+ }
+ },
+ {
+ "filename": "CRIT",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 17,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 17,
+ "h": 7
+ },
+ "frame": {
+ "x": 38,
+ "y": 0,
+ "w": 17,
+ "h": 7
+ }
+ },
+ {
+ "filename": "ACC",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 55,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "ATK",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 68,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "DEF",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 81,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "EVA",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 94,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ },
+ {
+ "filename": "SPD",
+ "rotated": false,
+ "trimmed": true,
+ "sourceSize": {
+ "w": 13,
+ "h": 8
+ },
+ "spriteSourceSize": {
+ "x": 0,
+ "y": 1,
+ "w": 13,
+ "h": 7
+ },
+ "frame": {
+ "x": 107,
+ "y": 0,
+ "w": 13,
+ "h": 7
+ }
+ }
+ ]
+ }
+ ],
+ "meta": {
+ "app": "https://www.codeandweb.com/texturepacker",
+ "version": "3.0",
+ "smartupdate": "$TexturePacker:SmartUpdate:86fbd1b45d46271597a7d9de482aaa74:df702dd9d88db50369f1a096f82fd915:05882267d3999884e0491134e98b1b53$"
+ }
+}
diff --git a/public/images/ui/pbinfo_stat.png b/public/images/ui/pbinfo_stat.png
new file mode 100644
index 000000000..46169091e
Binary files /dev/null and b/public/images/ui/pbinfo_stat.png differ
diff --git a/public/images/ui/pbinfo_stat_numbers.json b/public/images/ui/pbinfo_stat_numbers.json
new file mode 100644
index 000000000..ec4f7117b
--- /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 000000000..c778ba992
Binary files /dev/null and b/public/images/ui/pbinfo_stat_numbers.png differ
diff --git a/src/battle-scene.ts b/src/battle-scene.ts
index 4253a1805..f1f527323 100644
--- a/src/battle-scene.ts
+++ b/src/battle-scene.ts
@@ -85,6 +85,7 @@ export enum Button {
ACTION,
CANCEL,
MENU,
+ STATS,
CYCLE_SHINY,
CYCLE_FORM,
CYCLE_GENDER,
@@ -196,25 +197,26 @@ export default class BattleScene extends SceneBase {
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.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);
+ 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]: 8, // share
+ [Button.STATS]: 9, // options
+ [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 = '';
@@ -615,6 +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.SHIFT],
[Button.CYCLE_SHINY]: [keyCodes.R],
[Button.CYCLE_FORM]: [keyCodes.F],
[Button.CYCLE_GENDER]: [keyCodes.G],
@@ -1432,8 +1435,16 @@ export default class BattleScene extends SceneBase {
if (this.ui?.getMode() === Mode.SETTINGS)
(this.ui.getHandler() as SettingsUiHandler).show([]);
}
- } else
- return;
+ } else {
+ let pressed = false;
+ if (this.buttonJustReleased(Button.STATS) || (pressed = this.buttonJustPressed(Button.STATS))) {
+ for (let p of this.getField().filter(p => 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 11629cf05..198ff07ce 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 9a7bfb486..7072875d3 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 2f37b900a..875d618ec 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 2722c02ad..f37afcae9 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 2722c02ad..f37afcae9 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 2722c02ad..f37afcae9 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 c9f8a392e..55262b195 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 2722c02ad..f37afcae9 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 8eda33de2..ceba555f2 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 918c68b9b..88e88fa80 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 ae794a256..3c2b541c6 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 {