diff --git a/public/audio/se/egg_crack.wav b/public/audio/se/egg_crack.wav index 33d587199a8..72a8d22b628 100644 Binary files a/public/audio/se/egg_crack.wav and b/public/audio/se/egg_crack.wav differ diff --git a/public/audio/se/egg_hatch.wav b/public/audio/se/egg_hatch.wav index 74ddf340a80..8e631b10f6d 100644 Binary files a/public/audio/se/egg_hatch.wav and b/public/audio/se/egg_hatch.wav differ diff --git a/public/audio/se/gacha_dial.wav b/public/audio/se/gacha_dial.wav new file mode 100644 index 00000000000..605b24fa58d Binary files /dev/null and b/public/audio/se/gacha_dial.wav differ diff --git a/public/audio/se/gacha_dispense.wav b/public/audio/se/gacha_dispense.wav new file mode 100644 index 00000000000..67238bc5423 Binary files /dev/null and b/public/audio/se/gacha_dispense.wav differ diff --git a/public/audio/se/gacha_running.wav b/public/audio/se/gacha_running.wav new file mode 100644 index 00000000000..90f9e158f6a Binary files /dev/null and b/public/audio/se/gacha_running.wav differ diff --git a/public/battle-anims/copycat.json b/public/battle-anims/copycat.json index 028722802e0..314b46ec664 100644 --- a/public/battle-anims/copycat.json +++ b/public/battle-anims/copycat.json @@ -1,6 +1,6 @@ { "id": 383, - "graphic": "'!", + "graphic": "!", "frames": [ [ { diff --git a/public/images/egg.png b/public/images/egg.png deleted file mode 100644 index f2bdfa1e123..00000000000 Binary files a/public/images/egg.png and /dev/null differ diff --git a/public/images/egg/default.png b/public/images/egg/default.png new file mode 100644 index 00000000000..160ac2542eb Binary files /dev/null and b/public/images/egg/default.png differ diff --git a/public/images/egg.json b/public/images/egg/egg.json similarity index 60% rename from public/images/egg.json rename to public/images/egg/egg.json index 19658c63733..420d9e57e7b 100644 --- a/public/images/egg.json +++ b/public/images/egg/egg.json @@ -4,7 +4,7 @@ "image": "egg.png", "format": "RGBA8888", "size": { - "w": 112, + "w": 138, "h": 30 }, "scale": 1, @@ -12,14 +12,14 @@ { "filename": "egg_0", "rotated": false, - "trimmed": true, + "trimmed": false, "sourceSize": { - "w": 32, - "h": 32 + "w": 28, + "h": 30 }, "spriteSourceSize": { - "x": 2, - "y": 1, + "x": 0, + "y": 0, "w": 28, "h": 30 }, @@ -33,14 +33,14 @@ { "filename": "egg_1", "rotated": false, - "trimmed": true, + "trimmed": false, "sourceSize": { - "w": 32, - "h": 32 + "w": 28, + "h": 30 }, "spriteSourceSize": { - "x": 2, - "y": 1, + "x": 0, + "y": 0, "w": 28, "h": 30 }, @@ -54,14 +54,14 @@ { "filename": "egg_2", "rotated": false, - "trimmed": true, + "trimmed": false, "sourceSize": { - "w": 32, - "h": 32 + "w": 28, + "h": 30 }, "spriteSourceSize": { - "x": 2, - "y": 1, + "x": 0, + "y": 0, "w": 28, "h": 30 }, @@ -75,14 +75,14 @@ { "filename": "egg_3", "rotated": false, - "trimmed": true, + "trimmed": false, "sourceSize": { - "w": 32, - "h": 32 + "w": 28, + "h": 30 }, "spriteSourceSize": { - "x": 2, - "y": 1, + "x": 0, + "y": 0, "w": 28, "h": 30 }, @@ -92,6 +92,27 @@ "w": 28, "h": 30 } + }, + { + "filename": "egg_manaphy", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 26, + "h": 30 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 26, + "h": 30 + }, + "frame": { + "x": 112, + "y": 0, + "w": 26, + "h": 30 + } } ] } @@ -99,6 +120,6 @@ "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:a2a114a3e275355f11c124f7ddc3a158:87e6ddecd2221fa223d5a07b1b3bb040:f2ac48b1c7b5b0a41ac50c4888a029cf$" + "smartupdate": "$TexturePacker:SmartUpdate:ba653f2a1c1d028d27d209346c8f5cda:d1a96146bbb57b7f2dbd12209e9e846d:f2ac48b1c7b5b0a41ac50c4888a029cf$" } } diff --git a/public/images/egg/egg.png b/public/images/egg/egg.png new file mode 100644 index 00000000000..5269eff1680 Binary files /dev/null and b/public/images/egg/egg.png differ diff --git a/public/images/egg_crack.json b/public/images/egg/egg_crack.json similarity index 100% rename from public/images/egg_crack.json rename to public/images/egg/egg_crack.json diff --git a/public/images/egg_crack.png b/public/images/egg/egg_crack.png similarity index 100% rename from public/images/egg_crack.png rename to public/images/egg/egg_crack.png diff --git a/public/images/egg/egg_icons.json b/public/images/egg/egg_icons.json new file mode 100644 index 00000000000..4008b8f4ede --- /dev/null +++ b/public/images/egg/egg_icons.json @@ -0,0 +1,125 @@ +{ + "textures": [ + { + "image": "egg_icons.png", + "format": "RGBA8888", + "size": { + "w": 64, + "h": 15 + }, + "scale": 1, + "frames": [ + { + "filename": "0", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 14, + "y": 14, + "w": 13, + "h": 14 + }, + "frame": { + "x": 0, + "y": 0, + "w": 13, + "h": 14 + } + }, + { + "filename": "1", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 14, + "y": 14, + "w": 13, + "h": 14 + }, + "frame": { + "x": 13, + "y": 0, + "w": 13, + "h": 14 + } + }, + { + "filename": "2", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 14, + "y": 14, + "w": 13, + "h": 14 + }, + "frame": { + "x": 26, + "y": 0, + "w": 13, + "h": 14 + } + }, + { + "filename": "3", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 14, + "y": 14, + "w": 13, + "h": 14 + }, + "frame": { + "x": 39, + "y": 0, + "w": 13, + "h": 14 + } + }, + { + "filename": "manaphy", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 40, + "h": 30 + }, + "spriteSourceSize": { + "x": 14, + "y": 13, + "w": 12, + "h": 15 + }, + "frame": { + "x": 52, + "y": 0, + "w": 12, + "h": 15 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:5bdeccfea3b20316b6f997ded4917832:9d7fd6a01652d18587263aea89256028:9ca79c86befa783c0f0fdd62dae4f950$" + } +} diff --git a/public/images/egg/egg_icons.png b/public/images/egg/egg_icons.png new file mode 100644 index 00000000000..c69187baa51 Binary files /dev/null and b/public/images/egg/egg_icons.png differ diff --git a/public/images/egg_lightrays.json b/public/images/egg/egg_lightrays.json similarity index 100% rename from public/images/egg_lightrays.json rename to public/images/egg/egg_lightrays.json diff --git a/public/images/egg_lightrays.png b/public/images/egg/egg_lightrays.png similarity index 100% rename from public/images/egg_lightrays.png rename to public/images/egg/egg_lightrays.png diff --git a/public/images/egg_shard.json b/public/images/egg/egg_shard.json similarity index 100% rename from public/images/egg_shard.json rename to public/images/egg/egg_shard.json diff --git a/public/images/egg_shard.png b/public/images/egg/egg_shard.png similarity index 100% rename from public/images/egg_shard.png rename to public/images/egg/egg_shard.png diff --git a/public/images/egg/gacha_glass.png b/public/images/egg/gacha_glass.png new file mode 100644 index 00000000000..b8c4a423454 Binary files /dev/null and b/public/images/egg/gacha_glass.png differ diff --git a/public/images/egg/gacha_hatch.json b/public/images/egg/gacha_hatch.json new file mode 100644 index 00000000000..f81332e47c9 --- /dev/null +++ b/public/images/egg/gacha_hatch.json @@ -0,0 +1,104 @@ +{ + "textures": [ + { + "image": "gacha_hatch.png", + "format": "RGBA8888", + "size": { + "w": 53, + "h": 53 + }, + "scale": 1, + "frames": [ + { + "filename": "1.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 25, + "h": 32 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 25, + "h": 32 + }, + "frame": { + "x": 0, + "y": 0, + "w": 25, + "h": 32 + } + }, + { + "filename": "2.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 25, + "h": 32 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 25, + "h": 31 + }, + "frame": { + "x": 25, + "y": 0, + "w": 25, + "h": 31 + } + }, + { + "filename": "3.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 25, + "h": 32 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 25, + "h": 22 + }, + "frame": { + "x": 25, + "y": 31, + "w": 25, + "h": 22 + } + }, + { + "filename": "4.png", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 25, + "h": 32 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 25, + "h": 12 + }, + "frame": { + "x": 0, + "y": 32, + "w": 25, + "h": 12 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:dba061ae0c944cad946da89a3db61ef3:6bcb3cebd91542179a70caca502090cd:03d3c0cdbe3979a45ab948bf5fc6c5fe$" + } +} diff --git a/public/images/egg/gacha_hatch.png b/public/images/egg/gacha_hatch.png new file mode 100644 index 00000000000..39fa7de58c1 Binary files /dev/null and b/public/images/egg/gacha_hatch.png differ diff --git a/public/images/egg/gacha_knob.png b/public/images/egg/gacha_knob.png new file mode 100644 index 00000000000..9b20c081cf2 Binary files /dev/null and b/public/images/egg/gacha_knob.png differ diff --git a/public/images/egg/gacha_legendary.png b/public/images/egg/gacha_legendary.png new file mode 100644 index 00000000000..8cd6fa38e29 Binary files /dev/null and b/public/images/egg/gacha_legendary.png differ diff --git a/public/images/egg/gacha_shiny.png b/public/images/egg/gacha_shiny.png new file mode 100644 index 00000000000..ffc1314f597 Binary files /dev/null and b/public/images/egg/gacha_shiny.png differ diff --git a/public/images/egg/gacha_type.png b/public/images/egg/gacha_type.png new file mode 100644 index 00000000000..19b3668424a Binary files /dev/null and b/public/images/egg/gacha_type.png differ diff --git a/public/images/egg/gacha_underlay_legendary.json b/public/images/egg/gacha_underlay_legendary.json new file mode 100644 index 00000000000..cce1c3cd417 --- /dev/null +++ b/public/images/egg/gacha_underlay_legendary.json @@ -0,0 +1,62 @@ +{ + "textures": [ + { + "image": "gacha_underlay_legendary.png", + "format": "RGBA8888", + "size": { + "w": 25, + "h": 104 + }, + "scale": 1, + "frames": [ + { + "filename": "default", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 25, + "h": 52 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 25, + "h": 52 + }, + "frame": { + "x": 0, + "y": 0, + "w": 25, + "h": 52 + } + }, + { + "filename": "open_hatch", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 25, + "h": 52 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 25, + "h": 52 + }, + "frame": { + "x": 0, + "y": 52, + "w": 25, + "h": 52 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:2714c584c99d3f151df83633a3e573e2:9a5a390cb558062cd2b0d8b9e577816a:dc9ad86988e4cd7eb47a54564121d8fa$" + } +} diff --git a/public/images/egg/gacha_underlay_legendary.png b/public/images/egg/gacha_underlay_legendary.png new file mode 100644 index 00000000000..5d116d3e11f Binary files /dev/null and b/public/images/egg/gacha_underlay_legendary.png differ diff --git a/public/images/egg/gacha_underlay_shiny.json b/public/images/egg/gacha_underlay_shiny.json new file mode 100644 index 00000000000..7eea33e9b1e --- /dev/null +++ b/public/images/egg/gacha_underlay_shiny.json @@ -0,0 +1,62 @@ +{ + "textures": [ + { + "image": "gacha_underlay_shiny.png", + "format": "RGBA8888", + "size": { + "w": 25, + "h": 104 + }, + "scale": 1, + "frames": [ + { + "filename": "default", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 25, + "h": 52 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 25, + "h": 52 + }, + "frame": { + "x": 0, + "y": 0, + "w": 25, + "h": 52 + } + }, + { + "filename": "open_hatch", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 25, + "h": 52 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 25, + "h": 52 + }, + "frame": { + "x": 0, + "y": 52, + "w": 25, + "h": 52 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:2714c584c99d3f151df83633a3e573e2:9a5a390cb558062cd2b0d8b9e577816a:dc9ad86988e4cd7eb47a54564121d8fa$" + } +} diff --git a/public/images/egg/gacha_underlay_shiny.png b/public/images/egg/gacha_underlay_shiny.png new file mode 100644 index 00000000000..a2b40fa2b0b Binary files /dev/null and b/public/images/egg/gacha_underlay_shiny.png differ diff --git a/public/images/egg/gacha_underlay_type.json b/public/images/egg/gacha_underlay_type.json new file mode 100644 index 00000000000..e4b0b3a25ad --- /dev/null +++ b/public/images/egg/gacha_underlay_type.json @@ -0,0 +1,62 @@ +{ + "textures": [ + { + "image": "gacha_underlay_type.png", + "format": "RGBA8888", + "size": { + "w": 25, + "h": 104 + }, + "scale": 1, + "frames": [ + { + "filename": "default", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 25, + "h": 52 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 25, + "h": 52 + }, + "frame": { + "x": 0, + "y": 0, + "w": 25, + "h": 52 + } + }, + { + "filename": "open_hatch", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 25, + "h": 52 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 25, + "h": 52 + }, + "frame": { + "x": 0, + "y": 52, + "w": 25, + "h": 52 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:2714c584c99d3f151df83633a3e573e2:9a5a390cb558062cd2b0d8b9e577816a:dc9ad86988e4cd7eb47a54564121d8fa$" + } +} diff --git a/public/images/egg/gacha_underlay_type.png b/public/images/egg/gacha_underlay_type.png new file mode 100644 index 00000000000..437b2bca3ab Binary files /dev/null and b/public/images/egg/gacha_underlay_type.png differ diff --git a/public/images/egg/open_hatch.png b/public/images/egg/open_hatch.png new file mode 100644 index 00000000000..fd91aca14d3 Binary files /dev/null and b/public/images/egg/open_hatch.png differ diff --git a/public/images/items.json b/public/images/items.json index 37db8a598b2..2a0ea464c23 100644 --- a/public/images/items.json +++ b/public/images/items.json @@ -4,8 +4,8 @@ "image": "items.png", "format": "RGBA8888", "size": { - "w": 318, - "h": 318 + "w": 320, + "h": 320 }, "scale": 1, "frames": [ @@ -821,6 +821,27 @@ "w": 16, "h": 16 }, + "frame": { + "x": 304, + "y": 16, + "w": 16, + "h": 16 + } + }, + { + "filename": "mewtwonite_x", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 8, + "w": 16, + "h": 16 + }, "frame": { "x": 0, "y": 30, @@ -829,7 +850,7 @@ } }, { - "filename": "mewtwonite_x", + "filename": "mewtwonite_y", "rotated": false, "trimmed": true, "sourceSize": { @@ -850,7 +871,7 @@ } }, { - "filename": "mewtwonite_y", + "filename": "nugget", "rotated": false, "trimmed": true, "sourceSize": { @@ -871,7 +892,7 @@ } }, { - "filename": "nugget", + "filename": "pidgeotite", "rotated": false, "trimmed": true, "sourceSize": { @@ -892,7 +913,7 @@ } }, { - "filename": "pidgeotite", + "filename": "pinsirite", "rotated": false, "trimmed": true, "sourceSize": { @@ -913,7 +934,7 @@ } }, { - "filename": "pinsirite", + "filename": "rayquazite", "rotated": false, "trimmed": true, "sourceSize": { @@ -934,7 +955,7 @@ } }, { - "filename": "rayquazite", + "filename": "sablenite", "rotated": false, "trimmed": true, "sourceSize": { @@ -955,7 +976,7 @@ } }, { - "filename": "sablenite", + "filename": "salamencite", "rotated": false, "trimmed": true, "sourceSize": { @@ -976,7 +997,7 @@ } }, { - "filename": "salamencite", + "filename": "sceptilite", "rotated": false, "trimmed": true, "sourceSize": { @@ -997,7 +1018,7 @@ } }, { - "filename": "sceptilite", + "filename": "scizorite", "rotated": false, "trimmed": true, "sourceSize": { @@ -1018,7 +1039,7 @@ } }, { - "filename": "scizorite", + "filename": "sharpedonite", "rotated": false, "trimmed": true, "sourceSize": { @@ -1039,7 +1060,7 @@ } }, { - "filename": "sharpedonite", + "filename": "slowbronite", "rotated": false, "trimmed": true, "sourceSize": { @@ -1060,7 +1081,7 @@ } }, { - "filename": "slowbronite", + "filename": "steelixite", "rotated": false, "trimmed": true, "sourceSize": { @@ -1081,7 +1102,7 @@ } }, { - "filename": "steelixite", + "filename": "swampertite", "rotated": false, "trimmed": true, "sourceSize": { @@ -1102,7 +1123,7 @@ } }, { - "filename": "swampertite", + "filename": "tyranitarite", "rotated": false, "trimmed": true, "sourceSize": { @@ -1123,7 +1144,7 @@ } }, { - "filename": "tyranitarite", + "filename": "venusaurite", "rotated": false, "trimmed": true, "sourceSize": { @@ -1143,27 +1164,6 @@ "h": 16 } }, - { - "filename": "venusaurite", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 8, - "w": 16, - "h": 16 - }, - "frame": { - "x": 256, - "y": 32, - "w": 16, - "h": 16 - } - }, { "filename": "black_glasses", "rotated": false, @@ -1179,7 +1179,7 @@ "h": 17 }, "frame": { - "x": 272, + "x": 256, "y": 32, "w": 23, "h": 17 @@ -1200,12 +1200,33 @@ "h": 17 }, "frame": { - "x": 295, + "x": 279, "y": 32, "w": 20, "h": 17 } }, + { + "filename": "wl_ability_urge", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 299, + "y": 32, + "w": 20, + "h": 18 + } + }, { "filename": "wise_glasses", "rotated": false, @@ -1290,27 +1311,6 @@ "h": 18 } }, - { - "filename": "wl_ability_urge", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 94, - "y": 48, - "w": 20, - "h": 18 - } - }, { "filename": "wl_antidote", "rotated": false, @@ -1326,7 +1326,7 @@ "h": 18 }, "frame": { - "x": 114, + "x": 94, "y": 48, "w": 20, "h": 18 @@ -1347,7 +1347,7 @@ "h": 18 }, "frame": { - "x": 134, + "x": 114, "y": 48, "w": 20, "h": 18 @@ -1368,7 +1368,7 @@ "h": 18 }, "frame": { - "x": 154, + "x": 134, "y": 48, "w": 20, "h": 18 @@ -1389,7 +1389,7 @@ "h": 18 }, "frame": { - "x": 174, + "x": 154, "y": 48, "w": 20, "h": 18 @@ -1410,7 +1410,7 @@ "h": 18 }, "frame": { - "x": 194, + "x": 174, "y": 48, "w": 20, "h": 18 @@ -1431,7 +1431,7 @@ "h": 18 }, "frame": { - "x": 214, + "x": 194, "y": 48, "w": 20, "h": 18 @@ -1452,33 +1452,12 @@ "h": 18 }, "frame": { - "x": 234, + "x": 214, "y": 48, "w": 20, "h": 18 } }, - { - "filename": "oval_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 7, - "w": 18, - "h": 19 - }, - "frame": { - "x": 254, - "y": 48, - "w": 18, - "h": 19 - } - }, { "filename": "wl_hyper_potion", "rotated": false, @@ -1494,8 +1473,8 @@ "h": 18 }, "frame": { - "x": 272, - "y": 49, + "x": 234, + "y": 48, "w": 20, "h": 18 } @@ -1515,7 +1494,7 @@ "h": 18 }, "frame": { - "x": 292, + "x": 254, "y": 49, "w": 20, "h": 18 @@ -1535,6 +1514,48 @@ "w": 20, "h": 18 }, + "frame": { + "x": 274, + "y": 49, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_item_urge", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, + "frame": { + "x": 294, + "y": 50, + "w": 20, + "h": 18 + } + }, + { + "filename": "wl_max_potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 8, + "w": 20, + "h": 18 + }, "frame": { "x": 0, "y": 64, @@ -1543,7 +1564,7 @@ } }, { - "filename": "wl_item_urge", + "filename": "wl_max_revive", "rotated": false, "trimmed": true, "sourceSize": { @@ -1563,48 +1584,6 @@ "h": 18 } }, - { - "filename": "wl_max_potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 40, - "y": 66, - "w": 20, - "h": 18 - } - }, - { - "filename": "wl_max_revive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 8, - "w": 20, - "h": 18 - }, - "frame": { - "x": 60, - "y": 66, - "w": 20, - "h": 18 - } - }, { "filename": "wl_paralyze_heal", "rotated": false, @@ -1620,7 +1599,7 @@ "h": 18 }, "frame": { - "x": 80, + "x": 40, "y": 66, "w": 20, "h": 18 @@ -1641,7 +1620,7 @@ "h": 18 }, "frame": { - "x": 100, + "x": 60, "y": 66, "w": 20, "h": 18 @@ -1662,7 +1641,7 @@ "h": 18 }, "frame": { - "x": 120, + "x": 80, "y": 66, "w": 20, "h": 18 @@ -1683,7 +1662,7 @@ "h": 18 }, "frame": { - "x": 140, + "x": 100, "y": 66, "w": 20, "h": 18 @@ -1704,7 +1683,7 @@ "h": 18 }, "frame": { - "x": 160, + "x": 120, "y": 66, "w": 20, "h": 18 @@ -1725,7 +1704,7 @@ "h": 19 }, "frame": { - "x": 180, + "x": 140, "y": 66, "w": 19, "h": 19 @@ -1746,12 +1725,33 @@ "h": 19 }, "frame": { - "x": 199, + "x": 159, "y": 66, "w": 22, "h": 19 } }, + { + "filename": "coupon", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 23, + "h": 19 + }, + "frame": { + "x": 181, + "y": 66, + "w": 23, + "h": 19 + } + }, { "filename": "dubious_disc", "rotated": false, @@ -1767,12 +1767,33 @@ "h": 19 }, "frame": { - "x": 221, + "x": 204, "y": 66, "w": 22, "h": 19 } }, + { + "filename": "golden_mystic_ticket", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 23, + "h": 19 + }, + "frame": { + "x": 226, + "y": 66, + "w": 23, + "h": 19 + } + }, { "filename": "lum_berry", "rotated": false, @@ -1788,7 +1809,7 @@ "h": 19 }, "frame": { - "x": 243, + "x": 249, "y": 67, "w": 20, "h": 19 @@ -1809,12 +1830,54 @@ "h": 19 }, "frame": { - "x": 263, + "x": 269, "y": 67, "w": 19, "h": 19 } }, + { + "filename": "mystic_ticket", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 7, + "w": 23, + "h": 19 + }, + "frame": { + "x": 288, + "y": 68, + "w": 23, + "h": 19 + } + }, + { + "filename": "oval_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 7, + "w": 18, + "h": 19 + }, + "frame": { + "x": 0, + "y": 82, + "w": 18, + "h": 19 + } + }, { "filename": "razor_claw", "rotated": false, @@ -1830,14 +1893,14 @@ "h": 19 }, "frame": { - "x": 282, - "y": 67, + "x": 18, + "y": 83, "w": 20, "h": 19 } }, { - "filename": "leftovers", + "filename": "pair_of_tickets", "rotated": false, "trimmed": true, "sourceSize": { @@ -1845,16 +1908,37 @@ "h": 32 }, "spriteSourceSize": { - "x": 8, - "y": 5, - "w": 15, - "h": 22 + "x": 4, + "y": 7, + "w": 23, + "h": 19 }, "frame": { - "x": 302, - "y": 67, - "w": 15, - "h": 22 + "x": 38, + "y": 84, + "w": 23, + "h": 19 + } + }, + { + "filename": "upgrade", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 7, + "w": 22, + "h": 19 + }, + "frame": { + "x": 61, + "y": 84, + "w": 22, + "h": 19 } }, { @@ -1872,8 +1956,8 @@ "h": 20 }, "frame": { - "x": 0, - "y": 82, + "x": 83, + "y": 84, "w": 19, "h": 20 } @@ -1893,112 +1977,7 @@ "h": 20 }, "frame": { - "x": 19, - "y": 83, - "w": 20, - "h": 20 - } - }, - { - "filename": "upgrade", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 7, - "w": 22, - "h": 19 - }, - "frame": { - "x": 39, - "y": 84, - "w": 22, - "h": 19 - } - }, - { - "filename": "binding_band", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 23, - "h": 20 - }, - "frame": { - "x": 61, - "y": 84, - "w": 23, - "h": 20 - } - }, - { - "filename": "candy_jar", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 19, - "h": 20 - }, - "frame": { - "x": 84, - "y": 84, - "w": 19, - "h": 20 - } - }, - { - "filename": "deep_sea_scale", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 22, - "h": 20 - }, - "frame": { - "x": 103, - "y": 84, - "w": 22, - "h": 20 - } - }, - { - "filename": "gb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 125, + "x": 102, "y": 84, "w": 20, "h": 20 @@ -2019,14 +1998,14 @@ "h": 20 }, "frame": { - "x": 145, + "x": 122, "y": 84, "w": 17, "h": 20 } }, { - "filename": "lucky_egg", + "filename": "binding_band", "rotated": false, "trimmed": true, "sourceSize": { @@ -2034,15 +2013,78 @@ "h": 32 }, "spriteSourceSize": { - "x": 7, + "x": 5, "y": 6, - "w": 17, + "w": 23, + "h": 20 + }, + "frame": { + "x": 139, + "y": 85, + "w": 23, + "h": 20 + } + }, + { + "filename": "candy_jar", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 19, "h": 20 }, "frame": { "x": 162, - "y": 84, - "w": 17, + "y": 85, + "w": 19, + "h": 20 + } + }, + { + "filename": "deep_sea_scale", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 22, + "h": 20 + }, + "frame": { + "x": 181, + "y": 85, + "w": 22, + "h": 20 + } + }, + { + "filename": "gb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 203, + "y": 85, + "w": 20, "h": 20 } }, @@ -2061,12 +2103,33 @@ "h": 20 }, "frame": { - "x": 179, + "x": 223, "y": 85, "w": 19, "h": 20 } }, + { + "filename": "lucky_egg", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 6, + "w": 17, + "h": 20 + }, + "frame": { + "x": 242, + "y": 86, + "w": 17, + "h": 20 + } + }, { "filename": "magnet", "rotated": false, @@ -2082,8 +2145,8 @@ "h": 20 }, "frame": { - "x": 198, - "y": 85, + "x": 259, + "y": 86, "w": 20, "h": 20 } @@ -2103,8 +2166,8 @@ "h": 20 }, "frame": { - "x": 218, - "y": 85, + "x": 279, + "y": 87, "w": 20, "h": 20 } @@ -2124,29 +2187,8 @@ "h": 20 }, "frame": { - "x": 238, - "y": 86, - "w": 20, - "h": 20 - } - }, - { - "filename": "pb_gold", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 6, - "w": 20, - "h": 20 - }, - "frame": { - "x": 258, - "y": 86, + "x": 299, + "y": 87, "w": 20, "h": 20 } @@ -2166,14 +2208,14 @@ "h": 20 }, "frame": { - "x": 278, - "y": 86, + "x": 0, + "y": 101, "w": 18, "h": 20 } }, { - "filename": "strange_ball", + "filename": "pb_gold", "rotated": false, "trimmed": true, "sourceSize": { @@ -2187,8 +2229,8 @@ "h": 20 }, "frame": { - "x": 296, - "y": 89, + "x": 18, + "y": 102, "w": 20, "h": 20 } @@ -2208,12 +2250,33 @@ "h": 20 }, "frame": { - "x": 0, + "x": 38, "y": 103, "w": 23, "h": 20 } }, + { + "filename": "strange_ball", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 6, + "w": 20, + "h": 20 + }, + "frame": { + "x": 61, + "y": 103, + "w": 20, + "h": 20 + } + }, { "filename": "sacred_ash", "rotated": false, @@ -2229,8 +2292,8 @@ "h": 20 }, "frame": { - "x": 23, - "y": 103, + "x": 81, + "y": 104, "w": 24, "h": 20 } @@ -2250,7 +2313,7 @@ "h": 20 }, "frame": { - "x": 47, + "x": 105, "y": 104, "w": 23, "h": 20 @@ -2271,8 +2334,8 @@ "h": 20 }, "frame": { - "x": 70, - "y": 104, + "x": 128, + "y": 105, "w": 24, "h": 20 } @@ -2292,8 +2355,8 @@ "h": 20 }, "frame": { - "x": 94, - "y": 104, + "x": 152, + "y": 105, "w": 20, "h": 20 } @@ -2313,8 +2376,8 @@ "h": 21 }, "frame": { - "x": 114, - "y": 104, + "x": 172, + "y": 105, "w": 23, "h": 21 } @@ -2334,8 +2397,8 @@ "h": 21 }, "frame": { - "x": 137, - "y": 104, + "x": 195, + "y": 105, "w": 20, "h": 21 } @@ -2355,8 +2418,8 @@ "h": 21 }, "frame": { - "x": 157, - "y": 104, + "x": 215, + "y": 105, "w": 22, "h": 21 } @@ -2376,8 +2439,29 @@ "h": 21 }, "frame": { - "x": 179, - "y": 105, + "x": 237, + "y": 106, + "w": 21, + "h": 21 + } + }, + { + "filename": "poison_barb", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 21, + "h": 21 + }, + "frame": { + "x": 258, + "y": 106, "w": 21, "h": 21 } @@ -2397,75 +2481,12 @@ "h": 21 }, "frame": { - "x": 200, - "y": 105, + "x": 279, + "y": 107, "w": 22, "h": 21 } }, - { - "filename": "moon_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 6, - "w": 23, - "h": 21 - }, - "frame": { - "x": 222, - "y": 106, - "w": 23, - "h": 21 - } - }, - { - "filename": "poison_barb", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 21, - "h": 21 - }, - "frame": { - "x": 245, - "y": 106, - "w": 21, - "h": 21 - } - }, - { - "filename": "shiny_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 6, - "w": 21, - "h": 21 - }, - "frame": { - "x": 266, - "y": 106, - "w": 21, - "h": 21 - } - }, { "filename": "spell_tag", "rotated": false, @@ -2481,12 +2502,75 @@ "h": 21 }, "frame": { - "x": 287, - "y": 109, + "x": 301, + "y": 107, "w": 19, "h": 21 } }, + { + "filename": "leftovers", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 5, + "w": 15, + "h": 22 + }, + "frame": { + "x": 0, + "y": 121, + "w": 15, + "h": 22 + } + }, + { + "filename": "moon_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 6, + "w": 23, + "h": 21 + }, + "frame": { + "x": 15, + "y": 122, + "w": 23, + "h": 21 + } + }, + { + "filename": "shiny_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 6, + "w": 21, + "h": 21 + }, + "frame": { + "x": 38, + "y": 123, + "w": 21, + "h": 21 + } + }, { "filename": "zoom_lens", "rotated": false, @@ -2502,7 +2586,7 @@ "h": 21 }, "frame": { - "x": 0, + "x": 59, "y": 123, "w": 21, "h": 21 @@ -2523,8 +2607,8 @@ "h": 22 }, "frame": { - "x": 21, - "y": 123, + "x": 80, + "y": 124, "w": 22, "h": 22 } @@ -2544,7 +2628,7 @@ "h": 22 }, "frame": { - "x": 43, + "x": 102, "y": 124, "w": 22, "h": 22 @@ -2565,8 +2649,8 @@ "h": 22 }, "frame": { - "x": 65, - "y": 124, + "x": 124, + "y": 125, "w": 22, "h": 22 } @@ -2586,8 +2670,8 @@ "h": 22 }, "frame": { - "x": 87, - "y": 124, + "x": 146, + "y": 125, "w": 22, "h": 22 } @@ -2607,8 +2691,8 @@ "h": 22 }, "frame": { - "x": 109, - "y": 125, + "x": 168, + "y": 126, "w": 22, "h": 22 } @@ -2628,29 +2712,8 @@ "h": 22 }, "frame": { - "x": 131, - "y": 125, - "w": 24, - "h": 22 - } - }, - { - "filename": "exp_share", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 24, - "h": 22 - }, - "frame": { - "x": 155, - "y": 125, + "x": 190, + "y": 126, "w": 24, "h": 22 } @@ -2670,12 +2733,33 @@ "h": 22 }, "frame": { - "x": 179, + "x": 214, "y": 126, "w": 22, "h": 22 } }, + { + "filename": "exp_share", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 22 + }, + "frame": { + "x": 236, + "y": 127, + "w": 24, + "h": 22 + } + }, { "filename": "metal_coat", "rotated": false, @@ -2691,8 +2775,8 @@ "h": 22 }, "frame": { - "x": 201, - "y": 126, + "x": 260, + "y": 127, "w": 19, "h": 22 } @@ -2712,71 +2796,8 @@ "h": 22 }, "frame": { - "x": 220, - "y": 127, - "w": 22, - "h": 22 - } - }, - { - "filename": "healing_charm", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 23, - "h": 22 - }, - "frame": { - "x": 242, - "y": 127, - "w": 23, - "h": 22 - } - }, - { - "filename": "ice_stone", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 265, - "y": 127, - "w": 22, - "h": 22 - } - }, - { - "filename": "magmarizer", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 287, - "y": 130, + "x": 279, + "y": 128, "w": 22, "h": 22 } @@ -2796,14 +2817,56 @@ "h": 22 }, "frame": { - "x": 0, - "y": 144, + "x": 301, + "y": 128, "w": 17, "h": 22 } }, { - "filename": "mini_black_hole", + "filename": "healing_charm", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 23, + "h": 22 + }, + "frame": { + "x": 0, + "y": 143, + "w": 23, + "h": 22 + } + }, + { + "filename": "full_heal", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 9, + "y": 4, + "w": 15, + "h": 23 + }, + "frame": { + "x": 23, + "y": 143, + "w": 15, + "h": 23 + } + }, + { + "filename": "ice_stone", "rotated": false, "trimmed": true, "sourceSize": { @@ -2817,50 +2880,8 @@ "h": 22 }, "frame": { - "x": 17, - "y": 145, - "w": 22, - "h": 22 - } - }, - { - "filename": "map", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 3, - "y": 5, - "w": 27, - "h": 22 - }, - "frame": { - "x": 39, - "y": 146, - "w": 27, - "h": 22 - } - }, - { - "filename": "protector", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 66, - "y": 146, + "x": 38, + "y": 144, "w": 22, "h": 22 } @@ -2880,12 +2901,117 @@ "h": 22 }, "frame": { - "x": 88, - "y": 146, + "x": 60, + "y": 144, "w": 20, "h": 22 } }, + { + "filename": "magmarizer", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 80, + "y": 146, + "w": 22, + "h": 22 + } + }, + { + "filename": "mini_black_hole", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 102, + "y": 146, + "w": 22, + "h": 22 + } + }, + { + "filename": "map", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 3, + "y": 5, + "w": 27, + "h": 22 + }, + "frame": { + "x": 124, + "y": 147, + "w": 27, + "h": 22 + } + }, + { + "filename": "hyper_potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 5, + "w": 17, + "h": 23 + }, + "frame": { + "x": 151, + "y": 147, + "w": 17, + "h": 23 + } + }, + { + "filename": "protector", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 168, + "y": 148, + "w": 22, + "h": 22 + } + }, { "filename": "shed_shell", "rotated": false, @@ -2901,8 +3027,8 @@ "h": 22 }, "frame": { - "x": 108, - "y": 147, + "x": 190, + "y": 148, "w": 22, "h": 22 } @@ -2922,8 +3048,8 @@ "h": 22 }, "frame": { - "x": 130, - "y": 147, + "x": 212, + "y": 148, "w": 22, "h": 22 } @@ -2943,8 +3069,8 @@ "h": 22 }, "frame": { - "x": 152, - "y": 147, + "x": 234, + "y": 149, "w": 22, "h": 22 } @@ -2964,8 +3090,8 @@ "h": 22 }, "frame": { - "x": 174, - "y": 148, + "x": 256, + "y": 149, "w": 22, "h": 22 } @@ -2985,12 +3111,33 @@ "h": 22 }, "frame": { - "x": 196, - "y": 148, + "x": 278, + "y": 150, "w": 22, "h": 22 } }, + { + "filename": "mystic_water", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 6, + "y": 5, + "w": 20, + "h": 23 + }, + "frame": { + "x": 300, + "y": 150, + "w": 20, + "h": 23 + } + }, { "filename": "tm_dragon", "rotated": false, @@ -3006,8 +3153,8 @@ "h": 22 }, "frame": { - "x": 218, - "y": 149, + "x": 0, + "y": 165, "w": 22, "h": 22 } @@ -3027,8 +3174,8 @@ "h": 22 }, "frame": { - "x": 240, - "y": 149, + "x": 22, + "y": 166, "w": 22, "h": 22 } @@ -3048,8 +3195,8 @@ "h": 22 }, "frame": { - "x": 262, - "y": 149, + "x": 44, + "y": 166, "w": 22, "h": 22 } @@ -3069,33 +3216,12 @@ "h": 22 }, "frame": { - "x": 284, - "y": 152, + "x": 66, + "y": 168, "w": 22, "h": 22 } }, - { - "filename": "full_heal", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 9, - "y": 4, - "w": 15, - "h": 23 - }, - "frame": { - "x": 0, - "y": 166, - "w": 15, - "h": 23 - } - }, { "filename": "tm_fire", "rotated": false, @@ -3111,8 +3237,8 @@ "h": 22 }, "frame": { - "x": 15, - "y": 167, + "x": 88, + "y": 168, "w": 22, "h": 22 } @@ -3132,12 +3258,33 @@ "h": 22 }, "frame": { - "x": 37, - "y": 168, + "x": 110, + "y": 169, "w": 22, "h": 22 } }, + { + "filename": "potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 5, + "w": 17, + "h": 23 + }, + "frame": { + "x": 132, + "y": 169, + "w": 17, + "h": 23 + } + }, { "filename": "tm_ghost", "rotated": false, @@ -3153,8 +3300,8 @@ "h": 22 }, "frame": { - "x": 59, - "y": 168, + "x": 149, + "y": 170, "w": 22, "h": 22 } @@ -3174,8 +3321,8 @@ "h": 22 }, "frame": { - "x": 81, - "y": 168, + "x": 171, + "y": 170, "w": 22, "h": 22 } @@ -3195,12 +3342,33 @@ "h": 22 }, "frame": { - "x": 103, - "y": 169, + "x": 193, + "y": 170, "w": 22, "h": 22 } }, + { + "filename": "super_potion", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 5, + "w": 17, + "h": 23 + }, + "frame": { + "x": 215, + "y": 170, + "w": 17, + "h": 23 + } + }, { "filename": "tm_ice", "rotated": false, @@ -3216,8 +3384,8 @@ "h": 22 }, "frame": { - "x": 125, - "y": 169, + "x": 232, + "y": 171, "w": 22, "h": 22 } @@ -3237,8 +3405,8 @@ "h": 22 }, "frame": { - "x": 147, - "y": 169, + "x": 254, + "y": 171, "w": 22, "h": 22 } @@ -3258,8 +3426,8 @@ "h": 22 }, "frame": { - "x": 169, - "y": 170, + "x": 276, + "y": 172, "w": 22, "h": 22 } @@ -3279,8 +3447,8 @@ "h": 22 }, "frame": { - "x": 191, - "y": 170, + "x": 298, + "y": 173, "w": 22, "h": 22 } @@ -3300,8 +3468,8 @@ "h": 22 }, "frame": { - "x": 213, - "y": 171, + "x": 0, + "y": 187, "w": 22, "h": 22 } @@ -3321,8 +3489,8 @@ "h": 22 }, "frame": { - "x": 235, - "y": 171, + "x": 22, + "y": 188, "w": 22, "h": 22 } @@ -3342,8 +3510,8 @@ "h": 22 }, "frame": { - "x": 257, - "y": 171, + "x": 44, + "y": 188, "w": 22, "h": 22 } @@ -3362,111 +3530,6 @@ "w": 22, "h": 22 }, - "frame": { - "x": 279, - "y": 174, - "w": 22, - "h": 22 - } - }, - { - "filename": "hyper_potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 5, - "w": 17, - "h": 23 - }, - "frame": { - "x": 301, - "y": 174, - "w": 17, - "h": 23 - } - }, - { - "filename": "x_accuracy", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 0, - "y": 189, - "w": 22, - "h": 22 - } - }, - { - "filename": "x_attack", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 22, - "y": 190, - "w": 22, - "h": 22 - } - }, - { - "filename": "x_defense", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, - "frame": { - "x": 44, - "y": 190, - "w": 22, - "h": 22 - } - }, - { - "filename": "x_sp_atk", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 5, - "w": 22, - "h": 22 - }, "frame": { "x": 66, "y": 190, @@ -3475,7 +3538,7 @@ } }, { - "filename": "x_sp_def", + "filename": "x_accuracy", "rotated": false, "trimmed": true, "sourceSize": { @@ -3490,13 +3553,13 @@ }, "frame": { "x": 88, - "y": 191, + "y": 190, "w": 22, "h": 22 } }, { - "filename": "x_speed", + "filename": "x_attack", "rotated": false, "trimmed": true, "sourceSize": { @@ -3516,6 +3579,90 @@ "h": 22 } }, + { + "filename": "x_defense", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 132, + "y": 192, + "w": 22, + "h": 22 + } + }, + { + "filename": "x_sp_atk", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 154, + "y": 192, + "w": 22, + "h": 22 + } + }, + { + "filename": "x_sp_def", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 176, + "y": 192, + "w": 22, + "h": 22 + } + }, + { + "filename": "x_speed", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 5, + "w": 22, + "h": 22 + }, + "frame": { + "x": 198, + "y": 193, + "w": 22, + "h": 22 + } + }, { "filename": "berry_pouch", "rotated": false, @@ -3531,8 +3678,8 @@ "h": 23 }, "frame": { - "x": 132, - "y": 191, + "x": 220, + "y": 193, "w": 23, "h": 23 } @@ -3552,8 +3699,8 @@ "h": 23 }, "frame": { - "x": 155, - "y": 192, + "x": 243, + "y": 193, "w": 22, "h": 23 } @@ -3573,8 +3720,8 @@ "h": 23 }, "frame": { - "x": 177, - "y": 192, + "x": 265, + "y": 194, "w": 24, "h": 23 } @@ -3594,8 +3741,8 @@ "h": 23 }, "frame": { - "x": 201, - "y": 193, + "x": 289, + "y": 195, "w": 24, "h": 23 } @@ -3615,8 +3762,8 @@ "h": 23 }, "frame": { - "x": 225, - "y": 193, + "x": 0, + "y": 209, "w": 21, "h": 23 } @@ -3636,12 +3783,33 @@ "h": 23 }, "frame": { - "x": 246, - "y": 193, + "x": 21, + "y": 210, "w": 24, "h": 23 } }, + { + "filename": "lansat_berry", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 4, + "w": 21, + "h": 23 + }, + "frame": { + "x": 45, + "y": 210, + "w": 21, + "h": 23 + } + }, { "filename": "fire_stone", "rotated": false, @@ -3657,8 +3825,8 @@ "h": 23 }, "frame": { - "x": 270, - "y": 196, + "x": 66, + "y": 212, "w": 22, "h": 23 } @@ -3678,33 +3846,12 @@ "h": 23 }, "frame": { - "x": 292, - "y": 197, + "x": 88, + "y": 212, "w": 22, "h": 23 } }, - { - "filename": "lansat_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 4, - "w": 21, - "h": 23 - }, - "frame": { - "x": 0, - "y": 211, - "w": 21, - "h": 23 - } - }, { "filename": "leaf_stone", "rotated": false, @@ -3720,33 +3867,12 @@ "h": 23 }, "frame": { - "x": 21, - "y": 212, + "x": 110, + "y": 213, "w": 21, "h": 23 } }, - { - "filename": "mystic_water", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 6, - "y": 5, - "w": 20, - "h": 23 - }, - "frame": { - "x": 42, - "y": 212, - "w": 20, - "h": 23 - } - }, { "filename": "never_melt_ice", "rotated": false, @@ -3762,8 +3888,8 @@ "h": 23 }, "frame": { - "x": 62, - "y": 212, + "x": 131, + "y": 214, "w": 22, "h": 23 } @@ -3783,33 +3909,12 @@ "h": 23 }, "frame": { - "x": 84, - "y": 213, + "x": 153, + "y": 214, "w": 22, "h": 23 } }, - { - "filename": "potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 5, - "w": 17, - "h": 23 - }, - "frame": { - "x": 106, - "y": 213, - "w": 17, - "h": 23 - } - }, { "filename": "rare_candy", "rotated": false, @@ -3825,33 +3930,12 @@ "h": 23 }, "frame": { - "x": 123, + "x": 175, "y": 214, "w": 23, "h": 23 } }, - { - "filename": "rarer_candy", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 5, - "w": 23, - "h": 23 - }, - "frame": { - "x": 146, - "y": 215, - "w": 23, - "h": 23 - } - }, { "filename": "reaper_cloth", "rotated": false, @@ -3867,14 +3951,14 @@ "h": 23 }, "frame": { - "x": 169, + "x": 198, "y": 215, "w": 22, "h": 23 } }, { - "filename": "scope-lens", + "filename": "rarer_candy", "rotated": false, "trimmed": true, "sourceSize": { @@ -3884,13 +3968,13 @@ "spriteSourceSize": { "x": 4, "y": 5, - "w": 24, + "w": 23, "h": 23 }, "frame": { - "x": 191, + "x": 220, "y": 216, - "w": 24, + "w": 23, "h": 23 } }, @@ -3909,12 +3993,33 @@ "h": 23 }, "frame": { - "x": 215, + "x": 243, "y": 216, "w": 21, "h": 23 } }, + { + "filename": "scope-lens", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 5, + "w": 24, + "h": 23 + }, + "frame": { + "x": 264, + "y": 217, + "w": 24, + "h": 23 + } + }, { "filename": "stick", "rotated": false, @@ -3930,33 +4035,12 @@ "h": 23 }, "frame": { - "x": 236, - "y": 216, + "x": 288, + "y": 218, "w": 23, "h": 23 } }, - { - "filename": "super_potion", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 5, - "w": 17, - "h": 23 - }, - "frame": { - "x": 259, - "y": 219, - "w": 17, - "h": 23 - } - }, { "filename": "calcium", "rotated": false, @@ -3972,8 +4056,8 @@ "h": 24 }, "frame": { - "x": 276, - "y": 219, + "x": 0, + "y": 232, "w": 16, "h": 24 } @@ -3993,33 +4077,12 @@ "h": 23 }, "frame": { - "x": 292, - "y": 220, + "x": 16, + "y": 233, "w": 24, "h": 23 } }, - { - "filename": "carbos", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 0, - "y": 234, - "w": 16, - "h": 24 - } - }, { "filename": "big_root", "rotated": false, @@ -4035,12 +4098,33 @@ "h": 24 }, "frame": { - "x": 16, - "y": 235, + "x": 40, + "y": 233, "w": 23, "h": 24 } }, + { + "filename": "carbos", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 63, + "y": 235, + "w": 16, + "h": 24 + } + }, { "filename": "catching_charm", "rotated": false, @@ -4056,7 +4140,7 @@ "h": 24 }, "frame": { - "x": 39, + "x": 79, "y": 235, "w": 21, "h": 24 @@ -4077,8 +4161,8 @@ "h": 24 }, "frame": { - "x": 60, - "y": 235, + "x": 100, + "y": 236, "w": 24, "h": 24 } @@ -4098,8 +4182,8 @@ "h": 24 }, "frame": { - "x": 84, - "y": 236, + "x": 124, + "y": 237, "w": 18, "h": 24 } @@ -4119,8 +4203,8 @@ "h": 24 }, "frame": { - "x": 102, - "y": 236, + "x": 142, + "y": 237, "w": 18, "h": 24 } @@ -4140,7 +4224,7 @@ "h": 24 }, "frame": { - "x": 120, + "x": 160, "y": 237, "w": 24, "h": 24 @@ -4161,54 +4245,12 @@ "h": 24 }, "frame": { - "x": 144, + "x": 184, "y": 238, "w": 18, "h": 24 } }, - { - "filename": "golden_punch", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 162, - "y": 238, - "w": 24, - "h": 24 - } - }, - { - "filename": "grip_claw", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 186, - "y": 239, - "w": 24, - "h": 24 - } - }, { "filename": "hp_up", "rotated": false, @@ -4224,12 +4266,33 @@ "h": 24 }, "frame": { - "x": 210, - "y": 239, + "x": 202, + "y": 238, "w": 16, "h": 24 } }, + { + "filename": "golden_punch", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 218, + "y": 239, + "w": 24, + "h": 24 + } + }, { "filename": "iron", "rotated": false, @@ -4245,12 +4308,96 @@ "h": 24 }, "frame": { - "x": 226, + "x": 242, "y": 239, "w": 16, "h": 24 } }, + { + "filename": "grip_claw", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 258, + "y": 240, + "w": 24, + "h": 24 + } + }, + { + "filename": "kings_rock", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 4, + "w": 23, + "h": 24 + }, + "frame": { + "x": 282, + "y": 241, + "w": 23, + "h": 24 + } + }, + { + "filename": "lucky_punch", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 0, + "y": 256, + "w": 24, + "h": 24 + } + }, + { + "filename": "pp_max", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 24, + "y": 256, + "w": 16, + "h": 24 + } + }, { "filename": "lure", "rotated": false, @@ -4266,117 +4413,12 @@ "h": 24 }, "frame": { - "x": 242, - "y": 239, + "x": 40, + "y": 257, "w": 17, "h": 24 } }, - { - "filename": "max_lure", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 17, - "h": 24 - }, - "frame": { - "x": 259, - "y": 242, - "w": 17, - "h": 24 - } - }, - { - "filename": "kings_rock", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 4, - "w": 23, - "h": 24 - }, - "frame": { - "x": 276, - "y": 243, - "w": 23, - "h": 24 - } - }, - { - "filename": "max_elixir", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 7, - "y": 4, - "w": 18, - "h": 24 - }, - "frame": { - "x": 299, - "y": 243, - "w": 18, - "h": 24 - } - }, - { - "filename": "pp_max", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 0, - "y": 258, - "w": 16, - "h": 24 - } - }, - { - "filename": "lucky_punch", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 16, - "y": 259, - "w": 24, - "h": 24 - } - }, { "filename": "lucky_punch_great", "rotated": false, @@ -4392,14 +4434,14 @@ "h": 24 }, "frame": { - "x": 40, + "x": 57, "y": 259, "w": 24, "h": 24 } }, { - "filename": "max_ether", + "filename": "max_elixir", "rotated": false, "trimmed": true, "sourceSize": { @@ -4413,7 +4455,7 @@ "h": 24 }, "frame": { - "x": 64, + "x": 81, "y": 259, "w": 18, "h": 24 @@ -4434,7 +4476,7 @@ "h": 24 }, "frame": { - "x": 82, + "x": 99, "y": 260, "w": 24, "h": 24 @@ -4455,12 +4497,54 @@ "h": 24 }, "frame": { - "x": 106, + "x": 123, "y": 261, "w": 24, "h": 24 } }, + { + "filename": "max_ether", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 7, + "y": 4, + "w": 18, + "h": 24 + }, + "frame": { + "x": 147, + "y": 261, + "w": 18, + "h": 24 + } + }, + { + "filename": "max_lure", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 17, + "h": 24 + }, + "frame": { + "x": 165, + "y": 261, + "w": 17, + "h": 24 + } + }, { "filename": "max_potion", "rotated": false, @@ -4476,33 +4560,12 @@ "h": 24 }, "frame": { - "x": 130, + "x": 182, "y": 262, "w": 18, "h": 24 } }, - { - "filename": "max_revive", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 5, - "y": 4, - "w": 22, - "h": 24 - }, - "frame": { - "x": 148, - "y": 262, - "w": 22, - "h": 24 - } - }, { "filename": "pp_up", "rotated": false, @@ -4518,12 +4581,54 @@ "h": 24 }, "frame": { - "x": 170, + "x": 200, "y": 262, "w": 16, "h": 24 } }, + { + "filename": "max_revive", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 5, + "y": 4, + "w": 22, + "h": 24 + }, + "frame": { + "x": 216, + "y": 263, + "w": 22, + "h": 24 + } + }, + { + "filename": "protein", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 238, + "y": 263, + "w": 16, + "h": 24 + } + }, { "filename": "muscle_band", "rotated": false, @@ -4539,8 +4644,8 @@ "h": 24 }, "frame": { - "x": 186, - "y": 263, + "x": 254, + "y": 264, "w": 24, "h": 24 } @@ -4560,117 +4665,12 @@ "h": 24 }, "frame": { - "x": 210, - "y": 263, + "x": 278, + "y": 265, "w": 21, "h": 24 } }, - { - "filename": "protein", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 231, - "y": 263, - "w": 16, - "h": 24 - } - }, - { - "filename": "reveal_glass", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 23, - "h": 24 - }, - "frame": { - "x": 247, - "y": 266, - "w": 23, - "h": 24 - } - }, - { - "filename": "salac_berry", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 270, - "y": 267, - "w": 24, - "h": 24 - } - }, - { - "filename": "scanner", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 4, - "y": 4, - "w": 24, - "h": 24 - }, - "frame": { - "x": 294, - "y": 267, - "w": 24, - "h": 24 - } - }, - { - "filename": "unknown", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 32, - "h": 32 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 16, - "h": 24 - }, - "frame": { - "x": 0, - "y": 282, - "w": 16, - "h": 24 - } - }, { "filename": "shiny_charm", "rotated": false, @@ -4686,14 +4686,14 @@ "h": 24 }, "frame": { - "x": 16, - "y": 283, + "x": 299, + "y": 265, "w": 21, "h": 24 } }, { - "filename": "silk_scarf", + "filename": "reveal_glass", "rotated": false, "trimmed": true, "sourceSize": { @@ -4703,13 +4703,13 @@ "spriteSourceSize": { "x": 4, "y": 4, - "w": 24, + "w": 23, "h": 24 }, "frame": { - "x": 37, - "y": 283, - "w": 24, + "x": 0, + "y": 280, + "w": 23, "h": 24 } }, @@ -4728,14 +4728,35 @@ "h": 24 }, "frame": { - "x": 61, - "y": 283, + "x": 23, + "y": 280, "w": 17, "h": 24 } }, { - "filename": "sun_stone", + "filename": "unknown", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 8, + "y": 4, + "w": 16, + "h": 24 + }, + "frame": { + "x": 40, + "y": 281, + "w": 16, + "h": 24 + } + }, + { + "filename": "salac_berry", "rotated": false, "trimmed": true, "sourceSize": { @@ -4749,8 +4770,8 @@ "h": 24 }, "frame": { - "x": 78, - "y": 284, + "x": 56, + "y": 283, "w": 24, "h": 24 } @@ -4770,12 +4791,75 @@ "h": 24 }, "frame": { - "x": 102, - "y": 285, + "x": 80, + "y": 283, "w": 16, "h": 24 } }, + { + "filename": "scanner", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 96, + "y": 284, + "w": 24, + "h": 24 + } + }, + { + "filename": "silk_scarf", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 120, + "y": 285, + "w": 24, + "h": 24 + } + }, + { + "filename": "sun_stone", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 32, + "h": 32 + }, + "spriteSourceSize": { + "x": 4, + "y": 4, + "w": 24, + "h": 24 + }, + "frame": { + "x": 144, + "y": 285, + "w": 24, + "h": 24 + } + }, { "filename": "ability_charm", "rotated": false, @@ -4791,7 +4875,7 @@ "h": 26 }, "frame": { - "x": 118, + "x": 168, "y": 286, "w": 23, "h": 26 @@ -4812,8 +4896,8 @@ "h": 26 }, "frame": { - "x": 141, - "y": 286, + "x": 191, + "y": 287, "w": 27, "h": 26 } @@ -4833,8 +4917,8 @@ "h": 31 }, "frame": { - "x": 168, - "y": 286, + "x": 218, + "y": 287, "w": 17, "h": 31 } @@ -4854,7 +4938,7 @@ "h": 31 }, "frame": { - "x": 185, + "x": 235, "y": 287, "w": 17, "h": 31 @@ -4875,8 +4959,8 @@ "h": 31 }, "frame": { - "x": 202, - "y": 287, + "x": 252, + "y": 288, "w": 17, "h": 31 } @@ -4887,6 +4971,6 @@ "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:357b8dcf0ed67d82a9e8f39b048a9d91:4c1f7a668341620ca5ab8d05f49f8946:110e074689c9edd2c54833ce2e4d9270$" + "smartupdate": "$TexturePacker:SmartUpdate:2c02d802e31fc2d6bc57df9348890d2b:160f2fe36d715f1125159d665c96df73:110e074689c9edd2c54833ce2e4d9270$" } } diff --git a/public/images/items.png b/public/images/items.png index 23302c9e524..daa7f46b04e 100644 Binary files a/public/images/items.png and b/public/images/items.png differ diff --git a/public/images/items/coupon.png b/public/images/items/coupon.png new file mode 100644 index 00000000000..b1e8089b485 Binary files /dev/null and b/public/images/items/coupon.png differ diff --git a/public/images/items/golden_mystic_ticket.png b/public/images/items/golden_mystic_ticket.png new file mode 100644 index 00000000000..ff44d3307b6 Binary files /dev/null and b/public/images/items/golden_mystic_ticket.png differ diff --git a/public/images/items/mystic_ticket.png b/public/images/items/mystic_ticket.png new file mode 100644 index 00000000000..bd206998fed Binary files /dev/null and b/public/images/items/mystic_ticket.png differ diff --git a/public/images/items/pair_of_tickets.png b/public/images/items/pair_of_tickets.png new file mode 100644 index 00000000000..b4b6ececbd2 Binary files /dev/null and b/public/images/items/pair_of_tickets.png differ diff --git a/public/images/pokemon/icons/egg/0.png b/public/images/pokemon/icons/egg/0.png new file mode 100644 index 00000000000..33473696ec5 Binary files /dev/null and b/public/images/pokemon/icons/egg/0.png differ diff --git a/public/images/pokemon/icons/egg/1.png b/public/images/pokemon/icons/egg/1.png new file mode 100644 index 00000000000..e3166fe95bc Binary files /dev/null and b/public/images/pokemon/icons/egg/1.png differ diff --git a/public/images/pokemon/icons/egg/2.png b/public/images/pokemon/icons/egg/2.png new file mode 100644 index 00000000000..c9f302da435 Binary files /dev/null and b/public/images/pokemon/icons/egg/2.png differ diff --git a/public/images/pokemon/icons/egg/3.png b/public/images/pokemon/icons/egg/3.png new file mode 100644 index 00000000000..7b5264d6099 Binary files /dev/null and b/public/images/pokemon/icons/egg/3.png differ diff --git a/public/images/pokemon/icons/egg/manaphy.png b/public/images/pokemon/icons/egg/manaphy.png new file mode 100644 index 00000000000..93762fb282f Binary files /dev/null and b/public/images/pokemon/icons/egg/manaphy.png differ diff --git a/public/images/ui/egg_list_bg.png b/public/images/ui/egg_list_bg.png new file mode 100644 index 00000000000..5600a3e6ab7 Binary files /dev/null and b/public/images/ui/egg_list_bg.png differ diff --git a/src/battle-phases.ts b/src/battle-phases.ts index bc90b37a4cf..53a515fa44d 100644 --- a/src/battle-phases.ts +++ b/src/battle-phases.ts @@ -34,7 +34,10 @@ import { Species } from "./data/species"; import { HealAchv, LevelAchv, MoneyAchv, achvs } from "./system/achv"; import { DexEntry } from "./system/game-data"; import { pokemonPrevolutions } from "./data/pokemon-evolutions"; -import { trainerConfigs } from "./data/trainer-type"; +import { TrainerType, trainerConfigs } from "./data/trainer-type"; +import { EggHatchPhase } from "./egg-hatch-phase"; +import { Egg } from "./data/egg"; +import { vouchers } from "./system/voucher"; export class CheckLoadPhase extends BattlePhase { private loaded: boolean; @@ -92,6 +95,11 @@ export class CheckLoadPhase extends BattlePhase { } } + for (let achv of Object.keys(this.scene.gameData.achvUnlocks)) { + if (vouchers.hasOwnProperty(achv)) + this.scene.validateVoucher(vouchers[achv]); + } + super.end(); } } @@ -2338,6 +2346,7 @@ export class VictoryPhase extends PokemonPhase { this.scene.pushPhase(new BattleEndPhase(this.scene)); if (this.scene.currentBattle.battleType === BattleType.TRAINER) this.scene.pushPhase(new TrainerVictoryPhase(this.scene)); + this.scene.pushPhase(new EggLapsePhase(this.scene)); if (this.scene.gameMode !== GameMode.CLASSIC || this.scene.currentBattle.waveIndex < this.scene.finalWave) { if (this.scene.currentBattle.waveIndex % 10) this.scene.pushPhase(new SelectModifierPhase(this.scene)); @@ -2347,8 +2356,10 @@ export class VictoryPhase extends PokemonPhase { if (this.scene.currentBattle.waveIndex <= 150 && !(this.scene.currentBattle.waveIndex % 50)) this.scene.pushPhase(new ModifierRewardPhase(this.scene, modifierTypes.GOLDEN_POKEBALL)); } - if (this.scene.gameMode !== GameMode.CLASSIC && !(this.scene.currentBattle.waveIndex % 50)) + if (this.scene.gameMode !== GameMode.CLASSIC && !(this.scene.currentBattle.waveIndex % 50)) { + this.scene.pushPhase(new ModifierRewardPhase(this.scene, modifierTypes.VOUCHER)); this.scene.pushPhase(new AddEnemyBuffModifierPhase(this.scene)); + } } this.scene.pushPhase(new NewBattlePhase(this.scene)); } else @@ -2367,6 +2378,10 @@ export class TrainerVictoryPhase extends BattlePhase { start() { this.scene.playBgm(this.scene.currentBattle.trainer.config.victoryBgm); + const trainerType = this.scene.currentBattle.trainer.config.trainerType; + if (vouchers.hasOwnProperty(TrainerType[trainerType])) + this.scene.validateVoucher(vouchers[TrainerType[trainerType]]); + this.scene.unshiftPhase(new MoneyRewardPhase(this.scene, this.scene.currentBattle.trainer.config.moneyMultiplier)); const modifierRewardFuncs = this.scene.currentBattle.trainer.config.modifierRewardFuncs; @@ -2964,18 +2979,7 @@ export class AttemptCapturePhase extends PokemonPhase { if (pokemon.species.mythical) this.scene.validateAchv(achvs.CATCH_MYTHICAL); - let dexEntry: DexEntry; - let speciesId = pokemon.species.speciesId; - do { - dexEntry = this.scene.gameData.dexData[speciesId]; - const dexIvs = dexEntry.ivs; - for (let i = 0; i < dexIvs.length; i++) { - if (dexIvs[i] < pokemon.ivs[i]) - dexIvs[i] = pokemon.ivs[i]; - } - if (dexIvs.filter(iv => iv === 31).length === 6) - this.scene.validateAchv(achvs.PERFECT_IVS); - } while (pokemonPrevolutions.hasOwnProperty(speciesId) && (speciesId = pokemonPrevolutions[speciesId])); + this.scene.gameData.updateSpeciesDexIvs(pokemon.species.speciesId, pokemon.ivs); this.scene.ui.showText(`${pokemon.name} was caught!`, null, () => { const end = () => { @@ -3229,6 +3233,31 @@ export class SelectModifierPhase extends BattlePhase { } } +export class EggLapsePhase extends BattlePhase { + constructor(scene: BattleScene) { + super(scene); + } + + start() { + super.start(); + + const eggsToHatch: Egg[] = []; + + for (let egg of this.scene.gameData.eggs) { + if (--egg.hatchWaves < 1) + eggsToHatch.push(egg); + } + + if (eggsToHatch.length) + this.scene.queueMessage('Oh?'); + + for (let egg of eggsToHatch) + this.scene.unshiftPhase(new EggHatchPhase(this.scene, egg)); + + this.end(); + } +} + export class AddEnemyBuffModifierPhase extends BattlePhase { constructor(scene: BattleScene) { super(scene); diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 87657ff302a..36a8913dc3f 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -35,6 +35,8 @@ import MessageUiHandler from './ui/message-ui-handler'; import { Species } from './data/species'; import InvertPostFX from './pipelines/invert'; import { Achv, ModifierAchv, achvs } from './system/achv'; +import { GachaType } from './data/egg'; +import { Voucher, vouchers } from './system/voucher'; const enableAuto = true; const quickStart = false; @@ -301,10 +303,22 @@ export default class BattleScene extends Phaser.Scene { this.loadAtlas('types', ''); this.loadAtlas('statuses', ''); this.loadAtlas('categories', ''); - this.loadAtlas('egg', ''); - this.loadAtlas('egg_crack', ''); - this.loadAtlas('egg_shard', ''); - this.loadAtlas('egg_lightrays', ''); + + this.loadAtlas('egg', 'egg'); + this.loadAtlas('egg_crack', 'egg'); + this.loadAtlas('egg_icons', 'egg'); + this.loadAtlas('egg_shard', 'egg'); + this.loadAtlas('egg_lightrays', 'egg'); + Utils.getEnumKeys(GachaType).forEach(gt => { + const key = gt.toLowerCase(); + this.loadImage(`gacha_${key}`, 'egg'); + this.loadAtlas(`gacha_underlay_${key}`, 'egg'); + }); + this.loadImage('gacha_glass', 'egg'); + this.loadAtlas('gacha_hatch', 'egg'); + this.loadImage('gacha_knob', 'egg'); + + this.loadImage('egg_list_bg', 'ui'); for (let i = 0; i < 10; i++) this.loadAtlas(`pokemon_icons_${i}`, 'ui'); @@ -345,6 +359,9 @@ export default class BattleScene extends Phaser.Scene { this.loadSe('egg_crack'); this.loadSe('egg_hatch'); + this.loadSe('gacha_dial'); + this.loadSe('gacha_running'); + this.loadSe('gacha_dispense'); this.loadSe('PRSFX- Transform', 'battle_anims'); @@ -713,10 +730,7 @@ export default class BattleScene extends Phaser.Scene { this.currentBattle.incrementTurn(this); //this.pushPhase(new TrainerMessageTestPhase(this)); - - //for (let t = 0; t < 4; t++) - //this.pushPhase(new EggHatchPhase(this, new Egg(2423432 + EGG_SEED * t, GachaType.LEGENDARY, new Date().getTime()))); - + if (!waveIndex) { const isNewBiome = !lastBattle || !(lastBattle.waveIndex % 10); const resetArenaState = isNewBiome || this.currentBattle.battleType === BattleType.TRAINER; @@ -1447,7 +1461,6 @@ export default class BattleScene extends Phaser.Scene { validateAchvs(achvType: { new(...args: any[]): Achv }, ...args: any[]): void { const filteredAchvs = Object.values(achvs).filter(a => a instanceof achvType); - let newAchv = false; for (let achv of filteredAchvs) this.validateAchv(achv, args); } @@ -1456,6 +1469,19 @@ export default class BattleScene extends Phaser.Scene { if (!this.gameData.achvUnlocks.hasOwnProperty(achv.id) && achv.validate(this, args)) { this.gameData.achvUnlocks[achv.id] = new Date().getTime(); this.ui.achvBar.showAchv(achv); + if (vouchers.hasOwnProperty(achv.id)) + this.validateVoucher(vouchers[achv.id]); + return true; + } + + return false; + } + + validateVoucher(voucher: Voucher, args?: any[]): boolean { + if (!this.gameData.voucherUnlocks.hasOwnProperty(voucher.id) && voucher.validate(this, args)) { + this.gameData.voucherUnlocks[voucher.id] = new Date().getTime(); + this.ui.achvBar.showAchv(voucher); + this.gameData.voucherCounts[voucher.voucherType]++; return true; } diff --git a/src/data/biome.ts b/src/data/biome.ts index d13d4a651f8..26f08c97da3 100644 --- a/src/data/biome.ts +++ b/src/data/biome.ts @@ -181,24 +181,20 @@ export const biomePokemonPools: BiomePokemonPools = { Species.VENONAT, Species.MEOWTH, Species.BELLSPROUT, - Species.PICHU, - Species.IGGLYBUFF, Species.LOTAD, Species.SEEDOT, Species.SHROOMISH, Species.NINCADA, Species.WHISMUR, - Species.AZURILL, Species.SKITTY, Species.KRICKETOT, - Species.BUDEW, Species.COMBEE, Species.CHERUBI, Species.VENIPEDE, Species.MINCCINO ], - [BiomePoolTier.RARE]: [ Species.ABRA, Species.CLEFFA, Species.SURSKIT ], - [BiomePoolTier.SUPER_RARE]: [ Species.EEVEE, Species.TOGEPI, Species.TYROGUE, Species.SMOOCHUM, Species.ELEKID, Species.MAGBY, Species.RALTS, Species.WYNAUT, Species.BONSLY, Species.MIME_JR, Species.HAPPINY, Species.MUNCHLAX, Species.RIOLU ], + [BiomePoolTier.RARE]: [ Species.ABRA, Species.SURSKIT ], + [BiomePoolTier.SUPER_RARE]: [ Species.EEVEE, Species.RALTS ], [BiomePoolTier.ULTRA_RARE]: [ Species.DITTO ], [BiomePoolTier.BOSS]: [], [BiomePoolTier.BOSS_RARE]: [], @@ -250,7 +246,7 @@ export const biomePokemonPools: BiomePokemonPools = { [BiomePoolTier.BOSS]: [ Species.JUMPLUFF, Species.SUNFLORA, Species.WHIMSICOTT ], [BiomePoolTier.BOSS_RARE]: [ Species.VENUSAUR, Species.SUDOWOODO, Species.TORTERRA ], [BiomePoolTier.BOSS_SUPER_RARE]: [], - [BiomePoolTier.BOSS_ULTRA_RARE]: [ Species.SHAYMIN ] + [BiomePoolTier.BOSS_ULTRA_RARE]: [] }, [Biome.TALL_GRASS]: { [BiomePoolTier.COMMON]: [ @@ -329,7 +325,7 @@ export const biomePokemonPools: BiomePokemonPools = { { 1: [ Species.ROWLET ], 17: [ Species.DARTRIX ], 36: [ Species.DECIDUEYE ] } ], [BiomePoolTier.SUPER_RARE]: [ Species.DURANT ], - [BiomePoolTier.ULTRA_RARE]: [ Species.CELEBI, Species.KARTANA ], + [BiomePoolTier.ULTRA_RARE]: [ Species.KARTANA ], [BiomePoolTier.BOSS]: [ Species.VENOMOTH, Species.VICTREEBEL, @@ -351,7 +347,7 @@ export const biomePokemonPools: BiomePokemonPools = { ], [BiomePoolTier.BOSS_RARE]: [ Species.HERACROSS, Species.STANTLER, Species.SCEPTILE, Species.ESCAVALIER, Species.ACCELGOR, Species.DURANT, Species.CHESNAUGHT, Species.DECIDUEYE, Species.LYCANROC ], [BiomePoolTier.BOSS_SUPER_RARE]: [ Species.KARTANA ], - [BiomePoolTier.BOSS_ULTRA_RARE]: [ Species.CELEBI, Species.CALYREX ] + [BiomePoolTier.BOSS_ULTRA_RARE]: [ Species.CALYREX ] }, [Biome.SEA]: { [BiomePoolTier.COMMON]: [ @@ -474,7 +470,7 @@ export const biomePokemonPools: BiomePokemonPools = { { 1: [ Species.SKRELP ], 48: [ Species.DRAGALGE ] }, Species.PINCURCHIN ], - [BiomePoolTier.RARE]: [ Species.QWILFISH, Species.CORSOLA, Species.OCTILLERY, { 1: [ Species.MANTYKE ], 20: [ Species.MANTINE ] }, Species.PHIONE, Species.ALOMOMOLA, { 1: [ Species.TYNAMO ], 39: [ Species.EELEKTRIK ] }, Species.DHELMISE ], + [BiomePoolTier.RARE]: [ Species.QWILFISH, Species.CORSOLA, Species.OCTILLERY, { 1: [ Species.MANTYKE ], 20: [ Species.MANTINE ] }, Species.ALOMOMOLA, { 1: [ Species.TYNAMO ], 39: [ Species.EELEKTRIK ] }, Species.DHELMISE ], [BiomePoolTier.SUPER_RARE]: [ { 1: [ Species.OMANYTE ], 40: [ Species.OMASTAR ] }, { 1: [ Species.KABUTO ], 40: [ Species.KABUTOPS ] }, @@ -484,10 +480,10 @@ export const biomePokemonPools: BiomePokemonPools = { Species.ARCTOVISH, Species.HISUI_QWILFISH ], - [BiomePoolTier.ULTRA_RARE]: [ Species.FEEBAS, Species.MANAPHY, Species.NIHILEGO ], + [BiomePoolTier.ULTRA_RARE]: [ Species.FEEBAS, Species.NIHILEGO ], [BiomePoolTier.BOSS]: [ 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 ], - [BiomePoolTier.BOSS_RARE]: [ Species.OMASTAR, Species.KABUTOPS, Species.RELICANTH, Species.PHIONE, Species.EELEKTROSS, Species.PYUKUMUKU, Species.DHELMISE, Species.ARCTOVISH, Species.BASCULEGION ], - [BiomePoolTier.BOSS_SUPER_RARE]: [ Species.MILOTIC, Species.MANAPHY, Species.NIHILEGO, Species.CURSOLA, Species.OVERQWIL ], + [BiomePoolTier.BOSS_RARE]: [ Species.OMASTAR, Species.KABUTOPS, Species.RELICANTH, Species.EELEKTROSS, Species.PYUKUMUKU, Species.DHELMISE, Species.ARCTOVISH, Species.BASCULEGION ], + [BiomePoolTier.BOSS_SUPER_RARE]: [ Species.MILOTIC, Species.NIHILEGO, Species.CURSOLA, Species.OVERQWIL ], [BiomePoolTier.BOSS_ULTRA_RARE]: [ Species.KYOGRE ] }, [Biome.MOUNTAIN]: { @@ -573,10 +569,10 @@ export const biomePokemonPools: BiomePokemonPools = { ], [BiomePoolTier.RARE]: [ Species.ONIX, { 1: [ Species.FERROSEED ], 40: [ Species.FERROTHORN ] }, Species.CARBINK ], [BiomePoolTier.SUPER_RARE]: [ Species.SHUCKLE ], - [BiomePoolTier.ULTRA_RARE]: [ Species.REGISTEEL, Species.UXIE ], + [BiomePoolTier.ULTRA_RARE]: [ Species.UXIE ], [BiomePoolTier.BOSS]: [ Species.PARASECT, Species.ONIX, Species.CROBAT, Species.URSARING, Species.EXPLOUD, Species.PROBOPASS, Species.GIGALITH, Species.SWOOBAT, Species.DIGGERSBY, Species.NOIVERN, Species.GOLISOPOD ], [BiomePoolTier.BOSS_RARE]: [ Species.SHUCKLE, Species.FERROTHORN, Species.LYCANROC ], - [BiomePoolTier.BOSS_SUPER_RARE]: [ Species.REGISTEEL, Species.UXIE ], + [BiomePoolTier.BOSS_SUPER_RARE]: [ Species.UXIE ], [BiomePoolTier.BOSS_ULTRA_RARE]: [] }, [Biome.DESERT]: { @@ -726,7 +722,7 @@ export const biomePokemonPools: BiomePokemonPools = { { 1: [ Species.CLOBBOPUS ], 20: [ Species.GRAPPLOCT ] } ], [BiomePoolTier.UNCOMMON]: [ { 1: [ Species.CROAGUNK ], 37: [ Species.TOXICROAK ] }, { 1: [ Species.SCRAGGY ], 39: [ Species.SCRAFTY ] }, { 1: [ Species.MIENFOO ], 50: [ Species.MIENSHAO ] } ], - [BiomePoolTier.RARE]: [ { 1: [ Species.TYROGUE ], 20: [ Species.HITMONLEE ] }, Species.HITMONCHAN, Species.LUCARIO, Species.THROH, Species.SAWK ], + [BiomePoolTier.RARE]: [ Species.HITMONLEE, Species.HITMONCHAN, Species.LUCARIO, Species.THROH, Species.SAWK ], [BiomePoolTier.SUPER_RARE]: [ Species.HITMONTOP, Species.GALLADE, Species.GALAR_FARFETCHD ], [BiomePoolTier.ULTRA_RARE]: [ Species.TERRAKION, Species.KUBFU, Species.GALAR_ZAPDOS ], [BiomePoolTier.BOSS]: [ Species.PRIMEAPE, Species.HITMONLEE, Species.HITMONCHAN, Species.HARIYAMA, Species.MEDICHAM, Species.LUCARIO, Species.TOXICROAK, Species.THROH, Species.SAWK, Species.SCRAFTY, Species.MIENSHAO, Species.BEWEAR, Species.GRAPPLOCT ], @@ -745,11 +741,11 @@ export const biomePokemonPools: BiomePokemonPools = { [BiomePoolTier.UNCOMMON]: [ { 1: [ Species.BRONZOR ], 33: [ Species.BRONZONG ] }, Species.KLEFKI ], [BiomePoolTier.RARE]: [], [BiomePoolTier.SUPER_RARE]: [ { 1: [ Species.PORYGON ], 20: [ Species.PORYGON2 ] }, { 1: [ Species.BELDUM ], 20: [ Species.METANG ], 45: [ Species.METAGROSS ] } ], - [BiomePoolTier.ULTRA_RARE]: [ Species.GENESECT, Species.MAGEARNA, Species.MELTAN ], + [BiomePoolTier.ULTRA_RARE]: [ Species.GENESECT, Species.MAGEARNA ], [BiomePoolTier.BOSS]: [ Species.KLINKLANG, Species.KLEFKI ], [BiomePoolTier.BOSS_RARE]: [], [BiomePoolTier.BOSS_SUPER_RARE]: [ Species.GENESECT, Species.MAGEARNA ], - [BiomePoolTier.BOSS_ULTRA_RARE]: [ Species.MELMETAL ] + [BiomePoolTier.BOSS_ULTRA_RARE]: [] }, [Biome.RUINS]: { [BiomePoolTier.COMMON]: [ @@ -763,11 +759,11 @@ export const biomePokemonPools: BiomePokemonPools = { [BiomePoolTier.UNCOMMON]: [ { 1: [ Species.ABRA ], 16: [ Species.KADABRA ] }, Species.SIGILYPH ], [BiomePoolTier.RARE]: [ Species.MR_MIME, Species.WOBBUFFET, { 1: [ Species.GOTHITA ], 32: [ Species.GOTHORITA ], 41: [ Species.GOTHITELLE ] }, Species.STONJOURNER ], [BiomePoolTier.SUPER_RARE]: [ Species.ESPEON, { 1: [ Species.ARCHEN ], 37: [ Species.ARCHEOPS ] }, { 1: [ Species.GALAR_YAMASK ], 34: [ Species.RUNERIGUS ] } ], - [BiomePoolTier.ULTRA_RARE]: [ Species.MEW, Species.VICTINI ], + [BiomePoolTier.ULTRA_RARE]: [ Species.REGISTEEL ], [BiomePoolTier.BOSS]: [ Species.ALAKAZAM, Species.HYPNO, Species.XATU, Species.GRUMPIG, Species.CLAYDOL, Species.SIGILYPH, Species.GOTHITELLE, Species.BEHEEYEM ], [BiomePoolTier.BOSS_RARE]: [ Species.MR_MIME, Species.ESPEON, Species.WOBBUFFET, Species.ARCHEOPS ], - [BiomePoolTier.BOSS_SUPER_RARE]: [ Species.VICTINI, Species.RUNERIGUS ], - [BiomePoolTier.BOSS_ULTRA_RARE]: [ Species.MEW ] + [BiomePoolTier.BOSS_SUPER_RARE]: [ Species.REGISTEEL, Species.RUNERIGUS ], + [BiomePoolTier.BOSS_ULTRA_RARE]: [] }, [Biome.WASTELAND]: { [BiomePoolTier.COMMON]: [ @@ -812,11 +808,11 @@ export const biomePokemonPools: BiomePokemonPools = { [BiomePoolTier.UNCOMMON]: [ { 1: [ Species.BALTOY ], 36: [ Species.CLAYDOL ] }, { 1: [ Species.ELGYEM ], 42: [ Species.BEHEEYEM ] } ], [BiomePoolTier.RARE]: [ { 1: [ Species.BELDUM ], 20: [ Species.METANG ], 45: [ Species.METAGROSS ] }, Species.SIGILYPH, { 1: [ Species.SOLOSIS ], 32: [ Species.DUOSION ], 41: [ Species.REUNICLUS ] } ], [BiomePoolTier.SUPER_RARE]: [ { 1: [ Species.PORYGON ], 20: [ Species.PORYGON2 ] } ], - [BiomePoolTier.ULTRA_RARE]: [ Species.JIRACHI, Species.DEOXYS, Species.CRESSELIA, { 1: [ Species.COSMOG ], 43: [ Species.COSMOEM ] }, Species.CELESTEELA ], + [BiomePoolTier.ULTRA_RARE]: [ Species.DEOXYS, Species.CRESSELIA, { 1: [ Species.COSMOG ], 43: [ Species.COSMOEM ] }, Species.CELESTEELA ], [BiomePoolTier.BOSS]: [ Species.CLEFABLE, Species.LUNATONE, Species.SOLROCK, Species.BRONZONG, Species.MUSHARNA, Species.REUNICLUS, Species.MINIOR ], [BiomePoolTier.BOSS_RARE]: [ Species.METAGROSS, Species.PORYGON_Z ], - [BiomePoolTier.BOSS_SUPER_RARE]: [ Species.JIRACHI, Species.DEOXYS, Species.CRESSELIA, Species.CELESTEELA ], - [BiomePoolTier.BOSS_ULTRA_RARE]: [ Species.RAYQUAZA, Species.ARCEUS, Species.SOLGALEO, Species.LUNALA, Species.NECROZMA ] + [BiomePoolTier.BOSS_SUPER_RARE]: [ Species.DEOXYS, Species.CRESSELIA, Species.CELESTEELA ], + [BiomePoolTier.BOSS_ULTRA_RARE]: [ Species.RAYQUAZA, Species.SOLGALEO, Species.LUNALA, Species.NECROZMA ] }, [Biome.CONSTRUCTION_SITE]: { [BiomePoolTier.COMMON]: [ @@ -831,7 +827,7 @@ export const biomePokemonPools: BiomePokemonPools = { { 1: [ Species.RHYHORN ], 42: [ Species.RHYDON ] }, { 1: [ Species.SCRAGGY ], 39: [ Species.SCRAFTY ] } ], - [BiomePoolTier.RARE]: [ Species.ONIX, { 1: [ Species.TYROGUE ], 20: [ Species.HITMONLEE ] }, Species.HITMONCHAN, Species.DURALUDON ], + [BiomePoolTier.RARE]: [ Species.ONIX, Species.HITMONLEE, Species.HITMONCHAN, Species.DURALUDON ], [BiomePoolTier.SUPER_RARE]: [ Species.DITTO, Species.HITMONTOP, { 1: [ Species.GALAR_MEOWTH ], 28: [ Species.PERRSERKER ] } ], [BiomePoolTier.ULTRA_RARE]: [ Species.COBALION ], [BiomePoolTier.BOSS]: [ Species.MACHAMP, Species.CONKELDURR ], @@ -1075,7 +1071,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { [BiomePoolTier.RARE]: [ TrainerType.BLACK_BELT ], [BiomePoolTier.SUPER_RARE]: [], [BiomePoolTier.ULTRA_RARE]: [], - [BiomePoolTier.BOSS]: [ TrainerType.NORMAN, TrainerType.CHEREN, TrainerType.LENORA ], + [BiomePoolTier.BOSS]: [ TrainerType.CILAN, TrainerType.CHILI, TrainerType.CRESS, TrainerType.CHEREN, TrainerType.LENORA ], [BiomePoolTier.BOSS_RARE]: [], [BiomePoolTier.BOSS_SUPER_RARE]: [], [BiomePoolTier.BOSS_ULTRA_RARE]: [] @@ -1108,7 +1104,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { [BiomePoolTier.RARE]: [ TrainerType.ARTIST ], [BiomePoolTier.SUPER_RARE]: [], [BiomePoolTier.ULTRA_RARE]: [], - [BiomePoolTier.BOSS]: [ TrainerType.CHEREN ], + [BiomePoolTier.BOSS]: [ TrainerType.NORMAN, TrainerType.CHEREN ], [BiomePoolTier.BOSS_RARE]: [], [BiomePoolTier.BOSS_SUPER_RARE]: [], [BiomePoolTier.BOSS_ULTRA_RARE]: [] @@ -2206,10 +2202,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { [ Biome.END, BiomePoolTier.ULTRA_RARE ] ] ], - [ Species.MEW, Type.PSYCHIC, -1, [ - [ Biome.RUINS, BiomePoolTier.ULTRA_RARE ], - [ Biome.RUINS, BiomePoolTier.BOSS_ULTRA_RARE ] - ] + [ Species.MEW, Type.PSYCHIC, -1, [ ] ], [ Species.CHIKORITA, Type.GRASS, -1, [ [ Biome.TALL_GRASS, BiomePoolTier.RARE ] @@ -2306,21 +2299,13 @@ export const biomeTrainerPools: BiomeTrainerPools = { [ Biome.SEABED, BiomePoolTier.BOSS ] ] ], - [ Species.PICHU, Type.ELECTRIC, -1, [ - [ Biome.TOWN, BiomePoolTier.UNCOMMON ] - ] + [ Species.PICHU, Type.ELECTRIC, -1, [ ] ], - [ Species.CLEFFA, Type.FAIRY, -1, [ - [ Biome.TOWN, BiomePoolTier.RARE ] - ] + [ Species.CLEFFA, Type.FAIRY, -1, [ ] ], - [ Species.IGGLYBUFF, Type.NORMAL, Type.FAIRY, [ - [ Biome.TOWN, BiomePoolTier.UNCOMMON ] - ] + [ Species.IGGLYBUFF, Type.NORMAL, Type.FAIRY, [ ] ], - [ Species.TOGEPI, Type.FAIRY, -1, [ - [ Biome.TOWN, BiomePoolTier.SUPER_RARE ] - ] + [ Species.TOGEPI, Type.FAIRY, -1, [ ] ], [ Species.TOGETIC, Type.FAIRY, Type.FLYING, [ [ Biome.FAIRY_CAVE, BiomePoolTier.UNCOMMON ] @@ -2615,11 +2600,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { [ Biome.METROPOLIS, BiomePoolTier.SUPER_RARE ] ] ], - [ Species.TYROGUE, Type.FIGHTING, -1, [ - [ Biome.TOWN, BiomePoolTier.SUPER_RARE ], - [ Biome.DOJO, BiomePoolTier.RARE ], - [ Biome.CONSTRUCTION_SITE, BiomePoolTier.RARE ] - ] + [ Species.TYROGUE, Type.FIGHTING, -1, [ ] ], [ Species.HITMONTOP, Type.FIGHTING, -1, [ [ Biome.DOJO, BiomePoolTier.SUPER_RARE ], @@ -2627,17 +2608,11 @@ export const biomeTrainerPools: BiomeTrainerPools = { [ Biome.CONSTRUCTION_SITE, BiomePoolTier.SUPER_RARE ] ] ], - [ Species.SMOOCHUM, Type.ICE, Type.PSYCHIC, [ - [ Biome.TOWN, BiomePoolTier.SUPER_RARE ] - ] + [ Species.SMOOCHUM, Type.ICE, Type.PSYCHIC, [ ] ], - [ Species.ELEKID, Type.ELECTRIC, -1, [ - [ Biome.TOWN, BiomePoolTier.SUPER_RARE ] - ] + [ Species.ELEKID, Type.ELECTRIC, -1, [ ] ], - [ Species.MAGBY, Type.FIRE, -1, [ - [ Biome.TOWN, BiomePoolTier.SUPER_RARE ] - ] + [ Species.MAGBY, Type.FIRE, -1, [ ] ], [ Species.MILTANK, Type.NORMAL, -1, [ [ Biome.MEADOW, BiomePoolTier.RARE ], @@ -2688,10 +2663,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { [ Biome.MOUNTAIN, BiomePoolTier.BOSS_ULTRA_RARE ] ] ], - [ Species.CELEBI, Type.PSYCHIC, Type.GRASS, [ - [ Biome.FOREST, BiomePoolTier.ULTRA_RARE ], - [ Biome.FOREST, BiomePoolTier.BOSS_ULTRA_RARE ] - ] + [ Species.CELEBI, Type.PSYCHIC, Type.GRASS, [ ] ], [ Species.TREECKO, Type.GRASS, -1, [ [ Biome.FOREST, BiomePoolTier.RARE ] @@ -2918,9 +2890,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { [ Biome.DOJO, BiomePoolTier.BOSS ] ] ], - [ Species.AZURILL, Type.NORMAL, Type.FAIRY, [ - [ Biome.TOWN, BiomePoolTier.UNCOMMON ] - ] + [ Species.AZURILL, Type.NORMAL, Type.FAIRY, [ ] ], [ Species.NOSEPASS, Type.ROCK, -1, [ [ Biome.CAVE, BiomePoolTier.UNCOMMON ] @@ -3216,9 +3186,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { [ Biome.ABYSS, BiomePoolTier.BOSS ] ] ], - [ Species.WYNAUT, Type.PSYCHIC, -1, [ - [ Biome.TOWN, BiomePoolTier.SUPER_RARE ] - ] + [ Species.WYNAUT, Type.PSYCHIC, -1, [ ] ], [ Species.SNORUNT, Type.ICE, -1, [ [ Biome.ICE_CAVE, BiomePoolTier.UNCOMMON ] @@ -3306,8 +3274,8 @@ export const biomeTrainerPools: BiomeTrainerPools = { ] ], [ Species.REGISTEEL, Type.STEEL, -1, [ - [ Biome.CAVE, BiomePoolTier.ULTRA_RARE ], - [ Biome.CAVE, BiomePoolTier.BOSS_SUPER_RARE ] + [ Biome.RUINS, BiomePoolTier.ULTRA_RARE ], + [ Biome.RUINS, BiomePoolTier.BOSS_SUPER_RARE ] ] ], [ Species.LATIAS, Type.DRAGON, Type.PSYCHIC, [ @@ -3333,10 +3301,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { [ Biome.END, BiomePoolTier.ULTRA_RARE ] ] ], - [ Species.JIRACHI, Type.STEEL, Type.PSYCHIC, [ - [ Biome.SPACE, BiomePoolTier.ULTRA_RARE ], - [ Biome.SPACE, BiomePoolTier.BOSS_SUPER_RARE ] - ] + [ Species.JIRACHI, Type.STEEL, Type.PSYCHIC, [ ] ], [ Species.DEOXYS, Type.PSYCHIC, -1, [ [ Biome.SPACE, BiomePoolTier.ULTRA_RARE ], @@ -3435,9 +3400,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { [ Biome.POWER_PLANT, BiomePoolTier.BOSS ] ] ], - [ Species.BUDEW, Type.GRASS, Type.POISON, [ - [ Biome.TOWN, BiomePoolTier.UNCOMMON ] - ] + [ Species.BUDEW, Type.GRASS, Type.POISON, [ ] ], [ Species.ROSERADE, Type.GRASS, Type.POISON, [ [ Biome.MEADOW, BiomePoolTier.BOSS ] @@ -3599,17 +3562,11 @@ export const biomeTrainerPools: BiomeTrainerPools = { [ Biome.LABORATORY, BiomePoolTier.BOSS ] ] ], - [ Species.BONSLY, Type.ROCK, -1, [ - [ Biome.TOWN, BiomePoolTier.SUPER_RARE ] - ] + [ Species.BONSLY, Type.ROCK, -1, [ ] ], - [ Species.MIME_JR, Type.PSYCHIC, Type.FAIRY, [ - [ Biome.TOWN, BiomePoolTier.SUPER_RARE ] - ] + [ Species.MIME_JR, Type.PSYCHIC, Type.FAIRY, [ ] ], - [ Species.HAPPINY, Type.NORMAL, -1, [ - [ Biome.TOWN, BiomePoolTier.SUPER_RARE ] - ] + [ Species.HAPPINY, Type.NORMAL, -1, [] ], [ Species.CHATOT, Type.NORMAL, Type.FLYING, [ [ Biome.JUNGLE, BiomePoolTier.SUPER_RARE ] @@ -3638,13 +3595,9 @@ export const biomeTrainerPools: BiomeTrainerPools = { [ Biome.END, BiomePoolTier.COMMON ] ] ], - [ Species.MUNCHLAX, Type.NORMAL, -1, [ - [ Biome.TOWN, BiomePoolTier.SUPER_RARE ] - ] + [ Species.MUNCHLAX, Type.NORMAL, -1, [ ] ], - [ Species.RIOLU, Type.FIGHTING, -1, [ - [ Biome.TOWN, BiomePoolTier.SUPER_RARE ] - ] + [ Species.RIOLU, Type.FIGHTING, -1, [ ] ], [ Species.LUCARIO, Type.FIGHTING, Type.STEEL, [ [ Biome.DOJO, BiomePoolTier.RARE ], @@ -3844,34 +3797,22 @@ export const biomeTrainerPools: BiomeTrainerPools = { [ Biome.SPACE, BiomePoolTier.BOSS_SUPER_RARE ] ] ], - [ Species.PHIONE, Type.WATER, -1, [ - [ Biome.SEABED, BiomePoolTier.RARE ], - [ Biome.SEABED, BiomePoolTier.BOSS_RARE ] - ] + [ Species.PHIONE, Type.WATER, -1, [ ] ], - [ Species.MANAPHY, Type.WATER, -1, [ - [ Biome.SEABED, BiomePoolTier.ULTRA_RARE ], - [ Biome.SEABED, BiomePoolTier.BOSS_SUPER_RARE ] - ] + [ Species.MANAPHY, Type.WATER, -1, [ ] ], [ Species.DARKRAI, Type.DARK, -1, [ [ Biome.ABYSS, BiomePoolTier.ULTRA_RARE ], [ Biome.ABYSS, BiomePoolTier.BOSS_SUPER_RARE ] ] ], - [ Species.SHAYMIN, Type.GRASS, -1, [ - [ Biome.GRASS, BiomePoolTier.BOSS_ULTRA_RARE ] - ] + [ Species.SHAYMIN, Type.GRASS, -1, [ ] ], [ Species.ARCEUS, Type.NORMAL, -1, [ - [ Biome.SPACE, BiomePoolTier.BOSS_ULTRA_RARE ], [ Biome.END, BiomePoolTier.ULTRA_RARE ] ] ], - [ Species.VICTINI, Type.PSYCHIC, Type.FIRE, [ - [ Biome.RUINS, BiomePoolTier.ULTRA_RARE ], - [ Biome.RUINS, BiomePoolTier.BOSS_SUPER_RARE ] - ] + [ Species.VICTINI, Type.PSYCHIC, Type.FIRE, [ ] ], [ Species.SNIVY, Type.GRASS, -1, [ [ Biome.JUNGLE, BiomePoolTier.RARE ] @@ -5345,13 +5286,9 @@ export const biomeTrainerPools: BiomeTrainerPools = { [ Biome.POWER_PLANT, BiomePoolTier.BOSS_SUPER_RARE ] ] ], - [ Species.MELTAN, Type.STEEL, -1, [ - [ Biome.FACTORY, BiomePoolTier.ULTRA_RARE ] - ] + [ Species.MELTAN, Type.STEEL, -1, [ ] ], - [ Species.MELMETAL, Type.STEEL, -1, [ - [ Biome.FACTORY, BiomePoolTier.BOSS_ULTRA_RARE ] - ] + [ Species.MELMETAL, Type.STEEL, -1, [ ] ], [ Species.GROOKEY, Type.GRASS, -1, [ [ Biome.JUNGLE, BiomePoolTier.RARE ] @@ -6619,7 +6556,7 @@ export const biomeTrainerPools: BiomeTrainerPools = { ] ], [ TrainerType.NORMAN, [ - [ Biome.PLAINS, BiomePoolTier.BOSS ] + [ Biome.METROPOLIS, BiomePoolTier.BOSS ] ] ], [ TrainerType.WINONA, [ @@ -6673,9 +6610,15 @@ export const biomeTrainerPools: BiomeTrainerPools = { [ Biome.POWER_PLANT, BiomePoolTier.BOSS ] ] ], - [ TrainerType.CILAN, [] ], - [ TrainerType.CHILI, [] ], - [ TrainerType.CRESS, [] ], + [ TrainerType.CILAN, [ + [ Biome.PLAINS, BiomePoolTier.BOSS ] + ] ], + [ TrainerType.CHILI, [ + [ Biome.PLAINS, BiomePoolTier.BOSS ] + ] ], + [ TrainerType.CRESS, [ + [ Biome.PLAINS, BiomePoolTier.BOSS ] + ] ], [ TrainerType.CHEREN, [ [ Biome.PLAINS, BiomePoolTier.BOSS ], [ Biome.METROPOLIS, BiomePoolTier.BOSS ] diff --git a/src/data/egg.ts b/src/data/egg.ts index 53fae38407a..8824dc2b308 100644 --- a/src/data/egg.ts +++ b/src/data/egg.ts @@ -1,4 +1,9 @@ import { ModifierTier } from "../modifier/modifier-type"; +import { Type } from "./type"; +import * as Utils from "../utils"; +import BattleScene from "../battle-scene"; +import { Species } from "./species"; +import { getPokemonSpecies, speciesStarters } from "./pokemon-species"; export const EGG_SEED = 1073741824; @@ -12,12 +17,99 @@ export class Egg { public id: integer; public tier: ModifierTier; public gachaType: GachaType; + public hatchWaves: integer; public timestamp: integer; - constructor(id: integer, gachaType: GachaType, timestamp: integer) { + constructor(id: integer, gachaType: GachaType, hatchWaves: integer, timestamp: integer) { this.id = id; this.tier = Math.floor(id / EGG_SEED); this.gachaType = gachaType; + this.hatchWaves = hatchWaves; this.timestamp = timestamp; } + + isManaphyEgg(): boolean { + return this.tier === ModifierTier.COMMON && !(this.id % 255); + } + + getKey(): string { + if (this.isManaphyEgg()) + return 'manaphy'; + return this.tier.toString(); + } +} + +export function getEggTierDefaultHatchWaves(tier: ModifierTier): integer { + switch (tier) { + case ModifierTier.COMMON: + return 10; + case ModifierTier.GREAT: + return 25; + case ModifierTier.ULTRA: + return 50; + } + return 100; +} + +export function getEggDescriptor(egg: Egg): string { + if (egg.isManaphyEgg()) + return 'Manaphy'; + switch (egg.tier) { + case ModifierTier.GREAT: + return 'Rare'; + case ModifierTier.ULTRA: + return 'Epic'; + case ModifierTier.MASTER: + return 'Legendary'; + default: + return 'Common'; + } +} + +export function getEggHatchWavesMessage(hatchWaves: integer): string { + if (hatchWaves <= 5) + return 'Sounds can be heard coming from inside! It will hatch soon!'; + if (hatchWaves <= 15) + return 'It appears to move occasionally. It may be close to hatching.'; + if (hatchWaves <= 50) + return 'What will hatch from this? It doesn\'t seem close to hatching.'; + return 'It looks like this Egg will take a long time to hatch.'; +} + +export function getEggGachaTypeDescriptor(scene: BattleScene, egg: Egg): string { + if (egg.isManaphyEgg()) + return ''; + switch (egg.gachaType) { + case GachaType.LEGENDARY: + return `Legendary Rate Up (${getPokemonSpecies(getLegendaryGachaSpeciesForTimestamp(scene, egg.timestamp)).getName()})`; + case GachaType.TYPE: + return `Type Rate Up (${Utils.toReadableString(Type[getTypeGachaTypeForTimestamp(scene, egg.timestamp)])})`; + case GachaType.SHINY: + return 'Shiny Rate Up'; + } +} + +export function getLegendaryGachaSpeciesForTimestamp(scene: BattleScene, timestamp: integer): Species { + const legendarySpecies = Object.entries(speciesStarters) + .filter(s => s[1] >= 8 && s[1] <= 9) + .map(s => parseInt(s[0])); + + let ret: Species; + + scene.executeWithSeedOffset(() => { + ret = Phaser.Math.RND.pick(legendarySpecies); + }, Utils.getSunday(new Date(timestamp)).getTime(), EGG_SEED.toString()); + + return ret; +} + +export function getTypeGachaTypeForTimestamp(scene: BattleScene, timestamp: integer): Type { + const types = Utils.getEnumValues(Type); + let ret: Type; + + scene.executeWithSeedOffset(() => { + ret = Phaser.Math.RND.pick(types); + }, Utils.getSunday(new Date(timestamp)).getTime(), EGG_SEED.toString()); + + return ret; } \ No newline at end of file diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index 6b6566f6568..23e11a82622 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -230,7 +230,7 @@ export abstract class PokemonSpeciesForm { const originalWarn = console.warn; // Ignore warnings for missing frames, because there will be a lot console.warn = () => {}; - const frameNames = scene.anims.generateFrameNames(this.getSpriteKey(female, formIndex, shiny), { zeroPad: 4, suffix: ".png", start: 1, end: 256 }); + const frameNames = scene.anims.generateFrameNames(this.getSpriteKey(female, formIndex, shiny), { zeroPad: 4, suffix: ".png", start: 1, end: 400 }); console.warn = originalWarn; scene.anims.create({ key: this.getSpriteKey(female, formIndex, shiny), diff --git a/src/egg-hatch-phase.ts b/src/egg-hatch-phase.ts index 9e1b1dd05c3..e22a05d938b 100644 --- a/src/egg-hatch-phase.ts +++ b/src/egg-hatch-phase.ts @@ -3,12 +3,16 @@ import { BattlePhase } from "./battle-phase"; import BattleScene, { AnySound } from "./battle-scene"; import * as Utils from "./utils"; import { Mode } from "./ui/ui"; -import { Egg } from "./data/egg"; +import { EGG_SEED, Egg, GachaType, getLegendaryGachaSpeciesForTimestamp, getTypeGachaTypeForTimestamp } from "./data/egg"; import EggHatchSceneHandler from "./ui/egg-hatch-scene-handler"; import { ModifierTier } from "./modifier/modifier-type"; import { Species } from "./data/species"; import Pokemon, { PlayerPokemon } from "./pokemon"; import { getPokemonSpecies, speciesStarters } from "./data/pokemon-species"; +import { StatsContainer } from "./ui/stats-container"; +import { TextStyle, addTextObject } from "./ui/text"; +import { Gender, getGenderColor, getGenderSymbol } from "./data/gender"; +import { achvs } from "./system/achv"; export class EggHatchPhase extends BattlePhase { private egg: Egg; @@ -22,6 +26,9 @@ export class EggHatchPhase extends BattlePhase { private eggLightraysOverlay: Phaser.GameObjects.Sprite; private pokemonSprite: Phaser.GameObjects.Sprite; + private infoContainer: Phaser.GameObjects.Container; + private statsContainer: StatsContainer; + constructor(scene: BattleScene, egg: Egg) { super(scene); @@ -36,6 +43,13 @@ export class EggHatchPhase extends BattlePhase { if (!this.egg) return this.end(); + const eggIndex = this.scene.gameData.eggs.findIndex(e => e.id === this.egg.id); + + if (eggIndex === -1) + return this.end(); + + this.scene.gameData.eggs.splice(eggIndex, 1); + this.scene.fadeOutBgm(null, false); const eggHatchHandler = this.scene.ui.getHandler() as EggHatchSceneHandler; @@ -48,7 +62,7 @@ export class EggHatchPhase extends BattlePhase { this.eggContainer = this.scene.add.container(this.eggHatchBg.displayWidth / 2, this.eggHatchBg.displayHeight / 2); - this.eggSprite = this.scene.add.sprite(0, 0, 'egg', `egg_${this.egg.tier}`); + this.eggSprite = this.scene.add.sprite(0, 0, 'egg', `egg_${this.egg.getKey()}`); this.eggCrackSprite = this.scene.add.sprite(0, 0, 'egg_crack', '0'); this.eggCrackSprite.setVisible(false); @@ -70,9 +84,58 @@ export class EggHatchPhase extends BattlePhase { this.eggHatchOverlay.setAlpha(0); this.scene.fieldUI.add(this.eggHatchOverlay); + const infoBg = this.scene.add.nineslice(0, 0, 'window', null, 96, 116, 6, 6, 6, 6); + + this.infoContainer = this.scene.add.container(this.eggHatchBg.displayWidth + infoBg.width / 2, this.eggHatchBg.displayHeight / 2); + + this.statsContainer = new StatsContainer(this.scene, -48, -54, true); + + this.infoContainer.add(infoBg); + this.infoContainer.add(this.statsContainer); + + const pokemonGenderLabelText = addTextObject(this.scene, -16, 32, 'Gender:', TextStyle.WINDOW, { fontSize: '64px' }); + pokemonGenderLabelText.setOrigin(1, 0); + pokemonGenderLabelText.setVisible(false); + this.infoContainer.add(pokemonGenderLabelText); + + const pokemonGenderText = addTextObject(this.scene, -12, 32, '', TextStyle.WINDOW, { fontSize: '64px' }); + pokemonGenderText.setOrigin(0, 0); + pokemonGenderText.setVisible(false); + this.infoContainer.add(pokemonGenderText); + + const pokemonAbilityLabelText = addTextObject(this.scene, -16, 32, 'Ability:', TextStyle.WINDOW, { fontSize: '64px' }); + pokemonAbilityLabelText.setOrigin(1, 0); + this.infoContainer.add(pokemonAbilityLabelText); + + const pokemonAbilityText = addTextObject(this.scene, -12, 32, '', TextStyle.WINDOW, { fontSize: '64px' }); + pokemonAbilityText.setOrigin(0, 0); + this.infoContainer.add(pokemonAbilityText); + + this.eggHatchContainer.add(this.infoContainer); + const pokemon = this.generatePokemon(); - console.log(pokemon.name, pokemon); + let abilityYOffset = 5; + + if (pokemon.gender > Gender.GENDERLESS) { + pokemonGenderText.setText(getGenderSymbol(pokemon.gender)); + pokemonGenderText.setColor(getGenderColor(pokemon.gender)); + pokemonGenderText.setShadowColor(getGenderColor(pokemon.gender, true)); + pokemonGenderLabelText.setVisible(true); + pokemonGenderText.setVisible(true); + + abilityYOffset = 10; + } + + [ pokemonAbilityLabelText, pokemonAbilityText ].map(t => t.y += abilityYOffset); + + pokemonAbilityText.setText(pokemon.getAbility().name); + + const originalIvs: integer[] = this.scene.gameData.dexData[pokemon.species.speciesId].caughtAttr + ? this.scene.gameData.dexData[pokemon.species.speciesId].ivs + : null; + + this.statsContainer.updateIvs(pokemon.ivs, originalIvs); this.pokemonSprite.setVisible(false); @@ -108,19 +171,35 @@ export class EggHatchPhase extends BattlePhase { ease: 'Cubic.easeIn' }); this.scene.time.delayedCall(Utils.fixedInt(1500), () => { + if (pokemon.species.mythical) + this.scene.validateAchv(achvs.HATCH_MYTHICAL); + if (pokemon.species.legendary) + this.scene.validateAchv(achvs.HATCH_LEGENDARY); + if (pokemon.isShiny()) + this.scene.validateAchv(achvs.HATCH_SHINY); this.eggContainer.setVisible(false); this.pokemonSprite.play(pokemon.getSpriteKey(true)); this.pokemonSprite.setVisible(true); this.scene.time.delayedCall(Utils.fixedInt(1000), () => { pokemon.cry(); this.scene.time.delayedCall(Utils.fixedInt(1250), () => { + this.scene.tweens.add({ + targets: this.infoContainer, + duration: Utils.fixedInt(750), + ease: 'Cubic.easeInOut', + x: this.eggHatchBg.displayWidth - 48 + }); + this.scene.playSoundWithoutBgm('evolution_fanfare'); this.scene.ui.showText(`${pokemon.name} hatched from the egg!`, null, () => { - this.scene.ui.showText(null, 0); - this.end(); + this.scene.gameData.updateSpeciesDexIvs(pokemon.species.speciesId, pokemon.ivs); + this.scene.gameData.setPokemonCaught(pokemon).then(() => { + this.scene.ui.showText(null, 0); + this.end(); + }); }, null, true, 3000); - this.scene.time.delayedCall(Utils.fixedInt(4250), () => this.scene.playBgm()); + //this.scene.time.delayedCall(Utils.fixedInt(4250), () => this.scene.playBgm()); }); }); this.scene.tweens.add({ @@ -193,7 +272,8 @@ export class EggHatchPhase extends BattlePhase { doSprayParticle(trigIndex: integer, offsetY: number) { const initialX = this.eggHatchBg.displayWidth / 2; const initialY = this.eggHatchBg.displayHeight / 2 + offsetY; - const particle = this.scene.add.image(initialX, initialY, 'egg_shard', `${this.egg.tier}_${Math.floor(trigIndex / 2)}`); + const shardKey = !this.egg.isManaphyEgg() ? this.egg.tier.toString() : '1'; + const particle = this.scene.add.image(initialX, initialY, 'egg_shard', `${shardKey}_${Math.floor(trigIndex / 2)}`); this.eggHatchContainer.add(particle); let f = 0; @@ -228,58 +308,99 @@ export class EggHatchPhase extends BattlePhase { } generatePokemon(): Pokemon { - let minStarterValue: integer; - let maxStarterValue: integer; + let ret: Pokemon; + let speciesOverride: Species; - switch (this.egg.tier) { - case ModifierTier.GREAT: - minStarterValue = 3; - maxStarterValue = 5; - break; - case ModifierTier.ULTRA: - minStarterValue = 6; - maxStarterValue = 7; - break; - case ModifierTier.MASTER: - minStarterValue = 8; - maxStarterValue = 9; - break; - default: - minStarterValue = 1; - maxStarterValue = 2; - break; + if (this.egg.isManaphyEgg()) { + this.scene.executeWithSeedOffset(() => { + const rand = Utils.randSeedInt(8); + + speciesOverride = rand ? Species.PHIONE : Species.MANAPHY; + }, this.egg.id, EGG_SEED.toString()); + } else if (this.egg.tier === ModifierTier.MASTER + && this.egg.gachaType === GachaType.LEGENDARY) { + this.scene.executeWithSeedOffset(() => { + if (!Utils.randSeedInt(2)) + speciesOverride = getLegendaryGachaSpeciesForTimestamp(this.scene, this.egg.timestamp); + }, this.egg.id, EGG_SEED.toString()); } - const speciesPool = Object.keys(speciesStarters) - .filter(s => speciesStarters[s] >= minStarterValue && speciesStarters[s] <= maxStarterValue) - .map(s => parseInt(s) as Species) - .filter(s => getPokemonSpecies(s).isObtainable()); + if (speciesOverride) { + this.scene.executeWithSeedOffset(() => { + ret = new PlayerPokemon(this.scene, getPokemonSpecies(speciesOverride), 5, null, null, undefined, false); + }, this.egg.id, EGG_SEED.toString()); + } else { + let minStarterValue: integer; + let maxStarterValue: integer; - let totalWeight = 0; - const speciesWeights = []; - for (let speciesId of speciesPool) { - const weight = Math.floor((((maxStarterValue - speciesStarters[speciesId]) / ((maxStarterValue - minStarterValue) + 1)) * 1.5 + 1) * 100); - speciesWeights.push(totalWeight + weight); - totalWeight += weight; - } - - let species: Species; - - this.scene.executeWithSeedOffset(() => { - const rand = Utils.randSeedInt(totalWeight); - for (let s = 0; s < speciesWeights.length; s++) { - if (rand < speciesWeights[s]) { - species = speciesPool[s]; + switch (this.egg.tier) { + case ModifierTier.GREAT: + minStarterValue = 4; + maxStarterValue = 5; break; + case ModifierTier.ULTRA: + minStarterValue = 6; + maxStarterValue = 7; + break; + case ModifierTier.MASTER: + minStarterValue = 8; + maxStarterValue = 9; + break; + default: + minStarterValue = 1; + maxStarterValue = 3; + break; + } + + const ignoredSpecies = [ Species.PHIONE, Species.MANAPHY, Species.ETERNATUS ]; + + let speciesPool = Object.keys(speciesStarters) + .filter(s => speciesStarters[s] >= minStarterValue && speciesStarters[s] <= maxStarterValue) + .map(s => parseInt(s) as Species) + .filter(s => getPokemonSpecies(s).isObtainable() && ignoredSpecies.indexOf(s) === -1); + + if (this.egg.gachaType === GachaType.TYPE) { + let tryOverrideType: boolean; + + this.scene.executeWithSeedOffset(() => { + tryOverrideType = !Utils.randSeedInt(2); + }, this.egg.id, EGG_SEED.toString()); + + if (tryOverrideType) { + const type = getTypeGachaTypeForTimestamp(this.scene, this.egg.timestamp); + const typeFilteredSpeciesPool = speciesPool + .filter(s => getPokemonSpecies(s).isOfType(type)); + if (typeFilteredSpeciesPool.length) + speciesPool = typeFilteredSpeciesPool; } } - }, this.egg.id); - console.log(species, totalWeight); + let totalWeight = 0; + const speciesWeights = []; + for (let speciesId of speciesPool) { + const weight = Math.floor((((maxStarterValue - speciesStarters[speciesId]) / ((maxStarterValue - minStarterValue) + 1)) * 1.5 + 1) * 100); + speciesWeights.push(totalWeight + weight); + totalWeight += weight; + } - const pokemon = new PlayerPokemon(this.scene, getPokemonSpecies(species), 5, null, null); + let species: Species; - return pokemon; + this.scene.executeWithSeedOffset(() => { + const rand = Utils.randSeedInt(totalWeight); + for (let s = 0; s < speciesWeights.length; s++) { + if (rand < speciesWeights[s]) { + species = speciesPool[s]; + break; + } + } + + ret = new PlayerPokemon(this.scene, getPokemonSpecies(species), 5, null, null, undefined, false); + }, this.egg.id, EGG_SEED.toString()); + } + + ret.trySetShiny(this.egg.gachaType === GachaType.SHINY ? 1024 : 512); + + return ret; } } diff --git a/src/main.ts b/src/main.ts index db44f052201..8af3a44c4b2 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,6 +2,7 @@ import Phaser from 'phaser'; import BattleScene from './battle-scene'; import InvertPostFX from './pipelines/invert'; import { version } from '../package.json'; +import BBCodeTextPlugin from 'phaser3-rex-plugins/plugins/bbcodetext-plugin'; const config: Phaser.Types.Core.GameConfig = { type: Phaser.WEBGL, @@ -11,6 +12,13 @@ const config: Phaser.Types.Core.GameConfig = { height: 1080, mode: Phaser.Scale.FIT }, + plugins: { + global: [{ + key: 'rexBBCodeTextPlugin', + plugin: BBCodeTextPlugin, + start: true + }] + }, pixelArt: true, pipeline: [ InvertPostFX ] as unknown as Phaser.Types.Core.PipelineConfig, scene: [ BattleScene ], diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index c66037a19ec..7cdd09d9fe9 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -15,6 +15,7 @@ import { GameMode } from '../game-mode'; import { StatusEffect, getStatusEffectDescriptor } from '../data/status-effect'; import { SpeciesFormKey } from '../data/pokemon-species'; import BattleScene from '../battle-scene'; +import { VoucherType, getVoucherTypeIcon, getVoucherTypeName } from '../system/voucher'; type Modifier = Modifiers.Modifier; @@ -96,6 +97,13 @@ class AddPokeballModifierType extends ModifierType { } } +class AddVoucherModifierType extends ModifierType { + constructor(voucherType: VoucherType, count: integer) { + super(`${count}x ${getVoucherTypeName(voucherType)}`, `Receive ${getVoucherTypeName(voucherType)} x${count}`, + (_type, _args) => new Modifiers.AddVoucherModifier(this, voucherType, count), getVoucherTypeIcon(voucherType), 'voucher'); + } +} + export class PokemonModifierType extends ModifierType { public selectFilter: PokemonSelectFilter; @@ -702,6 +710,10 @@ export const modifierTypes = { MINI_BLACK_HOLE: () => new TurnHeldItemTransferModifierType('Mini Black Hole'), + VOUCHER: () => new AddVoucherModifierType(VoucherType.REGULAR, 1), + VOUCHER_PLUS: () => new AddVoucherModifierType(VoucherType.PLUS, 1), + VOUCHER_PREMIUM: () => new AddVoucherModifierType(VoucherType.PREMIUM, 1), + GOLDEN_POKEBALL: () => new ModifierType(`Golden ${getPokeballName(PokeballType.POKEBALL)}`, 'Adds 1 extra item option at the end of every battle', (type, _args) => new Modifiers.ExtraModifierModifier(type), 'pb_gold', null, 'pb_bounce_1'), @@ -811,16 +823,17 @@ const modifierPool = { new WeightedModifierType(modifierTypes.ABILITY_CHARM, 2), new WeightedModifierType(modifierTypes.IV_SCANNER, 2), new WeightedModifierType(modifierTypes.EXP_BALANCE, 1), - new WeightedModifierType(modifierTypes.COIN_CASE, 1), new WeightedModifierType(modifierTypes.MEGA_EVOLUTION_ITEM, (party: Pokemon[]) => party[0].scene.getModifiers(Modifiers.MegaEvolutionAccessModifier).length && !party.filter(p => p.getFormKey().indexOf(SpeciesFormKey.MEGA) > -1).length ? 1 : 0), new WeightedModifierType(modifierTypes.REVERSE_DNA_SPLICERS, (party: Pokemon[]) => party[0].scene.gameMode !== GameMode.SPLICED_ENDLESS && party.filter(p => p.fusionSpecies).length ? 3 : 0), ].map(m => { m.setTier(ModifierTier.ULTRA); return m; }), [ModifierTier.MASTER]: [ - new WeightedModifierType(modifierTypes.MASTER_BALL, 3), - new WeightedModifierType(modifierTypes.SHINY_CHARM, 2), - new WeightedModifierType(modifierTypes.MEGA_BRACELET, 1), - new WeightedModifierType(modifierTypes.DNA_SPLICERS, (party: Pokemon[]) => party[0].scene.gameMode !== GameMode.SPLICED_ENDLESS && party.filter(p => !p.fusionSpecies).length > 1 ? 1 : 0), - new WeightedModifierType(modifierTypes.MINI_BLACK_HOLE, (party: Pokemon[]) => party[0].scene.gameData.unlocks[Unlockables.MINI_BLACK_HOLE] ? 1 : 0), + new WeightedModifierType(modifierTypes.MASTER_BALL, 32), + new WeightedModifierType(modifierTypes.SHINY_CHARM, 18), + new WeightedModifierType(modifierTypes.MEGA_BRACELET, 12), + new WeightedModifierType(modifierTypes.VOUCHER, 6), + new WeightedModifierType(modifierTypes.VOUCHER_PLUS, 1), + new WeightedModifierType(modifierTypes.DNA_SPLICERS, (party: Pokemon[]) => party[0].scene.gameMode !== GameMode.SPLICED_ENDLESS && party.filter(p => !p.fusionSpecies).length > 1 ? 12 : 0), + new WeightedModifierType(modifierTypes.MINI_BLACK_HOLE, (party: Pokemon[]) => party[0].scene.gameData.unlocks[Unlockables.MINI_BLACK_HOLE] ? 2 : 0), ].map(m => { m.setTier(ModifierTier.MASTER); return m; }), [ModifierTier.LUXURY]: [ new WeightedModifierType(modifierTypes.GOLDEN_EXP_CHARM, 1), diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index f0c421ae90d..4228c217612 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -15,6 +15,7 @@ import { TempBattleStat } from '../data/temp-battle-stat'; import { BerryType, getBerryEffectFunc, getBerryPredicate } from '../data/berry'; import { StatusEffect, getStatusEffectDescriptor } from '../data/status-effect'; import { MoneyAchv } from '../system/achv'; +import { VoucherType } from '../system/voucher'; type ModifierType = ModifierTypes.ModifierType; export type ModifierPredicate = (modifier: Modifier) => boolean; @@ -234,6 +235,25 @@ export class AddPokeballModifier extends ConsumableModifier { } } +export class AddVoucherModifier extends ConsumableModifier { + private voucherType: VoucherType; + private count: integer; + + constructor(type: ModifierType, voucherType: VoucherType, count: integer) { + super(type); + + this.voucherType = voucherType; + this.count = count; + } + + apply(args: any[]): boolean { + const voucherCounts = (args[0] as BattleScene).gameData.voucherCounts; + voucherCounts[this.voucherType] += this.count; + + return true; + } +} + export abstract class LapsingPersistentModifier extends PersistentModifier { protected battlesLeft: integer; @@ -1299,7 +1319,7 @@ export class ShinyRateBoosterModifier extends PersistentModifier { } apply(args: any[]): boolean { - (args[0] as Utils.IntegerHolder).value /= Math.pow(2, -3 - this.getStackCount()); + (args[0] as Utils.IntegerHolder).value *= Math.pow(2, 2 + this.getStackCount()); return true; } diff --git a/src/pokemon.ts b/src/pokemon.ts index 6ea4005dc7b..d2770aced47 100644 --- a/src/pokemon.ts +++ b/src/pokemon.ts @@ -271,7 +271,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const originalWarn = console.warn; // Ignore warnings for missing frames, because there will be a lot console.warn = () => {}; - const battleFrameNames = this.scene.anims.generateFrameNames(this.getBattleSpriteKey(), { zeroPad: 4, suffix: ".png", start: 1, end: 256 }); + const battleFrameNames = this.scene.anims.generateFrameNames(this.getBattleSpriteKey(), { zeroPad: 4, suffix: ".png", start: 1, end: 400 }); console.warn = originalWarn; this.scene.anims.create({ key: this.getBattleSpriteKey(), @@ -686,7 +686,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.summonData.moveset[moveIndex] = move; } - trySetShiny(): boolean { + trySetShiny(thresholdOverride?: integer): boolean { const rand1 = Utils.binToDec(Utils.decToBin(this.id).substring(0, 16)); const rand2 = Utils.binToDec(Utils.decToBin(this.id).substring(16, 32)); @@ -694,10 +694,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const F = rand1 ^ rand2; let shinyThreshold = new Utils.IntegerHolder(32); - if (!this.hasTrainer()) { - this.scene.applyModifiers(ShinyRateBoosterModifier, true, shinyThreshold); - console.log(shinyThreshold.value); - } + if (thresholdOverride === undefined) { + if (!this.hasTrainer()) { + this.scene.applyModifiers(ShinyRateBoosterModifier, true, shinyThreshold); + console.log(shinyThreshold.value, 'SHINY THRESHOLD'); + } + } else + shinyThreshold.value = thresholdOverride; this.shiny = (E ^ F) < shinyThreshold.value; if ((E ^ F) < 32) @@ -1836,11 +1839,13 @@ export class EnemyPokemon extends Pokemon { constructor(scene: BattleScene, species: PokemonSpecies, level: integer, trainer: boolean, dataSource?: PokemonData) { super(scene, 236, 84, species, level, dataSource?.abilityIndex, dataSource ? dataSource.formIndex : scene.getSpeciesFormIndex(species), - dataSource?.gender, dataSource?.shiny, null, dataSource); + dataSource?.gender, dataSource ? dataSource.shiny : false, null, dataSource); this.trainer = trainer; if (!dataSource) { + this.trySetShiny(); + let prevolution: Species; let speciesId = species.speciesId; while ((prevolution = pokemonPrevolutions[speciesId])) { diff --git a/src/system/achv.ts b/src/system/achv.ts index 112823e4d43..c5c6f0e059b 100644 --- a/src/system/achv.ts +++ b/src/system/achv.ts @@ -31,6 +31,14 @@ export class Achv { this.conditionFunc = conditionFunc; } + getName(): string { + return this.name; + } + + getIconImage(): string { + return this.iconImage; + } + setSecret(hasParent?: boolean): this { this.secret = true; this.hasParent = !!hasParent; @@ -118,10 +126,13 @@ export const achvs = { MEGA_EVOLVE: new Achv('Megamorph', 'Mega evolve a Pokémon', 'mega_bracelet', 50), SPLICE: new Achv('Infinite Fusion', 'Splice two Pokémon together with DNA Splicers', 'dna_splicers', 10), MINI_BLACK_HOLE: new ModifierAchv('A Hole Lot of Items', 'Acquire a Mini Black Hole', 'mini_black_hole', 25, modifier => modifier instanceof TurnHeldItemTransferModifier).setSecret(), - CATCH_LEGENDARY: new Achv('Legendary', 'Catch a legendary Pokémon', 'mb', 50).setSecret(), CATCH_MYTHICAL: new Achv('Mythical', 'Catch a mythical Pokémon', 'strange_ball', 50).setSecret(), + CATCH_LEGENDARY: new Achv('Legendary', 'Catch a legendary Pokémon', 'mb', 75).setSecret(), SEE_SHINY: new Achv('Shiny', 'Find a shiny Pokémon in the wild', 'pb_gold', 75), SHINY_PARTY: new Achv('That\'s Dedication', 'Have a full party of shiny Pokémon', 'shiny_charm', 100).setSecret(true), + HATCH_MYTHICAL: new Achv('Mythical Egg', 'Hatch a mythical Pokémon from an egg', 'pair_of_tickets', 75).setSecret(), + HATCH_LEGENDARY: new Achv('Legendary Egg', 'Hatch a legendary Pokémon from an egg', 'mystic_ticket', 100).setSecret(), + HATCH_SHINY: new Achv('Shiny Egg', 'Hatch a shiny Pokémon from an egg', 'golden_mystic_ticket', 100).setSecret(), HIDDEN_ABILITY: new Achv('Hidden Potential', 'Catch a Pokémon with a hidden ability', 'ability_charm', 75), PERFECT_IVS: new Achv('Certificate of Authenticity', 'Get perfect IVs on a Pokémon', 'blunder_policy', 100), CLASSIC_VICTORY: new Achv('Undefeated', 'Beat the game in classic mode', 'relic_crown', 150) diff --git a/src/system/egg-data.ts b/src/system/egg-data.ts index 3c6f20363fb..c1642d1060b 100644 --- a/src/system/egg-data.ts +++ b/src/system/egg-data.ts @@ -3,16 +3,18 @@ import { Egg, GachaType } from "../data/egg"; export default class EggData { public id: integer; public gachaType: GachaType; + public hatchWaves: integer; public timestamp: integer; constructor(source: Egg | any) { const sourceEgg = source instanceof Egg ? source as Egg : null; this.id = sourceEgg ? sourceEgg.id : source.id; this.gachaType = sourceEgg ? sourceEgg.gachaType : source.gachaType; + this.hatchWaves = sourceEgg ? sourceEgg.hatchWaves : source.hatchWaves; this.timestamp = sourceEgg ? sourceEgg.timestamp : source.timestamp; } toEgg(): Egg { - return new Egg(this.id, this.gachaType, this.timestamp); + return new Egg(this.id, this.gachaType, this.hatchWaves, this.timestamp); } } \ No newline at end of file diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 43b7719211e..d9ab91b48ec 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -16,6 +16,7 @@ import { Setting, setSetting, settingDefaults } from "./settings"; import { achvs } from "./achv"; import EggData from "./egg-data"; import { Egg } from "../data/egg"; +import { VoucherType, vouchers } from "./voucher"; interface SystemSaveData { trainerId: integer; @@ -23,6 +24,8 @@ interface SystemSaveData { dexData: DexData; unlocks: Unlocks; achvUnlocks: AchvUnlocks; + voucherUnlocks: VoucherUnlocks; + voucherCounts: VoucherCounts; eggs: EggData[]; gameVersion: string; timestamp: integer; @@ -54,6 +57,14 @@ interface AchvUnlocks { [key: string]: integer } +interface VoucherUnlocks { + [key: string]: integer +} + +export interface VoucherCounts { + [type: string]: integer; +} + export interface DexData { [key: integer]: DexEntry } @@ -96,6 +107,8 @@ export class GameData { public achvUnlocks: AchvUnlocks; + public voucherUnlocks: VoucherUnlocks; + public voucherCounts: VoucherCounts; public eggs: Egg[]; constructor(scene: BattleScene) { @@ -109,6 +122,12 @@ export class GameData { [Unlockables.SPLICED_ENDLESS_MODE]: false }; this.achvUnlocks = {}; + this.voucherUnlocks = {}; + this.voucherCounts = { + [VoucherType.REGULAR]: 0, + [VoucherType.PLUS]: 0, + [VoucherType.PREMIUM]: 0 + }; this.eggs = []; this.initDexData(); this.loadSystem(); @@ -124,6 +143,8 @@ export class GameData { dexData: this.dexData, unlocks: this.unlocks, achvUnlocks: this.achvUnlocks, + voucherUnlocks: this.voucherUnlocks, + voucherCounts: this.voucherCounts, eggs: this.eggs.map(e => new EggData(e)), gameVersion: this.scene.game.config.gameVersion, timestamp: new Date().getTime() @@ -141,7 +162,16 @@ export class GameData { if (!localStorage.hasOwnProperty('data')) return false; - const data = JSON.parse(atob(localStorage.getItem('data')), (k: string, v: any) => k.endsWith('Attr') ? BigInt(v) : v) as SystemSaveData; + const data = JSON.parse(atob(localStorage.getItem('data')), (k: string, v: any) => { + if (k === 'eggs') { + const ret: EggData[] = []; + for (let e of v) + ret.push(new EggData(e)); + return ret; + } + + return k.endsWith('Attr') ? BigInt(v) : v; + }) as SystemSaveData; console.debug(data); @@ -168,6 +198,20 @@ export class GameData { } } + if (data.voucherUnlocks) { + for (let v of Object.keys(data.voucherUnlocks)) { + if (vouchers.hasOwnProperty(v)) + this.voucherUnlocks[v] = data.voucherUnlocks[v]; + } + } + + if (data.voucherCounts) { + Utils.getEnumKeys(VoucherType).forEach(key => { + const index = VoucherType[key]; + this.voucherCounts[index] = data.voucherCounts[index] || 0; + }); + } + this.eggs = data.eggs ? data.eggs.map(e => e.toEgg()) : []; @@ -423,6 +467,20 @@ export class GameData { }); } + updateSpeciesDexIvs(speciesId: Species, ivs: integer[]): void { + let dexEntry: DexEntry; + do { + dexEntry = this.scene.gameData.dexData[speciesId]; + const dexIvs = dexEntry.ivs; + for (let i = 0; i < dexIvs.length; i++) { + if (dexIvs[i] < ivs[i]) + dexIvs[i] = ivs[i]; + } + if (dexIvs.filter(iv => iv === 31).length === 6) + this.scene.validateAchv(achvs.PERFECT_IVS); + } while (pokemonPrevolutions.hasOwnProperty(speciesId) && (speciesId = pokemonPrevolutions[speciesId])); + } + getSpeciesDefaultDexAttr(species: PokemonSpecies): bigint { let ret = 0n; const dexEntry = this.dexData[species.speciesId]; diff --git a/src/system/voucher.ts b/src/system/voucher.ts new file mode 100644 index 00000000000..007ca049318 --- /dev/null +++ b/src/system/voucher.ts @@ -0,0 +1,106 @@ +import BattleScene from "../battle-scene"; +import { TrainerType, trainerConfigs } from "../data/trainer-type"; +import { ModifierTier } from "../modifier/modifier-type"; +import { Achv, achvs } from "./achv"; + +export enum VoucherType { + REGULAR, + PLUS, + PREMIUM +} + +export class Voucher { + public id: string; + public voucherType: VoucherType; + public description: string; + + private conditionFunc: (scene: BattleScene, args: any[]) => boolean; + + constructor(voucherType: VoucherType, description: string, conditionFunc?: (scene: BattleScene, args: any[]) => boolean) { + this.description = description; + this.voucherType = voucherType; + this.conditionFunc = conditionFunc; + } + + validate(scene: BattleScene, args: any[]): boolean { + return !this.conditionFunc || this.conditionFunc(scene, args); + } + + getName(): string { + return getVoucherTypeName(this.voucherType); + } + + getIconImage(): string { + return getVoucherTypeIcon(this.voucherType); + } + + getTier(): ModifierTier { + switch (this.voucherType) { + case VoucherType.REGULAR: + return ModifierTier.GREAT; + case VoucherType.PLUS: + return ModifierTier.ULTRA; + case VoucherType.PREMIUM: + return ModifierTier.MASTER; + } + } +} + +export function getVoucherTypeName(voucherType: VoucherType): string { + switch (voucherType) { + case VoucherType.REGULAR: + return 'Egg Voucher'; + case VoucherType.PLUS: + return 'Egg Voucher Plus'; + case VoucherType.PREMIUM: + return 'Egg Voucher Premium'; + } +} + +export function getVoucherTypeIcon(voucherType: VoucherType): string { + switch (voucherType) { + case VoucherType.REGULAR: + return 'coupon'; + case VoucherType.PLUS: + return 'pair_of_tickets'; + case VoucherType.PREMIUM: + return 'mystic_ticket'; + } +} + + +export interface Vouchers { + [key: string]: Voucher +} + +export const vouchers: Vouchers = {}; + +const voucherAchvs: Achv[] = [ achvs.CLASSIC_VICTORY ]; + +{ + (function() { + const bossTrainerTypes = Object.keys(trainerConfigs) + .filter(tt => trainerConfigs[tt].isBoss && trainerConfigs[tt].getDerivedType() !== TrainerType.RIVAL); + + for (let trainerType of bossTrainerTypes) { + const voucherType = trainerConfigs[trainerType].moneyMultiplier < 10 + ? VoucherType.REGULAR + : VoucherType.PLUS; + const key = TrainerType[trainerType]; + vouchers[key] = new Voucher(voucherType, `Defeat ${trainerConfigs[trainerType].name}`); + } + + for (let achv of voucherAchvs) { + const voucherType = achv.score >= 150 + ? VoucherType.PREMIUM + : achv.score >= 100 + ? VoucherType.PLUS + : VoucherType.REGULAR; + vouchers[achv.id] = new Voucher(voucherType, achv.description); + } + + const voucherKeys = Object.keys(vouchers); + for (let k of voucherKeys) + vouchers[k].id = k; + })(); +} \ No newline at end of file diff --git a/src/ui/achv-bar.ts b/src/ui/achv-bar.ts index f06b9affec6..78dda7d3616 100644 --- a/src/ui/achv-bar.ts +++ b/src/ui/achv-bar.ts @@ -1,5 +1,6 @@ import BattleScene from "../battle-scene"; import { Achv } from "../system/achv"; +import { Voucher } from "../system/voucher"; import { TextStyle, addTextObject } from "./text"; export default class AchvBar extends Phaser.GameObjects.Container { @@ -9,7 +10,7 @@ export default class AchvBar extends Phaser.GameObjects.Container { private scoreText: Phaser.GameObjects.Text; private descriptionText: Phaser.GameObjects.Text; - private queue: Achv[] = []; + private queue: (Achv | Voucher)[] = []; public shown: boolean; @@ -47,7 +48,7 @@ export default class AchvBar extends Phaser.GameObjects.Container { this.shown = false; } - showAchv(achv: Achv): void { + showAchv(achv: Achv | Voucher): void { if (this.shown) { this.queue.push(achv); return; @@ -56,10 +57,12 @@ export default class AchvBar extends Phaser.GameObjects.Container { const tier = achv.getTier(); this.bg.setTexture(`achv_bar${tier ? `_${tier + 1}` : ''}`); - this.icon.setFrame(achv.iconImage); - this.titleText.setText(achv.name); + this.icon.setFrame(achv.getIconImage()); + this.titleText.setText(achv.getName()); this.descriptionText.setText(achv.description); - this.scoreText.setText(`+${achv.score}pt`); + + if (achv instanceof Achv) + this.scoreText.setText(`+${(achv as Achv).score}pt`); (this.scene as BattleScene).playSound('achv'); diff --git a/src/ui/command-ui-handler.ts b/src/ui/command-ui-handler.ts index b083ba02f0c..8bbe16d2148 100644 --- a/src/ui/command-ui-handler.ts +++ b/src/ui/command-ui-handler.ts @@ -127,10 +127,10 @@ export default class CommandUiHandler extends UiHandler { if (!this.cursorObj) { this.cursorObj = this.scene.add.image(0, 0, 'cursor'); - ui.add(this.cursorObj); + this.commandsContainer.add(this.cursorObj); } - this.cursorObj.setPosition(211 + (cursor % 2 === 1 ? 56 : 0), -31 + (cursor >= 2 ? 16 : 0)); + this.cursorObj.setPosition(-5 + (cursor % 2 === 1 ? 56 : 0), 8 + (cursor >= 2 ? 16 : 0)); return changed; } diff --git a/src/ui/egg-gacha-ui-handler.ts b/src/ui/egg-gacha-ui-handler.ts new file mode 100644 index 00000000000..7b17317b137 --- /dev/null +++ b/src/ui/egg-gacha-ui-handler.ts @@ -0,0 +1,600 @@ +import BattleScene, { Button } from "../battle-scene"; +import { Mode } from "./ui"; +import { TextStyle, addTextObject, getModifierTierTextTint } from "./text"; +import MessageUiHandler from "./message-ui-handler"; +import * as Utils from "../utils"; +import { ModifierTier } from "../modifier/modifier-type"; +import { EGG_SEED, Egg, GachaType, getEggTierDefaultHatchWaves, getEggDescriptor, getLegendaryGachaSpeciesForTimestamp, getTypeGachaTypeForTimestamp } from "../data/egg"; +import { VoucherType, getVoucherTypeIcon } from "../system/voucher"; +import { getPokemonSpecies } from "../data/pokemon-species"; +import { Type } from "../data/type"; + +const defaultText = 'Select a machine.'; + +export default class EggGachaUiHandler extends MessageUiHandler { + private eggGachaContainer: Phaser.GameObjects.Container; + private eggGachaMessageBox: Phaser.GameObjects.NineSlice; + private eggGachaOptionsContainer: Phaser.GameObjects.Container; + private eggGachaOptionSelectBg: Phaser.GameObjects.NineSlice; + + private gachaContainers: Phaser.GameObjects.Container[]; + private gachaKnobs: Phaser.GameObjects.Sprite[]; + private gachaHatches: Phaser.GameObjects.Sprite[]; + private gachaInfoContainers: Phaser.GameObjects.Container[]; + private eggGachaOverlay: Phaser.GameObjects.Rectangle; + private eggGachaSummaryContainer: Phaser.GameObjects.Container; + + private voucherCountLabels: Phaser.GameObjects.Text[]; + + private gachaCursor: integer; + + private cursorObj: Phaser.GameObjects.Image; + private transitioning: boolean; + private transitionCancelled: boolean; + + constructor(scene: BattleScene) { + super(scene, Mode.EGG_GACHA); + + this.gachaContainers = []; + this.gachaKnobs = []; + this.gachaHatches = []; + this.gachaInfoContainers = []; + + this.voucherCountLabels = []; + } + + setup() { + this.gachaCursor = 0; + + const ui = this.getUi(); + + this.eggGachaContainer = this.scene.add.container(0, -this.scene.game.canvas.height / 6); + this.eggGachaContainer.setVisible(false); + ui.add(this.eggGachaContainer); + + const bg = this.scene.add.nineslice(0, 0, 'default_bg', null, 320, 180, 0, 0, 16, 0); + bg.setOrigin(0, 0); + + this.eggGachaContainer.add(bg); + + const hatchFrameNames = this.scene.anims.generateFrameNames('gacha_hatch', { suffix: ".png", start: 1, end: 4 }); + this.scene.anims.create({ + key: 'open', + frames: hatchFrameNames, + frameRate: 12 + }); + this.scene.anims.create({ + key: 'close', + frames: hatchFrameNames.reverse(), + frameRate: 12 + }); + + Utils.getEnumValues(GachaType).forEach((gachaType, g) => { + const gachaTypeKey = GachaType[gachaType].toString().toLowerCase(); + const gachaContainer = this.scene.add.container(180 * g, 18); + + const gacha = this.scene.add.sprite(0, 0, `gacha_${gachaTypeKey}`); + gacha.setOrigin(0, 0); + + const gachaUnderlay = this.scene.add.sprite(115, 80, `gacha_underlay_${gachaTypeKey}`); + gachaUnderlay.setOrigin(0, 0); + + const gachaGlass = this.scene.add.sprite(0, 0, 'gacha_glass'); + gachaGlass.setOrigin(0, 0); + + const gachaInfoContainer = this.scene.add.container(160, 46); + + const gachaUpLabel = addTextObject(this.scene, 4, 0, 'UP!', TextStyle.WINDOW); + gachaUpLabel.setOrigin(0, 0); + gachaInfoContainer.add(gachaUpLabel); + + switch (gachaType as GachaType) { + case GachaType.LEGENDARY: + const pokemonIcon = this.scene.add.sprite(-20, 6, 'pokemon_icons_0'); + pokemonIcon.setScale(0.5); + pokemonIcon.setOrigin(0, 0.5); + + gachaInfoContainer.add(pokemonIcon); + break; + case GachaType.TYPE: + const typeIcon = this.scene.add.sprite(-22, 7, 'types', 'unknown'); + typeIcon.setScale(0.75); + typeIcon.setOrigin(0, 0.5); + + gachaUpLabel.x += 4; + + gachaInfoContainer.add(typeIcon); + break; + case GachaType.SHINY: + gachaUpLabel.setText('Shiny UP!'); + gachaUpLabel.setX(0); + gachaUpLabel.setOrigin(0.5, 0); + break; + } + + const gachaKnob = this.scene.add.sprite(191, 89, 'gacha_knob'); + + const gachaHatch = this.scene.add.sprite(115, 73, 'gacha_hatch'); + gachaHatch.setOrigin(0, 0); + + gachaContainer.add(gachaUnderlay); + gachaContainer.add(gacha); + gachaContainer.add(gachaGlass); + gachaContainer.add(gachaKnob); + gachaContainer.add(gachaHatch); + gachaContainer.add(gachaInfoContainer); + + gachaGlass.setAlpha(0.5); + gachaHatch.setAlpha(0.9); + + gachaHatch.on('animationupdate', (_anim, frame) => gachaUnderlay.setFrame(frame.textureFrame === '4.png' ? 'open_hatch' : 'default')); + + this.gachaContainers.push(gachaContainer); + this.gachaKnobs.push(gachaKnob); + this.gachaHatches.push(gachaHatch); + this.gachaInfoContainers.push(gachaInfoContainer); + + this.eggGachaContainer.add(gachaContainer); + + this.updateGachaInfo(g); + }); + + this.eggGachaOptionsContainer = this.scene.add.container() + + this.eggGachaOptionsContainer = this.scene.add.container((this.scene.game.canvas.width / 6), 148); + this.eggGachaContainer.add(this.eggGachaOptionsContainer); + + this.eggGachaOptionSelectBg = this.scene.add.nineslice(0, 0, 'window', null, 96, 96, 6, 6, 6, 6); + this.eggGachaOptionSelectBg.setOrigin(1, 1); + this.eggGachaOptionsContainer.add(this.eggGachaOptionSelectBg); + + const optionText = addTextObject(this.scene, 0, 0, ' x1 1 Pull\n x10 10 Pulls\n x1 5 Pulls\n x1 10 Pulls\nCancel', TextStyle.WINDOW, { maxLines: 5 }); + optionText.setLineSpacing(12); + this.eggGachaOptionsContainer.add(optionText); + + optionText.setPositionRelative(this.eggGachaOptionSelectBg, 16, 9); + + new Array(4).fill(null).map((_, i) => { + const voucherType = i < 2 ? VoucherType.REGULAR : i === 2 ? VoucherType.PLUS : VoucherType.PREMIUM; + const icon = this.scene.add.sprite(0, 0, 'items', getVoucherTypeIcon(voucherType)); + icon.setScale(0.5); + icon.setPositionRelative(this.eggGachaOptionSelectBg, 20, 17 + i * 16); + this.eggGachaOptionsContainer.add(icon); + }); + + this.eggGachaContainer.add(this.eggGachaOptionsContainer); + + new Array(Utils.getEnumKeys(VoucherType).length).fill(null).map((_, i) => { + const container = this.scene.add.container((this.scene.game.canvas.width / 6) - 56 * i, 0); + + const bg = this.scene.add.nineslice(0, 0, 'window', null, 56, 22, 6, 6, 6, 6); + bg.setOrigin(1, 0); + container.add(bg); + + const countLabel = addTextObject(this.scene, -48, 3, '0', TextStyle.WINDOW); + countLabel.setOrigin(0, 0); + container.add(countLabel); + + this.voucherCountLabels.push(countLabel); + + const iconImage = getVoucherTypeIcon(i as VoucherType); + + const icon = this.scene.add.sprite(-19, 2, 'items', iconImage); + icon.setOrigin(0, 0); + icon.setScale(0.5); + container.add(icon); + + this.eggGachaContainer.add(container); + }); + + this.eggGachaOverlay = this.scene.add.rectangle(0, 0, bg.displayWidth, bg.displayHeight, 0x000000); + this.eggGachaOverlay.setOrigin(0, 0); + this.eggGachaOverlay.setAlpha(0); + + this.eggGachaContainer.add(this.eggGachaOverlay); + + this.eggGachaSummaryContainer = this.scene.add.container(0, 0); + this.eggGachaSummaryContainer.setVisible(false); + this.eggGachaContainer.add(this.eggGachaSummaryContainer); + + const gachaMessageBoxContainer = this.scene.add.container(0, 148); + this.eggGachaContainer.add(gachaMessageBoxContainer); + + const gachaMessageBox = this.scene.add.nineslice(0, 0, 'window', null, 320, 32, 6, 6, 6, 6); + gachaMessageBox.setOrigin(0, 0); + gachaMessageBoxContainer.add(gachaMessageBox); + + this.eggGachaMessageBox = gachaMessageBox; + + const gachaMessageText = addTextObject(this.scene, 8, 8, '', TextStyle.WINDOW, { maxLines: 2 }); + gachaMessageText.setOrigin(0, 0); + gachaMessageBoxContainer.add(gachaMessageText); + + this.message = gachaMessageText; + + this.eggGachaContainer.add(gachaMessageBoxContainer); + + this.setCursor(0); + } + + show(args: any[]): void { + super.show(args); + + this.getUi().showText(defaultText, 0); + + this.setGachaCursor(1); + + for (let g = 0; g < this.gachaContainers.length; g++) + this.updateGachaInfo(g); + + this.updateVoucherCounts(); + + this.eggGachaContainer.setVisible(true); + } + + getDelayValue(delay: integer) { + if (this.transitioning && this.transitionCancelled) + delay = Math.ceil(delay / 5); + return Utils.fixedInt(delay); + } + + pull(pullCount?: integer, count?: integer, eggs?: Egg[]) { + this.eggGachaOptionsContainer.setVisible(false); + this.setTransitioning(true); + + if (!pullCount) + pullCount = 1; + if (!count) + count = 0; + if (!eggs) { + eggs = []; + + const tiers = new Array(pullCount).fill(null).map(() => { + const tierValue = Utils.randInt(256); + return tierValue >= 52 ? ModifierTier.COMMON : tierValue >= 8 ? ModifierTier.GREAT : tierValue >= 1 ? ModifierTier.ULTRA : ModifierTier.MASTER; + }); + /*if (pullCount >= 100 && !tiers.filter(t => t >= ModifierTier.ULTRA).length) + tiers[Utils.randInt(tiers.length)] = ModifierTier.ULTRA;*/ + if (pullCount >= 10 && !tiers.filter(t => t >= ModifierTier.GREAT).length) + tiers[Utils.randInt(tiers.length)] = ModifierTier.GREAT; + + const timestamp = new Date().getTime(); + + for (let tier of tiers) { + const egg = new Egg(Utils.randInt(EGG_SEED, EGG_SEED * tier), this.gachaCursor, getEggTierDefaultHatchWaves(tier), timestamp); + if (egg.isManaphyEgg()) + egg.hatchWaves = getEggTierDefaultHatchWaves(ModifierTier.ULTRA); + eggs.push(egg); + this.scene.gameData.eggs.push(egg); + } + + this.scene.gameData.saveSystem(); + } + + if (this.transitionCancelled) { + return this.showSummary(eggs); + } + + const egg = this.scene.add.sprite(127, 75, 'egg', `egg_${eggs[count].getKey()}`); + egg.setScale(0.5); + + this.gachaContainers[this.gachaCursor].add(egg); + this.gachaContainers[this.gachaCursor].moveTo(egg, 1); + + const doPullAnim = () => { + this.scene.playSound('gacha_running', { loop: true }); + this.scene.time.delayedCall(this.getDelayValue(count ? 500 : 1250), () => { + this.scene.playSound('gacha_dispense'); + this.scene.time.delayedCall(this.getDelayValue(750), () => { + this.scene.sound.stopByKey('gacha_running'); + this.scene.tweens.add({ + targets: egg, + duration: this.getDelayValue(350), + y: 95, + ease: 'Bounce.easeOut', + onComplete: () => { + this.scene.time.delayedCall(this.getDelayValue(125), () => { + this.scene.playSound('pb_catch'); + this.gachaHatches[this.gachaCursor].play('open'); + this.scene.tweens.add({ + targets: egg, + duration: this.getDelayValue(350), + scale: 0.75, + ease: 'Sine.easeIn' + }); + this.scene.tweens.add({ + targets: egg, + y: 110, + duration: this.getDelayValue(350), + ease: 'Back.easeOut', + onComplete: () => { + this.gachaHatches[this.gachaCursor].play('close'); + this.scene.tweens.add({ + targets: egg, + y: 200, + duration: this.getDelayValue(350), + ease: 'Cubic.easeIn', + onComplete: () => { + if (++count < pullCount) + this.pull(pullCount, count, eggs); + else + this.showSummary(eggs); + } + }); + } + }); + }); + } + }); + }); + }); + }; + + if (!count) { + this.scene.playSound('gacha_dial'); + this.scene.tweens.add({ + targets: this.gachaKnobs[this.gachaCursor], + duration: this.getDelayValue(350), + angle: 90, + ease: 'Cubic.easeInOut', + onComplete: () => { + this.scene.tweens.add({ + targets: this.gachaKnobs[this.gachaCursor], + duration: this.getDelayValue(350), + angle: 0, + ease: 'Sine.easeInOut' + }); + this.scene.time.delayedCall(this.getDelayValue(350), doPullAnim); + } + }); + } else + doPullAnim(); + } + + showSummary(eggs: Egg[]): void { + this.transitioning = false; + this.eggGachaSummaryContainer.setVisible(true); + + this.scene.tweens.add({ + targets: this.eggGachaOverlay, + alpha: 0.5, + ease: 'Sine.easeOut', + duration: 750, + onComplete: () => { + const rows = Math.ceil(eggs.length / 5); + const cols = Math.min(eggs.length, 5); + const height = this.eggGachaOverlay.displayHeight - this.eggGachaMessageBox.displayHeight; + const eggContainers = eggs.map((egg, t) => { + const col = t % 5; + const row = Math.floor(t / 5); + const sliceWidth = this.eggGachaOverlay.displayWidth / (cols + 2); + const sliceHeight = height / (rows + 2); + const yOffset = (sliceHeight / 2 * (row / Math.max(rows - 1, 1))) + sliceHeight / 4; + const ret = this.scene.add.container(sliceWidth * (col + 1) + (sliceWidth * 0.5), sliceHeight * (row + 1) + yOffset); + ret.setScale(0.0001); + + const eggSprite = this.scene.add.sprite(0, 0, 'egg', `egg_${egg.getKey()}`); + ret.add(eggSprite); + + const eggText = addTextObject(this.scene, 0, 14, getEggDescriptor(egg), TextStyle.PARTY, { align: 'center' }); + eggText.setOrigin(0.5, 0); + eggText.setTint(getModifierTierTextTint(!egg.isManaphyEgg() ? egg.tier : ModifierTier.ULTRA)); + ret.add(eggText); + + this.eggGachaSummaryContainer.add(ret); + return ret; + }); + + eggContainers.forEach((eggContainer, e) => { + this.scene.tweens.add({ + targets: eggContainer, + delay: this.getDelayValue(e * 100), + duration: this.getDelayValue(350), + scale: 1, + ease: 'Sine.easeOut' + }); + }); + } + }); + } + + hideSummary() { + this.setTransitioning(true); + this.scene.tweens.add({ + targets: [ this.eggGachaOverlay, this.eggGachaSummaryContainer ], + alpha: 0, + duration: this.getDelayValue(250), + ease: 'Cubic.easeIn', + onComplete: () => { + this.eggGachaSummaryContainer.setVisible(false); + this.eggGachaSummaryContainer.setAlpha(1); + this.eggGachaSummaryContainer.removeAll(true); + this.setTransitioning(false); + this.eggGachaOptionsContainer.setVisible(true); + } + }); + } + + updateGachaInfo(gachaType: GachaType): void { + const infoContainer = this.gachaInfoContainers[gachaType]; + switch (gachaType as GachaType) { + case GachaType.LEGENDARY: + const species = getPokemonSpecies(getLegendaryGachaSpeciesForTimestamp(this.scene, new Date().getTime())); + const pokemonIcon = infoContainer.getAt(1) as Phaser.GameObjects.Sprite; + pokemonIcon.setTexture(species.getIconAtlasKey(), species.getIconId(false)); + break; + case GachaType.TYPE: + const typeIcon = infoContainer.getAt(1) as Phaser.GameObjects.Sprite; + typeIcon.setFrame(Type[getTypeGachaTypeForTimestamp(this.scene, new Date().getTime())].toLowerCase()); + break; + } + } + + consumeVouchers(voucherType: VoucherType, count: integer): void { + this.scene.gameData.voucherCounts[voucherType] = Math.max(this.scene.gameData.voucherCounts[voucherType] - count, 0); + this.updateVoucherCounts(); + } + + updateVoucherCounts(): void { + this.voucherCountLabels.forEach((label, type) => { + label.setText(this.scene.gameData.voucherCounts[type].toString()); + }); + } + + showError(text: string): void { + this.showText(text, null, () => this.showText(defaultText), Utils.fixedInt(1500)); + } + + setTransitioning(transitioning: boolean): void { + if (this.transitioning === transitioning) + return; + this.transitioning = transitioning; + this.transitionCancelled = false; + } + + processInput(button: Button): boolean { + const ui = this.getUi(); + + let success = false; + let error = false; + + if (this.transitioning) { + if (!this.transitionCancelled && (button === Button.ACTION || button === Button.CANCEL)) { + this.transitionCancelled = true; + success = true; + } else + return false; + } else { + + if (this.eggGachaSummaryContainer.visible) { + if (button === Button.ACTION || button === Button.CANCEL) { + this.hideSummary(); + success = true; + } + } else { + switch (button) { + case Button.ACTION: + switch (this.cursor) { + case 0: + if (!this.scene.gameData.voucherCounts[VoucherType.REGULAR]) { + error = true; + this.showError('You don\'t have enough vouchers!'); + } else if (this.scene.gameData.eggs.length < 99) { + this.consumeVouchers(VoucherType.REGULAR, 1); + this.pull(); + success = true; + } else { + error = true; + this.showError('You have too many eggs!'); + } + break; + case 2: + if (!this.scene.gameData.voucherCounts[VoucherType.PLUS]) { + error = true; + this.showError('You don\'t have enough vouchers!'); + } else if (this.scene.gameData.eggs.length < 95) { + this.consumeVouchers(VoucherType.PLUS, 1); + this.pull(5); + success = true; + } else { + error = true; + this.showError('You have too many eggs!'); + } + break; + case 1: + case 3: + if ((this.cursor === 1 && this.scene.gameData.voucherCounts[VoucherType.REGULAR] < 10) + || (this.cursor === 3 && !this.scene.gameData.voucherCounts[VoucherType.PREMIUM])) { + error = true; + this.showError('You don\'t have enough vouchers!'); + } else if (this.scene.gameData.eggs.length < 90) { + if (this.cursor === 3) + this.consumeVouchers(VoucherType.PREMIUM, 1); + else + this.consumeVouchers(VoucherType.REGULAR, 10); + this.pull(10); + success = true; + } else { + error = true; + this.showError('You have too many eggs!'); + } + break; + case 4: + ui.revertMode(); + success = true; + break; + } + break; + case Button.CANCEL: + this.getUi().revertMode(); + success = true; + break; + case Button.UP: + if (this.cursor) + success = this.setCursor(this.cursor - 1); + break; + case Button.DOWN: + if (this.cursor < 4) + success = this.setCursor(this.cursor + 1); + break; + case Button.LEFT: + if (this.gachaCursor) + success = this.setGachaCursor(this.gachaCursor - 1); + break; + case Button.RIGHT: + if (this.gachaCursor < Utils.getEnumKeys(GachaType).length - 1) + success = this.setGachaCursor(this.gachaCursor + 1); + break; + } + } + } + + if (success) + ui.playSelect(); + else if (error) + ui.playError(); + + return success || error; + } + + setCursor(cursor: integer): boolean { + const ret = super.setCursor(cursor); + + if (!this.cursorObj) { + this.cursorObj = this.scene.add.image(0, 0, 'cursor'); + this.eggGachaOptionsContainer.add(this.cursorObj); + } + + this.cursorObj.setPositionRelative(this.eggGachaOptionSelectBg, 10, 17 + this.cursor * 16); + + return ret; + } + + setGachaCursor(cursor: integer): boolean { + let oldCursor = this.gachaCursor; + + let changed = oldCursor !== cursor; + + if (changed) { + this.gachaCursor = cursor; + + this.setTransitioning(true); + + this.scene.tweens.add({ + targets: this.gachaContainers, + duration: this.eggGachaContainer.visible ? 500 : 0, + x: (_target, _key, _value, index) => 180 * (index - cursor), + ease: 'Cubic.easeInOut', + onComplete: () => this.setTransitioning(false) + }); + } + + return changed; + } + + clear(): void { + super.clear(); + this.setGachaCursor(-1); + this.eggGachaContainer.setVisible(false); + } +} \ No newline at end of file diff --git a/src/ui/egg-hatch-scene-handler.ts b/src/ui/egg-hatch-scene-handler.ts index 7105e13ea5e..8d050637a81 100644 --- a/src/ui/egg-hatch-scene-handler.ts +++ b/src/ui/egg-hatch-scene-handler.ts @@ -3,39 +3,40 @@ import { Mode } from "./ui"; import UiHandler from "./uiHandler"; export default class EggHatchSceneHandler extends UiHandler { - public eggHatchContainer: Phaser.GameObjects.Container; + public eggHatchContainer: Phaser.GameObjects.Container; - constructor(scene: BattleScene) { - super(scene, Mode.EGG_HATCH_SCENE); - } - - setup() { - this.eggHatchContainer = this.scene.add.container(0, -this.scene.game.canvas.height / 6); - this.scene.fieldUI.add(this.eggHatchContainer); + constructor(scene: BattleScene) { + super(scene, Mode.EGG_HATCH_SCENE); + } - const eggLightraysAnimFrames = this.scene.anims.generateFrameNames('egg_lightrays', { start: 0, end: 3 }); - this.scene.anims.create({ - key: 'egg_lightrays', - frames: eggLightraysAnimFrames, - frameRate: 32 - }); - } + setup() { + this.eggHatchContainer = this.scene.add.container(0, -this.scene.game.canvas.height / 6); + this.scene.fieldUI.add(this.eggHatchContainer); - show(_args: any[]): void { - super.show(_args); - - this.scene.fieldUI.bringToTop(this.eggHatchContainer); - } - - processInput(button: Button): boolean { - return this.scene.ui.getMessageHandler().processInput(button); - } - - setCursor(_cursor: integer): boolean { - return false; - } + const eggLightraysAnimFrames = this.scene.anims.generateFrameNames('egg_lightrays', { start: 0, end: 3 }); + this.scene.anims.create({ + key: 'egg_lightrays', + frames: eggLightraysAnimFrames, + frameRate: 32 + }); + } - clear() { - this.eggHatchContainer.removeAll(true); - } - } \ No newline at end of file + show(_args: any[]): void { + super.show(_args); + + this.getUi().showText(null, 0); + } + + processInput(button: Button): boolean { + return this.scene.ui.getMessageHandler().processInput(button); + } + + setCursor(_cursor: integer): boolean { + return false; + } + + clear() { + super.clear(); + this.eggHatchContainer.removeAll(true); + } +} \ No newline at end of file diff --git a/src/ui/egg-list-ui-handler.ts b/src/ui/egg-list-ui-handler.ts new file mode 100644 index 00000000000..e62524316cc --- /dev/null +++ b/src/ui/egg-list-ui-handler.ts @@ -0,0 +1,201 @@ +import BattleScene, { Button } from "../battle-scene"; +import { Mode } from "./ui"; +import PokemonIconAnimHandler, { PokemonIconAnimMode } from "./pokemon-icon-anim-handler"; +import { TextStyle, addTextObject } from "./text"; +import MessageUiHandler from "./message-ui-handler"; +import { EGG_SEED, Egg, GachaType, getEggGachaTypeDescriptor, getEggHatchWavesMessage, getEggDescriptor } from "../data/egg"; +import * as Utils from "../utils"; + +export default class EggListUiHandler extends MessageUiHandler { + private eggListContainer: Phaser.GameObjects.Container; + private eggListIconContainer: Phaser.GameObjects.Container; + private eggSprite: Phaser.GameObjects.Sprite; + private eggNameText: Phaser.GameObjects.Text; + private eggDateText: Phaser.GameObjects.Text; + private eggHatchWavesText: Phaser.GameObjects.Text; + private eggGachaInfoText: Phaser.GameObjects.Text; + private eggListMessageBoxContainer: Phaser.GameObjects.Container; + + private cursorObj: Phaser.GameObjects.Image; + + private iconAnimHandler: PokemonIconAnimHandler; + + constructor(scene: BattleScene) { + super(scene, Mode.EGG_LIST); + } + + setup() { + const ui = this.getUi(); + + this.eggListContainer = this.scene.add.container(0, -this.scene.game.canvas.height / 6); + this.eggListContainer.setVisible(false); + ui.add(this.eggListContainer); + + const bgColor = this.scene.add.rectangle(0, 0, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6, 0x006860); + bgColor.setOrigin(0, 0); + this.eggListContainer.add(bgColor); + + const starterSelectBg = this.scene.add.image(1, 1, 'egg_list_bg'); + starterSelectBg.setOrigin(0, 0); + this.eggListContainer.add(starterSelectBg); + + this.iconAnimHandler = new PokemonIconAnimHandler(); + this.iconAnimHandler.setup(this.scene); + + this.eggNameText = addTextObject(this.scene, 6, 66, '', TextStyle.SUMMARY); + this.eggNameText.setOrigin(0, 0); + this.eggListContainer.add(this.eggNameText); + + this.eggDateText = addTextObject(this.scene, 8, 91, '', TextStyle.TOOLTIP_CONTENT); + this.eggListContainer.add(this.eggDateText); + + this.eggHatchWavesText = addTextObject(this.scene, 8, 108, '', TextStyle.TOOLTIP_CONTENT); + this.eggHatchWavesText.setWordWrapWidth(540); + this.eggListContainer.add(this.eggHatchWavesText); + + this.eggGachaInfoText = addTextObject(this.scene, 8, 152, '', TextStyle.TOOLTIP_CONTENT); + this.eggGachaInfoText.setWordWrapWidth(540); + this.eggListContainer.add(this.eggGachaInfoText); + + this.eggListIconContainer = this.scene.add.container(115, 9); + this.eggListContainer.add(this.eggListIconContainer); + + this.cursorObj = this.scene.add.image(0, 0, 'starter_select_cursor'); + this.cursorObj.setOrigin(0, 0); + this.eggListContainer.add(this.cursorObj); + + this.eggSprite = this.scene.add.sprite(54, 37, `egg`); + this.eggListContainer.add(this.eggSprite); + + this.eggListMessageBoxContainer = this.scene.add.container(0, this.scene.game.canvas.height / 6); + this.eggListMessageBoxContainer.setVisible(false); + this.eggListContainer.add(this.eggListMessageBoxContainer); + + const starterSelectMessageBox = this.scene.add.image(0, 0, 'starter_select_message'); + starterSelectMessageBox.setOrigin(0, 1); + this.eggListMessageBoxContainer.add(starterSelectMessageBox); + + this.message = addTextObject(this.scene, 8, -8, '', TextStyle.WINDOW, { maxLines: 1 }); + this.message.setOrigin(0, 1); + this.eggListMessageBoxContainer.add(this.message); + + this.cursor = -1; + } + + show(args: any[]): void { + super.show(args); + + this.eggListContainer.setVisible(true); + + let e = 0; + + /*this.scene.gameData.eggs = [ + new Egg(1, 1, 5, new Date().getTime()), + new Egg(1 + EGG_SEED, 1, 15, new Date().getTime()), + new Egg(1 + EGG_SEED * 2, 1, 50, new Date().getTime()), + new Egg(1 + EGG_SEED * 3, GachaType.LEGENDARY, 100, new Date().getTime()) + ];*/ + + for (let egg of this.scene.gameData.eggs) { + const x = (e % 11) * 18; + const y = Math.floor(e / 11) * 18; + const icon = this.scene.add.sprite(x - 2, y + 2, 'egg_icons'); + icon.setScale(0.5); + icon.setOrigin(0, 0); + icon.setFrame(egg.getKey()); + this.eggListIconContainer.add(icon); + this.iconAnimHandler.addOrUpdate(icon, PokemonIconAnimMode.NONE); + e++; + } + + this.setCursor(0); + } + + showText(text: string, delay?: integer, callback?: Function, callbackDelay?: integer, prompt?: boolean, promptDelay?: integer) { + super.showText(text, delay, callback, callbackDelay, prompt, promptDelay); + } + + processInput(button: Button): boolean { + const ui = this.getUi(); + + let success = false; + let error = false; + + if (button === Button.CANCEL) { + ui.revertMode(); + success = true; + } else { + const eggCount = this.eggListIconContainer.getAll().length; + const rows = Math.ceil(eggCount / 11); + const row = Math.floor(this.cursor / 11); + switch (button) { + case Button.UP: + if (row) + success = this.setCursor(this.cursor - 11); + break; + case Button.DOWN: + if (row < rows - 2 || (row < rows - 1 && this.cursor % 11 <= (eggCount - 1) % 11)) + success = this.setCursor(this.cursor + 11); + break; + case Button.LEFT: + if (this.cursor % 11) + success = this.setCursor(this.cursor - 1); + break; + case Button.RIGHT: + if (this.cursor % 11 < (row < rows - 1 ? 10 : (eggCount - 1) % 11)) + success = this.setCursor(this.cursor + 1); + break; + } + } + + if (success) + ui.playSelect(); + else if (error) + ui.playError(); + + return success || error; + } + + setEggDetails(egg: Egg): void { + this.eggSprite.setFrame(`egg_${egg.getKey()}`); + this.eggNameText.setText(`Egg (${getEggDescriptor(egg)})`); + this.eggDateText.setText( + new Date(egg.timestamp).toLocaleString(undefined, { + weekday: 'short', + year: 'numeric', + month: '2-digit', + day: 'numeric' + }) + ); + this.eggHatchWavesText.setText(getEggHatchWavesMessage(egg.hatchWaves)); + this.eggGachaInfoText.setText(getEggGachaTypeDescriptor(this.scene, egg)); + } + + setCursor(cursor: integer): boolean { + let changed = false; + + let lastCursor = this.cursor; + + changed = super.setCursor(cursor); + + if (changed) { + this.cursorObj.setPosition(114 + 18 * (cursor % 11), 10 + 18 * Math.floor(cursor / 11)); + + if (lastCursor > -1) + this.iconAnimHandler.addOrUpdate(this.eggListIconContainer.getAt(lastCursor) as Phaser.GameObjects.Sprite, PokemonIconAnimMode.NONE); + this.iconAnimHandler.addOrUpdate(this.eggListIconContainer.getAt(cursor) as Phaser.GameObjects.Sprite, PokemonIconAnimMode.ACTIVE); + + this.setEggDetails(this.scene.gameData.eggs[cursor]); + } + + return changed; + } + + clear(): void { + super.clear(); + this.cursor = -1; + this.eggListContainer.setVisible(false); + this.iconAnimHandler.removeAll(); + this.eggListIconContainer.removeAll(true); + } +} \ No newline at end of file diff --git a/src/ui/menu-ui-handler.ts b/src/ui/menu-ui-handler.ts index 244da125e5a..f6282e849f8 100644 --- a/src/ui/menu-ui-handler.ts +++ b/src/ui/menu-ui-handler.ts @@ -6,7 +6,10 @@ import * as Utils from "../utils"; export enum MenuOptions { SETTINGS, - ACHIEVEMENTS + ACHIEVEMENTS, + VOUCHERS, + EGG_LIST, + EGG_GACHA } export default class MenuUiHandler extends UiHandler { @@ -62,6 +65,7 @@ export default class MenuUiHandler extends UiHandler { const ui = this.getUi(); let success = false; + let error = false; if (button === Button.ACTION) { switch (this.cursor as MenuOptions) { @@ -73,6 +77,24 @@ export default class MenuUiHandler extends UiHandler { this.scene.ui.setOverlayMode(Mode.ACHIEVEMENTS); success = true; break; + case MenuOptions.VOUCHERS: + this.scene.ui.setOverlayMode(Mode.VOUCHERS); + success = true; + break; + case MenuOptions.EGG_LIST: + if (this.scene.gameData.eggs.length) { + this.scene.ui.revertMode(); + this.scene.ui.setOverlayMode(Mode.EGG_LIST); + success = true; + } else + error = true; + break; + case MenuOptions.EGG_GACHA: + this.scene.ui.revertMode(); + this.scene.ui.setOverlayMode(Mode.EGG_GACHA); + success = true; + break; + } } else if (button === Button.CANCEL) { success = true; @@ -93,6 +115,8 @@ export default class MenuUiHandler extends UiHandler { if (success) ui.playSelect(); + else if (error) + ui.playError(); return true; } diff --git a/src/ui/pokemon-icon-anim-handler.ts b/src/ui/pokemon-icon-anim-handler.ts index 29f7366e57b..efa16f296fe 100644 --- a/src/ui/pokemon-icon-anim-handler.ts +++ b/src/ui/pokemon-icon-anim-handler.ts @@ -8,7 +8,6 @@ export enum PokemonIconAnimMode { } export default class PokemonIconAnimHandler { - private counter: Phaser.Tweens.Tween; private icons: Map; private toggled: boolean; @@ -22,7 +21,7 @@ export default class PokemonIconAnimHandler { for (let i of this.icons.keys()) i.y += this.getModeYDelta(this.icons.get(i)) * (this.toggled ? 1 : -1); }; - this.counter = scene.tweens.addCounter({ + scene.tweens.addCounter({ duration: Utils.fixedInt(200), from: 0, to: 1, @@ -70,4 +69,12 @@ export default class PokemonIconAnimHandler { this.icons.delete(i); } } + + removeAll(): void { + for (let i of this.icons.keys()) { + if (this.toggled) + i.y -= this.getModeYDelta(this.icons.get(i)); + this.icons.delete(i); + } + } } \ No newline at end of file diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index e6c002f7237..1a71efc4c5d 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -25,850 +25,850 @@ export interface Starter { const gens = [ 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII' ]; export default class StarterSelectUiHandler extends MessageUiHandler { - private starterSelectContainer: Phaser.GameObjects.Container; - private starterSelectGenIconContainers: Phaser.GameObjects.Container[]; - private pokemonNumberText: Phaser.GameObjects.Text; - private pokemonSprite: Phaser.GameObjects.Sprite; - private pokemonNameText: Phaser.GameObjects.Text; - private pokemonGrowthRateLabelText: Phaser.GameObjects.Text; - private pokemonGrowthRateText: Phaser.GameObjects.Text; - private pokemonGenderText: Phaser.GameObjects.Text; - private pokemonAbilityLabelText: Phaser.GameObjects.Text; - private pokemonAbilityText: Phaser.GameObjects.Text; - private genOptionsText: Phaser.GameObjects.Text; - private instructionsText: Phaser.GameObjects.Text; - private starterSelectMessageBoxContainer: Phaser.GameObjects.Container; - private statsContainer: StatsContainer; + private starterSelectContainer: Phaser.GameObjects.Container; + private starterSelectGenIconContainers: Phaser.GameObjects.Container[]; + private pokemonNumberText: Phaser.GameObjects.Text; + private pokemonSprite: Phaser.GameObjects.Sprite; + private pokemonNameText: Phaser.GameObjects.Text; + private pokemonGrowthRateLabelText: Phaser.GameObjects.Text; + private pokemonGrowthRateText: Phaser.GameObjects.Text; + private pokemonGenderText: Phaser.GameObjects.Text; + private pokemonAbilityLabelText: Phaser.GameObjects.Text; + private pokemonAbilityText: Phaser.GameObjects.Text; + private genOptionsText: Phaser.GameObjects.Text; + private instructionsText: Phaser.GameObjects.Text; + private starterSelectMessageBoxContainer: Phaser.GameObjects.Container; + private statsContainer: StatsContainer; - private genMode: boolean; - private statsMode: boolean; - private dexAttrCursor: bigint = 0n; - private genCursor: integer = 0; - private genScrollCursor: integer = 0; + private genMode: boolean; + private statsMode: boolean; + private dexAttrCursor: bigint = 0n; + private genCursor: integer = 0; + private genScrollCursor: integer = 0; - private genSpecies: PokemonSpecies[][] = []; - private lastSpecies: PokemonSpecies; - private speciesLoaded: Map = new Map(); - private starterGens: integer[] = []; - private starterCursors: integer[] = []; - private pokerusGens: integer[] = []; - private pokerusCursors: integer[] = []; - private starterAttr: bigint[] = []; - private speciesStarterDexEntry: DexEntry; - private canCycleShiny: boolean; - private canCycleForm: boolean; - private canCycleGender: boolean; - private canCycleAbility: boolean; - private value: integer = 0; + private genSpecies: PokemonSpecies[][] = []; + private lastSpecies: PokemonSpecies; + private speciesLoaded: Map = new Map(); + private starterGens: integer[] = []; + private starterCursors: integer[] = []; + private pokerusGens: integer[] = []; + private pokerusCursors: integer[] = []; + private starterAttr: bigint[] = []; + private speciesStarterDexEntry: DexEntry; + private canCycleShiny: boolean; + private canCycleForm: boolean; + private canCycleGender: boolean; + private canCycleAbility: boolean; + private value: integer = 0; - private assetLoadCancelled: Utils.BooleanHolder; - private cursorObj: Phaser.GameObjects.Image; - private starterCursorObjs: Phaser.GameObjects.Image[]; - private pokerusCursorObjs: Phaser.GameObjects.Image[]; - private starterIcons: Phaser.GameObjects.Sprite[]; - private genCursorObj: Phaser.GameObjects.Image; - private genCursorHighlightObj: Phaser.GameObjects.Image; - private valueLimitLabel: Phaser.GameObjects.Text; - private startCursorObj: Phaser.GameObjects.NineSlice; - private starterValueLabels: Phaser.GameObjects.Text[]; - private shinyIcons: Phaser.GameObjects.Image[]; + private assetLoadCancelled: Utils.BooleanHolder; + private cursorObj: Phaser.GameObjects.Image; + private starterCursorObjs: Phaser.GameObjects.Image[]; + private pokerusCursorObjs: Phaser.GameObjects.Image[]; + private starterIcons: Phaser.GameObjects.Sprite[]; + private genCursorObj: Phaser.GameObjects.Image; + private genCursorHighlightObj: Phaser.GameObjects.Image; + private valueLimitLabel: Phaser.GameObjects.Text; + private startCursorObj: Phaser.GameObjects.NineSlice; + private starterValueLabels: Phaser.GameObjects.Text[]; + private shinyIcons: Phaser.GameObjects.Image[]; - private iconAnimHandler: PokemonIconAnimHandler; + private iconAnimHandler: PokemonIconAnimHandler; - private starterSelectCallback: StarterSelectCallback; - - constructor(scene: BattleScene) { - super(scene, Mode.STARTER_SELECT); - } - - setup() { - const ui = this.getUi(); - - this.starterSelectContainer = this.scene.add.container(0, -this.scene.game.canvas.height / 6); - this.starterSelectContainer.setVisible(false); - ui.add(this.starterSelectContainer); + private starterSelectCallback: StarterSelectCallback; - const bgColor = this.scene.add.rectangle(0, 0, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6, 0x006860); - bgColor.setOrigin(0, 0); - this.starterSelectContainer.add(bgColor); + constructor(scene: BattleScene) { + super(scene, Mode.STARTER_SELECT); + } - const starterSelectBg = this.scene.add.image(1, 1, 'starter_select_bg'); - starterSelectBg.setOrigin(0, 0); - this.starterSelectContainer.add(starterSelectBg); + setup() { + const ui = this.getUi(); - this.iconAnimHandler = new PokemonIconAnimHandler(); - this.iconAnimHandler.setup(this.scene); + this.starterSelectContainer = this.scene.add.container(0, -this.scene.game.canvas.height / 6); + this.starterSelectContainer.setVisible(false); + ui.add(this.starterSelectContainer); - this.pokemonNumberText = addTextObject(this.scene, 17, 1, '000', TextStyle.SUMMARY); - this.pokemonNumberText.setOrigin(0, 0); - this.starterSelectContainer.add(this.pokemonNumberText); + const bgColor = this.scene.add.rectangle(0, 0, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6, 0x006860); + bgColor.setOrigin(0, 0); + this.starterSelectContainer.add(bgColor); - this.pokemonNameText = addTextObject(this.scene, 6, 112, '', TextStyle.SUMMARY); - this.pokemonNameText.setOrigin(0, 0); - this.starterSelectContainer.add(this.pokemonNameText); + const starterSelectBg = this.scene.add.image(1, 1, 'starter_select_bg'); + starterSelectBg.setOrigin(0, 0); + this.starterSelectContainer.add(starterSelectBg); - this.pokemonGrowthRateLabelText = addTextObject(this.scene, 8, 103, 'Growth Rate:', TextStyle.SUMMARY, { fontSize: '48px' }); - this.pokemonGrowthRateLabelText.setOrigin(0, 0); - this.pokemonGrowthRateLabelText.setVisible(false); - this.starterSelectContainer.add(this.pokemonGrowthRateLabelText); + this.iconAnimHandler = new PokemonIconAnimHandler(); + this.iconAnimHandler.setup(this.scene); - this.pokemonGrowthRateText = addTextObject(this.scene, 44, 103, '', TextStyle.SUMMARY_RED, { fontSize: '48px' }); - this.pokemonGrowthRateText.setOrigin(0, 0); - this.starterSelectContainer.add(this.pokemonGrowthRateText); + this.pokemonNumberText = addTextObject(this.scene, 17, 1, '000', TextStyle.SUMMARY); + this.pokemonNumberText.setOrigin(0, 0); + this.starterSelectContainer.add(this.pokemonNumberText); - this.pokemonGenderText = addTextObject(this.scene, 96, 112, '', TextStyle.SUMMARY); - this.pokemonGenderText.setOrigin(0, 0); - this.starterSelectContainer.add(this.pokemonGenderText); + this.pokemonNameText = addTextObject(this.scene, 6, 112, '', TextStyle.SUMMARY); + this.pokemonNameText.setOrigin(0, 0); + this.starterSelectContainer.add(this.pokemonNameText); - this.pokemonAbilityLabelText = addTextObject(this.scene, 6, 126, 'Ability:', TextStyle.SUMMARY, { fontSize: '64px' }); - this.pokemonAbilityLabelText.setOrigin(0, 0); - this.pokemonAbilityLabelText.setVisible(false); - this.starterSelectContainer.add(this.pokemonAbilityLabelText); + this.pokemonGrowthRateLabelText = addTextObject(this.scene, 8, 103, 'Growth Rate:', TextStyle.SUMMARY, { fontSize: '48px' }); + this.pokemonGrowthRateLabelText.setOrigin(0, 0); + this.pokemonGrowthRateLabelText.setVisible(false); + this.starterSelectContainer.add(this.pokemonGrowthRateLabelText); - this.pokemonAbilityText = addTextObject(this.scene, 38, 126, '', TextStyle.SUMMARY, { fontSize: '64px' }); - this.pokemonAbilityText.setOrigin(0, 0); - this.starterSelectContainer.add(this.pokemonAbilityText); + this.pokemonGrowthRateText = addTextObject(this.scene, 44, 103, '', TextStyle.SUMMARY_RED, { fontSize: '48px' }); + this.pokemonGrowthRateText.setOrigin(0, 0); + this.starterSelectContainer.add(this.pokemonGrowthRateText); - this.genOptionsText = addTextObject(this.scene, 124, 7, '', TextStyle.WINDOW, { fontSize: 72, lineSpacing: 39, align: 'center' }); - this.genOptionsText.setShadowOffset(4.5, 4.5); - this.genOptionsText.setOrigin(0.5, 0); - this.starterSelectContainer.add(this.genOptionsText); + this.pokemonGenderText = addTextObject(this.scene, 96, 112, '', TextStyle.SUMMARY); + this.pokemonGenderText.setOrigin(0, 0); + this.starterSelectContainer.add(this.pokemonGenderText); - this.updateGenOptions(); + this.pokemonAbilityLabelText = addTextObject(this.scene, 6, 126, 'Ability:', TextStyle.SUMMARY, { fontSize: '64px' }); + this.pokemonAbilityLabelText.setOrigin(0, 0); + this.pokemonAbilityLabelText.setVisible(false); + this.starterSelectContainer.add(this.pokemonAbilityLabelText); - this.starterSelectGenIconContainers = new Array(gens.length).fill(null).map((_, i) => { - const container = this.scene.add.container(149, 9); - if (i) - container.setVisible(false); - this.starterSelectContainer.add(container); - return container; - }); + this.pokemonAbilityText = addTextObject(this.scene, 38, 126, '', TextStyle.SUMMARY, { fontSize: '64px' }); + this.pokemonAbilityText.setOrigin(0, 0); + this.starterSelectContainer.add(this.pokemonAbilityText); - this.pokerusCursorObjs = new Array(3).fill(null).map(() => { - const cursorObj = this.scene.add.image(0, 0, 'starter_select_cursor_pokerus'); - cursorObj.setVisible(false); - cursorObj.setOrigin(0, 0); - this.starterSelectContainer.add(cursorObj); - return cursorObj; - }); + this.genOptionsText = addTextObject(this.scene, 124, 7, '', TextStyle.WINDOW, { fontSize: 72, lineSpacing: 39, align: 'center' }); + this.genOptionsText.setShadowOffset(4.5, 4.5); + this.genOptionsText.setOrigin(0.5, 0); + this.starterSelectContainer.add(this.genOptionsText); - this.starterCursorObjs = new Array(3).fill(null).map(() => { - const cursorObj = this.scene.add.image(0, 0, 'starter_select_cursor_highlight'); - cursorObj.setVisible(false); - cursorObj.setOrigin(0, 0); - this.starterSelectContainer.add(cursorObj); - return cursorObj; - }); + this.updateGenOptions(); - this.cursorObj = this.scene.add.image(0, 0, 'starter_select_cursor'); - this.cursorObj.setOrigin(0, 0); - this.starterSelectContainer.add(this.cursorObj); + this.starterSelectGenIconContainers = new Array(gens.length).fill(null).map((_, i) => { + const container = this.scene.add.container(149, 9); + if (i) + container.setVisible(false); + this.starterSelectContainer.add(container); + return container; + }); - this.genCursorHighlightObj = this.scene.add.image(111, 5, 'starter_select_gen_cursor_highlight'); - this.genCursorHighlightObj.setOrigin(0, 0); - this.starterSelectContainer.add(this.genCursorHighlightObj); + this.pokerusCursorObjs = new Array(3).fill(null).map(() => { + const cursorObj = this.scene.add.image(0, 0, 'starter_select_cursor_pokerus'); + cursorObj.setVisible(false); + cursorObj.setOrigin(0, 0); + this.starterSelectContainer.add(cursorObj); + return cursorObj; + }); - this.genCursorObj = this.scene.add.image(111, 5, 'starter_select_gen_cursor'); - this.genCursorObj.setVisible(false); - this.genCursorObj.setOrigin(0, 0); - this.starterSelectContainer.add(this.genCursorObj); - - this.valueLimitLabel = addTextObject(this.scene, 124, 150, '0/10', TextStyle.TOOLTIP_CONTENT); - this.valueLimitLabel.setOrigin(0.5, 0); - this.starterSelectContainer.add(this.valueLimitLabel); + this.starterCursorObjs = new Array(3).fill(null).map(() => { + const cursorObj = this.scene.add.image(0, 0, 'starter_select_cursor_highlight'); + cursorObj.setVisible(false); + cursorObj.setOrigin(0, 0); + this.starterSelectContainer.add(cursorObj); + return cursorObj; + }); - const startLabel = addTextObject(this.scene, 124, 162, 'Start', TextStyle.TOOLTIP_CONTENT); - startLabel.setOrigin(0.5, 0); - this.starterSelectContainer.add(startLabel); + this.cursorObj = this.scene.add.image(0, 0, 'starter_select_cursor'); + this.cursorObj.setOrigin(0, 0); + this.starterSelectContainer.add(this.cursorObj); - this.startCursorObj = this.scene.add.nineslice(111, 160, 'starter_select_cursor', null, 26, 15, 1, 1, 1, 1); - this.startCursorObj.setVisible(false); - this.startCursorObj.setOrigin(0, 0); - this.starterSelectContainer.add(this.startCursorObj); + this.genCursorHighlightObj = this.scene.add.image(111, 5, 'starter_select_gen_cursor_highlight'); + this.genCursorHighlightObj.setOrigin(0, 0); + this.starterSelectContainer.add(this.genCursorHighlightObj); - const starterSpecies: Species[] = []; - - for (let g = 0; g < this.starterSelectGenIconContainers.length; g++) { - let s = 0; - this.genSpecies.push([]); + this.genCursorObj = this.scene.add.image(111, 5, 'starter_select_gen_cursor'); + this.genCursorObj.setVisible(false); + this.genCursorObj.setOrigin(0, 0); + this.starterSelectContainer.add(this.genCursorObj); + + this.valueLimitLabel = addTextObject(this.scene, 124, 150, '0/10', TextStyle.TOOLTIP_CONTENT); + this.valueLimitLabel.setOrigin(0.5, 0); + this.starterSelectContainer.add(this.valueLimitLabel); - for (let species of allSpecies) { - if (!speciesStarterValues.hasOwnProperty(species.speciesId) || species.generation !== g + 1) - continue; - starterSpecies.push(species.speciesId); - this.speciesLoaded.set(species.speciesId, false); - this.genSpecies[g].push(species); - const defaultDexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(species); - const defaultProps = this.scene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr); - const x = (s % 9) * 18; - const y = Math.floor(s / 9) * 18; - const icon = this.scene.add.sprite(x - 2, y + 2, species.getIconAtlasKey(defaultProps.formIndex)); - icon.setScale(0.5); - icon.setOrigin(0, 0); - icon.setFrame(species.getIconId(defaultProps.female, defaultProps.formIndex, defaultProps.shiny)); - icon.setTintFill(0); - this.starterSelectGenIconContainers[g].add(icon); - this.iconAnimHandler.addOrUpdate(icon, PokemonIconAnimMode.NONE); - s++; - } - } + const startLabel = addTextObject(this.scene, 124, 162, 'Start', TextStyle.TOOLTIP_CONTENT); + startLabel.setOrigin(0.5, 0); + this.starterSelectContainer.add(startLabel); - this.starterIcons = new Array(3).fill(null).map((_, i) => { - const icon = this.scene.add.sprite(113, 97 + 16 * i, 'pokemon_icons_0'); + this.startCursorObj = this.scene.add.nineslice(111, 160, 'starter_select_cursor', null, 26, 15, 1, 1, 1, 1); + this.startCursorObj.setVisible(false); + this.startCursorObj.setOrigin(0, 0); + this.starterSelectContainer.add(this.startCursorObj); + + const starterSpecies: Species[] = []; + + for (let g = 0; g < this.starterSelectGenIconContainers.length; g++) { + let s = 0; + this.genSpecies.push([]); + + for (let species of allSpecies) { + if (!speciesStarterValues.hasOwnProperty(species.speciesId) || species.generation !== g + 1) + continue; + starterSpecies.push(species.speciesId); + this.speciesLoaded.set(species.speciesId, false); + this.genSpecies[g].push(species); + const defaultDexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(species); + const defaultProps = this.scene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr); + const x = (s % 9) * 18; + const y = Math.floor(s / 9) * 18; + const icon = this.scene.add.sprite(x - 2, y + 2, species.getIconAtlasKey(defaultProps.formIndex)); icon.setScale(0.5); icon.setOrigin(0, 0); - icon.setFrame('unknown'); - this.starterSelectContainer.add(icon); - this.iconAnimHandler.addOrUpdate(icon, PokemonIconAnimMode.PASSIVE); - return icon; - }); + icon.setFrame(species.getIconId(defaultProps.female, defaultProps.formIndex, defaultProps.shiny)); + icon.setTintFill(0); + this.starterSelectGenIconContainers[g].add(icon); + this.iconAnimHandler.addOrUpdate(icon, PokemonIconAnimMode.NONE); + s++; + } + } - this.starterValueLabels = new Array(81).fill(null).map((_, i) => { - const x = (i % 9) * 18; - const y = Math.floor(i / 9) * 18; - const ret = addTextObject(this.scene, x + 150, y + 11, '0', TextStyle.WINDOW, { fontSize: '32px' }); - ret.setShadowOffset(2, 2); - ret.setOrigin(0, 0); - ret.setVisible(false); - this.starterSelectContainer.add(ret); - return ret; - }); + this.starterIcons = new Array(3).fill(null).map((_, i) => { + const icon = this.scene.add.sprite(113, 97 + 16 * i, 'pokemon_icons_0'); + icon.setScale(0.5); + icon.setOrigin(0, 0); + icon.setFrame('unknown'); + this.starterSelectContainer.add(icon); + this.iconAnimHandler.addOrUpdate(icon, PokemonIconAnimMode.PASSIVE); + return icon; + }); - this.shinyIcons = new Array(81).fill(null).map((_, i) => { - const x = (i % 9) * 18; - const y = Math.floor(i / 9) * 18; - const ret = this.scene.add.image(x + 161, y + 11, 'shiny_star'); - ret.setOrigin(0, 0); - ret.setScale(0.5); - ret.setVisible(false); - this.starterSelectContainer.add(ret); - return ret; - }); + this.starterValueLabels = new Array(81).fill(null).map((_, i) => { + const x = (i % 9) * 18; + const y = Math.floor(i / 9) * 18; + const ret = addTextObject(this.scene, x + 150, y + 11, '0', TextStyle.WINDOW, { fontSize: '32px' }); + ret.setShadowOffset(2, 2); + ret.setOrigin(0, 0); + ret.setVisible(false); + this.starterSelectContainer.add(ret); + return ret; + }); - this.pokemonSprite = this.scene.add.sprite(53, 63, `pkmn__sub`); - this.starterSelectContainer.add(this.pokemonSprite); + this.shinyIcons = new Array(81).fill(null).map((_, i) => { + const x = (i % 9) * 18; + const y = Math.floor(i / 9) * 18; + const ret = this.scene.add.image(x + 161, y + 11, 'shiny_star'); + ret.setOrigin(0, 0); + ret.setScale(0.5); + ret.setVisible(false); + this.starterSelectContainer.add(ret); + return ret; + }); - this.instructionsText = addTextObject(this.scene, 4, 140, '', TextStyle.PARTY, { fontSize: '42px' }); - this.starterSelectContainer.add(this.instructionsText); + this.pokemonSprite = this.scene.add.sprite(53, 63, `pkmn__sub`); + this.starterSelectContainer.add(this.pokemonSprite); - this.starterSelectMessageBoxContainer = this.scene.add.container(0, this.scene.game.canvas.height / 6); - this.starterSelectMessageBoxContainer.setVisible(false); - this.starterSelectContainer.add(this.starterSelectMessageBoxContainer); + this.instructionsText = addTextObject(this.scene, 4, 140, '', TextStyle.PARTY, { fontSize: '42px' }); + this.starterSelectContainer.add(this.instructionsText); - const starterSelectMessageBox = this.scene.add.image(0, 0, 'starter_select_message'); - starterSelectMessageBox.setOrigin(0, 1); - this.starterSelectMessageBoxContainer.add(starterSelectMessageBox); + this.starterSelectMessageBoxContainer = this.scene.add.container(0, this.scene.game.canvas.height / 6); + this.starterSelectMessageBoxContainer.setVisible(false); + this.starterSelectContainer.add(this.starterSelectMessageBoxContainer); - this.message = addTextObject(this.scene, 8, -8, '', TextStyle.WINDOW, { maxLines: 1 }); - this.message.setOrigin(0, 1); - this.starterSelectMessageBoxContainer.add(this.message); + const starterSelectMessageBox = this.scene.add.image(0, 0, 'starter_select_message'); + starterSelectMessageBox.setOrigin(0, 1); + this.starterSelectMessageBoxContainer.add(starterSelectMessageBox); - const date = new Date(); - date.setUTCHours(0, 0, 0, 0); + this.message = addTextObject(this.scene, 8, -8, '', TextStyle.WINDOW, { maxLines: 1 }); + this.message.setOrigin(0, 1); + this.starterSelectMessageBoxContainer.add(this.message); - this.scene.executeWithSeedOffset(() => { - for (let c = 0; c < 3; c++) { - let randomSpeciesId: Species; - let species: PokemonSpecies; - let pokerusCursor: integer; + const date = new Date(); + date.setUTCHours(0, 0, 0, 0); - const generateSpecies = () => { - randomSpeciesId = Phaser.Math.RND.pick(starterSpecies); - species = getPokemonSpecies(randomSpeciesId); - pokerusCursor = this.genSpecies[species.generation - 1].indexOf(species); - }; - - let dupe = false; + this.scene.executeWithSeedOffset(() => { + for (let c = 0; c < 3; c++) { + let randomSpeciesId: Species; + let species: PokemonSpecies; + let pokerusCursor: integer; - do { - generateSpecies(); + const generateSpecies = () => { + randomSpeciesId = Phaser.Math.RND.pick(starterSpecies); + species = getPokemonSpecies(randomSpeciesId); + pokerusCursor = this.genSpecies[species.generation - 1].indexOf(species); + }; + + let dupe = false; - for (let pc = 0; pc < c; pc++) { - if (this.pokerusGens[pc] === species.generation -1 && this.pokerusCursors[pc] === pokerusCursor) { - dupe = true; + do { + generateSpecies(); + + for (let pc = 0; pc < c; pc++) { + if (this.pokerusGens[pc] === species.generation -1 && this.pokerusCursors[pc] === pokerusCursor) { + dupe = true; + break; + } + } + } while (dupe); + + this.pokerusGens.push(species.generation - 1); + this.pokerusCursors.push(pokerusCursor); + this.pokerusCursorObjs[c].setPosition(148 + 18 * (pokerusCursor % 9), 10 + 18 * Math.floor(pokerusCursor / 9)); + } + }, 0, date.getTime().toString()); + + this.statsContainer = new StatsContainer(this.scene, 6, 16); + + this.scene.add.existing(this.statsContainer); + + this.statsContainer.setVisible(false); + + this.starterSelectContainer.add(this.statsContainer); + + this.updateInstructions(); + } + + show(args: any[]): void { + if (args.length >= 1 && args[0] instanceof Function) { + super.show(args); + + for (let g = 0; g < this.genSpecies.length; g++) { + this.genSpecies[g].forEach((species, s) => { + const dexEntry = this.scene.gameData.dexData[species.speciesId]; + const icon = this.starterSelectGenIconContainers[g].getAt(s) as Phaser.GameObjects.Sprite; + if (dexEntry.caughtAttr) + icon.clearTint(); + }); + } + + this.starterSelectCallback = args[0] as StarterSelectCallback; + + this.starterSelectContainer.setVisible(true); + + this.setGenMode(false); + this.setCursor(0); + this.setGenMode(true); + this.setCursor(0); + } + } + + showText(text: string, delay?: integer, callback?: Function, callbackDelay?: integer, prompt?: boolean, promptDelay?: integer) { + super.showText(text, delay, callback, callbackDelay, prompt, promptDelay); + + this.starterSelectMessageBoxContainer.setVisible(true); + } + + processInput(button: Button): boolean { + const ui = this.getUi(); + + let success = false; + let error = false; + + if (this.startCursorObj.visible) { + switch (button) { + case Button.ACTION: + if (this.tryStart()) + success = true; + else + error = true; + break; + case Button.UP: + this.startCursorObj.setVisible(false); + this.setGenMode(true); + success = true; + break; + case Button.RIGHT: + this.startCursorObj.setVisible(false); + this.setGenMode(false); + success = true; + break; + } + } else if (this.genMode) { + switch (button) { + case Button.UP: + if (this.genCursor) + success = this.setCursor(this.genCursor - 1); + break; + case Button.DOWN: + if (this.genCursor < 4) + success = this.setCursor(this.genCursor + 1); + else { + this.startCursorObj.setVisible(true); + this.setGenMode(true); + success = true; + } + break; + case Button.RIGHT: + success = this.setGenMode(false); + break; + } + } else { + if (button === Button.ACTION) { + if (!this.speciesStarterDexEntry?.caughtAttr) + error = true; + else if (this.starterCursors.length < 3) { + ui.setModeWithoutClear(Mode.OPTION_SELECT, 'Add to Party', () => { + ui.setMode(Mode.STARTER_SELECT); + let isDupe = false; + for (let s = 0; s < this.starterCursors.length; s++) { + if (this.starterGens[s] === this.getGenCursorWithScroll() && this.starterCursors[s] === this.cursor) { + isDupe = true; break; } } - } while (dupe); - - this.pokerusGens.push(species.generation - 1); - this.pokerusCursors.push(pokerusCursor); - this.pokerusCursorObjs[c].setPosition(148 + 18 * (pokerusCursor % 9), 10 + 18 * Math.floor(pokerusCursor / 9)); - } - }, 0, date.getTime().toString()); - - this.statsContainer = new StatsContainer(this.scene, 6, 16); - - this.scene.add.existing(this.statsContainer); - - this.statsContainer.setVisible(false); - - this.starterSelectContainer.add(this.statsContainer); - - this.updateInstructions(); - } - - show(args: any[]): void { - if (args.length >= 1 && args[0] instanceof Function) { - super.show(args); - - for (let g = 0; g < this.genSpecies.length; g++) { - this.genSpecies[g].forEach((species, s) => { - const dexEntry = this.scene.gameData.dexData[species.speciesId]; - const icon = this.starterSelectGenIconContainers[g].getAt(s) as Phaser.GameObjects.Sprite; - if (dexEntry.caughtAttr) - icon.clearTint(); + const species = this.genSpecies[this.getGenCursorWithScroll()][this.cursor]; + if (!isDupe && this.tryUpdateValue(speciesStarterValues[species.speciesId])) { + const cursorObj = this.starterCursorObjs[this.starterCursors.length]; + cursorObj.setVisible(true); + cursorObj.setPosition(this.cursorObj.x, this.cursorObj.y); + const props = this.scene.gameData.getSpeciesDexAttrProps(species, this.dexAttrCursor); + this.starterIcons[this.starterCursors.length].setTexture(species.getIconAtlasKey(props.formIndex)); + this.starterIcons[this.starterCursors.length].setFrame(species.getIconId(props.female, props.formIndex, props.shiny)); + this.starterGens.push(this.getGenCursorWithScroll()); + this.starterCursors.push(this.cursor); + this.starterAttr.push(this.dexAttrCursor); + if (this.speciesLoaded.get(species.speciesId)) + species.cry(this.scene); + if (this.starterCursors.length === 3) + this.tryStart(); + this.updateInstructions(); + ui.playSelect(); + } else + ui.playError(); + }, 'Toggle IVs', () => { + this.toggleStatsMode(); + ui.setMode(Mode.STARTER_SELECT); }); + success = true; } - - this.starterSelectCallback = args[0] as StarterSelectCallback; - - this.starterSelectContainer.setVisible(true); - - this.setGenMode(false); - this.setCursor(0); - this.setGenMode(true); - this.setCursor(0); - } - } - - showText(text: string, delay?: integer, callback?: Function, callbackDelay?: integer, prompt?: boolean, promptDelay?: integer) { - super.showText(text, delay, callback, callbackDelay, prompt, promptDelay); - - this.starterSelectMessageBoxContainer.setVisible(true); - } - - processInput(button: Button): boolean { - const ui = this.getUi(); - - let success = false; - let error = false; - - if (this.startCursorObj.visible) { - switch (button) { - case Button.ACTION: - if (this.tryStart()) - success = true; - else - error = true; - break; - case Button.UP: - this.startCursorObj.setVisible(false); - this.setGenMode(true); - success = true; - break; - case Button.RIGHT: - this.startCursorObj.setVisible(false); - this.setGenMode(false); - success = true; - break; + } else if (button === Button.CANCEL) { + if (this.statsMode) { + this.toggleStatsMode(false); + success = true; + } else if (this.starterCursors.length) { + this.popStarter(); + success = true; + this.updateInstructions(); } - } else if (this.genMode) { + } else { + const genStarters = this.starterSelectGenIconContainers[this.getGenCursorWithScroll()].getAll().length; + const rows = Math.ceil(genStarters / 9); + const row = Math.floor(this.cursor / 9); + const props = this.scene.gameData.getSpeciesDexAttrProps(this.lastSpecies, this.dexAttrCursor); switch (button) { - case Button.UP: - if (this.genCursor) - success = this.setCursor(this.genCursor - 1); + case Button.CYCLE_SHINY: + if (this.canCycleShiny) { + this.setSpeciesDetails(this.lastSpecies, !props.shiny, undefined, undefined, undefined); + if (this.dexAttrCursor & DexAttr.SHINY) + this.scene.playSound('sparkle'); + else + success = true; + } break; - case Button.DOWN: - if (this.genCursor < 4) - success = this.setCursor(this.genCursor + 1); - else { - this.startCursorObj.setVisible(true); - this.setGenMode(true); + case Button.CYCLE_FORM: + if (this.canCycleForm) { + const formCount = this.lastSpecies.forms.length; + let newFormIndex = props.formIndex; + do { + newFormIndex = (newFormIndex + 1) % formCount; + if (this.speciesStarterDexEntry.caughtAttr & this.scene.gameData.getFormAttr(newFormIndex)) + break; + } while (newFormIndex !== props.formIndex); + this.setSpeciesDetails(this.lastSpecies, undefined, newFormIndex, undefined, undefined); success = true; } break; + case Button.CYCLE_GENDER: + if (this.canCycleGender) { + this.setSpeciesDetails(this.lastSpecies, undefined, undefined, !props.female, undefined); + success = true; + } + break; + case Button.CYCLE_ABILITY: + if (this.canCycleAbility) { + const abilityCount = this.lastSpecies.getAbilityCount(); + let newAbilityIndex = props.abilityIndex; + do { + newAbilityIndex = (newAbilityIndex + 1) % abilityCount; + if (!newAbilityIndex) { + if (this.speciesStarterDexEntry.caughtAttr & DexAttr.ABILITY_1) + break; + } else if (newAbilityIndex === 1) { + if (this.speciesStarterDexEntry.caughtAttr & (this.lastSpecies.ability2 ? DexAttr.ABILITY_2 : DexAttr.ABILITY_HIDDEN)) + break; + } else { + if (this.speciesStarterDexEntry.caughtAttr & DexAttr.ABILITY_HIDDEN) + break; + } + } while (newAbilityIndex !== props.abilityIndex); + this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, newAbilityIndex); + success = true; + } + break; + case Button.UP: + if (row) + success = this.setCursor(this.cursor - 9); + break; + case Button.DOWN: + if (row < rows - 2 || (row < rows - 1 && this.cursor % 9 <= (genStarters - 1) % 9)) + success = this.setCursor(this.cursor + 9); + break; + case Button.LEFT: + if (this.cursor % 9) + success = this.setCursor(this.cursor - 1); + else { + if (row >= Math.min(5, rows - 1)) + this.startCursorObj.setVisible(true); + success = this.setGenMode(true); + } + break; case Button.RIGHT: - success = this.setGenMode(false); + if (this.cursor % 9 < (row < rows - 1 ? 8 : (genStarters - 1) % 9)) + success = this.setCursor(this.cursor + 1); break; } - } else { - if (button === Button.ACTION) { - if (!this.speciesStarterDexEntry?.caughtAttr) - error = true; - else if (this.starterCursors.length < 3) { - ui.setModeWithoutClear(Mode.OPTION_SELECT, 'Add to Party', () => { - ui.setMode(Mode.STARTER_SELECT); - let isDupe = false; - for (let s = 0; s < this.starterCursors.length; s++) { - if (this.starterGens[s] === this.getGenCursorWithScroll() && this.starterCursors[s] === this.cursor) { - isDupe = true; - break; - } - } - const species = this.genSpecies[this.getGenCursorWithScroll()][this.cursor]; - if (!isDupe && this.tryUpdateValue(speciesStarterValues[species.speciesId])) { - const cursorObj = this.starterCursorObjs[this.starterCursors.length]; - cursorObj.setVisible(true); - cursorObj.setPosition(this.cursorObj.x, this.cursorObj.y); - const props = this.scene.gameData.getSpeciesDexAttrProps(species, this.dexAttrCursor); - this.starterIcons[this.starterCursors.length].setTexture(species.getIconAtlasKey(props.formIndex)); - this.starterIcons[this.starterCursors.length].setFrame(species.getIconId(props.female, props.formIndex, props.shiny)); - this.starterGens.push(this.getGenCursorWithScroll()); - this.starterCursors.push(this.cursor); - this.starterAttr.push(this.dexAttrCursor); - if (this.speciesLoaded.get(species.speciesId)) - species.cry(this.scene); - if (this.starterCursors.length === 3) - this.tryStart(); - this.updateInstructions(); - ui.playSelect(); - } else - ui.playError(); - }, 'Toggle IVs', () => { - this.toggleStatsMode(); - ui.setMode(Mode.STARTER_SELECT); - }); - success = true; - } - } else if (button === Button.CANCEL) { - if (this.statsMode) { - this.toggleStatsMode(false); - success = true; - } else if (this.starterCursors.length) { - this.popStarter(); - success = true; - this.updateInstructions(); - } - } else { - const genStarters = this.starterSelectGenIconContainers[this.getGenCursorWithScroll()].getAll().length; - const rows = Math.ceil(genStarters / 9); - const row = Math.floor(this.cursor / 9); - const props = this.scene.gameData.getSpeciesDexAttrProps(this.lastSpecies, this.dexAttrCursor); - switch (button) { - case Button.CYCLE_SHINY: - if (this.canCycleShiny) { - this.setSpeciesDetails(this.lastSpecies, !props.shiny, undefined, undefined, undefined); - if (this.dexAttrCursor & DexAttr.SHINY) - this.scene.playSound('sparkle'); - else - success = true; - } - break; - case Button.CYCLE_FORM: - if (this.canCycleForm) { - const formCount = this.lastSpecies.forms.length; - let newFormIndex = props.formIndex; - do { - newFormIndex = (newFormIndex + 1) % formCount; - if (this.speciesStarterDexEntry.caughtAttr & this.scene.gameData.getFormAttr(newFormIndex)) - break; - } while (newFormIndex !== props.formIndex); - this.setSpeciesDetails(this.lastSpecies, undefined, newFormIndex, undefined, undefined); - success = true; - } - break; - case Button.CYCLE_GENDER: - if (this.canCycleGender) { - this.setSpeciesDetails(this.lastSpecies, undefined, undefined, !props.female, undefined); - success = true; - } - break; - case Button.CYCLE_ABILITY: - if (this.canCycleAbility) { - const abilityCount = this.lastSpecies.getAbilityCount(); - let newAbilityIndex = props.abilityIndex; - do { - newAbilityIndex = (newAbilityIndex + 1) % abilityCount; - if (!newAbilityIndex) { - if (this.speciesStarterDexEntry.caughtAttr & DexAttr.ABILITY_1) - break; - } else if (newAbilityIndex === 1) { - if (this.speciesStarterDexEntry.caughtAttr & (this.lastSpecies.ability2 ? DexAttr.ABILITY_2 : DexAttr.ABILITY_HIDDEN)) - break; - } else { - if (this.speciesStarterDexEntry.caughtAttr & DexAttr.ABILITY_HIDDEN) - break; - } - } while (newAbilityIndex !== props.abilityIndex); - this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, newAbilityIndex); - success = true; - } - break; - case Button.UP: - if (row) - success = this.setCursor(this.cursor - 9); - break; - case Button.DOWN: - if (row < rows - 2 || (row < rows - 1 && this.cursor % 9 <= (genStarters - 1) % 9)) - success = this.setCursor(this.cursor + 9); - break; - case Button.LEFT: - if (this.cursor % 9) - success = this.setCursor(this.cursor - 1); - else { - if (row >= Math.min(5, rows - 1)) - this.startCursorObj.setVisible(true); - success = this.setGenMode(true); - } - break; - case Button.RIGHT: - if (this.cursor % 9 < (row < rows - 1 ? 8 : (genStarters - 1) % 9)) - success = this.setCursor(this.cursor + 1); - break; - } - } } - - if (success) - ui.playSelect(); - else if (error) - ui.playError(); - - return success || error; - } - - updateInstructions(): void { - let instructionLines = [ - 'Arrow Keys/WASD: Move' - ]; - let cycleInstructionLines = []; - if (!this.genMode) - instructionLines.push('A/Space/Enter: Select'); - if (this.starterCursors.length) - instructionLines.push('X/Backspace/Esc: Undo'); - if (this.speciesStarterDexEntry?.caughtAttr) { - if (this.canCycleShiny) - cycleInstructionLines.push('R: Cycle Shiny'); - if (this.canCycleForm) - cycleInstructionLines.push('F: Cycle Form'); - if (this.canCycleGender) - cycleInstructionLines.push('G: Cycle Gender'); - if (this.canCycleAbility) - cycleInstructionLines.push('E: Cycle Ability'); - } - - if (cycleInstructionLines.length > 2) { - cycleInstructionLines[0] += ' | ' + cycleInstructionLines.splice(1, 1); - if (cycleInstructionLines.length > 2) - cycleInstructionLines[1] += ' | ' + cycleInstructionLines.splice(2, 1); - } - - for (let cil of cycleInstructionLines) - instructionLines.push(cil); - - this.instructionsText.setText(instructionLines.join('\n')); } - setCursor(cursor: integer): boolean { - let changed = false; + if (success) + ui.playSelect(); + else if (error) + ui.playError(); - if (this.genMode) { - changed = this.genCursor !== cursor; - - let genCursorWithScroll = this.getGenCursorWithScroll(); - - if (!cursor && this.genScrollCursor) { - this.genScrollCursor--; - cursor++; - this.updateGenOptions(); - } else if (cursor === 4 && this.genScrollCursor < gens.length - 5) { - this.genScrollCursor++; - cursor--; - this.updateGenOptions(); - } - - if (genCursorWithScroll !== undefined) - this.starterSelectGenIconContainers[genCursorWithScroll].setVisible(false); - this.cursor = 0; - this.genCursor = cursor; - genCursorWithScroll = this.getGenCursorWithScroll(); - this.genCursorObj.setY(5 + 17 * this.genCursor); - this.genCursorHighlightObj.setY(this.genCursorObj.y); - this.starterSelectGenIconContainers[genCursorWithScroll].setVisible(true); - - for (let s = 0; s < this.starterCursorObjs.length; s++) - this.starterCursorObjs[s].setVisible(this.starterGens[s] === genCursorWithScroll); - for (let s = 0; s < this.pokerusCursorObjs.length; s++) - this.pokerusCursorObjs[s].setVisible(this.pokerusGens[s] === genCursorWithScroll); - - const genLimit = this.genSpecies[genCursorWithScroll].length; - for (let s = 0; s < 81; s++) { - const slotVisible = s < genLimit && !!(this.scene.gameData.dexData[this.genSpecies[genCursorWithScroll][s].speciesId].caughtAttr); - this.starterValueLabels[s].setText(slotVisible ? speciesStarterValues[this.genSpecies[genCursorWithScroll][s].speciesId] : 0); - this.starterValueLabels[s].setVisible(slotVisible); - this.shinyIcons[s].setVisible(slotVisible && !!(this.scene.gameData.dexData[this.genSpecies[genCursorWithScroll][s].speciesId].caughtAttr & DexAttr.SHINY)); - } - } else { - changed = super.setCursor(cursor); - - this.cursorObj.setPosition(148 + 18 * (cursor % 9), 10 + 18 * Math.floor(cursor / 9)); - - this.setSpecies(this.genSpecies[this.getGenCursorWithScroll()][cursor]); - - this.updateInstructions(); - } + return success || error; + } - return changed; + updateInstructions(): void { + let instructionLines = [ + 'Arrow Keys/WASD: Move' + ]; + let cycleInstructionLines = []; + if (!this.genMode) + instructionLines.push('A/Space/Enter: Select'); + if (this.starterCursors.length) + instructionLines.push('X/Backspace/Esc: Undo'); + if (this.speciesStarterDexEntry?.caughtAttr) { + if (this.canCycleShiny) + cycleInstructionLines.push('R: Cycle Shiny'); + if (this.canCycleForm) + cycleInstructionLines.push('F: Cycle Form'); + if (this.canCycleGender) + cycleInstructionLines.push('G: Cycle Gender'); + if (this.canCycleAbility) + cycleInstructionLines.push('E: Cycle Ability'); } - getGenCursorWithScroll(): integer { - return this.genCursor !== undefined - ? this.genCursor + this.genScrollCursor - : undefined; + if (cycleInstructionLines.length > 2) { + cycleInstructionLines[0] += ' | ' + cycleInstructionLines.splice(1, 1); + if (cycleInstructionLines.length > 2) + cycleInstructionLines[1] += ' | ' + cycleInstructionLines.splice(2, 1); } - updateGenOptions(): void { - let text = ''; - for (let g = this.genScrollCursor; g <= this.genScrollCursor + 4; g++) { - let optionText = gens[g]; - if (g === this.genScrollCursor && this.genScrollCursor) - optionText = '↑'; - else if (g === this.genScrollCursor + 4 && this.genScrollCursor < gens.length - 5) - optionText = '↓' - text += `${text ? '\n' : ''}${optionText}`; - } - this.genOptionsText.setText(text); - } + for (let cil of cycleInstructionLines) + instructionLines.push(cil); - setGenMode(genMode: boolean): boolean { - this.genCursorObj.setVisible(genMode && !this.startCursorObj.visible); - this.cursorObj.setVisible(!genMode && !this.startCursorObj.visible); - - if (genMode !== this.genMode) { - this.genMode = genMode; + this.instructionsText.setText(instructionLines.join('\n')); + } - this.setCursor(genMode ? this.genCursor : this.cursor); - if (genMode) - this.setSpecies(null); + setCursor(cursor: integer): boolean { + let changed = false; - return true; + if (this.genMode) { + changed = this.genCursor !== cursor; + + let genCursorWithScroll = this.getGenCursorWithScroll(); + + if (!cursor && this.genScrollCursor) { + this.genScrollCursor--; + cursor++; + this.updateGenOptions(); + } else if (cursor === 4 && this.genScrollCursor < gens.length - 5) { + this.genScrollCursor++; + cursor--; + this.updateGenOptions(); } - return false; - } + if (genCursorWithScroll !== undefined) + this.starterSelectGenIconContainers[genCursorWithScroll].setVisible(false); + this.cursor = 0; + this.genCursor = cursor; + genCursorWithScroll = this.getGenCursorWithScroll(); + this.genCursorObj.setY(5 + 17 * this.genCursor); + this.genCursorHighlightObj.setY(this.genCursorObj.y); + this.starterSelectGenIconContainers[genCursorWithScroll].setVisible(true); - setSpecies(species: PokemonSpecies) { - this.speciesStarterDexEntry = species ? this.scene.gameData.dexData[species.speciesId] : null; - this.dexAttrCursor = species ? this.scene.gameData.getSpeciesDefaultDexAttr(species) : 0n; + for (let s = 0; s < this.starterCursorObjs.length; s++) + this.starterCursorObjs[s].setVisible(this.starterGens[s] === genCursorWithScroll); + for (let s = 0; s < this.pokerusCursorObjs.length; s++) + this.pokerusCursorObjs[s].setVisible(this.pokerusGens[s] === genCursorWithScroll); - if (this.statsMode) { - if (this.speciesStarterDexEntry?.caughtAttr) { - this.statsContainer.setVisible(true); - this.showStats(); - } else { - this.statsContainer.setVisible(false); - this.statsContainer.updateIvs(null); - } + const genLimit = this.genSpecies[genCursorWithScroll].length; + for (let s = 0; s < 81; s++) { + const slotVisible = s < genLimit && !!(this.scene.gameData.dexData[this.genSpecies[genCursorWithScroll][s].speciesId].caughtAttr); + this.starterValueLabels[s].setText(slotVisible ? speciesStarterValues[this.genSpecies[genCursorWithScroll][s].speciesId] : 0); + this.starterValueLabels[s].setVisible(slotVisible); + this.shinyIcons[s].setVisible(slotVisible && !!(this.scene.gameData.dexData[this.genSpecies[genCursorWithScroll][s].speciesId].caughtAttr & DexAttr.SHINY)); } + } else { + changed = super.setCursor(cursor); - if (this.lastSpecies) { - const dexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(this.lastSpecies); - const props = this.scene.gameData.getSpeciesDexAttrProps(this.lastSpecies, dexAttr); - const lastSpeciesIcon = (this.starterSelectGenIconContainers[this.lastSpecies.generation - 1].getAt(this.genSpecies[this.lastSpecies.generation - 1].indexOf(this.lastSpecies)) as Phaser.GameObjects.Sprite); - lastSpeciesIcon.setFrame(this.lastSpecies.getIconId(props.female, props.formIndex, props.shiny)); - this.iconAnimHandler.addOrUpdate(lastSpeciesIcon, PokemonIconAnimMode.NONE); - } + this.cursorObj.setPosition(148 + 18 * (cursor % 9), 10 + 18 * Math.floor(cursor / 9)); - this.lastSpecies = species; - - if (species && this.speciesStarterDexEntry?.caughtAttr) { - this.pokemonNumberText.setText(Utils.padInt(species.speciesId, 3)); - this.pokemonNameText.setText(species.name); - this.pokemonGrowthRateText.setText(Utils.toReadableString(GrowthRate[species.growthRate])); - this.pokemonGrowthRateText.setColor(getGrowthRateColor(species.growthRate)); - this.pokemonGrowthRateText.setShadowColor(getGrowthRateColor(species.growthRate, true)); - this.pokemonGrowthRateLabelText.setVisible(true); - this.pokemonAbilityLabelText.setVisible(true); - this.iconAnimHandler.addOrUpdate(this.starterSelectGenIconContainers[species.generation - 1].getAt(this.genSpecies[species.generation - 1].indexOf(species)) as Phaser.GameObjects.Sprite, PokemonIconAnimMode.PASSIVE); - - const defaultDexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(species); - const props = this.scene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr); - - this.setSpeciesDetails(species, props.shiny, props.formIndex, props.female, props.abilityIndex); - } else { - this.pokemonNumberText.setText(Utils.padInt(0, 3)); - this.pokemonNameText.setText(species ? '???' : ''); - this.pokemonGrowthRateText.setText(''); - this.pokemonGrowthRateLabelText.setVisible(false); - this.pokemonAbilityLabelText.setVisible(false); - - this.setSpeciesDetails(species, false, 0, false, 0); - } - } - - setSpeciesDetails(species: PokemonSpecies, shiny: boolean, formIndex: integer, female: boolean, abilityIndex: integer): void { - const oldProps = species ? this.scene.gameData.getSpeciesDexAttrProps(species, this.dexAttrCursor) : null; - this.dexAttrCursor = 0n; - - if (species) { - this.dexAttrCursor |= (shiny !== undefined ? !shiny : !(shiny = oldProps.shiny)) ? DexAttr.NON_SHINY : DexAttr.SHINY; - this.dexAttrCursor |= (female !== undefined ? !female : !(female = oldProps.female)) ? DexAttr.MALE : DexAttr.FEMALE; - this.dexAttrCursor |= (abilityIndex !== undefined ? !abilityIndex : !(abilityIndex = oldProps.abilityIndex)) ? DexAttr.ABILITY_1 : species.ability2 && abilityIndex === 1 ? DexAttr.ABILITY_2 : DexAttr.ABILITY_HIDDEN; - this.dexAttrCursor |= this.scene.gameData.getFormAttr(formIndex !== undefined ? formIndex : (formIndex = oldProps.formIndex)); - } - - this.pokemonSprite.setVisible(false); - - if (this.assetLoadCancelled) { - this.assetLoadCancelled.value = true; - this.assetLoadCancelled = null; - } - - if (species) { - const dexEntry = this.scene.gameData.dexData[species.speciesId]; - if (!dexEntry.caughtAttr) { - const props = this.scene.gameData.getSpeciesDexAttrProps(species, this.scene.gameData.getSpeciesDefaultDexAttr(species)); - if (shiny === undefined || shiny !== props.shiny) - shiny = props.shiny; - if (formIndex === undefined || formIndex !== props.formIndex) - formIndex = props.formIndex; - if (female === undefined || female !== props.female) - female = props.female; - if (abilityIndex === undefined || abilityIndex !== props.abilityIndex) - abilityIndex = props.abilityIndex; - } - - if (this.speciesStarterDexEntry?.caughtAttr) { - const assetLoadCancelled = new Utils.BooleanHolder(false); - this.assetLoadCancelled = assetLoadCancelled; - - species.loadAssets(this.scene, female, formIndex, shiny, true).then(() => { - if (assetLoadCancelled.value) - return; - this.assetLoadCancelled = null; - this.speciesLoaded.set(species.speciesId, true); - this.pokemonSprite.play(species.getSpriteKey(female, formIndex, shiny)); - this.pokemonSprite.setVisible(!this.statsMode); - }); - - (this.starterSelectGenIconContainers[this.getGenCursorWithScroll()].getAt(this.cursor) as Phaser.GameObjects.Sprite).setFrame(species.getIconId(female, formIndex, shiny)); - - this.canCycleShiny = !!(dexEntry.caughtAttr & DexAttr.NON_SHINY && dexEntry.caughtAttr & DexAttr.SHINY); - this.canCycleGender = !!(dexEntry.caughtAttr & DexAttr.MALE && dexEntry.caughtAttr & DexAttr.FEMALE); - this.canCycleAbility = [ dexEntry.caughtAttr & DexAttr.ABILITY_1, dexEntry.caughtAttr & DexAttr.ABILITY_2, dexEntry.caughtAttr & DexAttr.ABILITY_HIDDEN ].filter(a => a).length > 1; - this.canCycleForm = species.forms.filter(f => !f.formKey || f.formKey.indexOf(SpeciesFormKey.MEGA) === -1) - .map((_, f) => dexEntry.caughtAttr & this.scene.gameData.getFormAttr(f)).filter(a => a).length > 1; - } - - if (dexEntry.caughtAttr && species.malePercent !== null) { - const gender = !female ? Gender.MALE : Gender.FEMALE; - this.pokemonGenderText.setText(getGenderSymbol(gender)); - this.pokemonGenderText.setColor(getGenderColor(gender)); - this.pokemonGenderText.setShadowColor(getGenderColor(gender, true)); - } else - this.pokemonGenderText.setText(''); - - if (dexEntry.caughtAttr) { - const ability = this.lastSpecies.getAbility(abilityIndex); - this.pokemonAbilityText.setText(allAbilities[ability].name); - - const isHidden = ability === this.lastSpecies.abilityHidden; - this.pokemonAbilityText.setColor(getTextColor(!isHidden ? TextStyle.SUMMARY : TextStyle.SUMMARY_GOLD)); - this.pokemonAbilityText.setShadowColor(getTextColor(!isHidden ? TextStyle.SUMMARY : TextStyle.SUMMARY_GOLD, true)); - } else - this.pokemonAbilityText.setText(''); - } else { - this.pokemonGenderText.setText(''); - this.pokemonAbilityText.setText(''); - } + this.setSpecies(this.genSpecies[this.getGenCursorWithScroll()][cursor]); this.updateInstructions(); } - popStarter(): void { - this.starterGens.pop(); - this.starterCursors.pop(); - this.starterAttr.pop(); - this.starterCursorObjs[this.starterCursors.length].setVisible(false); - this.starterIcons[this.starterCursors.length].setTexture('pokemon_icons_0'); - this.starterIcons[this.starterCursors.length].setFrame('unknown'); - this.tryUpdateValue(); + return changed; + } + + getGenCursorWithScroll(): integer { + return this.genCursor !== undefined + ? this.genCursor + this.genScrollCursor + : undefined; + } + + updateGenOptions(): void { + let text = ''; + for (let g = this.genScrollCursor; g <= this.genScrollCursor + 4; g++) { + let optionText = gens[g]; + if (g === this.genScrollCursor && this.genScrollCursor) + optionText = '↑'; + else if (g === this.genScrollCursor + 4 && this.genScrollCursor < gens.length - 5) + optionText = '↓' + text += `${text ? '\n' : ''}${optionText}`; } + this.genOptionsText.setText(text); + } - tryUpdateValue(add?: integer): boolean { - const value = this.starterGens.reduce((total: integer, gen: integer, i: integer) => total += speciesStarterValues[this.genSpecies[gen][this.starterCursors[i]].speciesId], 0); - const newValue = value + (add || 0); - const overLimit = newValue > 10; - this.valueLimitLabel.setText(`${newValue}/10`); - this.valueLimitLabel.setColor(getTextColor(!overLimit ? TextStyle.TOOLTIP_CONTENT : TextStyle.SUMMARY_RED)); - this.valueLimitLabel.setShadowColor(getTextColor(!overLimit ? TextStyle.TOOLTIP_CONTENT : TextStyle.SUMMARY_RED, true)); - if (overLimit) { - this.scene.time.delayedCall(Utils.fixedInt(500), () => this.tryUpdateValue()); - return false; - } - this.value = newValue; - return true; - } + setGenMode(genMode: boolean): boolean { + this.genCursorObj.setVisible(genMode && !this.startCursorObj.visible); + this.cursorObj.setVisible(!genMode && !this.startCursorObj.visible); + + if (genMode !== this.genMode) { + this.genMode = genMode; - tryStart(): boolean { - if (!this.starterGens.length) - return false; - - const ui = this.getUi(); - - const cancel = () => { - ui.setMode(Mode.STARTER_SELECT); - this.popStarter(); - this.clearText(); - }; - - ui.showText('Begin with these Pokémon?', null, () => { - ui.setModeWithoutClear(Mode.CONFIRM, () => { - const startRun = (gameMode: GameMode) => { - this.scene.gameMode = gameMode; - ui.setMode(Mode.STARTER_SELECT); - const thisObj = this; - const originalStarterSelectCallback = this.starterSelectCallback; - this.starterSelectCallback = null; - originalStarterSelectCallback(new Array(this.starterGens.length).fill(0).map(function (_, i) { - const starterSpecies = thisObj.genSpecies[thisObj.starterGens[i]][thisObj.starterCursors[i]]; - return { - species: starterSpecies, - dexAttr: thisObj.starterAttr[i], - pokerus: !![ 0, 1, 2 ].filter(n => thisObj.pokerusGens[n] === starterSpecies.generation - 1 && thisObj.pokerusCursors[n] === thisObj.genSpecies[starterSpecies.generation - 1].indexOf(starterSpecies)).length - }; - })); - }; - if (this.scene.gameData.unlocks[Unlockables.ENDLESS_MODE]) { - ui.setMode(Mode.STARTER_SELECT); - ui.showText('Select a game mode.', null, () => ui.setModeWithoutClear(Mode.GAME_MODE_SELECT, startRun, cancel)); - } else - startRun(GameMode.CLASSIC); - }, cancel); - }); + this.setCursor(genMode ? this.genCursor : this.cursor); + if (genMode) + this.setSpecies(null); return true; } - toggleStatsMode(on?: boolean): void { - if (on === undefined) - on = !this.statsMode; - if (on) { + return false; + } + + setSpecies(species: PokemonSpecies) { + this.speciesStarterDexEntry = species ? this.scene.gameData.dexData[species.speciesId] : null; + this.dexAttrCursor = species ? this.scene.gameData.getSpeciesDefaultDexAttr(species) : 0n; + + if (this.statsMode) { + if (this.speciesStarterDexEntry?.caughtAttr) { + this.statsContainer.setVisible(true); this.showStats(); - this.statsMode = true; - this.pokemonSprite.setVisible(false); } else { - this.statsMode = false; this.statsContainer.setVisible(false); - this.pokemonSprite.setVisible(!!this.speciesStarterDexEntry?.caughtAttr); this.statsContainer.updateIvs(null); } } - - showStats(): void { - if (!this.speciesStarterDexEntry) - return; - this.statsContainer.setVisible(true); - - this.statsContainer.updateIvs(this.speciesStarterDexEntry.ivs); + if (this.lastSpecies) { + const dexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(this.lastSpecies); + const props = this.scene.gameData.getSpeciesDexAttrProps(this.lastSpecies, dexAttr); + const lastSpeciesIcon = (this.starterSelectGenIconContainers[this.lastSpecies.generation - 1].getAt(this.genSpecies[this.lastSpecies.generation - 1].indexOf(this.lastSpecies)) as Phaser.GameObjects.Sprite); + lastSpeciesIcon.setFrame(this.lastSpecies.getIconId(props.female, props.formIndex, props.shiny)); + this.iconAnimHandler.addOrUpdate(lastSpeciesIcon, PokemonIconAnimMode.NONE); } - clearText() { - this.starterSelectMessageBoxContainer.setVisible(false); - super.clearText(); + this.lastSpecies = species; + + if (species && this.speciesStarterDexEntry?.caughtAttr) { + this.pokemonNumberText.setText(Utils.padInt(species.speciesId, 3)); + this.pokemonNameText.setText(species.name); + this.pokemonGrowthRateText.setText(Utils.toReadableString(GrowthRate[species.growthRate])); + this.pokemonGrowthRateText.setColor(getGrowthRateColor(species.growthRate)); + this.pokemonGrowthRateText.setShadowColor(getGrowthRateColor(species.growthRate, true)); + this.pokemonGrowthRateLabelText.setVisible(true); + this.pokemonAbilityLabelText.setVisible(true); + this.iconAnimHandler.addOrUpdate(this.starterSelectGenIconContainers[species.generation - 1].getAt(this.genSpecies[species.generation - 1].indexOf(species)) as Phaser.GameObjects.Sprite, PokemonIconAnimMode.PASSIVE); + + const defaultDexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(species); + const props = this.scene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr); + + this.setSpeciesDetails(species, props.shiny, props.formIndex, props.female, props.abilityIndex); + } else { + this.pokemonNumberText.setText(Utils.padInt(0, 3)); + this.pokemonNameText.setText(species ? '???' : ''); + this.pokemonGrowthRateText.setText(''); + this.pokemonGrowthRateLabelText.setVisible(false); + this.pokemonAbilityLabelText.setVisible(false); + + this.setSpeciesDetails(species, false, 0, false, 0); } + } + + setSpeciesDetails(species: PokemonSpecies, shiny: boolean, formIndex: integer, female: boolean, abilityIndex: integer): void { + const oldProps = species ? this.scene.gameData.getSpeciesDexAttrProps(species, this.dexAttrCursor) : null; + this.dexAttrCursor = 0n; + + if (species) { + this.dexAttrCursor |= (shiny !== undefined ? !shiny : !(shiny = oldProps.shiny)) ? DexAttr.NON_SHINY : DexAttr.SHINY; + this.dexAttrCursor |= (female !== undefined ? !female : !(female = oldProps.female)) ? DexAttr.MALE : DexAttr.FEMALE; + this.dexAttrCursor |= (abilityIndex !== undefined ? !abilityIndex : !(abilityIndex = oldProps.abilityIndex)) ? DexAttr.ABILITY_1 : species.ability2 && abilityIndex === 1 ? DexAttr.ABILITY_2 : DexAttr.ABILITY_HIDDEN; + this.dexAttrCursor |= this.scene.gameData.getFormAttr(formIndex !== undefined ? formIndex : (formIndex = oldProps.formIndex)); + } + + this.pokemonSprite.setVisible(false); + + if (this.assetLoadCancelled) { + this.assetLoadCancelled.value = true; + this.assetLoadCancelled = null; + } + + if (species) { + const dexEntry = this.scene.gameData.dexData[species.speciesId]; + if (!dexEntry.caughtAttr) { + const props = this.scene.gameData.getSpeciesDexAttrProps(species, this.scene.gameData.getSpeciesDefaultDexAttr(species)); + if (shiny === undefined || shiny !== props.shiny) + shiny = props.shiny; + if (formIndex === undefined || formIndex !== props.formIndex) + formIndex = props.formIndex; + if (female === undefined || female !== props.female) + female = props.female; + if (abilityIndex === undefined || abilityIndex !== props.abilityIndex) + abilityIndex = props.abilityIndex; + } + + if (this.speciesStarterDexEntry?.caughtAttr) { + const assetLoadCancelled = new Utils.BooleanHolder(false); + this.assetLoadCancelled = assetLoadCancelled; + + species.loadAssets(this.scene, female, formIndex, shiny, true).then(() => { + if (assetLoadCancelled.value) + return; + this.assetLoadCancelled = null; + this.speciesLoaded.set(species.speciesId, true); + this.pokemonSprite.play(species.getSpriteKey(female, formIndex, shiny)); + this.pokemonSprite.setVisible(!this.statsMode); + }); + + (this.starterSelectGenIconContainers[this.getGenCursorWithScroll()].getAt(this.cursor) as Phaser.GameObjects.Sprite).setFrame(species.getIconId(female, formIndex, shiny)); + + this.canCycleShiny = !!(dexEntry.caughtAttr & DexAttr.NON_SHINY && dexEntry.caughtAttr & DexAttr.SHINY); + this.canCycleGender = !!(dexEntry.caughtAttr & DexAttr.MALE && dexEntry.caughtAttr & DexAttr.FEMALE); + this.canCycleAbility = [ dexEntry.caughtAttr & DexAttr.ABILITY_1, dexEntry.caughtAttr & DexAttr.ABILITY_2, dexEntry.caughtAttr & DexAttr.ABILITY_HIDDEN ].filter(a => a).length > 1; + this.canCycleForm = species.forms.filter(f => !f.formKey || f.formKey.indexOf(SpeciesFormKey.MEGA) === -1) + .map((_, f) => dexEntry.caughtAttr & this.scene.gameData.getFormAttr(f)).filter(a => a).length > 1; + } + + if (dexEntry.caughtAttr && species.malePercent !== null) { + const gender = !female ? Gender.MALE : Gender.FEMALE; + this.pokemonGenderText.setText(getGenderSymbol(gender)); + this.pokemonGenderText.setColor(getGenderColor(gender)); + this.pokemonGenderText.setShadowColor(getGenderColor(gender, true)); + } else + this.pokemonGenderText.setText(''); + + if (dexEntry.caughtAttr) { + const ability = this.lastSpecies.getAbility(abilityIndex); + this.pokemonAbilityText.setText(allAbilities[ability].name); + + const isHidden = ability === this.lastSpecies.abilityHidden; + this.pokemonAbilityText.setColor(getTextColor(!isHidden ? TextStyle.SUMMARY : TextStyle.SUMMARY_GOLD)); + this.pokemonAbilityText.setShadowColor(getTextColor(!isHidden ? TextStyle.SUMMARY : TextStyle.SUMMARY_GOLD, true)); + } else + this.pokemonAbilityText.setText(''); + } else { + this.pokemonGenderText.setText(''); + this.pokemonAbilityText.setText(''); + } + + this.updateInstructions(); + } + + popStarter(): void { + this.starterGens.pop(); + this.starterCursors.pop(); + this.starterAttr.pop(); + this.starterCursorObjs[this.starterCursors.length].setVisible(false); + this.starterIcons[this.starterCursors.length].setTexture('pokemon_icons_0'); + this.starterIcons[this.starterCursors.length].setFrame('unknown'); + this.tryUpdateValue(); + } + + tryUpdateValue(add?: integer): boolean { + const value = this.starterGens.reduce((total: integer, gen: integer, i: integer) => total += speciesStarterValues[this.genSpecies[gen][this.starterCursors[i]].speciesId], 0); + const newValue = value + (add || 0); + const overLimit = newValue > 10; + this.valueLimitLabel.setText(`${newValue}/10`); + this.valueLimitLabel.setColor(getTextColor(!overLimit ? TextStyle.TOOLTIP_CONTENT : TextStyle.SUMMARY_RED)); + this.valueLimitLabel.setShadowColor(getTextColor(!overLimit ? TextStyle.TOOLTIP_CONTENT : TextStyle.SUMMARY_RED, true)); + if (overLimit) { + this.scene.time.delayedCall(Utils.fixedInt(500), () => this.tryUpdateValue()); + return false; + } + this.value = newValue; + return true; + } + + tryStart(): boolean { + if (!this.starterGens.length) + return false; + + const ui = this.getUi(); + + const cancel = () => { + ui.setMode(Mode.STARTER_SELECT); + this.popStarter(); + this.clearText(); + }; + + ui.showText('Begin with these Pokémon?', null, () => { + ui.setModeWithoutClear(Mode.CONFIRM, () => { + const startRun = (gameMode: GameMode) => { + this.scene.gameMode = gameMode; + ui.setMode(Mode.STARTER_SELECT); + const thisObj = this; + const originalStarterSelectCallback = this.starterSelectCallback; + this.starterSelectCallback = null; + originalStarterSelectCallback(new Array(this.starterGens.length).fill(0).map(function (_, i) { + const starterSpecies = thisObj.genSpecies[thisObj.starterGens[i]][thisObj.starterCursors[i]]; + return { + species: starterSpecies, + dexAttr: thisObj.starterAttr[i], + pokerus: !![ 0, 1, 2 ].filter(n => thisObj.pokerusGens[n] === starterSpecies.generation - 1 && thisObj.pokerusCursors[n] === thisObj.genSpecies[starterSpecies.generation - 1].indexOf(starterSpecies)).length + }; + })); + }; + if (this.scene.gameData.unlocks[Unlockables.ENDLESS_MODE]) { + ui.setMode(Mode.STARTER_SELECT); + ui.showText('Select a game mode.', null, () => ui.setModeWithoutClear(Mode.GAME_MODE_SELECT, startRun, cancel)); + } else + startRun(GameMode.CLASSIC); + }, cancel); + }); + + return true; + } + + toggleStatsMode(on?: boolean): void { + if (on === undefined) + on = !this.statsMode; + if (on) { + this.showStats(); + this.statsMode = true; + this.pokemonSprite.setVisible(false); + } else { + this.statsMode = false; + this.statsContainer.setVisible(false); + this.pokemonSprite.setVisible(!!this.speciesStarterDexEntry?.caughtAttr); + this.statsContainer.updateIvs(null); + } + } - clear(): void { - super.clear(); - this.cursor = -1; - this.starterSelectContainer.setVisible(false); + showStats(): void { + if (!this.speciesStarterDexEntry) + return; - while (this.starterCursors.length) - this.popStarter(); + this.statsContainer.setVisible(true); - if (this.statsMode) - this.toggleStatsMode(false); - } - } \ No newline at end of file + this.statsContainer.updateIvs(this.speciesStarterDexEntry.ivs); + } + + clearText() { + this.starterSelectMessageBoxContainer.setVisible(false); + super.clearText(); + } + + clear(): void { + super.clear(); + this.cursor = -1; + this.starterSelectContainer.setVisible(false); + + while (this.starterCursors.length) + this.popStarter(); + + if (this.statsMode) + this.toggleStatsMode(false); + } +} \ No newline at end of file diff --git a/src/ui/stats-container.ts b/src/ui/stats-container.ts index a22941956d1..e53840d2025 100644 --- a/src/ui/stats-container.ts +++ b/src/ui/stats-container.ts @@ -1,19 +1,24 @@ +import BBCodeText from "phaser3-rex-plugins/plugins/gameobjects/tagtext/bbcodetext/BBCodeText"; import BattleScene from "../battle-scene"; import { Stat, getStatName } from "../data/pokemon-stat"; -import { TextStyle, addTextObject } from "./text"; +import { TextStyle, addBBCodeTextObject, addTextObject, getTextColor } from "./text"; +import { Gender, getGenderColor } from "../data/gender"; 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 defaultIvChartData = new Array(12).fill(null).map(() => 0); export class StatsContainer extends Phaser.GameObjects.Container { + private showDiff: boolean; private statsIvsCache: integer[]; private ivChart: Phaser.GameObjects.Polygon; - private ivStatValueTexts: Phaser.GameObjects.Text[]; + private ivStatValueTexts: BBCodeText[]; - constructor(scene: BattleScene, x: number, y: number) { + constructor(scene: BattleScene, x: number, y: number, showDiff?: boolean) { super(scene, x, y); + this.showDiff = !!showDiff; + this.setup(); } @@ -48,7 +53,7 @@ export class StatsContainer extends Phaser.GameObjects.Container { const statLabel = addTextObject(this.scene, ivChartBg.x + (ivChartSize) * ivChartStatCoordMultipliers[i][0] * 1.325, ivChartBg.y + (ivChartSize) * ivChartStatCoordMultipliers[i][1] * 1.325 - 4, getStatName(i as Stat), TextStyle.TOOLTIP_CONTENT); statLabel.setOrigin(0.5); - this.ivStatValueTexts[i] = addTextObject(this.scene, statLabel.x, statLabel.y + 8, '0', TextStyle.TOOLTIP_CONTENT); + this.ivStatValueTexts[i] = addBBCodeTextObject(this.scene, statLabel.x, statLabel.y + 8, '0', TextStyle.TOOLTIP_CONTENT); this.ivStatValueTexts[i].setOrigin(0.5) this.add(statLabel); @@ -56,13 +61,22 @@ export class StatsContainer extends Phaser.GameObjects.Container { }); } - updateIvs(ivs: integer[]): void { + 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 lastIvChartData = this.statsIvsCache || defaultIvChartData; this.statsIvsCache = ivChartData.slice(0); - this.ivStatValueTexts.map((t: Phaser.GameObjects.Text, i: integer) => t.setText(ivs[i].toString())); + this.ivStatValueTexts.map((t: BBCodeText, i: integer) => { + let label = ivs[i].toString(); + if (this.showDiff && originalIvs) { + if (originalIvs[i] < ivs[i]) + label += ` ([color=${getGenderColor(Gender.MALE)}]+${ivs[i] - originalIvs[i]}[/color])`; + else + label += ' (-)'; + } + t.setText(`[shadow]${label}[/shadow]`); + }); this.scene.tweens.addCounter({ from: 0, diff --git a/src/ui/text.ts b/src/ui/text.ts index 9b31bf6e3fb..43942c6aa3e 100644 --- a/src/ui/text.ts +++ b/src/ui/text.ts @@ -1,3 +1,5 @@ +import BBCodeText from "phaser3-rex-plugins/plugins/gameobjects/tagtext/bbcodetext/BBCodeText"; + export enum TextStyle { MESSAGE, WINDOW, @@ -14,7 +16,32 @@ export enum TextStyle { TOOLTIP_CONTENT }; -export function addTextObject(scene: Phaser.Scene, x: number, y: number, content: string, style: TextStyle, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle) { +export function addTextObject(scene: Phaser.Scene, x: number, y: number, content: string, style: TextStyle, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle): Phaser.GameObjects.Text { + const [ styleOptions, shadowColor, shadowSize ] = getTextStyleOptions(style, extraStyleOptions); + + const ret = scene.add.text(x, y, content, styleOptions); + ret.setScale(0.1666666667); + ret.setShadow(shadowSize, shadowSize, shadowColor); + if (!styleOptions.lineSpacing) + ret.setLineSpacing(5); + + return ret; +} + +export function addBBCodeTextObject(scene: Phaser.Scene, x: number, y: number, content: string, style: TextStyle, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle): BBCodeText { + const [ styleOptions, shadowColor, shadowSize ] = getTextStyleOptions(style, extraStyleOptions); + + const ret = new BBCodeText(scene, x, y, content, styleOptions as BBCodeText.TextStyle); + scene.add.existing(ret); + ret.setScale(0.1666666667); + ret.setShadow(shadowSize, shadowSize, shadowColor); + if (!styleOptions.lineSpacing) + ret.setLineSpacing(5); + + return ret; +} + +function getTextStyleOptions(style: TextStyle, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle): [ Phaser.Types.GameObjects.Text.TextStyle, string, integer ] { let shadowColor: string; let shadowSize = 6; @@ -64,16 +91,10 @@ export function addTextObject(scene: Phaser.Scene, x: number, y: number, content styleOptions = Object.assign(styleOptions, extraStyleOptions); } - const ret = scene.add.text(x, y, content, styleOptions); - ret.setScale(0.1666666667); - ret.setShadow(shadowSize, shadowSize, shadowColor); - if (!styleOptions.lineSpacing) - ret.setLineSpacing(5); - - return ret; + return [ styleOptions, shadowColor, shadowSize ]; } -export function getTextColor(textStyle: TextStyle, shadow?: boolean) { +export function getTextColor(textStyle: TextStyle, shadow?: boolean): string { switch (textStyle) { case TextStyle.MESSAGE: return !shadow ? '#f8f8f8' : '#6b5a73'; diff --git a/src/ui/ui.ts b/src/ui/ui.ts index 24b816d0360..0d36bdba138 100644 --- a/src/ui/ui.ts +++ b/src/ui/ui.ts @@ -21,6 +21,10 @@ import MenuUiHandler from './menu-ui-handler'; import AchvsUiHandler from './achvs-ui-handler'; import OptionSelectUiHandler from './option-select-ui-handler'; import EggHatchSceneHandler from './egg-hatch-scene-handler'; +import EggListUiHandler from './egg-list-ui-handler'; +import EggGachaUiHandler from './egg-gacha-ui-handler'; +import VouchersUiHandler from './vouchers-ui-handler'; +import VoucherBar from './voucher-bar'; export enum Mode { MESSAGE, @@ -40,7 +44,10 @@ export enum Mode { GAME_MODE_SELECT, MENU, SETTINGS, - ACHIEVEMENTS + ACHIEVEMENTS, + VOUCHERS, + EGG_LIST, + EGG_GACHA }; const transitionModes = [ @@ -48,7 +55,9 @@ const transitionModes = [ Mode.SUMMARY, Mode.STARTER_SELECT, Mode.EVOLUTION_SCENE, - Mode.EGG_HATCH_SCENE + Mode.EGG_HATCH_SCENE, + Mode.EGG_LIST, + Mode.EGG_GACHA ]; const noTransitionModes = [ @@ -56,7 +65,9 @@ const noTransitionModes = [ Mode.OPTION_SELECT, Mode.GAME_MODE_SELECT, Mode.MENU, - Mode.SETTINGS + Mode.SETTINGS, + Mode.ACHIEVEMENTS, + Mode.VOUCHERS ]; export default class UI extends Phaser.GameObjects.Container { @@ -65,6 +76,7 @@ export default class UI extends Phaser.GameObjects.Container { private handlers: UiHandler[]; private overlay: Phaser.GameObjects.Rectangle; public achvBar: AchvBar; + public voucherBar: VoucherBar; private tooltipContainer: Phaser.GameObjects.Container; private tooltipBg: Phaser.GameObjects.NineSlice; @@ -96,7 +108,10 @@ export default class UI extends Phaser.GameObjects.Container { new GameModeSelectUiHandler(scene), new MenuUiHandler(scene), new SettingsUiHandler(scene), - new AchvsUiHandler(scene) + new AchvsUiHandler(scene), + new VouchersUiHandler(scene), + new EggListUiHandler(scene), + new EggGachaUiHandler(scene) ]; } @@ -110,7 +125,8 @@ export default class UI extends Phaser.GameObjects.Container { this.setupTooltip(); this.achvBar = new AchvBar(this.scene as BattleScene); - this.achvBar.setup(); + this.achvBar.setup(); + (this.scene as BattleScene).uiContainer.add(this.achvBar); } @@ -267,8 +283,9 @@ export default class UI extends Phaser.GameObjects.Container { } resolve(); }; - if ((transitionModes.indexOf(this.mode) > -1 || transitionModes.indexOf(mode) > -1) - && (noTransitionModes.indexOf(this.mode) === -1 && noTransitionModes.indexOf(mode) === -1) && !(this.scene as BattleScene).auto) { + if (((!chainMode && ((transitionModes.indexOf(this.mode) > -1 || transitionModes.indexOf(mode) > -1) + && (noTransitionModes.indexOf(this.mode) === -1 && noTransitionModes.indexOf(mode) === -1))) + || (chainMode && noTransitionModes.indexOf(mode) === -1)) && !(this.scene as BattleScene).auto) { this.fadeOut(250).then(() => { this.scene.time.delayedCall(100, () => { doSetMode(); @@ -300,12 +317,29 @@ export default class UI extends Phaser.GameObjects.Container { return this.setModeInternal(mode, false, false, true, args); } - revertMode(): boolean { - if (!this.modeChain.length) - return false; - - this.getHandler().clear(); - this.mode = this.modeChain.pop(); - return true; + revertMode(): Promise { + return new Promise(resolve => { + if (!this.modeChain.length) + return resolve(false); + + const lastMode = this.mode; + + const doRevertMode = () => { + this.getHandler().clear(); + this.mode = this.modeChain.pop(); + }; + + if (noTransitionModes.indexOf(lastMode) === -1) { + this.fadeOut(250).then(() => { + this.scene.time.delayedCall(100, () => { + doRevertMode(); + this.fadeIn(250); + }); + }); + } else + doRevertMode(); + + resolve(true); + }); } } \ No newline at end of file diff --git a/src/ui/vouchers-ui-handler.ts b/src/ui/vouchers-ui-handler.ts new file mode 100644 index 00000000000..a8d0421ccdd --- /dev/null +++ b/src/ui/vouchers-ui-handler.ts @@ -0,0 +1,196 @@ +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"; + +export default class VouchersUiHandler extends MessageUiHandler { + private vouchersContainer: Phaser.GameObjects.Container; + private voucherIconsContainer: Phaser.GameObjects.Container; + + private voucherIconsBg: Phaser.GameObjects.NineSlice; + private voucherIcons: Phaser.GameObjects.Sprite[]; + private titleText: Phaser.GameObjects.Text; + private unlockText: Phaser.GameObjects.Text; + + private cursorObj: Phaser.GameObjects.NineSlice; + + constructor(scene: BattleScene, mode?: Mode) { + super(scene, mode); + } + + setup() { + const ui = this.getUi(); + + this.vouchersContainer = this.scene.add.container(1, -(this.scene.game.canvas.height / 6) + 1); + + this.vouchersContainer.setInteractive(new Phaser.Geom.Rectangle(0, 0, this.scene.game.canvas.width / 6, this.scene.game.canvas.height / 6), Phaser.Geom.Rectangle.Contains); + + const headerBg = this.scene.add.nineslice(0, 0, 'window', null, (this.scene.game.canvas.width / 6) - 2, 24, 6, 6, 6, 6); + headerBg.setOrigin(0, 0); + + const headerText = addTextObject(this.scene, 0, 0, 'Vouchers', TextStyle.SETTINGS_LABEL); + headerText.setOrigin(0, 0); + headerText.setPositionRelative(headerBg, 8, 4); + + this.voucherIconsBg = this.scene.add.nineslice(0, headerBg.height, 'window', null, (this.scene.game.canvas.width / 6) - 2, (this.scene.game.canvas.height / 6) - headerBg.height - 68, 6, 6, 6, 6); + this.voucherIconsBg.setOrigin(0, 0); + + this.voucherIconsContainer = this.scene.add.container(6, headerBg.height + 6); + + this.voucherIcons = []; + + for (let a = 0; a < Object.keys(vouchers).length; a++) { + const x = (a % 17) * 18; + const y = Math.floor(a / 17) * 18; + + const icon = this.scene.add.sprite(x, y, 'items', 'unknown'); + icon.setOrigin(0, 0); + icon.setScale(0.5); + + this.voucherIcons.push(icon); + this.voucherIconsContainer.add(icon); + } + + const titleBg = this.scene.add.nineslice(0, headerBg.height + this.voucherIconsBg.height, 'window', null, 220, 24, 6, 6, 6, 6); + titleBg.setOrigin(0, 0); + + this.titleText = addTextObject(this.scene, 0, 0, '', TextStyle.WINDOW); + this.titleText.setOrigin(0, 0); + this.titleText.setPositionRelative(titleBg, 8, 4); + + const unlockBg = this.scene.add.nineslice(titleBg.x + titleBg.width, titleBg.y, 'window', null, 98, 24, 6, 6, 6, 6); + unlockBg.setOrigin(0, 0); + + this.unlockText = addTextObject(this.scene, 0, 0, '', TextStyle.WINDOW); + this.unlockText.setOrigin(0, 0); + this.unlockText.setPositionRelative(unlockBg, 8, 4); + + const descriptionBg = this.scene.add.nineslice(0, titleBg.y + titleBg.height, 'window', null, (this.scene.game.canvas.width / 6) - 2, 42, 6, 6, 6, 6); + descriptionBg.setOrigin(0, 0); + + const descriptionText = addTextObject(this.scene, 0, 0, '', TextStyle.WINDOW, { maxLines: 2 }); + descriptionText.setWordWrapWidth(1870); + descriptionText.setOrigin(0, 0); + descriptionText.setPositionRelative(descriptionBg, 8, 4); + + this.message = descriptionText; + + this.vouchersContainer.add(headerBg); + this.vouchersContainer.add(headerText); + this.vouchersContainer.add(this.voucherIconsBg); + this.vouchersContainer.add(this.voucherIconsContainer); + this.vouchersContainer.add(titleBg); + this.vouchersContainer.add(this.titleText); + this.vouchersContainer.add(unlockBg); + this.vouchersContainer.add(this.unlockText); + this.vouchersContainer.add(descriptionBg); + this.vouchersContainer.add(descriptionText); + + ui.add(this.vouchersContainer); + + this.setCursor(0); + + this.vouchersContainer.setVisible(false); + } + + show(args: any[]) { + super.show(args); + + const voucherUnlocks = this.scene.gameData.voucherUnlocks; + + Object.values(vouchers).forEach((voucher: Voucher, i: integer) => { + const icon = this.voucherIcons[i]; + const unlocked = voucherUnlocks.hasOwnProperty(voucher.id); + + icon.setFrame(getVoucherTypeIcon(voucher.voucherType)); + if (!unlocked) + icon.setTintFill(0); + else + icon.clearTint(); + }); + + this.vouchersContainer.setVisible(true); + this.setCursor(0); + + this.getUi().moveTo(this.vouchersContainer, this.getUi().length - 1); + + this.getUi().hideTooltip(); + } + + protected showVoucher(voucher: Voucher) { + const voucherUnlocks = this.scene.gameData.voucherUnlocks; + const unlocked = voucherUnlocks.hasOwnProperty(voucher.id); + + this.titleText.setText(getVoucherTypeName(voucher.voucherType)); + this.showText(voucher.description); + this.unlockText.setText(unlocked ? new Date(voucherUnlocks[voucher.id]).toLocaleDateString() : 'Locked'); + } + + processInput(button: Button): boolean { + const ui = this.getUi(); + + let success = false; + + if (button === Button.CANCEL) { + success = true; + this.scene.ui.revertMode(); + } else { + switch (button) { + case Button.UP: + if (this.cursor >= 17) + success = this.setCursor(this.cursor - 17); + break; + case Button.DOWN: + if (this.cursor + 17 < Object.keys(vouchers).length) + success = this.setCursor(this.cursor + 17); + break; + case Button.LEFT: + if (this.cursor) + success = this.setCursor(this.cursor - 1); + break; + case Button.RIGHT: + if (this.cursor < Object.keys(vouchers).length - 1) + success = this.setCursor(this.cursor + 1); + break; + } + } + + if (success) + ui.playSelect(); + + return success; + } + + setCursor(cursor: integer): boolean { + let ret = super.setCursor(cursor); + + let updateVoucher = ret; + + if (!this.cursorObj) { + this.cursorObj = this.scene.add.nineslice(0, 0, 'starter_select_cursor_highlight', null, 16, 16, 1, 1, 1, 1); + this.cursorObj.setOrigin(0, 0); + this.voucherIconsContainer.add(this.cursorObj); + updateVoucher = true; + } + + this.cursorObj.setPositionRelative(this.voucherIcons[this.cursor], 0, 0); + + if (updateVoucher) + this.showVoucher(vouchers[Object.keys(vouchers)[cursor]]); + + return ret; + } + + clear() { + super.clear(); + this.vouchersContainer.setVisible(false); + this.eraseCursor(); + } + + eraseCursor() { + if (this.cursorObj) + this.cursorObj.destroy(); + this.cursorObj = null; + } +} \ No newline at end of file diff --git a/src/utils.ts b/src/utils.ts index fbc384ff699..a9c10a354c1 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -76,6 +76,13 @@ export function randIntRange(min: integer, max: integer): integer { return randInt(max - min, min); } +export function getSunday(date: Date): Date { + const day = date.getDay(), + diff = date.getDate() - day; + const newDate = new Date(date.setDate(diff)); + return new Date(newDate.getFullYear(), newDate.getMonth(), newDate.getDate()); +} + export function getFrameMs(frameCount: integer): integer { return Math.floor((1 / 60) * 1000 * frameCount); }