diff --git a/README.md b/README.md index 866687d54b7..2b219b46afb 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,7 @@ Check out [Github Issues](https://github.com/pagefaultgames/pokerogue/issues) to - Involuntary-Twitch - selstar - koda_want_to_sleep + - thedreadedden ### 🎨 Move Animations - Pokémon Reborn diff --git a/package-lock.json b/package-lock.json index 9d6e2440f44..78eabb07fd1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "i18next-http-backend": "^2.6.1", "i18next-korean-postposition-processor": "^1.0.0", "json-stable-stringify": "^1.1.0", + "jszip": "^3.10.1", "phaser": "^3.70.0", "phaser3-rex-plugins": "^1.1.84" }, @@ -2723,6 +2724,11 @@ "node": ">= 0.6" } }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, "node_modules/cross-fetch": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", @@ -4045,6 +4051,11 @@ "node": ">= 4" } }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -4072,6 +4083,11 @@ "node": ">=0.8.19" } }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, "node_modules/ini": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", @@ -4481,6 +4497,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -4648,6 +4675,14 @@ "node": ">= 0.8.0" } }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dependencies": { + "immediate": "~3.0.5" + } + }, "node_modules/linkify-it": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", @@ -5237,6 +5272,11 @@ "dev": true, "license": "BlueOak-1.0.0" }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, "node_modules/papaparse": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.4.1.tgz", @@ -5485,6 +5525,11 @@ "node": ">= 0.8.0" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -5551,6 +5596,25 @@ } ] }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, "node_modules/rechoir": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", @@ -5741,6 +5805,11 @@ "tslib": "^2.1.0" } }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "node_modules/safe-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-2.1.1.tgz", @@ -5800,6 +5869,11 @@ "node": ">= 0.4" } }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -5917,6 +5991,14 @@ "dev": true, "license": "MIT" }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -6473,6 +6555,11 @@ "requires-port": "^1.0.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "node_modules/vite": { "version": "5.4.8", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.8.tgz", diff --git a/package.json b/package.json index ef2d4938087..bf24d2a6804 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "i18next-http-backend": "^2.6.1", "i18next-korean-postposition-processor": "^1.0.0", "json-stable-stringify": "^1.1.0", + "jszip": "^3.10.1", "phaser": "^3.70.0", "phaser3-rex-plugins": "^1.1.84" }, diff --git a/public/audio/bgm/forest.mp3 b/public/audio/bgm/forest.mp3 index a1d9ecb4b28..6382d3fc0b2 100644 Binary files a/public/audio/bgm/forest.mp3 and b/public/audio/bgm/forest.mp3 differ diff --git a/public/images/pokemon/451.json b/public/images/pokemon/451.json index 0e99c96f876..6c266f21a24 100644 --- a/public/images/pokemon/451.json +++ b/public/images/pokemon/451.json @@ -1,2330 +1,715 @@ -{ - "textures": [ - { - "image": "451.png", - "format": "RGBA8888", - "size": { - "w": 281, - "h": 281 - }, - "scale": 1, - "frames": [ - { - "filename": "0033.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 5, - "w": 69, - "h": 41 - }, - "frame": { - "x": 0, - "y": 0, - "w": 69, - "h": 41 - } - }, - { - "filename": "0034.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 5, - "w": 69, - "h": 41 - }, - "frame": { - "x": 0, - "y": 0, - "w": 69, - "h": 41 - } - }, - { - "filename": "0077.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 5, - "w": 69, - "h": 41 - }, - "frame": { - "x": 0, - "y": 0, - "w": 69, - "h": 41 - } - }, - { - "filename": "0078.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 5, - "w": 69, - "h": 41 - }, - "frame": { - "x": 0, - "y": 0, - "w": 69, - "h": 41 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 63, - "h": 43 - }, - "frame": { - "x": 69, - "y": 0, - "w": 63, - "h": 43 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 63, - "h": 43 - }, - "frame": { - "x": 69, - "y": 0, - "w": 63, - "h": 43 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 63, - "h": 43 - }, - "frame": { - "x": 69, - "y": 0, - "w": 63, - "h": 43 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 63, - "h": 43 - }, - "frame": { - "x": 69, - "y": 0, - "w": 63, - "h": 43 - } - }, - { - "filename": "0053.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 63, - "h": 43 - }, - "frame": { - "x": 69, - "y": 0, - "w": 63, - "h": 43 - } - }, - { - "filename": "0054.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 63, - "h": 43 - }, - "frame": { - "x": 69, - "y": 0, - "w": 63, - "h": 43 - } - }, - { - "filename": "0057.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 63, - "h": 43 - }, - "frame": { - "x": 69, - "y": 0, - "w": 63, - "h": 43 - } - }, - { - "filename": "0058.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 63, - "h": 43 - }, - "frame": { - "x": 69, - "y": 0, - "w": 63, - "h": 43 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 66, - "h": 43 - }, - "frame": { - "x": 132, - "y": 0, - "w": 66, - "h": 43 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 66, - "h": 43 - }, - "frame": { - "x": 132, - "y": 0, - "w": 66, - "h": 43 - } - }, - { - "filename": "0055.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 66, - "h": 43 - }, - "frame": { - "x": 132, - "y": 0, - "w": 66, - "h": 43 - } - }, - { - "filename": "0056.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 66, - "h": 43 - }, - "frame": { - "x": 132, - "y": 0, - "w": 66, - "h": 43 - } - }, - { - "filename": "0031.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 65, - "h": 43 - }, - "frame": { - "x": 198, - "y": 0, - "w": 65, - "h": 43 - } - }, - { - "filename": "0032.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 65, - "h": 43 - }, - "frame": { - "x": 198, - "y": 0, - "w": 65, - "h": 43 - } - }, - { - "filename": "0075.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 65, - "h": 43 - }, - "frame": { - "x": 198, - "y": 0, - "w": 65, - "h": 43 - } - }, - { - "filename": "0076.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 65, - "h": 43 - }, - "frame": { - "x": 198, - "y": 0, - "w": 65, - "h": 43 - } - }, - { - "filename": "0035.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 65, - "h": 43 - }, - "frame": { - "x": 0, - "y": 41, - "w": 65, - "h": 43 - } - }, - { - "filename": "0036.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 65, - "h": 43 - }, - "frame": { - "x": 0, - "y": 41, - "w": 65, - "h": 43 - } - }, - { - "filename": "0079.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 65, - "h": 43 - }, - "frame": { - "x": 0, - "y": 41, - "w": 65, - "h": 43 - } - }, - { - "filename": "0080.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 65, - "h": 43 - }, - "frame": { - "x": 0, - "y": 41, - "w": 65, - "h": 43 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 61, - "h": 44 - }, - "frame": { - "x": 65, - "y": 43, - "w": 61, - "h": 44 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 61, - "h": 44 - }, - "frame": { - "x": 65, - "y": 43, - "w": 61, - "h": 44 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 61, - "h": 44 - }, - "frame": { - "x": 65, - "y": 43, - "w": 61, - "h": 44 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 61, - "h": 44 - }, - "frame": { - "x": 65, - "y": 43, - "w": 61, - "h": 44 - } - }, - { - "filename": "0051.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 61, - "h": 44 - }, - "frame": { - "x": 65, - "y": 43, - "w": 61, - "h": 44 - } - }, - { - "filename": "0052.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 61, - "h": 44 - }, - "frame": { - "x": 65, - "y": 43, - "w": 61, - "h": 44 - } - }, - { - "filename": "0059.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 61, - "h": 44 - }, - "frame": { - "x": 65, - "y": 43, - "w": 61, - "h": 44 - } - }, - { - "filename": "0060.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 61, - "h": 44 - }, - "frame": { - "x": 65, - "y": 43, - "w": 61, - "h": 44 - } - }, - { - "filename": "0029.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 62, - "h": 44 - }, - "frame": { - "x": 126, - "y": 43, - "w": 62, - "h": 44 - } - }, - { - "filename": "0030.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 62, - "h": 44 - }, - "frame": { - "x": 126, - "y": 43, - "w": 62, - "h": 44 - } - }, - { - "filename": "0073.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 62, - "h": 44 - }, - "frame": { - "x": 126, - "y": 43, - "w": 62, - "h": 44 - } - }, - { - "filename": "0074.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 62, - "h": 44 - }, - "frame": { - "x": 126, - "y": 43, - "w": 62, - "h": 44 - } - }, - { - "filename": "0037.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 63, - "h": 44 - }, - "frame": { - "x": 188, - "y": 43, - "w": 63, - "h": 44 - } - }, - { - "filename": "0038.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 63, - "h": 44 - }, - "frame": { - "x": 188, - "y": 43, - "w": 63, - "h": 44 - } - }, - { - "filename": "0081.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 63, - "h": 44 - }, - "frame": { - "x": 188, - "y": 43, - "w": 63, - "h": 44 - } - }, - { - "filename": "0082.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 63, - "h": 44 - }, - "frame": { - "x": 188, - "y": 43, - "w": 63, - "h": 44 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 59, - "h": 45 - }, - "frame": { - "x": 0, - "y": 84, - "w": 59, - "h": 45 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 59, - "h": 45 - }, - "frame": { - "x": 0, - "y": 84, - "w": 59, - "h": 45 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 59, - "h": 45 - }, - "frame": { - "x": 0, - "y": 84, - "w": 59, - "h": 45 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 59, - "h": 45 - }, - "frame": { - "x": 0, - "y": 84, - "w": 59, - "h": 45 - } - }, - { - "filename": "0049.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 59, - "h": 45 - }, - "frame": { - "x": 0, - "y": 84, - "w": 59, - "h": 45 - } - }, - { - "filename": "0050.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 59, - "h": 45 - }, - "frame": { - "x": 0, - "y": 84, - "w": 59, - "h": 45 - } - }, - { - "filename": "0061.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 59, - "h": 45 - }, - "frame": { - "x": 0, - "y": 84, - "w": 59, - "h": 45 - } - }, - { - "filename": "0062.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 59, - "h": 45 - }, - "frame": { - "x": 0, - "y": 84, - "w": 59, - "h": 45 - } - }, - { - "filename": "0027.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 59, - "h": 45 - }, - "frame": { - "x": 59, - "y": 87, - "w": 59, - "h": 45 - } - }, - { - "filename": "0028.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 59, - "h": 45 - }, - "frame": { - "x": 59, - "y": 87, - "w": 59, - "h": 45 - } - }, - { - "filename": "0071.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 59, - "h": 45 - }, - "frame": { - "x": 59, - "y": 87, - "w": 59, - "h": 45 - } - }, - { - "filename": "0072.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 59, - "h": 45 - }, - "frame": { - "x": 59, - "y": 87, - "w": 59, - "h": 45 - } - }, - { - "filename": "0039.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 61, - "h": 45 - }, - "frame": { - "x": 118, - "y": 87, - "w": 61, - "h": 45 - } - }, - { - "filename": "0040.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 61, - "h": 45 - }, - "frame": { - "x": 118, - "y": 87, - "w": 61, - "h": 45 - } - }, - { - "filename": "0083.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 61, - "h": 45 - }, - "frame": { - "x": 118, - "y": 87, - "w": 61, - "h": 45 - } - }, - { - "filename": "0084.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 61, - "h": 45 - }, - "frame": { - "x": 118, - "y": 87, - "w": 61, - "h": 45 - } - }, - { - "filename": "0089.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 57, - "h": 45 - }, - "frame": { - "x": 179, - "y": 87, - "w": 57, - "h": 45 - } - }, - { - "filename": "0090.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 57, - "h": 45 - }, - "frame": { - "x": 179, - "y": 87, - "w": 57, - "h": 45 - } - }, - { - "filename": "0091.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 57, - "h": 45 - }, - "frame": { - "x": 0, - "y": 129, - "w": 57, - "h": 45 - } - }, - { - "filename": "0092.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 57, - "h": 45 - }, - "frame": { - "x": 0, - "y": 129, - "w": 57, - "h": 45 - } - }, - { - "filename": "0093.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 57, - "h": 45 - }, - "frame": { - "x": 57, - "y": 132, - "w": 57, - "h": 45 - } - }, - { - "filename": "0094.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 57, - "h": 45 - }, - "frame": { - "x": 57, - "y": 132, - "w": 57, - "h": 45 - } - }, - { - "filename": "0095.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 56, - "h": 45 - }, - "frame": { - "x": 114, - "y": 132, - "w": 56, - "h": 45 - } - }, - { - "filename": "0096.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 56, - "h": 45 - }, - "frame": { - "x": 114, - "y": 132, - "w": 56, - "h": 45 - } - }, - { - "filename": "0097.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 54, - "h": 45 - }, - "frame": { - "x": 170, - "y": 132, - "w": 54, - "h": 45 - } - }, - { - "filename": "0098.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 54, - "h": 45 - }, - "frame": { - "x": 170, - "y": 132, - "w": 54, - "h": 45 - } - }, - { - "filename": "0099.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 54, - "h": 45 - }, - "frame": { - "x": 224, - "y": 132, - "w": 54, - "h": 45 - } - }, - { - "filename": "0100.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 54, - "h": 45 - }, - "frame": { - "x": 224, - "y": 132, - "w": 54, - "h": 45 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 174, - "w": 54, - "h": 46 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 174, - "w": 54, - "h": 46 - } - }, - { - "filename": "0021.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 174, - "w": 54, - "h": 46 - } - }, - { - "filename": "0022.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 174, - "w": 54, - "h": 46 - } - }, - { - "filename": "0023.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 174, - "w": 54, - "h": 46 - } - }, - { - "filename": "0024.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 174, - "w": 54, - "h": 46 - } - }, - { - "filename": "0045.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 174, - "w": 54, - "h": 46 - } - }, - { - "filename": "0046.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 174, - "w": 54, - "h": 46 - } - }, - { - "filename": "0065.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 174, - "w": 54, - "h": 46 - } - }, - { - "filename": "0066.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 174, - "w": 54, - "h": 46 - } - }, - { - "filename": "0067.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 174, - "w": 54, - "h": 46 - } - }, - { - "filename": "0068.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 174, - "w": 54, - "h": 46 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 54, - "y": 177, - "w": 57, - "h": 46 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 54, - "y": 177, - "w": 57, - "h": 46 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 54, - "y": 177, - "w": 57, - "h": 46 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 54, - "y": 177, - "w": 57, - "h": 46 - } - }, - { - "filename": "0047.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 54, - "y": 177, - "w": 57, - "h": 46 - } - }, - { - "filename": "0048.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 54, - "y": 177, - "w": 57, - "h": 46 - } - }, - { - "filename": "0063.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 54, - "y": 177, - "w": 57, - "h": 46 - } - }, - { - "filename": "0064.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 54, - "y": 177, - "w": 57, - "h": 46 - } - }, - { - "filename": "0025.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 111, - "y": 177, - "w": 57, - "h": 46 - } - }, - { - "filename": "0026.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 111, - "y": 177, - "w": 57, - "h": 46 - } - }, - { - "filename": "0069.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 111, - "y": 177, - "w": 57, - "h": 46 - } - }, - { - "filename": "0070.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 111, - "y": 177, - "w": 57, - "h": 46 - } - }, - { - "filename": "0041.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 60, - "h": 46 - }, - "frame": { - "x": 168, - "y": 177, - "w": 60, - "h": 46 - } - }, - { - "filename": "0042.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 60, - "h": 46 - }, - "frame": { - "x": 168, - "y": 177, - "w": 60, - "h": 46 - } - }, - { - "filename": "0085.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 60, - "h": 46 - }, - "frame": { - "x": 168, - "y": 177, - "w": 60, - "h": 46 - } - }, - { - "filename": "0086.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 60, - "h": 46 - }, - "frame": { - "x": 168, - "y": 177, - "w": 60, - "h": 46 - } - }, - { - "filename": "0109.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 53, - "h": 46 - }, - "frame": { - "x": 228, - "y": 177, - "w": 53, - "h": 46 - } - }, - { - "filename": "0110.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 53, - "h": 46 - }, - "frame": { - "x": 228, - "y": 177, - "w": 53, - "h": 46 - } - }, - { - "filename": "0101.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 220, - "w": 54, - "h": 46 - } - }, - { - "filename": "0102.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 220, - "w": 54, - "h": 46 - } - }, - { - "filename": "0043.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 54, - "y": 223, - "w": 57, - "h": 46 - } - }, - { - "filename": "0044.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 54, - "y": 223, - "w": 57, - "h": 46 - } - }, - { - "filename": "0087.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 54, - "y": 223, - "w": 57, - "h": 46 - } - }, - { - "filename": "0088.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 54, - "y": 223, - "w": 57, - "h": 46 - } - }, - { - "filename": "0103.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 55, - "h": 46 - }, - "frame": { - "x": 111, - "y": 223, - "w": 55, - "h": 46 - } - }, - { - "filename": "0104.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 55, - "h": 46 - }, - "frame": { - "x": 111, - "y": 223, - "w": 55, - "h": 46 - } - }, - { - "filename": "0105.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 55, - "h": 46 - }, - "frame": { - "x": 166, - "y": 223, - "w": 55, - "h": 46 - } - }, - { - "filename": "0106.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 55, - "h": 46 - }, - "frame": { - "x": 166, - "y": 223, - "w": 55, - "h": 46 - } - }, - { - "filename": "0107.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 221, - "y": 223, - "w": 54, - "h": 46 - } - }, - { - "filename": "0108.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 221, - "y": 223, - "w": 54, - "h": 46 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:e303c68c1876b77078f3e1fd4372a4ce:84139d6b94cea0f3c45dbd8fa7109c3d:c79e17c206de27e3b7f1ce96f7df8e51$" - } -} +{ "frames": [ + { + "filename": "0055.png", + "frame": { "x": 0, "y": 0, "w": 68, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 6, "w": 68, "h": 40 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0001.png", + "frame": { "x": 287, "y": 86, "w": 52, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 0, "w": 52, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0002.png", + "frame": { "x": 287, "y": 86, "w": 52, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 0, "w": 52, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0003.png", + "frame": { "x": 57, "y": 86, "w": 55, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 55, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0004.png", + "frame": { "x": 57, "y": 86, "w": 55, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 55, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0005.png", + "frame": { "x": 0, "y": 85, "w": 57, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 57, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0006.png", + "frame": { "x": 0, "y": 85, "w": 57, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 57, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0007.png", + "frame": { "x": 238, "y": 43, "w": 59, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 59, "h": 43 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0008.png", + "frame": { "x": 238, "y": 43, "w": 59, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 59, "h": 43 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0009.png", + "frame": { "x": 177, "y": 42, "w": 61, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 61, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0010.png", + "frame": { "x": 177, "y": 42, "w": 61, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 61, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0011.png", + "frame": { "x": 68, "y": 0, "w": 64, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 4, "w": 64, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0012.png", + "frame": { "x": 68, "y": 0, "w": 64, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 4, "w": 64, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0013.png", + "frame": { "x": 177, "y": 42, "w": 61, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 61, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0014.png", + "frame": { "x": 177, "y": 42, "w": 61, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 61, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0015.png", + "frame": { "x": 238, "y": 43, "w": 59, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 59, "h": 43 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0016.png", + "frame": { "x": 238, "y": 43, "w": 59, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 59, "h": 43 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0017.png", + "frame": { "x": 0, "y": 85, "w": 57, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 57, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0018.png", + "frame": { "x": 0, "y": 85, "w": 57, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 57, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0019.png", + "frame": { "x": 57, "y": 86, "w": 55, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 55, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0020.png", + "frame": { "x": 57, "y": 86, "w": 55, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 55, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0021.png", + "frame": { "x": 287, "y": 86, "w": 52, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 0, "w": 52, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0022.png", + "frame": { "x": 287, "y": 86, "w": 52, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 0, "w": 52, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0023.png", + "frame": { "x": 287, "y": 86, "w": 52, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 0, "w": 52, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0024.png", + "frame": { "x": 287, "y": 86, "w": 52, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 0, "w": 52, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0025.png", + "frame": { "x": 57, "y": 86, "w": 55, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 55, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0026.png", + "frame": { "x": 57, "y": 86, "w": 55, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 55, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0027.png", + "frame": { "x": 0, "y": 85, "w": 57, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 57, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0028.png", + "frame": { "x": 0, "y": 85, "w": 57, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 57, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0029.png", + "frame": { "x": 238, "y": 43, "w": 59, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 59, "h": 43 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0030.png", + "frame": { "x": 238, "y": 43, "w": 59, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 59, "h": 43 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0031.png", + "frame": { "x": 177, "y": 42, "w": 61, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 61, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0032.png", + "frame": { "x": 177, "y": 42, "w": 61, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 61, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0033.png", + "frame": { "x": 68, "y": 0, "w": 64, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 4, "w": 64, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0034.png", + "frame": { "x": 68, "y": 0, "w": 64, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 4, "w": 64, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0035.png", + "frame": { "x": 177, "y": 42, "w": 61, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 61, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0036.png", + "frame": { "x": 177, "y": 42, "w": 61, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 61, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0037.png", + "frame": { "x": 238, "y": 43, "w": 59, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 59, "h": 43 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0038.png", + "frame": { "x": 238, "y": 43, "w": 59, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 59, "h": 43 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0039.png", + "frame": { "x": 0, "y": 85, "w": 57, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 57, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0040.png", + "frame": { "x": 0, "y": 85, "w": 57, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 57, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0041.png", + "frame": { "x": 57, "y": 86, "w": 55, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 55, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0042.png", + "frame": { "x": 57, "y": 86, "w": 55, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 55, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0043.png", + "frame": { "x": 287, "y": 86, "w": 52, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 0, "w": 52, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0044.png", + "frame": { "x": 287, "y": 86, "w": 52, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 0, "w": 52, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0045.png", + "frame": { "x": 287, "y": 86, "w": 52, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 0, "w": 52, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0046.png", + "frame": { "x": 287, "y": 86, "w": 52, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 0, "w": 52, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0047.png", + "frame": { "x": 232, "y": 86, "w": 55, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 55, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0048.png", + "frame": { "x": 232, "y": 86, "w": 55, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 55, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0049.png", + "frame": { "x": 117, "y": 85, "w": 57, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 57, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0050.png", + "frame": { "x": 117, "y": 85, "w": 57, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 57, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0051.png", + "frame": { "x": 117, "y": 42, "w": 60, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 60, "h": 43 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0052.png", + "frame": { "x": 117, "y": 42, "w": 60, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 60, "h": 43 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0053.png", + "frame": { "x": 132, "y": 0, "w": 63, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 63, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0054.png", + "frame": { "x": 132, "y": 0, "w": 63, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 63, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0056.png", + "frame": { "x": 0, "y": 0, "w": 68, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 6, "w": 68, "h": 40 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0057.png", + "frame": { "x": 195, "y": 0, "w": 63, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 63, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0058.png", + "frame": { "x": 195, "y": 0, "w": 63, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 63, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0059.png", + "frame": { "x": 258, "y": 0, "w": 61, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 3, "w": 61, "h": 43 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0060.png", + "frame": { "x": 258, "y": 0, "w": 61, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 3, "w": 61, "h": 43 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0061.png", + "frame": { "x": 58, "y": 42, "w": 59, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 59, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0062.png", + "frame": { "x": 58, "y": 42, "w": 59, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 59, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0063.png", + "frame": { "x": 0, "y": 40, "w": 58, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 1, "w": 58, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0064.png", + "frame": { "x": 0, "y": 40, "w": 58, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 1, "w": 58, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0065.png", + "frame": { "x": 177, "y": 84, "w": 55, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 0, "w": 55, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0066.png", + "frame": { "x": 177, "y": 84, "w": 55, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 0, "w": 55, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0067.png", + "frame": { "x": 0, "y": 129, "w": 55, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 55, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0068.png", + "frame": { "x": 0, "y": 129, "w": 55, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 55, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0069.png", + "frame": { "x": 112, "y": 129, "w": 55, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 55, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0070.png", + "frame": { "x": 112, "y": 129, "w": 55, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 55, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0071.png", + "frame": { "x": 167, "y": 130, "w": 55, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 2, "w": 55, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0072.png", + "frame": { "x": 167, "y": 130, "w": 55, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 2, "w": 55, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0073.png", + "frame": { "x": 0, "y": 173, "w": 54, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 2, "w": 54, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0074.png", + "frame": { "x": 0, "y": 173, "w": 54, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 2, "w": 54, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0075.png", + "frame": { "x": 54, "y": 177, "w": 52, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 2, "w": 52, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0076.png", + "frame": { "x": 54, "y": 177, "w": 52, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 2, "w": 52, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0077.png", + "frame": { "x": 210, "y": 176, "w": 53, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 53, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0078.png", + "frame": { "x": 210, "y": 176, "w": 53, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 53, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0079.png", + "frame": { "x": 158, "y": 174, "w": 52, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 52, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0080.png", + "frame": { "x": 158, "y": 174, "w": 52, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 52, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0081.png", + "frame": { "x": 222, "y": 131, "w": 53, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 1, "w": 53, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0082.png", + "frame": { "x": 222, "y": 131, "w": 53, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 1, "w": 53, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0083.png", + "frame": { "x": 275, "y": 132, "w": 53, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 1, "w": 53, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0084.png", + "frame": { "x": 275, "y": 132, "w": 53, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 1, "w": 53, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0085.png", + "frame": { "x": 55, "y": 131, "w": 52, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 0, "w": 52, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0086.png", + "frame": { "x": 55, "y": 131, "w": 52, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 0, "w": 52, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0087.png", + "frame": { "x": 107, "y": 173, "w": 51, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 0, "w": 51, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0088.png", + "frame": { "x": 107, "y": 173, "w": 51, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 0, "w": 51, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + } + ], + "meta": { + "app": "https://www.aseprite.org/", + "version": "1.3.8.1-x64", + "image": "451.png", + "format": "I8", + "size": { "w": 339, "h": 221 }, + "scale": "1" + } +} \ No newline at end of file diff --git a/public/images/pokemon/451.png b/public/images/pokemon/451.png index fac8f5a0170..716e8a08041 100644 Binary files a/public/images/pokemon/451.png and b/public/images/pokemon/451.png differ diff --git a/public/images/pokemon/47.json b/public/images/pokemon/47.json index 437459a66e9..959bfe740f7 100644 --- a/public/images/pokemon/47.json +++ b/public/images/pokemon/47.json @@ -1,776 +1,299 @@ -{ - "textures": [ - { - "image": "47.png", - "format": "RGBA8888", - "size": { - "w": 230, - "h": 230 - }, - "scale": 1, - "frames": [ - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 6, - "y": 12, - "w": 56, - "h": 49 - }, - "frame": { - "x": 0, - "y": 0, - "w": 56, - "h": 49 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 6, - "y": 12, - "w": 56, - "h": 49 - }, - "frame": { - "x": 0, - "y": 0, - "w": 56, - "h": 49 - } - }, - { - "filename": "0027.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 12, - "w": 62, - "h": 51 - }, - "frame": { - "x": 56, - "y": 0, - "w": 62, - "h": 51 - } - }, - { - "filename": "0028.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 12, - "w": 62, - "h": 51 - }, - "frame": { - "x": 56, - "y": 0, - "w": 62, - "h": 51 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 7, - "y": 8, - "w": 55, - "h": 53 - }, - "frame": { - "x": 118, - "y": 0, - "w": 55, - "h": 53 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 7, - "y": 8, - "w": 55, - "h": 53 - }, - "frame": { - "x": 118, - "y": 0, - "w": 55, - "h": 53 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 7, - "y": 7, - "w": 55, - "h": 54 - }, - "frame": { - "x": 173, - "y": 0, - "w": 55, - "h": 54 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 7, - "y": 7, - "w": 55, - "h": 54 - }, - "frame": { - "x": 173, - "y": 0, - "w": 55, - "h": 54 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 8, - "y": 5, - "w": 53, - "h": 56 - }, - "frame": { - "x": 0, - "y": 49, - "w": 53, - "h": 56 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 8, - "y": 5, - "w": 53, - "h": 56 - }, - "frame": { - "x": 0, - "y": 49, - "w": 53, - "h": 56 - } - }, - { - "filename": "0025.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 8, - "w": 62, - "h": 55 - }, - "frame": { - "x": 53, - "y": 51, - "w": 62, - "h": 55 - } - }, - { - "filename": "0026.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 8, - "w": 62, - "h": 55 - }, - "frame": { - "x": 53, - "y": 51, - "w": 62, - "h": 55 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 53, - "h": 57 - }, - "frame": { - "x": 115, - "y": 53, - "w": 53, - "h": 57 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 53, - "h": 57 - }, - "frame": { - "x": 115, - "y": 53, - "w": 53, - "h": 57 - } - }, - { - "filename": "0029.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 7, - "w": 62, - "h": 56 - }, - "frame": { - "x": 168, - "y": 54, - "w": 62, - "h": 56 - } - }, - { - "filename": "0030.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 7, - "w": 62, - "h": 56 - }, - "frame": { - "x": 168, - "y": 54, - "w": 62, - "h": 56 - } - }, - { - "filename": "0023.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 5, - "w": 61, - "h": 58 - }, - "frame": { - "x": 0, - "y": 106, - "w": 61, - "h": 58 - } - }, - { - "filename": "0024.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 5, - "w": 61, - "h": 58 - }, - "frame": { - "x": 0, - "y": 106, - "w": 61, - "h": 58 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 6, - "y": 2, - "w": 54, - "h": 59 - }, - "frame": { - "x": 61, - "y": 106, - "w": 54, - "h": 59 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 6, - "y": 2, - "w": 54, - "h": 59 - }, - "frame": { - "x": 61, - "y": 106, - "w": 54, - "h": 59 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 57, - "h": 59 - }, - "frame": { - "x": 115, - "y": 110, - "w": 57, - "h": 59 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 57, - "h": 59 - }, - "frame": { - "x": 115, - "y": 110, - "w": 57, - "h": 59 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 57, - "h": 59 - }, - "frame": { - "x": 115, - "y": 110, - "w": 57, - "h": 59 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 57, - "h": 59 - }, - "frame": { - "x": 115, - "y": 110, - "w": 57, - "h": 59 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 6, - "y": 2, - "w": 54, - "h": 59 - }, - "frame": { - "x": 172, - "y": 110, - "w": 54, - "h": 59 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 6, - "y": 2, - "w": 54, - "h": 59 - }, - "frame": { - "x": 172, - "y": 110, - "w": 54, - "h": 59 - } - }, - { - "filename": "0031.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 61, - "h": 59 - }, - "frame": { - "x": 0, - "y": 164, - "w": 61, - "h": 59 - } - }, - { - "filename": "0032.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 61, - "h": 59 - }, - "frame": { - "x": 0, - "y": 164, - "w": 61, - "h": 59 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 57, - "h": 61 - }, - "frame": { - "x": 61, - "y": 169, - "w": 57, - "h": 61 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 57, - "h": 61 - }, - "frame": { - "x": 61, - "y": 169, - "w": 57, - "h": 61 - } - }, - { - "filename": "0035.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 57, - "h": 61 - }, - "frame": { - "x": 61, - "y": 169, - "w": 57, - "h": 61 - } - }, - { - "filename": "0036.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 57, - "h": 61 - }, - "frame": { - "x": 61, - "y": 169, - "w": 57, - "h": 61 - } - }, - { - "filename": "0021.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 60, - "h": 61 - }, - "frame": { - "x": 118, - "y": 169, - "w": 60, - "h": 61 - } - }, - { - "filename": "0022.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 60, - "h": 61 - }, - "frame": { - "x": 118, - "y": 169, - "w": 60, - "h": 61 - } - }, - { - "filename": "0033.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 60, - "h": 61 - }, - "frame": { - "x": 118, - "y": 169, - "w": 60, - "h": 61 - } - }, - { - "filename": "0034.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 60, - "h": 61 - }, - "frame": { - "x": 118, - "y": 169, - "w": 60, - "h": 61 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:b28fe643197bcc1def0e0ac2ba9f4e67:516d08c8e1ff13b49a109b082ef12860:fe45e2d628a6cef0908f7b82468c8798$" - } -} \ No newline at end of file +{ "frames": [ + { + "filename": "0001.png", + "frame": { "x": 0, "y": 58, "w": 55, "h": 57 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 5, "w": 55, "h": 57 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0002.png", + "frame": { "x": 0, "y": 58, "w": 55, "h": 57 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 5, "w": 55, "h": 57 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0003.png", + "frame": { "x": 166, "y": 114, "w": 52, "h": 56 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 5, "w": 52, "h": 56 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0004.png", + "frame": { "x": 166, "y": 114, "w": 52, "h": 56 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 5, "w": 52, "h": 56 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0005.png", + "frame": { "x": 0, "y": 169, "w": 51, "h": 54 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 11, "y": 7, "w": 51, "h": 54 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0006.png", + "frame": { "x": 0, "y": 169, "w": 51, "h": 54 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 11, "y": 7, "w": 51, "h": 54 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0007.png", + "frame": { "x": 104, "y": 166, "w": 53, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 9, "w": 53, "h": 52 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0008.png", + "frame": { "x": 104, "y": 166, "w": 53, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 9, "w": 53, "h": 52 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0009.png", + "frame": { "x": 157, "y": 170, "w": 55, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 12, "w": 55, "h": 49 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0010.png", + "frame": { "x": 157, "y": 170, "w": 55, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 12, "w": 55, "h": 49 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0011.png", + "frame": { "x": 0, "y": 115, "w": 53, "h": 54 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 8, "w": 53, "h": 54 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0012.png", + "frame": { "x": 0, "y": 115, "w": 53, "h": 54 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 8, "w": 53, "h": 54 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0013.png", + "frame": { "x": 53, "y": 116, "w": 51, "h": 56 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 11, "y": 6, "w": 51, "h": 56 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0014.png", + "frame": { "x": 53, "y": 116, "w": 51, "h": 56 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 11, "y": 6, "w": 51, "h": 56 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0015.png", + "frame": { "x": 114, "y": 109, "w": 52, "h": 57 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 5, "w": 52, "h": 57 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0016.png", + "frame": { "x": 114, "y": 109, "w": 52, "h": 57 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 5, "w": 52, "h": 57 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0017.png", + "frame": { "x": 59, "y": 57, "w": 55, "h": 59 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 55, "h": 59 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0018.png", + "frame": { "x": 59, "y": 57, "w": 55, "h": 59 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 55, "h": 59 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0019.png", + "frame": { "x": 0, "y": 58, "w": 55, "h": 57 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 5, "w": 55, "h": 57 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0020.png", + "frame": { "x": 0, "y": 58, "w": 55, "h": 57 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 5, "w": 55, "h": 57 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0021.png", + "frame": { "x": 178, "y": 56, "w": 57, "h": 58 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 5, "w": 57, "h": 58 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0022.png", + "frame": { "x": 178, "y": 56, "w": 57, "h": 58 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 5, "w": 57, "h": 58 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0023.png", + "frame": { "x": 119, "y": 0, "w": 59, "h": 57 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 7, "w": 59, "h": 57 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0024.png", + "frame": { "x": 119, "y": 0, "w": 59, "h": 57 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 7, "w": 59, "h": 57 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0025.png", + "frame": { "x": 178, "y": 0, "w": 60, "h": 56 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 9, "w": 60, "h": 56 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0026.png", + "frame": { "x": 178, "y": 0, "w": 60, "h": 56 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 9, "w": 60, "h": 56 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0027.png", + "frame": { "x": 114, "y": 57, "w": 62, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 12, "w": 62, "h": 52 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0028.png", + "frame": { "x": 114, "y": 57, "w": 62, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 12, "w": 62, "h": 52 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0029.png", + "frame": { "x": 59, "y": 0, "w": 60, "h": 57 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 8, "w": 60, "h": 57 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0030.png", + "frame": { "x": 59, "y": 0, "w": 60, "h": 57 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 8, "w": 60, "h": 57 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0031.png", + "frame": { "x": 0, "y": 0, "w": 59, "h": 58 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 6, "w": 59, "h": 58 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0032.png", + "frame": { "x": 0, "y": 0, "w": 59, "h": 58 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 6, "w": 59, "h": 58 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0033.png", + "frame": { "x": 178, "y": 56, "w": 57, "h": 58 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 5, "w": 57, "h": 58 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0034.png", + "frame": { "x": 178, "y": 56, "w": 57, "h": 58 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 5, "w": 57, "h": 58 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0035.png", + "frame": { "x": 59, "y": 57, "w": 55, "h": 59 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 55, "h": 59 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0036.png", + "frame": { "x": 59, "y": 57, "w": 55, "h": 59 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 55, "h": 59 }, + "sourceSize": { "w": 65, "h": 65 } + } + ], + "meta": { + "app": "https://www.aseprite.org/", + "version": "1.3.8.1-x64", + "image": "47.png", + "format": "I8", + "size": { "w": 238, "h": 223 }, + "scale": "1" + } +} diff --git a/public/images/pokemon/47.png b/public/images/pokemon/47.png index f9474fda1c9..665cabf322e 100644 Binary files a/public/images/pokemon/47.png and b/public/images/pokemon/47.png differ diff --git a/public/images/pokemon/shiny/451.json b/public/images/pokemon/shiny/451.json index f492cdbcb04..273d546e2bb 100644 --- a/public/images/pokemon/shiny/451.json +++ b/public/images/pokemon/shiny/451.json @@ -1,2330 +1,715 @@ -{ - "textures": [ - { - "image": "451.png", - "format": "RGBA8888", - "size": { - "w": 281, - "h": 281 - }, - "scale": 1, - "frames": [ - { - "filename": "0033.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 5, - "w": 69, - "h": 41 - }, - "frame": { - "x": 0, - "y": 0, - "w": 69, - "h": 41 - } - }, - { - "filename": "0034.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 5, - "w": 69, - "h": 41 - }, - "frame": { - "x": 0, - "y": 0, - "w": 69, - "h": 41 - } - }, - { - "filename": "0077.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 5, - "w": 69, - "h": 41 - }, - "frame": { - "x": 0, - "y": 0, - "w": 69, - "h": 41 - } - }, - { - "filename": "0078.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 5, - "w": 69, - "h": 41 - }, - "frame": { - "x": 0, - "y": 0, - "w": 69, - "h": 41 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 63, - "h": 43 - }, - "frame": { - "x": 69, - "y": 0, - "w": 63, - "h": 43 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 63, - "h": 43 - }, - "frame": { - "x": 69, - "y": 0, - "w": 63, - "h": 43 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 63, - "h": 43 - }, - "frame": { - "x": 69, - "y": 0, - "w": 63, - "h": 43 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 63, - "h": 43 - }, - "frame": { - "x": 69, - "y": 0, - "w": 63, - "h": 43 - } - }, - { - "filename": "0053.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 63, - "h": 43 - }, - "frame": { - "x": 69, - "y": 0, - "w": 63, - "h": 43 - } - }, - { - "filename": "0054.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 63, - "h": 43 - }, - "frame": { - "x": 69, - "y": 0, - "w": 63, - "h": 43 - } - }, - { - "filename": "0057.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 63, - "h": 43 - }, - "frame": { - "x": 69, - "y": 0, - "w": 63, - "h": 43 - } - }, - { - "filename": "0058.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 63, - "h": 43 - }, - "frame": { - "x": 69, - "y": 0, - "w": 63, - "h": 43 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 66, - "h": 43 - }, - "frame": { - "x": 132, - "y": 0, - "w": 66, - "h": 43 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 66, - "h": 43 - }, - "frame": { - "x": 132, - "y": 0, - "w": 66, - "h": 43 - } - }, - { - "filename": "0055.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 66, - "h": 43 - }, - "frame": { - "x": 132, - "y": 0, - "w": 66, - "h": 43 - } - }, - { - "filename": "0056.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 3, - "w": 66, - "h": 43 - }, - "frame": { - "x": 132, - "y": 0, - "w": 66, - "h": 43 - } - }, - { - "filename": "0031.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 65, - "h": 43 - }, - "frame": { - "x": 198, - "y": 0, - "w": 65, - "h": 43 - } - }, - { - "filename": "0032.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 65, - "h": 43 - }, - "frame": { - "x": 198, - "y": 0, - "w": 65, - "h": 43 - } - }, - { - "filename": "0075.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 65, - "h": 43 - }, - "frame": { - "x": 198, - "y": 0, - "w": 65, - "h": 43 - } - }, - { - "filename": "0076.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 65, - "h": 43 - }, - "frame": { - "x": 198, - "y": 0, - "w": 65, - "h": 43 - } - }, - { - "filename": "0035.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 65, - "h": 43 - }, - "frame": { - "x": 0, - "y": 41, - "w": 65, - "h": 43 - } - }, - { - "filename": "0036.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 65, - "h": 43 - }, - "frame": { - "x": 0, - "y": 41, - "w": 65, - "h": 43 - } - }, - { - "filename": "0079.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 65, - "h": 43 - }, - "frame": { - "x": 0, - "y": 41, - "w": 65, - "h": 43 - } - }, - { - "filename": "0080.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 3, - "w": 65, - "h": 43 - }, - "frame": { - "x": 0, - "y": 41, - "w": 65, - "h": 43 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 61, - "h": 44 - }, - "frame": { - "x": 65, - "y": 43, - "w": 61, - "h": 44 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 61, - "h": 44 - }, - "frame": { - "x": 65, - "y": 43, - "w": 61, - "h": 44 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 61, - "h": 44 - }, - "frame": { - "x": 65, - "y": 43, - "w": 61, - "h": 44 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 61, - "h": 44 - }, - "frame": { - "x": 65, - "y": 43, - "w": 61, - "h": 44 - } - }, - { - "filename": "0051.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 61, - "h": 44 - }, - "frame": { - "x": 65, - "y": 43, - "w": 61, - "h": 44 - } - }, - { - "filename": "0052.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 61, - "h": 44 - }, - "frame": { - "x": 65, - "y": 43, - "w": 61, - "h": 44 - } - }, - { - "filename": "0059.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 61, - "h": 44 - }, - "frame": { - "x": 65, - "y": 43, - "w": 61, - "h": 44 - } - }, - { - "filename": "0060.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 61, - "h": 44 - }, - "frame": { - "x": 65, - "y": 43, - "w": 61, - "h": 44 - } - }, - { - "filename": "0029.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 62, - "h": 44 - }, - "frame": { - "x": 126, - "y": 43, - "w": 62, - "h": 44 - } - }, - { - "filename": "0030.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 62, - "h": 44 - }, - "frame": { - "x": 126, - "y": 43, - "w": 62, - "h": 44 - } - }, - { - "filename": "0073.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 62, - "h": 44 - }, - "frame": { - "x": 126, - "y": 43, - "w": 62, - "h": 44 - } - }, - { - "filename": "0074.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 4, - "y": 2, - "w": 62, - "h": 44 - }, - "frame": { - "x": 126, - "y": 43, - "w": 62, - "h": 44 - } - }, - { - "filename": "0037.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 63, - "h": 44 - }, - "frame": { - "x": 188, - "y": 43, - "w": 63, - "h": 44 - } - }, - { - "filename": "0038.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 63, - "h": 44 - }, - "frame": { - "x": 188, - "y": 43, - "w": 63, - "h": 44 - } - }, - { - "filename": "0081.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 63, - "h": 44 - }, - "frame": { - "x": 188, - "y": 43, - "w": 63, - "h": 44 - } - }, - { - "filename": "0082.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 2, - "w": 63, - "h": 44 - }, - "frame": { - "x": 188, - "y": 43, - "w": 63, - "h": 44 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 59, - "h": 45 - }, - "frame": { - "x": 0, - "y": 84, - "w": 59, - "h": 45 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 59, - "h": 45 - }, - "frame": { - "x": 0, - "y": 84, - "w": 59, - "h": 45 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 59, - "h": 45 - }, - "frame": { - "x": 0, - "y": 84, - "w": 59, - "h": 45 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 59, - "h": 45 - }, - "frame": { - "x": 0, - "y": 84, - "w": 59, - "h": 45 - } - }, - { - "filename": "0049.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 59, - "h": 45 - }, - "frame": { - "x": 0, - "y": 84, - "w": 59, - "h": 45 - } - }, - { - "filename": "0050.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 59, - "h": 45 - }, - "frame": { - "x": 0, - "y": 84, - "w": 59, - "h": 45 - } - }, - { - "filename": "0061.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 59, - "h": 45 - }, - "frame": { - "x": 0, - "y": 84, - "w": 59, - "h": 45 - } - }, - { - "filename": "0062.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 59, - "h": 45 - }, - "frame": { - "x": 0, - "y": 84, - "w": 59, - "h": 45 - } - }, - { - "filename": "0027.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 59, - "h": 45 - }, - "frame": { - "x": 59, - "y": 87, - "w": 59, - "h": 45 - } - }, - { - "filename": "0028.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 59, - "h": 45 - }, - "frame": { - "x": 59, - "y": 87, - "w": 59, - "h": 45 - } - }, - { - "filename": "0071.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 59, - "h": 45 - }, - "frame": { - "x": 59, - "y": 87, - "w": 59, - "h": 45 - } - }, - { - "filename": "0072.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 1, - "w": 59, - "h": 45 - }, - "frame": { - "x": 59, - "y": 87, - "w": 59, - "h": 45 - } - }, - { - "filename": "0039.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 61, - "h": 45 - }, - "frame": { - "x": 118, - "y": 87, - "w": 61, - "h": 45 - } - }, - { - "filename": "0040.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 61, - "h": 45 - }, - "frame": { - "x": 118, - "y": 87, - "w": 61, - "h": 45 - } - }, - { - "filename": "0083.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 61, - "h": 45 - }, - "frame": { - "x": 118, - "y": 87, - "w": 61, - "h": 45 - } - }, - { - "filename": "0084.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 1, - "w": 61, - "h": 45 - }, - "frame": { - "x": 118, - "y": 87, - "w": 61, - "h": 45 - } - }, - { - "filename": "0089.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 57, - "h": 45 - }, - "frame": { - "x": 179, - "y": 87, - "w": 57, - "h": 45 - } - }, - { - "filename": "0090.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 57, - "h": 45 - }, - "frame": { - "x": 179, - "y": 87, - "w": 57, - "h": 45 - } - }, - { - "filename": "0091.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 57, - "h": 45 - }, - "frame": { - "x": 0, - "y": 129, - "w": 57, - "h": 45 - } - }, - { - "filename": "0092.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 1, - "w": 57, - "h": 45 - }, - "frame": { - "x": 0, - "y": 129, - "w": 57, - "h": 45 - } - }, - { - "filename": "0093.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 57, - "h": 45 - }, - "frame": { - "x": 57, - "y": 132, - "w": 57, - "h": 45 - } - }, - { - "filename": "0094.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 57, - "h": 45 - }, - "frame": { - "x": 57, - "y": 132, - "w": 57, - "h": 45 - } - }, - { - "filename": "0095.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 56, - "h": 45 - }, - "frame": { - "x": 114, - "y": 132, - "w": 56, - "h": 45 - } - }, - { - "filename": "0096.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 56, - "h": 45 - }, - "frame": { - "x": 114, - "y": 132, - "w": 56, - "h": 45 - } - }, - { - "filename": "0097.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 54, - "h": 45 - }, - "frame": { - "x": 170, - "y": 132, - "w": 54, - "h": 45 - } - }, - { - "filename": "0098.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 1, - "y": 1, - "w": 54, - "h": 45 - }, - "frame": { - "x": 170, - "y": 132, - "w": 54, - "h": 45 - } - }, - { - "filename": "0099.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 54, - "h": 45 - }, - "frame": { - "x": 224, - "y": 132, - "w": 54, - "h": 45 - } - }, - { - "filename": "0100.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 0, - "y": 1, - "w": 54, - "h": 45 - }, - "frame": { - "x": 224, - "y": 132, - "w": 54, - "h": 45 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 174, - "w": 54, - "h": 46 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 174, - "w": 54, - "h": 46 - } - }, - { - "filename": "0021.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 174, - "w": 54, - "h": 46 - } - }, - { - "filename": "0022.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 174, - "w": 54, - "h": 46 - } - }, - { - "filename": "0023.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 174, - "w": 54, - "h": 46 - } - }, - { - "filename": "0024.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 174, - "w": 54, - "h": 46 - } - }, - { - "filename": "0045.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 174, - "w": 54, - "h": 46 - } - }, - { - "filename": "0046.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 174, - "w": 54, - "h": 46 - } - }, - { - "filename": "0065.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 174, - "w": 54, - "h": 46 - } - }, - { - "filename": "0066.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 174, - "w": 54, - "h": 46 - } - }, - { - "filename": "0067.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 174, - "w": 54, - "h": 46 - } - }, - { - "filename": "0068.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 174, - "w": 54, - "h": 46 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 54, - "y": 177, - "w": 57, - "h": 46 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 54, - "y": 177, - "w": 57, - "h": 46 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 54, - "y": 177, - "w": 57, - "h": 46 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 54, - "y": 177, - "w": 57, - "h": 46 - } - }, - { - "filename": "0047.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 54, - "y": 177, - "w": 57, - "h": 46 - } - }, - { - "filename": "0048.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 54, - "y": 177, - "w": 57, - "h": 46 - } - }, - { - "filename": "0063.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 54, - "y": 177, - "w": 57, - "h": 46 - } - }, - { - "filename": "0064.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 54, - "y": 177, - "w": 57, - "h": 46 - } - }, - { - "filename": "0025.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 111, - "y": 177, - "w": 57, - "h": 46 - } - }, - { - "filename": "0026.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 111, - "y": 177, - "w": 57, - "h": 46 - } - }, - { - "filename": "0069.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 111, - "y": 177, - "w": 57, - "h": 46 - } - }, - { - "filename": "0070.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 111, - "y": 177, - "w": 57, - "h": 46 - } - }, - { - "filename": "0041.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 60, - "h": 46 - }, - "frame": { - "x": 168, - "y": 177, - "w": 60, - "h": 46 - } - }, - { - "filename": "0042.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 60, - "h": 46 - }, - "frame": { - "x": 168, - "y": 177, - "w": 60, - "h": 46 - } - }, - { - "filename": "0085.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 60, - "h": 46 - }, - "frame": { - "x": 168, - "y": 177, - "w": 60, - "h": 46 - } - }, - { - "filename": "0086.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 60, - "h": 46 - }, - "frame": { - "x": 168, - "y": 177, - "w": 60, - "h": 46 - } - }, - { - "filename": "0109.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 53, - "h": 46 - }, - "frame": { - "x": 228, - "y": 177, - "w": 53, - "h": 46 - } - }, - { - "filename": "0110.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 6, - "y": 0, - "w": 53, - "h": 46 - }, - "frame": { - "x": 228, - "y": 177, - "w": 53, - "h": 46 - } - }, - { - "filename": "0101.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 220, - "w": 54, - "h": 46 - } - }, - { - "filename": "0102.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 1, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 0, - "y": 220, - "w": 54, - "h": 46 - } - }, - { - "filename": "0043.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 54, - "y": 223, - "w": 57, - "h": 46 - } - }, - { - "filename": "0044.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 54, - "y": 223, - "w": 57, - "h": 46 - } - }, - { - "filename": "0087.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 54, - "y": 223, - "w": 57, - "h": 46 - } - }, - { - "filename": "0088.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 57, - "h": 46 - }, - "frame": { - "x": 54, - "y": 223, - "w": 57, - "h": 46 - } - }, - { - "filename": "0103.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 55, - "h": 46 - }, - "frame": { - "x": 111, - "y": 223, - "w": 55, - "h": 46 - } - }, - { - "filename": "0104.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 55, - "h": 46 - }, - "frame": { - "x": 111, - "y": 223, - "w": 55, - "h": 46 - } - }, - { - "filename": "0105.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 55, - "h": 46 - }, - "frame": { - "x": 166, - "y": 223, - "w": 55, - "h": 46 - } - }, - { - "filename": "0106.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 3, - "y": 0, - "w": 55, - "h": 46 - }, - "frame": { - "x": 166, - "y": 223, - "w": 55, - "h": 46 - } - }, - { - "filename": "0107.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 221, - "y": 223, - "w": 54, - "h": 46 - } - }, - { - "filename": "0108.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 71, - "h": 46 - }, - "spriteSourceSize": { - "x": 5, - "y": 0, - "w": 54, - "h": 46 - }, - "frame": { - "x": 221, - "y": 223, - "w": 54, - "h": 46 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:9097bf5ffed4b93401c65aa14299faaa:d22b7c7f6e33b1453fda428e689d4529:c79e17c206de27e3b7f1ce96f7df8e51$" - } +{ "frames": [ + { + "filename": "0055.png", + "frame": { "x": 0, "y": 0, "w": 68, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 6, "w": 68, "h": 40 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0001.png", + "frame": { "x": 287, "y": 86, "w": 52, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 0, "w": 52, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0002.png", + "frame": { "x": 287, "y": 86, "w": 52, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 0, "w": 52, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0003.png", + "frame": { "x": 57, "y": 86, "w": 55, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 55, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0004.png", + "frame": { "x": 57, "y": 86, "w": 55, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 55, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0005.png", + "frame": { "x": 0, "y": 85, "w": 57, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 57, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0006.png", + "frame": { "x": 0, "y": 85, "w": 57, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 57, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0007.png", + "frame": { "x": 238, "y": 43, "w": 59, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 59, "h": 43 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0008.png", + "frame": { "x": 238, "y": 43, "w": 59, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 59, "h": 43 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0009.png", + "frame": { "x": 177, "y": 42, "w": 61, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 61, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0010.png", + "frame": { "x": 177, "y": 42, "w": 61, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 61, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0011.png", + "frame": { "x": 68, "y": 0, "w": 64, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 4, "w": 64, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0012.png", + "frame": { "x": 68, "y": 0, "w": 64, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 4, "w": 64, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0013.png", + "frame": { "x": 177, "y": 42, "w": 61, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 61, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0014.png", + "frame": { "x": 177, "y": 42, "w": 61, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 61, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0015.png", + "frame": { "x": 238, "y": 43, "w": 59, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 59, "h": 43 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0016.png", + "frame": { "x": 238, "y": 43, "w": 59, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 59, "h": 43 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0017.png", + "frame": { "x": 0, "y": 85, "w": 57, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 57, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0018.png", + "frame": { "x": 0, "y": 85, "w": 57, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 57, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0019.png", + "frame": { "x": 57, "y": 86, "w": 55, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 55, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0020.png", + "frame": { "x": 57, "y": 86, "w": 55, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 55, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0021.png", + "frame": { "x": 287, "y": 86, "w": 52, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 0, "w": 52, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0022.png", + "frame": { "x": 287, "y": 86, "w": 52, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 0, "w": 52, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0023.png", + "frame": { "x": 287, "y": 86, "w": 52, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 0, "w": 52, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0024.png", + "frame": { "x": 287, "y": 86, "w": 52, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 0, "w": 52, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0025.png", + "frame": { "x": 57, "y": 86, "w": 55, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 55, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0026.png", + "frame": { "x": 57, "y": 86, "w": 55, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 55, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0027.png", + "frame": { "x": 0, "y": 85, "w": 57, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 57, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0028.png", + "frame": { "x": 0, "y": 85, "w": 57, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 57, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0029.png", + "frame": { "x": 238, "y": 43, "w": 59, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 59, "h": 43 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0030.png", + "frame": { "x": 238, "y": 43, "w": 59, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 59, "h": 43 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0031.png", + "frame": { "x": 177, "y": 42, "w": 61, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 61, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0032.png", + "frame": { "x": 177, "y": 42, "w": 61, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 61, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0033.png", + "frame": { "x": 68, "y": 0, "w": 64, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 4, "w": 64, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0034.png", + "frame": { "x": 68, "y": 0, "w": 64, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 4, "w": 64, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0035.png", + "frame": { "x": 177, "y": 42, "w": 61, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 61, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0036.png", + "frame": { "x": 177, "y": 42, "w": 61, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 61, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0037.png", + "frame": { "x": 238, "y": 43, "w": 59, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 59, "h": 43 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0038.png", + "frame": { "x": 238, "y": 43, "w": 59, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 59, "h": 43 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0039.png", + "frame": { "x": 0, "y": 85, "w": 57, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 57, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0040.png", + "frame": { "x": 0, "y": 85, "w": 57, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 57, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0041.png", + "frame": { "x": 57, "y": 86, "w": 55, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 55, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0042.png", + "frame": { "x": 57, "y": 86, "w": 55, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 55, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0043.png", + "frame": { "x": 287, "y": 86, "w": 52, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 0, "w": 52, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0044.png", + "frame": { "x": 287, "y": 86, "w": 52, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 0, "w": 52, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0045.png", + "frame": { "x": 287, "y": 86, "w": 52, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 0, "w": 52, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0046.png", + "frame": { "x": 287, "y": 86, "w": 52, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 0, "w": 52, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0047.png", + "frame": { "x": 232, "y": 86, "w": 55, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 55, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0048.png", + "frame": { "x": 232, "y": 86, "w": 55, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 1, "w": 55, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0049.png", + "frame": { "x": 117, "y": 85, "w": 57, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 57, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0050.png", + "frame": { "x": 117, "y": 85, "w": 57, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 2, "w": 57, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0051.png", + "frame": { "x": 117, "y": 42, "w": 60, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 60, "h": 43 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0052.png", + "frame": { "x": 117, "y": 42, "w": 60, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 5, "y": 3, "w": 60, "h": 43 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0053.png", + "frame": { "x": 132, "y": 0, "w": 63, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 63, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0054.png", + "frame": { "x": 132, "y": 0, "w": 63, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 63, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0056.png", + "frame": { "x": 0, "y": 0, "w": 68, "h": 40 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 6, "w": 68, "h": 40 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0057.png", + "frame": { "x": 195, "y": 0, "w": 63, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 63, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0058.png", + "frame": { "x": 195, "y": 0, "w": 63, "h": 42 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 4, "w": 63, "h": 42 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0059.png", + "frame": { "x": 258, "y": 0, "w": 61, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 3, "w": 61, "h": 43 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0060.png", + "frame": { "x": 258, "y": 0, "w": 61, "h": 43 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 3, "w": 61, "h": 43 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0061.png", + "frame": { "x": 58, "y": 42, "w": 59, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 59, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0062.png", + "frame": { "x": 58, "y": 42, "w": 59, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 2, "w": 59, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0063.png", + "frame": { "x": 0, "y": 40, "w": 58, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 1, "w": 58, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0064.png", + "frame": { "x": 0, "y": 40, "w": 58, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 1, "w": 58, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0065.png", + "frame": { "x": 177, "y": 84, "w": 55, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 0, "w": 55, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0066.png", + "frame": { "x": 177, "y": 84, "w": 55, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 0, "w": 55, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0067.png", + "frame": { "x": 0, "y": 129, "w": 55, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 55, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0068.png", + "frame": { "x": 0, "y": 129, "w": 55, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 55, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0069.png", + "frame": { "x": 112, "y": 129, "w": 55, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 55, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0070.png", + "frame": { "x": 112, "y": 129, "w": 55, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 2, "w": 55, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0071.png", + "frame": { "x": 167, "y": 130, "w": 55, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 2, "w": 55, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0072.png", + "frame": { "x": 167, "y": 130, "w": 55, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 2, "w": 55, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0073.png", + "frame": { "x": 0, "y": 173, "w": 54, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 2, "w": 54, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0074.png", + "frame": { "x": 0, "y": 173, "w": 54, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 2, "w": 54, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0075.png", + "frame": { "x": 54, "y": 177, "w": 52, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 2, "w": 52, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0076.png", + "frame": { "x": 54, "y": 177, "w": 52, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 2, "w": 52, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0077.png", + "frame": { "x": 210, "y": 176, "w": 53, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 53, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0078.png", + "frame": { "x": 210, "y": 176, "w": 53, "h": 44 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 0, "y": 2, "w": 53, "h": 44 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0079.png", + "frame": { "x": 158, "y": 174, "w": 52, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 52, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0080.png", + "frame": { "x": 158, "y": 174, "w": 52, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 1, "w": 52, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0081.png", + "frame": { "x": 222, "y": 131, "w": 53, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 1, "w": 53, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0082.png", + "frame": { "x": 222, "y": 131, "w": 53, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 1, "w": 53, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0083.png", + "frame": { "x": 275, "y": 132, "w": 53, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 1, "w": 53, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0084.png", + "frame": { "x": 275, "y": 132, "w": 53, "h": 45 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 1, "w": 53, "h": 45 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0085.png", + "frame": { "x": 55, "y": 131, "w": 52, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 0, "w": 52, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0086.png", + "frame": { "x": 55, "y": 131, "w": 52, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 0, "w": 52, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0087.png", + "frame": { "x": 107, "y": 173, "w": 51, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 0, "w": 51, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + }, + { + "filename": "0088.png", + "frame": { "x": 107, "y": 173, "w": 51, "h": 46 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 7, "y": 0, "w": 51, "h": 46 }, + "sourceSize": { "w": 71, "h": 46 } + } + ], + "meta": { + "app": "https://www.aseprite.org/", + "version": "1.3.8.1-x64", + "image": "451.png", + "format": "I8", + "size": { "w": 339, "h": 221 }, + "scale": "1" + } } diff --git a/public/images/pokemon/shiny/451.png b/public/images/pokemon/shiny/451.png index 69d165c9ae8..4f8120ce668 100644 Binary files a/public/images/pokemon/shiny/451.png and b/public/images/pokemon/shiny/451.png differ diff --git a/public/images/pokemon/shiny/47.json b/public/images/pokemon/shiny/47.json index 185bcf4b527..0aa03eab585 100644 --- a/public/images/pokemon/shiny/47.json +++ b/public/images/pokemon/shiny/47.json @@ -1,776 +1,299 @@ -{ - "textures": [ - { - "image": "47.png", - "format": "RGBA8888", - "size": { - "w": 230, - "h": 230 - }, - "scale": 1, - "frames": [ - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 6, - "y": 12, - "w": 56, - "h": 49 - }, - "frame": { - "x": 0, - "y": 0, - "w": 56, - "h": 49 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 6, - "y": 12, - "w": 56, - "h": 49 - }, - "frame": { - "x": 0, - "y": 0, - "w": 56, - "h": 49 - } - }, - { - "filename": "0027.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 12, - "w": 62, - "h": 51 - }, - "frame": { - "x": 56, - "y": 0, - "w": 62, - "h": 51 - } - }, - { - "filename": "0028.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 12, - "w": 62, - "h": 51 - }, - "frame": { - "x": 56, - "y": 0, - "w": 62, - "h": 51 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 7, - "y": 8, - "w": 55, - "h": 53 - }, - "frame": { - "x": 118, - "y": 0, - "w": 55, - "h": 53 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 7, - "y": 8, - "w": 55, - "h": 53 - }, - "frame": { - "x": 118, - "y": 0, - "w": 55, - "h": 53 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 7, - "y": 7, - "w": 55, - "h": 54 - }, - "frame": { - "x": 173, - "y": 0, - "w": 55, - "h": 54 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 7, - "y": 7, - "w": 55, - "h": 54 - }, - "frame": { - "x": 173, - "y": 0, - "w": 55, - "h": 54 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 8, - "y": 5, - "w": 53, - "h": 56 - }, - "frame": { - "x": 0, - "y": 49, - "w": 53, - "h": 56 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 8, - "y": 5, - "w": 53, - "h": 56 - }, - "frame": { - "x": 0, - "y": 49, - "w": 53, - "h": 56 - } - }, - { - "filename": "0025.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 8, - "w": 62, - "h": 55 - }, - "frame": { - "x": 53, - "y": 51, - "w": 62, - "h": 55 - } - }, - { - "filename": "0026.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 8, - "w": 62, - "h": 55 - }, - "frame": { - "x": 53, - "y": 51, - "w": 62, - "h": 55 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 53, - "h": 57 - }, - "frame": { - "x": 115, - "y": 53, - "w": 53, - "h": 57 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 8, - "y": 4, - "w": 53, - "h": 57 - }, - "frame": { - "x": 115, - "y": 53, - "w": 53, - "h": 57 - } - }, - { - "filename": "0029.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 7, - "w": 62, - "h": 56 - }, - "frame": { - "x": 168, - "y": 54, - "w": 62, - "h": 56 - } - }, - { - "filename": "0030.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 7, - "w": 62, - "h": 56 - }, - "frame": { - "x": 168, - "y": 54, - "w": 62, - "h": 56 - } - }, - { - "filename": "0023.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 5, - "w": 61, - "h": 58 - }, - "frame": { - "x": 0, - "y": 106, - "w": 61, - "h": 58 - } - }, - { - "filename": "0024.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 5, - "w": 61, - "h": 58 - }, - "frame": { - "x": 0, - "y": 106, - "w": 61, - "h": 58 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 6, - "y": 2, - "w": 54, - "h": 59 - }, - "frame": { - "x": 61, - "y": 106, - "w": 54, - "h": 59 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 6, - "y": 2, - "w": 54, - "h": 59 - }, - "frame": { - "x": 61, - "y": 106, - "w": 54, - "h": 59 - } - }, - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 57, - "h": 59 - }, - "frame": { - "x": 115, - "y": 110, - "w": 57, - "h": 59 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 57, - "h": 59 - }, - "frame": { - "x": 115, - "y": 110, - "w": 57, - "h": 59 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 57, - "h": 59 - }, - "frame": { - "x": 115, - "y": 110, - "w": 57, - "h": 59 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 2, - "y": 2, - "w": 57, - "h": 59 - }, - "frame": { - "x": 115, - "y": 110, - "w": 57, - "h": 59 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 6, - "y": 2, - "w": 54, - "h": 59 - }, - "frame": { - "x": 172, - "y": 110, - "w": 54, - "h": 59 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 6, - "y": 2, - "w": 54, - "h": 59 - }, - "frame": { - "x": 172, - "y": 110, - "w": 54, - "h": 59 - } - }, - { - "filename": "0031.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 61, - "h": 59 - }, - "frame": { - "x": 0, - "y": 164, - "w": 61, - "h": 59 - } - }, - { - "filename": "0032.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 4, - "w": 61, - "h": 59 - }, - "frame": { - "x": 0, - "y": 164, - "w": 61, - "h": 59 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 57, - "h": 61 - }, - "frame": { - "x": 61, - "y": 169, - "w": 57, - "h": 61 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 57, - "h": 61 - }, - "frame": { - "x": 61, - "y": 169, - "w": 57, - "h": 61 - } - }, - { - "filename": "0035.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 57, - "h": 61 - }, - "frame": { - "x": 61, - "y": 169, - "w": 57, - "h": 61 - } - }, - { - "filename": "0036.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 2, - "y": 0, - "w": 57, - "h": 61 - }, - "frame": { - "x": 61, - "y": 169, - "w": 57, - "h": 61 - } - }, - { - "filename": "0021.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 60, - "h": 61 - }, - "frame": { - "x": 118, - "y": 169, - "w": 60, - "h": 61 - } - }, - { - "filename": "0022.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 60, - "h": 61 - }, - "frame": { - "x": 118, - "y": 169, - "w": 60, - "h": 61 - } - }, - { - "filename": "0033.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 60, - "h": 61 - }, - "frame": { - "x": 118, - "y": 169, - "w": 60, - "h": 61 - } - }, - { - "filename": "0034.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 62, - "h": 63 - }, - "spriteSourceSize": { - "x": 0, - "y": 2, - "w": 60, - "h": 61 - }, - "frame": { - "x": 118, - "y": 169, - "w": 60, - "h": 61 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:38ba9918eb8f68ab2190b03c6512ef47:46578d6dd482a1b04fa7c2884107a0f5:fe45e2d628a6cef0908f7b82468c8798$" - } -} \ No newline at end of file +{ "frames": [ + { + "filename": "0001.png", + "frame": { "x": 0, "y": 58, "w": 55, "h": 57 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 5, "w": 55, "h": 57 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0002.png", + "frame": { "x": 0, "y": 58, "w": 55, "h": 57 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 5, "w": 55, "h": 57 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0003.png", + "frame": { "x": 166, "y": 114, "w": 52, "h": 56 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 5, "w": 52, "h": 56 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0004.png", + "frame": { "x": 166, "y": 114, "w": 52, "h": 56 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 5, "w": 52, "h": 56 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0005.png", + "frame": { "x": 0, "y": 169, "w": 51, "h": 54 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 11, "y": 7, "w": 51, "h": 54 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0006.png", + "frame": { "x": 0, "y": 169, "w": 51, "h": 54 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 11, "y": 7, "w": 51, "h": 54 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0007.png", + "frame": { "x": 104, "y": 166, "w": 53, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 9, "w": 53, "h": 52 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0008.png", + "frame": { "x": 104, "y": 166, "w": 53, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 9, "w": 53, "h": 52 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0009.png", + "frame": { "x": 157, "y": 170, "w": 55, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 12, "w": 55, "h": 49 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0010.png", + "frame": { "x": 157, "y": 170, "w": 55, "h": 49 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 12, "w": 55, "h": 49 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0011.png", + "frame": { "x": 0, "y": 115, "w": 53, "h": 54 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 8, "w": 53, "h": 54 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0012.png", + "frame": { "x": 0, "y": 115, "w": 53, "h": 54 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 10, "y": 8, "w": 53, "h": 54 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0013.png", + "frame": { "x": 53, "y": 116, "w": 51, "h": 56 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 11, "y": 6, "w": 51, "h": 56 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0014.png", + "frame": { "x": 53, "y": 116, "w": 51, "h": 56 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 11, "y": 6, "w": 51, "h": 56 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0015.png", + "frame": { "x": 114, "y": 109, "w": 52, "h": 57 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 5, "w": 52, "h": 57 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0016.png", + "frame": { "x": 114, "y": 109, "w": 52, "h": 57 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 9, "y": 5, "w": 52, "h": 57 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0017.png", + "frame": { "x": 59, "y": 57, "w": 55, "h": 59 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 55, "h": 59 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0018.png", + "frame": { "x": 59, "y": 57, "w": 55, "h": 59 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 55, "h": 59 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0019.png", + "frame": { "x": 0, "y": 58, "w": 55, "h": 57 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 5, "w": 55, "h": 57 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0020.png", + "frame": { "x": 0, "y": 58, "w": 55, "h": 57 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 5, "w": 55, "h": 57 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0021.png", + "frame": { "x": 178, "y": 56, "w": 57, "h": 58 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 5, "w": 57, "h": 58 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0022.png", + "frame": { "x": 178, "y": 56, "w": 57, "h": 58 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 5, "w": 57, "h": 58 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0023.png", + "frame": { "x": 119, "y": 0, "w": 59, "h": 57 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 7, "w": 59, "h": 57 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0024.png", + "frame": { "x": 119, "y": 0, "w": 59, "h": 57 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 7, "w": 59, "h": 57 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0025.png", + "frame": { "x": 178, "y": 0, "w": 60, "h": 56 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 9, "w": 60, "h": 56 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0026.png", + "frame": { "x": 178, "y": 0, "w": 60, "h": 56 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 9, "w": 60, "h": 56 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0027.png", + "frame": { "x": 114, "y": 57, "w": 62, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 12, "w": 62, "h": 52 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0028.png", + "frame": { "x": 114, "y": 57, "w": 62, "h": 52 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 2, "y": 12, "w": 62, "h": 52 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0029.png", + "frame": { "x": 59, "y": 0, "w": 60, "h": 57 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 8, "w": 60, "h": 57 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0030.png", + "frame": { "x": 59, "y": 0, "w": 60, "h": 57 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 8, "w": 60, "h": 57 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0031.png", + "frame": { "x": 0, "y": 0, "w": 59, "h": 58 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 6, "w": 59, "h": 58 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0032.png", + "frame": { "x": 0, "y": 0, "w": 59, "h": 58 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 3, "y": 6, "w": 59, "h": 58 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0033.png", + "frame": { "x": 178, "y": 56, "w": 57, "h": 58 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 5, "w": 57, "h": 58 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0034.png", + "frame": { "x": 178, "y": 56, "w": 57, "h": 58 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 4, "y": 5, "w": 57, "h": 58 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0035.png", + "frame": { "x": 59, "y": 57, "w": 55, "h": 59 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 55, "h": 59 }, + "sourceSize": { "w": 65, "h": 65 } + }, + { + "filename": "0036.png", + "frame": { "x": 59, "y": 57, "w": 55, "h": 59 }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { "x": 6, "y": 3, "w": 55, "h": 59 }, + "sourceSize": { "w": 65, "h": 65 } + } + ], + "meta": { + "app": "https://www.aseprite.org/", + "version": "1.3.8.1-x64", + "image": "47.png", + "format": "I8", + "size": { "w": 238, "h": 223 }, + "scale": "1" + } +} diff --git a/public/images/pokemon/shiny/47.png b/public/images/pokemon/shiny/47.png index ba5f60d1b8f..b1b0bb9a12a 100644 Binary files a/public/images/pokemon/shiny/47.png and b/public/images/pokemon/shiny/47.png differ diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 2f062667808..62e9d8ea717 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -3008,7 +3008,8 @@ export default class BattleScene extends SceneBase { } validateAchv(achv: Achv, args?: unknown[]): boolean { - if (!this.gameData.achvUnlocks.hasOwnProperty(achv.id) && achv.validate(this, args)) { + if ((!this.gameData.achvUnlocks.hasOwnProperty(achv.id) || Overrides.ACHIEVEMENTS_REUNLOCK_OVERRIDE) + && achv.validate(this, args)) { this.gameData.achvUnlocks[achv.id] = new Date().getTime(); this.ui.achvBar.showAchv(achv); if (vouchers.hasOwnProperty(achv.id)) { diff --git a/src/data/ability.ts b/src/data/ability.ts index 3103c08cee6..8ff4cfea59b 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -4112,9 +4112,13 @@ export class PostBattleAbAttr extends AbAttr { } export class PostBattleLootAbAttr extends PostBattleAbAttr { + /** + * @param args - `[0]`: boolean for if the battle ended in a victory + * @returns `true` if successful + */ applyPostBattle(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { const postBattleLoot = pokemon.scene.currentBattle.postBattleLoot; - if (!simulated && postBattleLoot.length) { + if (!simulated && postBattleLoot.length && args[0]) { const randItem = Utils.randSeedItem(postBattleLoot); //@ts-ignore - TODO see below if (pokemon.scene.tryTransferHeldItemModifier(randItem, pokemon, true, 1, true, undefined, false)) { // TODO: fix. This is a promise!? @@ -4575,14 +4579,15 @@ export class MoneyAbAttr extends PostBattleAbAttr { /** * @param pokemon {@linkcode Pokemon} that is the user of this ability. * @param passive N/A - * @param args N/A - * @returns true + * @param args - `[0]`: boolean for if the battle ended in a victory + * @returns `true` if successful */ applyPostBattle(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { - if (!simulated) { + if (!simulated && args[0]) { pokemon.scene.currentBattle.moneyScattered += pokemon.scene.getWaveMoneyAmount(0.2); + return true; } - return true; + return false; } } @@ -4590,13 +4595,12 @@ export class MoneyAbAttr extends PostBattleAbAttr { * Applies a stat change after a Pokémon is summoned, * conditioned on the presence of a specific arena tag. * - * @extends {PostSummonStatStageChangeAbAttr} + * @extends PostSummonStatStageChangeAbAttr */ export class PostSummonStatStageChangeOnArenaAbAttr extends PostSummonStatStageChangeAbAttr { /** * The type of arena tag that conditions the stat change. * @private - * @type {ArenaTagType} */ private tagType: ArenaTagType; @@ -4972,7 +4976,7 @@ class ForceSwitchOutHelper { pokemon.scene.clearEnemyHeldItemModifiers(); if (switchOutTarget.hp) { - pokemon.scene.pushPhase(new BattleEndPhase(pokemon.scene)); + pokemon.scene.pushPhase(new BattleEndPhase(pokemon.scene, false)); pokemon.scene.pushPhase(new NewBattlePhase(pokemon.scene)); } } @@ -5779,9 +5783,10 @@ export function initAbilities() { .attr(WonderSkinAbAttr) .ignorable(), new Ability(Abilities.ANALYTIC, 5) - .attr(MovePowerBoostAbAttr, (user, target, move) => - !!target?.getLastXMoves(1).find(m => m.turn === target?.scene.currentBattle.turn) - || user?.scene.currentBattle.turnCommands[target?.getBattlerIndex() ?? BattlerIndex.ATTACKER]?.command !== Command.FIGHT, 1.3), + .attr(MovePowerBoostAbAttr, (user, target, move) => { + const movePhase = user?.scene.findPhase((phase) => phase instanceof MovePhase && phase.pokemon.id !== user.id); + return Utils.isNullOrUndefined(movePhase); + }, 1.3), new Ability(Abilities.ILLUSION, 5) .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) @@ -5929,10 +5934,10 @@ export function initAbilities() { .attr(PostDefendStatStageChangeAbAttr, (target, user, move) => move.category !== MoveCategory.STATUS, Stat.DEF, 1), new Ability(Abilities.WIMP_OUT, 7) .attr(PostDamageForceSwitchAbAttr) - .edgeCase(), // Should not trigger when hurting itself in confusion + .edgeCase(), // Should not trigger when hurting itself in confusion, causes Fake Out to fail turn 1 and succeed turn 2 if pokemon is switched out before battle start via playing in Switch Mode new Ability(Abilities.EMERGENCY_EXIT, 7) .attr(PostDamageForceSwitchAbAttr) - .edgeCase(), // Should not trigger when hurting itself in confusion + .edgeCase(), // Should not trigger when hurting itself in confusion, causes Fake Out to fail turn 1 and succeed turn 2 if pokemon is switched out before battle start via playing in Switch Mode new Ability(Abilities.WATER_COMPACTION, 7) .attr(PostDefendStatStageChangeAbAttr, (target, user, move) => user.getMoveType(move) === Type.WATER && move.category !== MoveCategory.STATUS, Stat.DEF, 2), new Ability(Abilities.MERCILESS, 7) @@ -6340,8 +6345,7 @@ export function initAbilities() { .attr(IgnoreOpponentStatStagesAbAttr, [ Stat.EVA ]) .ignorable(), new Ability(Abilities.SUPERSWEET_SYRUP, 9) - .attr(PostSummonStatStageChangeAbAttr, [ Stat.EVA ], -1) - .condition(getOncePerBattleCondition(Abilities.SUPERSWEET_SYRUP)), + .attr(PostSummonStatStageChangeAbAttr, [ Stat.EVA ], -1), new Ability(Abilities.HOSPITALITY, 9) .attr(PostSummonAllyHealAbAttr, 4, true), new Ability(Abilities.TOXIC_CHAIN, 9) diff --git a/src/data/balance/special-species-groups.ts b/src/data/balance/special-species-groups.ts new file mode 100644 index 00000000000..eeba96595a6 --- /dev/null +++ b/src/data/balance/special-species-groups.ts @@ -0,0 +1,46 @@ +import { Species } from "#enums/species"; + +/** + * A list of all {@link https://bulbapedia.bulbagarden.net/wiki/Paradox_Pok%C3%A9mon | Paradox Pokemon}, NOT including the legendaries Miraidon and Koraidon. + */ +export const NON_LEGEND_PARADOX_POKEMON = [ + Species.GREAT_TUSK, + Species.SCREAM_TAIL, + Species.BRUTE_BONNET, + Species.FLUTTER_MANE, + Species.SLITHER_WING, + Species.SANDY_SHOCKS, + Species.ROARING_MOON, + Species.WALKING_WAKE, + Species.GOUGING_FIRE, + Species.RAGING_BOLT, + Species.IRON_TREADS, + Species.IRON_BUNDLE, + Species.IRON_HANDS, + Species.IRON_JUGULIS, + Species.IRON_MOTH, + Species.IRON_THORNS, + Species.IRON_VALIANT, + Species.IRON_LEAVES, + Species.IRON_BOULDER, + Species.IRON_CROWN, +]; + +/** + * A list of all {@link https://bulbapedia.bulbagarden.net/wiki/Ultra_Beast | Ultra Beasts}, NOT including legendaries such as Necrozma or the Cosmog line. + * + * Note that all of these Ultra Beasts are still considered Sub-Legendary. + */ +export const NON_LEGEND_ULTRA_BEASTS = [ + Species.NIHILEGO, + Species.BUZZWOLE, + Species.PHEROMOSA, + Species.XURKITREE, + Species.CELESTEELA, + Species.KARTANA, + Species.GUZZLORD, + Species.POIPOLE, + Species.NAGANADEL, + Species.STAKATAKA, + Species.BLACEPHALON, +]; diff --git a/src/data/move.ts b/src/data/move.ts index 2ac4d74b712..64f8e43cb7b 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -1385,14 +1385,38 @@ export class UserHpDamageAttr extends FixedDamageAttr { } export class TargetHalfHpDamageAttr extends FixedDamageAttr { + // the initial amount of hp the target had before the first hit + // used for multi lens + private initialHp: number; constructor() { super(0); } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - (args[0] as Utils.IntegerHolder).value = Utils.toDmgValue(target.hp / 2); + // first, determine if the hit is coming from multi lens or not + const lensCount = user.getHeldItems().find(i => i instanceof PokemonMultiHitModifier)?.getStackCount() ?? 0; + if (lensCount <= 0) { + // no multi lenses; we can just halve the target's hp and call it a day + (args[0] as Utils.NumberHolder).value = Utils.toDmgValue(target.hp / 2); + return true; + } - return true; + // figure out what hit # we're on + switch (user.turnData.hitCount - user.turnData.hitsLeft) { + case 0: + // first hit of move; update initialHp tracker + this.initialHp = target.hp; + default: + // multi lens added hit; use initialHp tracker to ensure correct damage + (args[0] as Utils.NumberHolder).value = Utils.toDmgValue(this.initialHp / 2); + return true; + break; + case lensCount + 1: + // parental bond added hit; calc damage as normal + (args[0] as Utils.NumberHolder).value = Utils.toDmgValue(target.hp / 2); + return true; + break; + } } getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number { @@ -5967,50 +5991,113 @@ export class ForceSwitchOutAttr extends MoveEffectAttr { * Check if Wimp Out/Emergency Exit activates due to being hit by U-turn or Volt Switch * If it did, the user of U-turn or Volt Switch will not be switched out. */ - if (target.getAbility().hasAttr(PostDamageForceSwitchAbAttr) && - (move.id === Moves.U_TURN || move.id === Moves.VOLT_SWITCH || move.id === Moves.FLIP_TURN) + if (target.getAbility().hasAttr(PostDamageForceSwitchAbAttr) + && [ Moves.U_TURN, Moves.VOLT_SWITCH, Moves.FLIP_TURN ].includes(move.id) ) { if (this.hpDroppedBelowHalf(target)) { return false; } } - // Switch out logic for the player's Pokemon - if (switchOutTarget.scene.getPlayerParty().filter((p) => p.isAllowedInBattle() && !p.isOnField()).length < 1) { + + // Find indices of off-field Pokemon that are eligible to be switched into + const eligibleNewIndices: number[] = []; + switchOutTarget.scene.getPlayerParty().forEach((pokemon, index) => { + if (pokemon.isAllowedInBattle() && !pokemon.isOnField()) { + eligibleNewIndices.push(index); + } + }); + + if (eligibleNewIndices.length < 1) { return false; } if (switchOutTarget.hp > 0) { - switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH); - user.scene.prependToPhase(new SwitchPhase(user.scene, this.switchType, switchOutTarget.getFieldIndex(), true, true), MoveEndPhase); - return true; + if (this.switchType === SwitchType.FORCE_SWITCH) { + switchOutTarget.leaveField(true); + const slotIndex = eligibleNewIndices[user.randSeedInt(eligibleNewIndices.length)]; + user.scene.prependToPhase( + new SwitchSummonPhase( + user.scene, + this.switchType, + switchOutTarget.getFieldIndex(), + slotIndex, + false, + true + ), + MoveEndPhase + ); + } else { + switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH); + user.scene.prependToPhase( + new SwitchPhase( + user.scene, + this.switchType, + switchOutTarget.getFieldIndex(), + true, + true + ), + MoveEndPhase + ); + return true; + } } return false; - } else if (user.scene.currentBattle.battleType !== BattleType.WILD) { - // Switch out logic for trainer battles - if (switchOutTarget.scene.getEnemyParty().filter((p) => p.isAllowedInBattle() && !p.isOnField()).length < 1) { + } else if (user.scene.currentBattle.battleType !== BattleType.WILD) { // Switch out logic for enemy trainers + // Find indices of off-field Pokemon that are eligible to be switched into + const eligibleNewIndices: number[] = []; + switchOutTarget.scene.getEnemyParty().forEach((pokemon, index) => { + if (pokemon.isAllowedInBattle() && !pokemon.isOnField()) { + eligibleNewIndices.push(index); + } + }); + + if (eligibleNewIndices.length < 1) { return false; } if (switchOutTarget.hp > 0) { - // for opponent switching out - switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH); - user.scene.prependToPhase(new SwitchSummonPhase(user.scene, this.switchType, switchOutTarget.getFieldIndex(), - (user.scene.currentBattle.trainer ? user.scene.currentBattle.trainer.getNextSummonIndex((switchOutTarget as EnemyPokemon).trainerSlot) : 0), - false, false), MoveEndPhase); + if (this.switchType === SwitchType.FORCE_SWITCH) { + switchOutTarget.leaveField(true); + const slotIndex = eligibleNewIndices[user.randSeedInt(eligibleNewIndices.length)]; + user.scene.prependToPhase( + new SwitchSummonPhase( + user.scene, + this.switchType, + switchOutTarget.getFieldIndex(), + slotIndex, + false, + false + ), + MoveEndPhase + ); + } else { + switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH); + user.scene.prependToPhase( + new SwitchSummonPhase( + user.scene, + this.switchType, + switchOutTarget.getFieldIndex(), + (user.scene.currentBattle.trainer ? user.scene.currentBattle.trainer.getNextSummonIndex((switchOutTarget as EnemyPokemon).trainerSlot) : 0), + false, + false + ), + MoveEndPhase + ); + } } - } else { + } else { // Switch out logic for wild pokemon /** * Check if Wimp Out/Emergency Exit activates due to being hit by U-turn or Volt Switch * If it did, the user of U-turn or Volt Switch will not be switched out. */ - if (target.getAbility().hasAttr(PostDamageForceSwitchAbAttr) && - (move.id === Moves.U_TURN || move.id === Moves.VOLT_SWITCH) || move.id === Moves.FLIP_TURN) { + if (target.getAbility().hasAttr(PostDamageForceSwitchAbAttr) + && [ Moves.U_TURN, Moves.VOLT_SWITCH, Moves.FLIP_TURN ].includes(move.id) + ) { if (this.hpDroppedBelowHalf(target)) { return false; } } - // Switch out logic for everything else (eg: WILD battles) if (user.scene.currentBattle.waveIndex % 10 === 0) { return false; } @@ -6035,7 +6122,7 @@ export class ForceSwitchOutAttr extends MoveEffectAttr { user.scene.clearEnemyHeldItemModifiers(); if (switchOutTarget.hp) { - user.scene.pushPhase(new BattleEndPhase(user.scene)); + user.scene.pushPhase(new BattleEndPhase(user.scene, false)); user.scene.pushPhase(new NewBattlePhase(user.scene)); } } @@ -7777,11 +7864,10 @@ export function initMoves() { .windMove(), new AttackMove(Moves.WING_ATTACK, Type.FLYING, MoveCategory.PHYSICAL, 60, 100, 35, -1, 0, 1), new StatusMove(Moves.WHIRLWIND, Type.NORMAL, -1, 20, -1, -6, 1) - .attr(ForceSwitchOutAttr) + .attr(ForceSwitchOutAttr, false, SwitchType.FORCE_SWITCH) .ignoresSubstitute() .hidesTarget() - .windMove() - .partial(), // Should force random switches + .windMove(), new ChargingAttackMove(Moves.FLY, Type.FLYING, MoveCategory.PHYSICAL, 90, 95, 15, -1, 0, 1) .chargeText(i18next.t("moveTriggers:flewUpHigh", { pokemonName: "{USER}" })) .chargeAttr(SemiInvulnerableAttr, BattlerTagType.FLYING) @@ -7857,10 +7943,9 @@ export function initMoves() { .soundBased() .target(MoveTarget.ALL_NEAR_ENEMIES), new StatusMove(Moves.ROAR, Type.NORMAL, -1, 20, -1, -6, 1) - .attr(ForceSwitchOutAttr) + .attr(ForceSwitchOutAttr, false, SwitchType.FORCE_SWITCH) .soundBased() - .hidesTarget() - .partial(), // Should force random switching + .hidesTarget(), new StatusMove(Moves.SING, Type.NORMAL, 55, 15, -1, 0, 1) .attr(StatusEffectAttr, StatusEffect.SLEEP) .soundBased(), @@ -9222,8 +9307,8 @@ export function initMoves() { .attr(StatStageChangeAttr, [ Stat.ATK ], 1, true) .attr(StatStageChangeAttr, [ Stat.SPD ], 2, true), new AttackMove(Moves.CIRCLE_THROW, Type.FIGHTING, MoveCategory.PHYSICAL, 60, 90, 10, -1, -6, 5) - .attr(ForceSwitchOutAttr) - .partial(), // Should force random switches + .attr(ForceSwitchOutAttr, false, SwitchType.FORCE_SWITCH) + .hidesTarget(), new AttackMove(Moves.INCINERATE, Type.FIRE, MoveCategory.SPECIAL, 60, 100, 15, -1, 0, 5) .target(MoveTarget.ALL_NEAR_ENEMIES) .attr(RemoveHeldItemAttr, true), @@ -9291,9 +9376,8 @@ export function initMoves() { new AttackMove(Moves.FROST_BREATH, Type.ICE, MoveCategory.SPECIAL, 60, 90, 10, 100, 0, 5) .attr(CritOnlyAttr), new AttackMove(Moves.DRAGON_TAIL, Type.DRAGON, MoveCategory.PHYSICAL, 60, 90, 10, -1, -6, 5) - .attr(ForceSwitchOutAttr) - .hidesTarget() - .partial(), // Should force random switches + .attr(ForceSwitchOutAttr, false, SwitchType.FORCE_SWITCH) + .hidesTarget(), new SelfStatusMove(Moves.WORK_UP, Type.NORMAL, -1, 30, -1, 0, 5) .attr(StatStageChangeAttr, [ Stat.ATK, Stat.SPATK ], 1, true), new AttackMove(Moves.ELECTROWEB, Type.ELECTRIC, MoveCategory.SPECIAL, 55, 95, 15, 100, 0, 5) @@ -10554,6 +10638,7 @@ export function initMoves() { new AttackMove(Moves.TWIN_BEAM, Type.PSYCHIC, MoveCategory.SPECIAL, 40, 100, 10, -1, 0, 9) .attr(MultiHitAttr, MultiHitType._2), new AttackMove(Moves.RAGE_FIST, Type.GHOST, MoveCategory.PHYSICAL, 50, 100, 10, -1, 0, 9) + .partial() // Counter resets every wave instead of on arena reset .attr(HitCountPowerAttr) .punchingMove(), new AttackMove(Moves.ARMOR_CANNON, Type.FIRE, MoveCategory.SPECIAL, 120, 100, 5, -1, 0, 9) diff --git a/src/data/mystery-encounters/encounters/dark-deal-encounter.ts b/src/data/mystery-encounters/encounters/dark-deal-encounter.ts index 2b801d70f61..05d6501f256 100644 --- a/src/data/mystery-encounters/encounters/dark-deal-encounter.ts +++ b/src/data/mystery-encounters/encounters/dark-deal-encounter.ts @@ -8,7 +8,7 @@ import { getPokemonSpecies } from "#app/data/pokemon-species"; import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter"; import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; import { EnemyPartyConfig, EnemyPokemonConfig, initBattleWithEnemyConfig, leaveEncounterWithoutBattle, } from "../utils/encounter-phase-utils"; -import { getRandomPlayerPokemon, getRandomSpeciesByStarterTier } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; +import { getRandomPlayerPokemon, getRandomSpeciesByStarterCost } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase"; @@ -174,7 +174,7 @@ export const DarkDealEncounter: MysteryEncounter = const roll = randSeedInt(100); const starterTier: number | [number, number] = roll >= 65 ? 6 : roll >= 15 ? 7 : roll >= 5 ? 8 : [ 9, 10 ]; - const bossSpecies = getPokemonSpecies(getRandomSpeciesByStarterTier(starterTier, excludedBosses, bossTypes)); + const bossSpecies = getPokemonSpecies(getRandomSpeciesByStarterCost(starterTier, excludedBosses, bossTypes)); const pokemonConfig: EnemyPokemonConfig = { species: bossSpecies, isBoss: true, diff --git a/src/data/mystery-encounters/encounters/safari-zone-encounter.ts b/src/data/mystery-encounters/encounters/safari-zone-encounter.ts index 0353d52a592..e16cf2d6973 100644 --- a/src/data/mystery-encounters/encounters/safari-zone-encounter.ts +++ b/src/data/mystery-encounters/encounters/safari-zone-encounter.ts @@ -9,9 +9,9 @@ import { EnemyPokemon } from "#app/field/pokemon"; import { PokeballType } from "#enums/pokeball"; import { PlayerGender } from "#enums/player-gender"; import { IntegerHolder, randSeedInt } from "#app/utils"; -import { getPokemonSpecies } from "#app/data/pokemon-species"; +import PokemonSpecies, { getPokemonSpecies } from "#app/data/pokemon-species"; import { MoneyRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements"; -import { doPlayerFlee, doPokemonFlee, getRandomSpeciesByStarterTier, trainerThrowPokeball } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; +import { doPlayerFlee, doPokemonFlee, getRandomSpeciesByStarterCost, trainerThrowPokeball } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { getEncounterText, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { getPokemonNameWithAffix } from "#app/messages"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; @@ -19,6 +19,7 @@ import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode import { ScanIvsPhase } from "#app/phases/scan-ivs-phase"; import { SummonPhase } from "#app/phases/summon-phase"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; +import { NON_LEGEND_PARADOX_POKEMON } from "#app/data/balance/special-species-groups"; /** the i18n namespace for the encounter */ const namespace = "mysteryEncounters/safariZone"; @@ -261,7 +262,7 @@ async function summonSafariPokemon(scene: BattleScene) { let enemySpecies; let pokemon; scene.executeWithSeedOffset(() => { - enemySpecies = getPokemonSpecies(getRandomSpeciesByStarterTier([ 0, 5 ], undefined, undefined, false, false, false)); + enemySpecies = getSafariSpeciesSpawn(); const level = scene.currentBattle.getLevelForWave(); enemySpecies = getPokemonSpecies(enemySpecies.getWildSpeciesForLevel(level, true, false, scene.gameMode)); pokemon = scene.addEnemyPokemon(enemySpecies, level, TrainerSlot.NONE, false); @@ -526,3 +527,10 @@ async function doEndTurn(scene: BattleScene, cursorIndex: number) { initSubsequentOptionSelect(scene, { overrideOptions: safariZoneGameOptions, startingCursorIndex: cursorIndex, hideDescription: true }); } } + +/** + * @returns A random species that has at most 5 starter cost and is not Mythical, Paradox, etc. + */ +export function getSafariSpeciesSpawn(): PokemonSpecies { + return getPokemonSpecies(getRandomSpeciesByStarterCost([ 0, 5 ], NON_LEGEND_PARADOX_POKEMON, undefined, false, false, false)); +} diff --git a/src/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter.ts b/src/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter.ts index 6a4c6592fda..5ac9852f27a 100644 --- a/src/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-expert-pokemon-breeder-encounter.ts @@ -21,7 +21,6 @@ import { EggSourceType } from "#enums/egg-source-types"; import { EggTier } from "#enums/egg-type"; import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; -import { achvs } from "#app/system/achv"; import { modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type"; import { Type } from "#enums/type"; import { getPokeballTintColor } from "#app/data/pokeball"; @@ -520,12 +519,6 @@ function removePokemonFromPartyAndStoreHeldItems(scene: BattleScene, encounter: ]; } -function checkAchievement(scene: BattleScene) { - if (scene.arena.biomeType === Biome.SPACE) { - scene.validateAchv(achvs.BREEDERS_IN_SPACE); - } -} - function restorePartyAndHeldItems(scene: BattleScene) { const encounter = scene.currentBattle.mysteryEncounter!; // Restore original party @@ -617,8 +610,6 @@ function onGameOver(scene: BattleScene) { function doPostEncounterCleanup(scene: BattleScene) { const encounter = scene.currentBattle.mysteryEncounter!; if (!encounter.misc.encounterFailed) { - // Give achievement if in Space biome - checkAchievement(scene); // Give 20 friendship to the chosen pokemon encounter.misc.chosenPokemon.addFriendship(FRIENDSHIP_ADDED); restorePartyAndHeldItems(scene); diff --git a/src/data/mystery-encounters/encounters/the-pokemon-salesman-encounter.ts b/src/data/mystery-encounters/encounters/the-pokemon-salesman-encounter.ts index 77d92e3749e..61a4de908e9 100644 --- a/src/data/mystery-encounters/encounters/the-pokemon-salesman-encounter.ts +++ b/src/data/mystery-encounters/encounters/the-pokemon-salesman-encounter.ts @@ -4,8 +4,8 @@ import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import BattleScene from "#app/battle-scene"; import MysteryEncounter, { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter"; import { MoneyRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements"; -import { catchPokemon, getRandomSpeciesByStarterTier, getSpriteKeysFromPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; -import { getPokemonSpecies } from "#app/data/pokemon-species"; +import { catchPokemon, getRandomSpeciesByStarterCost, getSpriteKeysFromPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; +import PokemonSpecies, { getPokemonSpecies } from "#app/data/pokemon-species"; import { speciesStarterCosts } from "#app/data/balance/starters"; import { Species } from "#enums/species"; import { PokeballType } from "#enums/pokeball"; @@ -17,6 +17,7 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode"; import { Abilities } from "#enums/abilities"; +import { NON_LEGEND_PARADOX_POKEMON } from "#app/data/balance/special-species-groups"; /** the i18n namespace for this encounter */ const namespace = "mysteryEncounters/thePokemonSalesman"; @@ -60,12 +61,12 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter = .withOnInit((scene: BattleScene) => { const encounter = scene.currentBattle.mysteryEncounter!; - let species = getPokemonSpecies(getRandomSpeciesByStarterTier([ 0, 5 ], undefined, undefined, false, false, false)); + let species = getSalesmanSpeciesOffer(); let tries = 0; // Reroll any species that don't have HAs while ((isNullOrUndefined(species.abilityHidden) || species.abilityHidden === Abilities.NONE) && tries < 5) { - species = getPokemonSpecies(getRandomSpeciesByStarterTier([ 0, 5 ], undefined, undefined, false, false, false)); + species = getSalesmanSpeciesOffer(); tries++; } @@ -164,3 +165,10 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter = } ) .build(); + +/** + * @returns A random species that has at most 5 starter cost and is not Mythical, Paradox, etc. + */ +export function getSalesmanSpeciesOffer(): PokemonSpecies { + return getPokemonSpecies(getRandomSpeciesByStarterCost([ 0, 5 ], NON_LEGEND_PARADOX_POKEMON, undefined, false, false, false)); +} diff --git a/src/data/mystery-encounters/utils/encounter-phase-utils.ts b/src/data/mystery-encounters/utils/encounter-phase-utils.ts index c6dda134346..b5dd43a9221 100644 --- a/src/data/mystery-encounters/utils/encounter-phase-utils.ts +++ b/src/data/mystery-encounters/utils/encounter-phase-utils.ts @@ -731,7 +731,7 @@ export function handleMysteryEncounterVictory(scene: BattleScene, addHealPhase: scene.pushPhase(new MysteryEncounterRewardsPhase(scene, addHealPhase)); scene.pushPhase(new EggLapsePhase(scene)); } else if (!scene.getEnemyParty().find(p => encounter.encounterMode !== MysteryEncounterMode.TRAINER_BATTLE ? p.isOnField() : !p?.isFainted(true))) { - scene.pushPhase(new BattleEndPhase(scene)); + scene.pushPhase(new BattleEndPhase(scene, true)); if (encounter.encounterMode === MysteryEncounterMode.TRAINER_BATTLE) { scene.pushPhase(new TrainerVictoryPhase(scene)); } diff --git a/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts b/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts index fc85754bdde..7adcfdc4974 100644 --- a/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts +++ b/src/data/mystery-encounters/utils/encounter-pokemon-utils.ts @@ -207,7 +207,7 @@ export function getHighestStatTotalPlayerPokemon(scene: BattleScene, isAllowed: * @param allowMythical * @returns */ -export function getRandomSpeciesByStarterTier(starterTiers: number | [number, number], excludedSpecies?: Species[], types?: Type[], allowSubLegendary: boolean = true, allowLegendary: boolean = true, allowMythical: boolean = true): Species { +export function getRandomSpeciesByStarterCost(starterTiers: number | [number, number], excludedSpecies?: Species[], types?: Type[], allowSubLegendary: boolean = true, allowLegendary: boolean = true, allowMythical: boolean = true): Species { let min = Array.isArray(starterTiers) ? starterTiers[0] : starterTiers; let max = Array.isArray(starterTiers) ? starterTiers[1] : starterTiers; diff --git a/src/enums/switch-type.ts b/src/enums/switch-type.ts index 752c0902636..d55872ae83b 100644 --- a/src/enums/switch-type.ts +++ b/src/enums/switch-type.ts @@ -10,5 +10,7 @@ export enum SwitchType { /** Transfers stat stages and other effects from the returning Pokemon to the switched in Pokemon */ BATON_PASS, /** Transfers the returning Pokemon's Substitute to the switched in Pokemon */ - SHED_TAIL + SHED_TAIL, + /** Force switchout to a random party member */ + FORCE_SWITCH, } diff --git a/src/field/arena.ts b/src/field/arena.ts index da74063ac06..3cbef659d7a 100644 --- a/src/field/arena.ts +++ b/src/field/arena.ts @@ -707,7 +707,7 @@ export class Arena { case Biome.METROPOLIS: return 141.470; case Biome.FOREST: - return 4.294; + return 0.341; case Biome.SEA: return 0.024; case Biome.SWAMP: diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 3b00aaa1174..8181e52357c 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -51,7 +51,7 @@ import { Biome } from "#enums/biome"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import { getPokemonNameWithAffix } from "#app/messages"; -import { DamagePhase } from "#app/phases/damage-phase"; +import { DamageAnimPhase } from "#app/phases/damage-anim-phase"; import { FaintPhase } from "#app/phases/faint-phase"; import { LearnMovePhase } from "#app/phases/learn-move-phase"; import { MoveEffectPhase } from "#app/phases/move-effect-phase"; @@ -2631,8 +2631,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { }; } - // If the attack deals fixed damaged, return a result with that much damage - const fixedDamage = new Utils.IntegerHolder(0); + // If the attack deals fixed damage, return a result with that much damage + const fixedDamage = new Utils.NumberHolder(0); applyMoveAttrs(FixedDamageAttr, source, this, move, fixedDamage); if (fixedDamage.value) { const multiLensMultiplier = new Utils.NumberHolder(1); @@ -3018,7 +3018,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @returns integer of damage done */ damageAndUpdate(damage: integer, result?: DamageResult, critical: boolean = false, ignoreSegments: boolean = false, preventEndure: boolean = false, ignoreFaintPhase: boolean = false, source?: Pokemon): integer { - const damagePhase = new DamagePhase(this.scene, this.getBattlerIndex(), damage, result as DamageResult, critical); + const damagePhase = new DamageAnimPhase(this.scene, this.getBattlerIndex(), damage, result as DamageResult, critical); this.scene.unshiftPhase(damagePhase); damage = this.damage(damage, ignoreSegments, preventEndure, ignoreFaintPhase); // Damage amount may have changed, but needed to be queued before calling damage function diff --git a/src/overrides.ts b/src/overrides.ts index 7b73cd47b03..dc166307314 100644 --- a/src/overrides.ts +++ b/src/overrides.ts @@ -86,6 +86,8 @@ class DefaultOverrides { readonly ITEM_UNLOCK_OVERRIDE: Unlockables[] = []; /** Set to `true` to show all tutorials */ readonly BYPASS_TUTORIAL_SKIP_OVERRIDE: boolean = false; + /** Set to `true` to be able to re-earn already unlocked achievements */ + readonly ACHIEVEMENTS_REUNLOCK_OVERRIDE: boolean = false; /** Set to `true` to force Paralysis and Freeze to always activate, or `false` to force them to not activate */ readonly STATUS_ACTIVATION_OVERRIDE: boolean | null = null; diff --git a/src/phases/attempt-run-phase.ts b/src/phases/attempt-run-phase.ts index b4768dc9a26..109fc5b582d 100644 --- a/src/phases/attempt-run-phase.ts +++ b/src/phases/attempt-run-phase.ts @@ -52,7 +52,7 @@ export class AttemptRunPhase extends PokemonPhase { enemyPokemon.trySetStatus(StatusEffect.FAINT); }); - this.scene.pushPhase(new BattleEndPhase(this.scene)); + this.scene.pushPhase(new BattleEndPhase(this.scene, false)); this.scene.pushPhase(new NewBattlePhase(this.scene)); } else { playerPokemon.turnData.failedRunAway = true; diff --git a/src/phases/battle-end-phase.ts b/src/phases/battle-end-phase.ts index 3b9ca012ef7..8926a2211e0 100644 --- a/src/phases/battle-end-phase.ts +++ b/src/phases/battle-end-phase.ts @@ -8,7 +8,7 @@ export class BattleEndPhase extends BattlePhase { /** If true, will increment battles won */ isVictory: boolean; - constructor(scene: BattleScene, isVictory: boolean = true) { + constructor(scene: BattleScene, isVictory: boolean) { super(scene); this.isVictory = isVictory; @@ -17,16 +17,17 @@ export class BattleEndPhase extends BattlePhase { start() { super.start(); + this.scene.gameData.gameStats.battles++; + if (this.scene.gameMode.isEndless && this.scene.currentBattle.waveIndex + 1 > this.scene.gameData.gameStats.highestEndlessWave) { + this.scene.gameData.gameStats.highestEndlessWave = this.scene.currentBattle.waveIndex + 1; + } + if (this.isVictory) { this.scene.currentBattle.addBattleScore(this.scene); - this.scene.gameData.gameStats.battles++; if (this.scene.currentBattle.trainer) { this.scene.gameData.gameStats.trainersDefeated++; } - if (this.scene.gameMode.isEndless && this.scene.currentBattle.waveIndex + 1 > this.scene.gameData.gameStats.highestEndlessWave) { - this.scene.gameData.gameStats.highestEndlessWave = this.scene.currentBattle.waveIndex + 1; - } } // Endless graceful end @@ -42,7 +43,7 @@ export class BattleEndPhase extends BattlePhase { } for (const pokemon of this.scene.getPokemonAllowedInBattle()) { - applyPostBattleAbAttrs(PostBattleAbAttr, pokemon); + applyPostBattleAbAttrs(PostBattleAbAttr, pokemon, false, this.isVictory); } if (this.scene.currentBattle.moneyScattered) { diff --git a/src/phases/damage-phase.ts b/src/phases/damage-anim-phase.ts similarity index 82% rename from src/phases/damage-phase.ts rename to src/phases/damage-anim-phase.ts index 44e3dfd4182..42f0e1ba845 100644 --- a/src/phases/damage-phase.ts +++ b/src/phases/damage-anim-phase.ts @@ -1,11 +1,11 @@ -import BattleScene from "#app/battle-scene"; -import { BattlerIndex } from "#app/battle"; -import { BattleSpec } from "#app/enums/battle-spec"; -import { DamageResult, HitResult } from "#app/field/pokemon"; -import * as Utils from "#app/utils"; -import { PokemonPhase } from "./pokemon-phase"; +import type BattleScene from "#app/battle-scene"; +import { type BattlerIndex } from "#app/battle"; +import { BattleSpec } from "#enums/battle-spec"; +import { type DamageResult, HitResult } from "#app/field/pokemon"; +import { fixedInt } from "#app/utils"; +import { PokemonPhase } from "#app/phases/pokemon-phase"; -export class DamagePhase extends PokemonPhase { +export class DamageAnimPhase extends PokemonPhase { private amount: integer; private damageResult: DamageResult; private critical: boolean; @@ -25,7 +25,7 @@ export class DamagePhase extends PokemonPhase { if (this.scene.moveAnimations) { this.scene.toggleInvert(true); } - this.scene.time.delayedCall(Utils.fixedInt(1000), () => { + this.scene.time.delayedCall(fixedInt(1000), () => { this.scene.toggleInvert(false); this.applyDamage(); }); diff --git a/src/phases/egg-lapse-phase.ts b/src/phases/egg-lapse-phase.ts index 4c57be09b79..8de26ee3ef0 100644 --- a/src/phases/egg-lapse-phase.ts +++ b/src/phases/egg-lapse-phase.ts @@ -34,7 +34,7 @@ export class EggLapsePhase extends Phase { if (eggsToHatchCount >= this.minEggsToSkip && this.scene.eggSkipPreference === 1) { this.scene.ui.showText(i18next.t("battle:eggHatching"), 0, () => { // show prompt for skip, blocking inputs for 1 second - this.scene.ui.showText(i18next.t("battle:eggSkipPrompt"), 0); + this.scene.ui.showText(i18next.t("battle:eggSkipPrompt", { eggsToHatch: eggsToHatchCount }), 0); this.scene.ui.setModeWithoutClear(Mode.CONFIRM, () => { this.hatchEggsSkipped(eggsToHatch); this.showSummary(); diff --git a/src/phases/faint-phase.ts b/src/phases/faint-phase.ts index 1c48bdfb37a..a0c10015fbf 100644 --- a/src/phases/faint-phase.ts +++ b/src/phases/faint-phase.ts @@ -12,7 +12,7 @@ import { getPokemonNameWithAffix } from "#app/messages"; import { PokemonInstantReviveModifier } from "#app/modifier/modifier"; import { SwitchType } from "#enums/switch-type"; import i18next from "i18next"; -import { DamagePhase } from "./damage-phase"; +import { DamageAnimPhase } from "./damage-anim-phase"; import { GameOverPhase } from "./game-over-phase"; import { PokemonPhase } from "./pokemon-phase"; import { SwitchPhase } from "./switch-phase"; @@ -206,7 +206,7 @@ export class FaintPhase extends PokemonPhase { } else { // Final boss' HP threshold has been bypassed; cancel faint and force check for 2nd phase enemy.hp++; - this.scene.unshiftPhase(new DamagePhase(this.scene, enemy.getBattlerIndex(), 0, HitResult.OTHER)); + this.scene.unshiftPhase(new DamageAnimPhase(this.scene, enemy.getBattlerIndex(), 0, HitResult.OTHER)); this.end(); } return true; diff --git a/src/phases/switch-summon-phase.ts b/src/phases/switch-summon-phase.ts index a667e17edf1..a1925768d83 100644 --- a/src/phases/switch-summon-phase.ts +++ b/src/phases/switch-summon-phase.ts @@ -1,5 +1,5 @@ import BattleScene from "#app/battle-scene"; -import { applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr } from "#app/data/ability"; +import { applyPreSwitchOutAbAttrs, PostDamageForceSwitchAbAttr, PreSwitchOutAbAttr } from "#app/data/ability"; import { allMoves, ForceSwitchOutAttr } from "#app/data/move"; import { getPokeballTintColor } from "#app/data/pokeball"; import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms"; @@ -166,10 +166,11 @@ export class SwitchSummonPhase extends SummonPhase { const currentCommand = pokemon.scene.currentBattle.turnCommands[this.fieldIndex]?.command; const lastPokemonIsForceSwitchedAndNotFainted = lastUsedMove?.hasAttr(ForceSwitchOutAttr) && !this.lastPokemon.isFainted(); + const lastPokemonHasForceSwitchAbAttr = this.lastPokemon.hasAbilityWithAttr(PostDamageForceSwitchAbAttr) && !this.lastPokemon.isFainted(); // Compensate for turn spent summoning // Or compensate for force switch move if switched out pokemon is not fainted - if (currentCommand === Command.POKEMON || lastPokemonIsForceSwitchedAndNotFainted) { + if (currentCommand === Command.POKEMON || lastPokemonIsForceSwitchedAndNotFainted || lastPokemonHasForceSwitchAbAttr) { pokemon.battleSummonData.turnCount--; pokemon.battleSummonData.waveTurnCount--; } diff --git a/src/phases/trainer-victory-phase.ts b/src/phases/trainer-victory-phase.ts index dc1b962f47e..d797e4360ac 100644 --- a/src/phases/trainer-victory-phase.ts +++ b/src/phases/trainer-victory-phase.ts @@ -9,6 +9,8 @@ import { BattlePhase } from "./battle-phase"; import { ModifierRewardPhase } from "./modifier-reward-phase"; import { MoneyRewardPhase } from "./money-reward-phase"; import { TrainerSlot } from "#app/data/trainer-config"; +import { Biome } from "#app/enums/biome"; +import { achvs } from "#app/system/achv"; export class TrainerVictoryPhase extends BattlePhase { constructor(scene: BattleScene) { @@ -34,11 +36,17 @@ export class TrainerVictoryPhase extends BattlePhase { } const trainerType = this.scene.currentBattle.trainer?.config.trainerType!; // TODO: is this bang correct? + // Validate Voucher for boss trainers if (vouchers.hasOwnProperty(TrainerType[trainerType])) { if (!this.scene.validateVoucher(vouchers[TrainerType[trainerType]]) && this.scene.currentBattle.trainer?.config.isBoss) { this.scene.unshiftPhase(new ModifierRewardPhase(this.scene, [ modifierTypes.VOUCHER, modifierTypes.VOUCHER, modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PREMIUM ][vouchers[TrainerType[trainerType]].voucherType])); } } + // Breeders in Space achievement + if (this.scene.arena.biomeType === Biome.SPACE + && (trainerType === TrainerType.BREEDER || trainerType === TrainerType.EXPERT_POKEMON_BREEDER)) { + this.scene.validateAchv(achvs.BREEDERS_IN_SPACE); + } this.scene.ui.showText(i18next.t("battle:trainerDefeated", { trainerName: this.scene.currentBattle.trainer?.getName(TrainerSlot.NONE, true) }), null, () => { const victoryMessages = this.scene.currentBattle.trainer?.getVictoryMessages()!; // TODO: is this bang correct? diff --git a/src/phases/victory-phase.ts b/src/phases/victory-phase.ts index 1faa31655df..62479241a6c 100644 --- a/src/phases/victory-phase.ts +++ b/src/phases/victory-phase.ts @@ -41,7 +41,7 @@ export class VictoryPhase extends PokemonPhase { } if (!this.scene.getEnemyParty().find(p => this.scene.currentBattle.battleType === BattleType.WILD ? p.isOnField() : !p?.isFainted(true))) { - this.scene.pushPhase(new BattleEndPhase(this.scene)); + this.scene.pushPhase(new BattleEndPhase(this.scene, true)); if (this.scene.currentBattle.battleType === BattleType.TRAINER) { this.scene.pushPhase(new TrainerVictoryPhase(this.scene)); } diff --git a/src/system/achv.ts b/src/system/achv.ts index d94fcba48f2..a98e396264d 100644 --- a/src/system/achv.ts +++ b/src/system/achv.ts @@ -358,7 +358,7 @@ export const achvs = { MONO_FAIRY: new ChallengeAchv("MONO_FAIRY", "", "MONO_FAIRY.description", "fairy_feather", 100, (c, scene) => c instanceof SingleTypeChallenge && c.value === 18 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), FRESH_START: new ChallengeAchv("FRESH_START", "", "FRESH_START.description", "reviver_seed", 100, (c, scene) => c instanceof FreshStartChallenge && c.value > 0 && !scene.gameMode.challenges.some(c => c.id === Challenges.INVERSE_BATTLE && c.value > 0)), INVERSE_BATTLE: new ChallengeAchv("INVERSE_BATTLE", "", "INVERSE_BATTLE.description", "inverse", 100, c => c instanceof InverseBattleChallenge && c.value > 0), - BREEDERS_IN_SPACE: new Achv("BREEDERS_IN_SPACE", "", "BREEDERS_IN_SPACE.description", "moon_stone", 100).setSecret(), + BREEDERS_IN_SPACE: new Achv("BREEDERS_IN_SPACE", "", "BREEDERS_IN_SPACE.description", "moon_stone", 50).setSecret(), }; export function initAchievements() { diff --git a/src/system/settings/settings.ts b/src/system/settings/settings.ts index d71edf603dd..64ddfdae5cf 100644 --- a/src/system/settings/settings.ts +++ b/src/system/settings/settings.ts @@ -1,9 +1,9 @@ import { Mode } from "#app/ui/ui"; import i18next from "i18next"; -import BattleScene from "../../battle-scene"; -import { hasTouchscreen } from "../../touch-controls"; -import { updateWindowType } from "../../ui/ui-theme"; -import { CandyUpgradeNotificationChangedEvent } from "../../events/battle-scene"; +import BattleScene from "#app/battle-scene"; +import { hasTouchscreen } from "#app/touch-controls"; +import { updateWindowType } from "#app/ui/ui-theme"; +import { CandyUpgradeNotificationChangedEvent } from "#app/events/battle-scene"; import SettingsUiHandler from "#app/ui/settings/settings-ui-handler"; import { EaseType } from "#enums/ease-type"; import { MoneyFormat } from "#enums/money-format"; @@ -44,6 +44,7 @@ const OFF_ON: SettingOption[] = [ label: i18next.t("settings:on") } ]; + const AUTO_DISABLED: SettingOption[] = [ { value: "Auto", @@ -55,6 +56,19 @@ const AUTO_DISABLED: SettingOption[] = [ } ]; +const TOUCH_CONTROLS_OPTIONS: SettingOption[] = [ + { + value: "Auto", + label: i18next.t("settings:auto") + }, + { + value: "Disabled", + label: i18next.t("settings:disabled"), + needConfirmation: true, + confirmationMessage: i18next.t("settings:confirmDisableTouch") + } +]; + const SHOP_CURSOR_TARGET_OPTIONS: SettingOption[] = [ { value: "Rewards", @@ -100,7 +114,9 @@ export enum SettingType { type SettingOption = { value: string, - label: string + label: string, + needConfirmation?: boolean, + confirmationMessage?: string }; export interface Setting { @@ -344,13 +360,6 @@ export const Setting: Array = [ default: 1, type: SettingType.GENERAL }, - { - key: SettingKeys.Touch_Controls, - label: i18next.t("settings:touchControls"), - options: AUTO_DISABLED, - default: 0, - type: SettingType.GENERAL - }, { key: SettingKeys.Vibration, label: i18next.t("settings:vibrations"), @@ -358,6 +367,28 @@ export const Setting: Array = [ default: 0, type: SettingType.GENERAL }, + { + key: SettingKeys.Touch_Controls, + label: i18next.t("settings:touchControls"), + options: TOUCH_CONTROLS_OPTIONS, + default: 0, + type: SettingType.GENERAL, + isHidden: () => !hasTouchscreen() + }, + { + key: SettingKeys.Move_Touch_Controls, + label: i18next.t("settings:moveTouchControls"), + options: [ + { + value: "Configure", + label: i18next.t("settings:change") + } + ], + default: 0, + type: SettingType.GENERAL, + activatable: true, + isHidden: () => !hasTouchscreen() + }, { key: SettingKeys.Language, label: i18next.t("settings:language"), @@ -643,20 +674,6 @@ export const Setting: Array = [ type: SettingType.AUDIO, requireReload: true }, - { - key: SettingKeys.Move_Touch_Controls, - label: i18next.t("settings:moveTouchControls"), - options: [ - { - value: "Configure", - label: i18next.t("settings:change") - } - ], - default: 0, - type: SettingType.GENERAL, - activatable: true, - isHidden: () => !hasTouchscreen() - }, { key: SettingKeys.Shop_Cursor_Target, label: i18next.t("settings:shopCursorTarget"), @@ -849,7 +866,7 @@ export function setSetting(scene: BattleScene, setting: string, value: integer): if (scene.ui) { const cancelHandler = () => { scene.ui.revertMode(); - (scene.ui.getHandler() as SettingsUiHandler).setOptionCursor(0, 0, true); + (scene.ui.getHandler() as SettingsUiHandler).setOptionCursor(-1, 0, true); }; const changeLocaleHandler = (locale: string): boolean => { try { diff --git a/src/test/abilities/analytic.test.ts b/src/test/abilities/analytic.test.ts new file mode 100644 index 00000000000..12777c545f0 --- /dev/null +++ b/src/test/abilities/analytic.test.ts @@ -0,0 +1,81 @@ +import { BattlerIndex } from "#app/battle"; +import { isBetween, toDmgValue } from "#app/utils"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Abilities - Analytic", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([ Moves.SPLASH, Moves.TACKLE ]) + .ability(Abilities.ANALYTIC) + .battleType("single") + .disableCrits() + .startingLevel(200) + .enemyLevel(200) + .enemySpecies(Species.SNORLAX) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH); + }); + + it("should increase damage if the user moves last", async () => { + await game.classicMode.startBattle([ Species.ARCEUS ]); + + const enemy = game.scene.getEnemyPokemon()!; + + game.move.select(Moves.TACKLE); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + await game.toNextTurn(); + const damage1 = enemy.getInverseHp(); + enemy.hp = enemy.getMaxHp(); + + game.move.select(Moves.TACKLE); + await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]); + await game.phaseInterceptor.to("BerryPhase"); + expect(isBetween(enemy.getInverseHp(), toDmgValue(damage1 * 1.3) - 3, toDmgValue(damage1 * 1.3) + 3)).toBe(true); + }); + + it("should increase damage only if the user moves last in doubles", async () => { + game.override.battleType("double"); + await game.classicMode.startBattle([ Species.GENGAR, Species.SHUCKLE ]); + + const [ enemy, ] = game.scene.getEnemyField(); + + game.move.select(Moves.TACKLE, 0, BattlerIndex.ENEMY); + game.move.select(Moves.SPLASH, 1); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]); + await game.toNextTurn(); + const damage1 = enemy.getInverseHp(); + enemy.hp = enemy.getMaxHp(); + + game.move.select(Moves.TACKLE, 0, BattlerIndex.ENEMY); + game.move.select(Moves.SPLASH, 1); + await game.setTurnOrder([ BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER ]); + await game.toNextTurn(); + expect(isBetween(enemy.getInverseHp(), toDmgValue(damage1 * 1.3) - 3, toDmgValue(damage1 * 1.3) + 3)).toBe(true); + enemy.hp = enemy.getMaxHp(); + + game.move.select(Moves.TACKLE, 0, BattlerIndex.ENEMY); + game.move.select(Moves.SPLASH, 1); + await game.setTurnOrder([ BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.PLAYER, BattlerIndex.ENEMY_2 ]); + await game.phaseInterceptor.to("BerryPhase"); + expect(enemy.getInverseHp()).toBe(damage1); + }); +}); diff --git a/src/test/abilities/forecast.test.ts b/src/test/abilities/forecast.test.ts index 18d43a67a9d..6d1f776da16 100644 --- a/src/test/abilities/forecast.test.ts +++ b/src/test/abilities/forecast.test.ts @@ -2,7 +2,7 @@ import { BattlerIndex } from "#app/battle"; import { allAbilities } from "#app/data/ability"; import { Abilities } from "#app/enums/abilities"; import { WeatherType } from "#app/enums/weather-type"; -import { DamagePhase } from "#app/phases/damage-phase"; +import { DamageAnimPhase } from "#app/phases/damage-anim-phase"; import { MovePhase } from "#app/phases/move-phase"; import { PostSummonPhase } from "#app/phases/post-summon-phase"; import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase"; @@ -273,7 +273,7 @@ describe("Abilities - Forecast", () => { const castform = game.scene.getPlayerPokemon()!; // Damage phase should come first - await game.phaseInterceptor.to(DamagePhase); + await game.phaseInterceptor.to(DamageAnimPhase); expect(castform.hp).toBeLessThan(castform.getMaxHp()); // Then change form diff --git a/src/test/abilities/honey_gather.test.ts b/src/test/abilities/honey_gather.test.ts new file mode 100644 index 00000000000..fc9d6cdd150 --- /dev/null +++ b/src/test/abilities/honey_gather.test.ts @@ -0,0 +1,74 @@ +import type { CommandPhase } from "#app/phases/command-phase"; +import { Command } from "#app/ui/command-ui-handler"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; + +describe("Abilities - Honey Gather", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([ Moves.SPLASH, Moves.ROAR, Moves.THUNDERBOLT ]) + .startingLevel(100) + .ability(Abilities.HONEY_GATHER) + .passiveAbility(Abilities.RUN_AWAY) + .battleType("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH); + }); + + it("should give money when winning a battle", async () => { + await game.classicMode.startBattle([ Species.MILOTIC ]); + game.scene.money = 1000; + + game.move.select(Moves.THUNDERBOLT); + await game.toNextWave(); + + expect(game.scene.money).toBeGreaterThan(1000); + }); + + it("should not give money when the enemy pokemon flees", async () => { + await game.classicMode.startBattle([ Species.MILOTIC ]); + game.scene.money = 1000; + + game.move.select(Moves.ROAR); + await game.toNextTurn(); + + expect(game.scene.money).toBe(1000); + expect(game.scene.currentBattle.waveIndex).toBe(2); + }); + + it("should not give money when the player flees", async () => { + await game.classicMode.startBattle([ Species.MILOTIC ]); + game.scene.money = 1000; + + // something weird is going on with the test framework, so this is required to prevent a crash + const enemy = game.scene.getEnemyPokemon()!; + vi.spyOn(enemy, "scene", "get").mockReturnValue(game.scene); + + const commandPhase = game.scene.getCurrentPhase() as CommandPhase; + commandPhase.handleCommand(Command.RUN, 0); + await game.toNextTurn(); + + expect(game.scene.money).toBe(1000); + expect(game.scene.currentBattle.waveIndex).toBe(2); + }); +}); diff --git a/src/test/abilities/hustle.test.ts b/src/test/abilities/hustle.test.ts index c4c4818040d..08a441315fb 100644 --- a/src/test/abilities/hustle.test.ts +++ b/src/test/abilities/hustle.test.ts @@ -42,7 +42,7 @@ describe("Abilities - Hustle", () => { game.move.select(Moves.TACKLE); await game.move.forceHit(); - await game.phaseInterceptor.to("DamagePhase"); + await game.phaseInterceptor.to("DamageAnimPhase"); expect(pikachu.getEffectiveStat).toHaveReturnedWith(Math.floor(atk * 1.5)); }); @@ -68,7 +68,7 @@ describe("Abilities - Hustle", () => { vi.spyOn(pikachu, "getAccuracyMultiplier"); game.move.select(Moves.GIGA_DRAIN); - await game.phaseInterceptor.to("DamagePhase"); + await game.phaseInterceptor.to("DamageAnimPhase"); expect(pikachu.getEffectiveStat).toHaveReturnedWith(spatk); expect(pikachu.getAccuracyMultiplier).toHaveReturnedWith(1); @@ -86,7 +86,7 @@ describe("Abilities - Hustle", () => { vi.spyOn(allMoves[Moves.FISSURE], "calculateBattleAccuracy"); game.move.select(Moves.FISSURE); - await game.phaseInterceptor.to("DamagePhase"); + await game.phaseInterceptor.to("DamageAnimPhase"); expect(enemyPokemon.turnData.damageTaken).toBe(enemyPokemon.getMaxHp()); expect(pikachu.getAccuracyMultiplier).toHaveReturnedWith(1); diff --git a/src/test/abilities/parental_bond.test.ts b/src/test/abilities/parental_bond.test.ts index 10048a774cd..6790e7e632c 100644 --- a/src/test/abilities/parental_bond.test.ts +++ b/src/test/abilities/parental_bond.test.ts @@ -51,7 +51,7 @@ describe("Abilities - Parental Bond", () => { game.move.select(Moves.TACKLE); - await game.phaseInterceptor.to("DamagePhase"); + await game.phaseInterceptor.to("DamageAnimPhase"); const firstStrikeDamage = enemyStartingHp - enemyPokemon.hp; enemyStartingHp = enemyPokemon.hp; @@ -129,7 +129,7 @@ describe("Abilities - Parental Bond", () => { game.move.select(Moves.SELF_DESTRUCT); - await game.phaseInterceptor.to("DamagePhase", false); + await game.phaseInterceptor.to("DamageAnimPhase", false); expect(leadPokemon.turnData.hitCount).toBe(1); } @@ -147,7 +147,7 @@ describe("Abilities - Parental Bond", () => { game.move.select(Moves.ROLLOUT); await game.move.forceHit(); - await game.phaseInterceptor.to("DamagePhase", false); + await game.phaseInterceptor.to("DamageAnimPhase", false); expect(leadPokemon.turnData.hitCount).toBe(1); } @@ -181,7 +181,7 @@ describe("Abilities - Parental Bond", () => { const enemyPokemon = game.scene.getEnemyPokemon()!; game.move.select(Moves.COUNTER); - await game.phaseInterceptor.to("DamagePhase"); + await game.phaseInterceptor.to("DamageAnimPhase"); const playerDamage = leadPokemon.getMaxHp() - leadPokemon.hp; @@ -221,7 +221,7 @@ describe("Abilities - Parental Bond", () => { const leadPokemon = game.scene.getPlayerPokemon()!; game.move.select(Moves.EARTHQUAKE); - await game.phaseInterceptor.to("DamagePhase", false); + await game.phaseInterceptor.to("DamageAnimPhase", false); expect(leadPokemon.turnData.hitCount).toBe(2); } @@ -238,7 +238,7 @@ describe("Abilities - Parental Bond", () => { game.move.select(Moves.MIND_BLOWN); - await game.phaseInterceptor.to("DamagePhase", false); + await game.phaseInterceptor.to("DamageAnimPhase", false); expect(leadPokemon.turnData.hitCount).toBe(2); @@ -285,7 +285,7 @@ describe("Abilities - Parental Bond", () => { game.move.select(Moves.TACKLE); - await game.phaseInterceptor.to("DamagePhase"); + await game.phaseInterceptor.to("DamageAnimPhase"); expect(leadPokemon.turnData.hitCount).toBe(3); } @@ -307,7 +307,7 @@ describe("Abilities - Parental Bond", () => { game.move.select(Moves.SEISMIC_TOSS); await game.move.forceHit(); - await game.phaseInterceptor.to("DamagePhase"); + await game.phaseInterceptor.to("DamageAnimPhase"); expect(leadPokemon.turnData.hitCount).toBe(3); @@ -329,7 +329,7 @@ describe("Abilities - Parental Bond", () => { game.move.select(Moves.HYPER_BEAM); await game.move.forceHit(); - await game.phaseInterceptor.to("DamagePhase"); + await game.phaseInterceptor.to("DamageAnimPhase"); expect(leadPokemon.turnData.hitCount).toBe(2); expect(leadPokemon.getTag(BattlerTagType.RECHARGING)).toBeUndefined(); @@ -353,7 +353,7 @@ describe("Abilities - Parental Bond", () => { game.move.select(Moves.ANCHOR_SHOT); await game.move.forceHit(); - await game.phaseInterceptor.to("DamagePhase"); + await game.phaseInterceptor.to("DamageAnimPhase"); expect(leadPokemon.turnData.hitCount).toBe(2); expect(enemyPokemon.getTag(BattlerTagType.TRAPPED)).toBeUndefined(); @@ -380,7 +380,7 @@ describe("Abilities - Parental Bond", () => { game.move.select(Moves.SMACK_DOWN); await game.move.forceHit(); - await game.phaseInterceptor.to("DamagePhase"); + await game.phaseInterceptor.to("DamageAnimPhase"); expect(leadPokemon.turnData.hitCount).toBe(2); expect(enemyPokemon.getTag(BattlerTagType.IGNORE_FLYING)).toBeUndefined(); @@ -424,7 +424,7 @@ describe("Abilities - Parental Bond", () => { game.move.select(Moves.WAKE_UP_SLAP); await game.move.forceHit(); - await game.phaseInterceptor.to("DamagePhase"); + await game.phaseInterceptor.to("DamageAnimPhase"); expect(leadPokemon.turnData.hitCount).toBe(2); expect(enemyPokemon.status?.effect).toBe(StatusEffect.SLEEP); diff --git a/src/test/abilities/speed_boost.test.ts b/src/test/abilities/speed_boost.test.ts index dd2e83aaa88..ff5184eedae 100644 --- a/src/test/abilities/speed_boost.test.ts +++ b/src/test/abilities/speed_boost.test.ts @@ -28,7 +28,9 @@ describe("Abilities - Speed Boost", () => { game.override .battleType("single") - .enemySpecies(Species.DRAGAPULT) + .enemySpecies(Species.SHUCKLE) + .enemyAbility(Abilities.BALL_FETCH) + .enemyLevel(100) .ability(Abilities.SPEED_BOOST) .enemyMoveset(Moves.SPLASH) .moveset([ Moves.SPLASH, Moves.U_TURN ]); @@ -70,21 +72,23 @@ describe("Abilities - Speed Boost", () => { Species.NINJASK ]); - game.move.select(Moves.U_TURN); - game.doSelectPartyPokemon(1); - await game.toNextTurn(); - let playerPokemon = game.scene.getPlayerPokemon()!; - expect(playerPokemon.getStatStage(Stat.SPD)).toBe(0); + const [ shuckle, ninjask ] = game.scene.getPlayerParty(); game.move.select(Moves.U_TURN); game.doSelectPartyPokemon(1); await game.toNextTurn(); - playerPokemon = game.scene.getPlayerPokemon()!; - expect(playerPokemon.getStatStage(Stat.SPD)).toBe(0); + expect(game.scene.getPlayerPokemon()!).toBe(ninjask); + expect(ninjask.getStatStage(Stat.SPD)).toBe(0); + + game.move.select(Moves.U_TURN); + game.doSelectPartyPokemon(1); + await game.toNextTurn(); + expect(game.scene.getPlayerPokemon()!).toBe(shuckle); + expect(shuckle.getStatStage(Stat.SPD)).toBe(0); game.move.select(Moves.SPLASH); await game.toNextTurn(); - expect(playerPokemon.getStatStage(Stat.SPD)).toBe(1); + expect(shuckle.getStatStage(Stat.SPD)).toBe(1); }); it("should not trigger this turn if pokemon was switched into combat via normal switch, but the turn after", diff --git a/src/test/abilities/sturdy.test.ts b/src/test/abilities/sturdy.test.ts index 49384e69f83..07ccbbb68e5 100644 --- a/src/test/abilities/sturdy.test.ts +++ b/src/test/abilities/sturdy.test.ts @@ -1,5 +1,5 @@ import { EnemyPokemon } from "#app/field/pokemon"; -import { DamagePhase } from "#app/phases/damage-phase"; +import { DamageAnimPhase } from "#app/phases/damage-anim-phase"; import { MoveEndPhase } from "#app/phases/move-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; @@ -55,7 +55,7 @@ describe("Abilities - Sturdy", () => { enemyPokemon.hp = enemyPokemon.getMaxHp() - 1; game.move.select(Moves.CLOSE_COMBAT); - await game.phaseInterceptor.to(DamagePhase); + await game.phaseInterceptor.to(DamageAnimPhase); expect(enemyPokemon.hp).toBe(0); expect(enemyPokemon.isFainted()).toBe(true); @@ -81,7 +81,7 @@ describe("Abilities - Sturdy", () => { await game.startBattle(); game.move.select(Moves.CLOSE_COMBAT); - await game.phaseInterceptor.to(DamagePhase); + await game.phaseInterceptor.to(DamageAnimPhase); const enemyPokemon: EnemyPokemon = game.scene.getEnemyParty()[0]; expect(enemyPokemon.hp).toBe(0); diff --git a/src/test/battle/battle.test.ts b/src/test/battle/battle.test.ts index 656cc62ac59..d2b074acce0 100644 --- a/src/test/battle/battle.test.ts +++ b/src/test/battle/battle.test.ts @@ -3,7 +3,7 @@ import { Stat } from "#enums/stat"; import { GameModes, getGameMode } from "#app/game-mode"; import { BattleEndPhase } from "#app/phases/battle-end-phase"; import { CommandPhase } from "#app/phases/command-phase"; -import { DamagePhase } from "#app/phases/damage-phase"; +import { DamageAnimPhase } from "#app/phases/damage-anim-phase"; import { EncounterPhase } from "#app/phases/encounter-phase"; import { EnemyCommandPhase } from "#app/phases/enemy-command-phase"; import { LoginPhase } from "#app/phases/login-phase"; @@ -267,7 +267,7 @@ describe("Test Battle Phase", () => { ]); game.move.select(moveToUse); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); await game.killPokemon(game.scene.currentBattle.enemyParty[0]); expect(game.scene.currentBattle.enemyParty[0].isFainted()).toBe(true); await game.phaseInterceptor.to(VictoryPhase, false); diff --git a/src/test/battle/damage_calculation.test.ts b/src/test/battle/damage_calculation.test.ts index e6ecbe4646f..e6aca828156 100644 --- a/src/test/battle/damage_calculation.test.ts +++ b/src/test/battle/damage_calculation.test.ts @@ -102,7 +102,7 @@ describe("Battle Mechanics - Damage Calculation", () => { game.move.select(Moves.JUMP_KICK); - await game.phaseInterceptor.to("DamagePhase"); + await game.phaseInterceptor.to("DamageAnimPhase"); expect(shedinja.hp).toBe(shedinja.getMaxHp() - 1); }); diff --git a/src/test/items/leftovers.test.ts b/src/test/items/leftovers.test.ts index cfbf7c2f734..672151d97cb 100644 --- a/src/test/items/leftovers.test.ts +++ b/src/test/items/leftovers.test.ts @@ -1,4 +1,4 @@ -import { DamagePhase } from "#app/phases/damage-phase"; +import { DamageAnimPhase } from "#app/phases/damage-anim-phase"; import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; @@ -48,7 +48,7 @@ describe("Items - Leftovers", () => { game.move.select(Moves.SPLASH); // We should have less hp after the attack - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(leadPokemon.hp).toBeLessThan(leadPokemon.getMaxHp()); const leadHpAfterDamage = leadPokemon.hp; diff --git a/src/test/items/multi_lens.test.ts b/src/test/items/multi_lens.test.ts index c5e60c9f9e5..f4b4c5712ee 100644 --- a/src/test/items/multi_lens.test.ts +++ b/src/test/items/multi_lens.test.ts @@ -135,4 +135,57 @@ describe("Items - Multi Lens", () => { expect(damageResults[0]).toBe(Math.floor(playerPokemon.level * 0.75)); expect(damageResults[1]).toBe(Math.floor(playerPokemon.level * 0.25)); }); + + it("should result in correct damage for hp% attacks with 1 lens", async () => { + game.override.startingHeldItems([{ name: "MULTI_LENS", count: 1 }]) + .moveset(Moves.SUPER_FANG) + .ability(Abilities.COMPOUND_EYES) + .enemyLevel(1000) + .enemySpecies(Species.BLISSEY); // allows for unrealistically high levels of accuracy + + await game.classicMode.startBattle([ Species.MAGIKARP ]); + + const enemyPokemon = game.scene.getEnemyPokemon()!; + + game.move.select(Moves.SUPER_FANG); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + await game.phaseInterceptor.to("MoveEndPhase"); + expect(enemyPokemon.getHpRatio()).toBeCloseTo(0.5, 5); + }); + + it("should result in correct damage for hp% attacks with 2 lenses", async () => { + game.override.startingHeldItems([{ name: "MULTI_LENS", count: 2 }]) + .moveset(Moves.SUPER_FANG) + .ability(Abilities.COMPOUND_EYES) + .enemyMoveset(Moves.SPLASH) + .enemyLevel(1000) + .enemySpecies(Species.BLISSEY); // allows for unrealistically high levels of accuracy + + await game.classicMode.startBattle([ Species.MAGIKARP ]); + + const enemyPokemon = game.scene.getEnemyPokemon()!; + + game.move.select(Moves.SUPER_FANG); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + await game.phaseInterceptor.to("MoveEndPhase"); + expect(enemyPokemon.getHpRatio()).toBeCloseTo(0.5, 5); + }); + it("should result in correct damage for hp% attacks with 2 lenses + Parental Bond", async () => { + game.override.startingHeldItems([{ name: "MULTI_LENS", count: 2 }]) + .moveset(Moves.SUPER_FANG) + .ability(Abilities.PARENTAL_BOND) + .passiveAbility(Abilities.COMPOUND_EYES) + .enemyMoveset(Moves.SPLASH) + .enemyLevel(1000) + .enemySpecies(Species.BLISSEY); // allows for unrealistically high levels of accuracy + + await game.classicMode.startBattle([ Species.MAGIKARP ]); + + const enemyPokemon = game.scene.getEnemyPokemon()!; + + game.move.select(Moves.SUPER_FANG); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + await game.phaseInterceptor.to("MoveEndPhase"); + expect(enemyPokemon.getHpRatio()).toBeCloseTo(0.25, 5); + }); }); diff --git a/src/test/moves/dragon_tail.test.ts b/src/test/moves/dragon_tail.test.ts index 6b3e669f770..96db67279d3 100644 --- a/src/test/moves/dragon_tail.test.ts +++ b/src/test/moves/dragon_tail.test.ts @@ -1,5 +1,9 @@ import { BattlerIndex } from "#app/battle"; import { allMoves } from "#app/data/move"; +import { Status } from "#app/data/status-effect"; +import { Challenges } from "#enums/challenges"; +import { StatusEffect } from "#enums/status-effect"; +import { Type } from "#enums/type"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; @@ -193,4 +197,122 @@ describe("Moves - Dragon Tail", () => { expect(dratini.hp).toBe(Math.floor(dratini.getMaxHp() / 2)); expect(game.scene.getPlayerField().length).toBe(1); }); + + it("should force switches randomly", async () => { + game.override.enemyMoveset(Moves.DRAGON_TAIL) + .startingLevel(100) + .enemyLevel(1); + await game.classicMode.startBattle([ Species.BULBASAUR, Species.CHARMANDER, Species.SQUIRTLE ]); + + const [ bulbasaur, charmander, squirtle ] = game.scene.getPlayerParty(); + + // Turn 1: Mock an RNG call that calls for switching to 1st backup Pokemon (Charmander) + vi.spyOn(game.scene, "randBattleSeedInt").mockImplementation((range, min: number = 0) => { + return min; + }); + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.DRAGON_TAIL); + await game.toNextTurn(); + + expect(bulbasaur.isOnField()).toBe(false); + expect(charmander.isOnField()).toBe(true); + expect(squirtle.isOnField()).toBe(false); + expect(bulbasaur.getInverseHp()).toBeGreaterThan(0); + + // Turn 2: Mock an RNG call that calls for switching to 2nd backup Pokemon (Squirtle) + vi.spyOn(game.scene, "randBattleSeedInt").mockImplementation((range, min: number = 0) => { + return min + 1; + }); + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + + expect(bulbasaur.isOnField()).toBe(false); + expect(charmander.isOnField()).toBe(false); + expect(squirtle.isOnField()).toBe(true); + expect(charmander.getInverseHp()).toBeGreaterThan(0); + }); + + it("should not force a switch to a challenge-ineligible Pokemon", async () => { + game.override.enemyMoveset(Moves.DRAGON_TAIL) + .startingLevel(100) + .enemyLevel(1); + // Mono-Water challenge, Eevee is ineligible + game.challengeMode.addChallenge(Challenges.SINGLE_TYPE, Type.WATER + 1, 0); + await game.challengeMode.startBattle([ Species.LAPRAS, Species.EEVEE, Species.TOXAPEX, Species.PRIMARINA ]); + + const [ lapras, eevee, toxapex, primarina ] = game.scene.getPlayerParty(); + + // Turn 1: Mock an RNG call that would normally call for switching to Eevee, but it is ineligible + vi.spyOn(game.scene, "randBattleSeedInt").mockImplementation((range, min: number = 0) => { + return min; + }); + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + + expect(lapras.isOnField()).toBe(false); + expect(eevee.isOnField()).toBe(false); + expect(toxapex.isOnField()).toBe(true); + expect(primarina.isOnField()).toBe(false); + expect(lapras.getInverseHp()).toBeGreaterThan(0); + }); + + it("should not force a switch to a fainted Pokemon", async () => { + game.override.enemyMoveset([ Moves.SPLASH, Moves.DRAGON_TAIL ]) + .startingLevel(100) + .enemyLevel(1); + await game.classicMode.startBattle([ Species.LAPRAS, Species.EEVEE, Species.TOXAPEX, Species.PRIMARINA ]); + + const [ lapras, eevee, toxapex, primarina ] = game.scene.getPlayerParty(); + + // Turn 1: Eevee faints + eevee.hp = 0; + eevee.status = new Status(StatusEffect.FAINT); + expect(eevee.isFainted()).toBe(true); + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.SPLASH); + await game.toNextTurn(); + + // Turn 2: Mock an RNG call that would normally call for switching to Eevee, but it is fainted + vi.spyOn(game.scene, "randBattleSeedInt").mockImplementation((range, min: number = 0) => { + return min; + }); + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.DRAGON_TAIL); + await game.toNextTurn(); + + expect(lapras.isOnField()).toBe(false); + expect(eevee.isOnField()).toBe(false); + expect(toxapex.isOnField()).toBe(true); + expect(primarina.isOnField()).toBe(false); + expect(lapras.getInverseHp()).toBeGreaterThan(0); + }); + + it("should not force a switch if there are no available Pokemon to switch into", async () => { + game.override.enemyMoveset([ Moves.SPLASH, Moves.DRAGON_TAIL ]) + .startingLevel(100) + .enemyLevel(1); + await game.classicMode.startBattle([ Species.LAPRAS, Species.EEVEE ]); + + const [ lapras, eevee ] = game.scene.getPlayerParty(); + + // Turn 1: Eevee faints + eevee.hp = 0; + eevee.status = new Status(StatusEffect.FAINT); + expect(eevee.isFainted()).toBe(true); + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.SPLASH); + await game.toNextTurn(); + + // Turn 2: Mock an RNG call that would normally call for switching to Eevee, but it is fainted + vi.spyOn(game.scene, "randBattleSeedInt").mockImplementation((range, min: number = 0) => { + return min; + }); + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.DRAGON_TAIL); + await game.toNextTurn(); + + expect(lapras.isOnField()).toBe(true); + expect(eevee.isOnField()).toBe(false); + expect(lapras.getInverseHp()).toBeGreaterThan(0); + }); }); diff --git a/src/test/moves/dynamax_cannon.test.ts b/src/test/moves/dynamax_cannon.test.ts index 001f986bd52..269374f7514 100644 --- a/src/test/moves/dynamax_cannon.test.ts +++ b/src/test/moves/dynamax_cannon.test.ts @@ -1,6 +1,6 @@ import { BattlerIndex } from "#app/battle"; import { allMoves } from "#app/data/move"; -import { DamagePhase } from "#app/phases/damage-phase"; +import { DamageAnimPhase } from "#app/phases/damage-anim-phase"; import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; @@ -51,7 +51,7 @@ describe("Moves - Dynamax Cannon", () => { await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(dynamaxCannon.id); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(dynamaxCannon.calculateBattlePower).toHaveLastReturnedWith(100); }, 20000); @@ -65,7 +65,7 @@ describe("Moves - Dynamax Cannon", () => { await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(dynamaxCannon.id); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(dynamaxCannon.calculateBattlePower).toHaveLastReturnedWith(100); }, 20000); @@ -82,7 +82,7 @@ describe("Moves - Dynamax Cannon", () => { expect(phase.move.moveId).toBe(dynamaxCannon.id); // Force level cap to be 100 vi.spyOn(phase.getFirstTarget()!.scene, "getMaxExpLevel").mockReturnValue(100); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(dynamaxCannon.calculateBattlePower).toHaveLastReturnedWith(120); }, 20000); @@ -99,7 +99,7 @@ describe("Moves - Dynamax Cannon", () => { expect(phase.move.moveId).toBe(dynamaxCannon.id); // Force level cap to be 100 vi.spyOn(phase.getFirstTarget()!.scene, "getMaxExpLevel").mockReturnValue(100); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(dynamaxCannon.calculateBattlePower).toHaveLastReturnedWith(140); }, 20000); @@ -116,7 +116,7 @@ describe("Moves - Dynamax Cannon", () => { expect(phase.move.moveId).toBe(dynamaxCannon.id); // Force level cap to be 100 vi.spyOn(phase.getFirstTarget()!.scene, "getMaxExpLevel").mockReturnValue(100); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(dynamaxCannon.calculateBattlePower).toHaveLastReturnedWith(160); }, 20000); @@ -133,7 +133,7 @@ describe("Moves - Dynamax Cannon", () => { expect(phase.move.moveId).toBe(dynamaxCannon.id); // Force level cap to be 100 vi.spyOn(phase.getFirstTarget()!.scene, "getMaxExpLevel").mockReturnValue(100); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(dynamaxCannon.calculateBattlePower).toHaveLastReturnedWith(180); }, 20000); @@ -150,7 +150,7 @@ describe("Moves - Dynamax Cannon", () => { expect(phase.move.moveId).toBe(dynamaxCannon.id); // Force level cap to be 100 vi.spyOn(phase.getFirstTarget()!.scene, "getMaxExpLevel").mockReturnValue(100); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(dynamaxCannon.calculateBattlePower).toHaveLastReturnedWith(200); }, 20000); @@ -165,7 +165,7 @@ describe("Moves - Dynamax Cannon", () => { await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(dynamaxCannon.id); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(dynamaxCannon.calculateBattlePower).toHaveLastReturnedWith(200); }, 20000); }); diff --git a/src/test/moves/fissure.test.ts b/src/test/moves/fissure.test.ts index 12f075f1b55..15dabb971cc 100644 --- a/src/test/moves/fissure.test.ts +++ b/src/test/moves/fissure.test.ts @@ -1,7 +1,7 @@ import { Stat } from "#enums/stat"; import { Species } from "#app/enums/species"; import { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon"; -import { DamagePhase } from "#app/phases/damage-phase"; +import { DamageAnimPhase } from "#app/phases/damage-anim-phase"; import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; @@ -56,7 +56,7 @@ describe("Moves - Fissure", () => { game.override.enemyAbility(Abilities.FUR_COAT); game.move.select(Moves.FISSURE); - await game.phaseInterceptor.to(DamagePhase, true); + await game.phaseInterceptor.to(DamageAnimPhase, true); expect(enemyPokemon.isFainted()).toBe(true); }); diff --git a/src/test/moves/fusion_flare_bolt.test.ts b/src/test/moves/fusion_flare_bolt.test.ts index 1bcd0514357..dbd4479dff8 100644 --- a/src/test/moves/fusion_flare_bolt.test.ts +++ b/src/test/moves/fusion_flare_bolt.test.ts @@ -1,7 +1,7 @@ import { Stat } from "#enums/stat"; import { BattlerIndex } from "#app/battle"; import { allMoves } from "#app/data/move"; -import { DamagePhase } from "#app/phases/damage-phase"; +import { DamageAnimPhase } from "#app/phases/damage-anim-phase"; import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import { MoveEndPhase } from "#app/phases/move-end-phase"; import { MovePhase } from "#app/phases/move-phase"; @@ -58,12 +58,12 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(100); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(200); }, 20000); @@ -81,12 +81,12 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(100); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200); }, 20000); @@ -104,7 +104,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(100); await game.phaseInterceptor.to(MoveEndPhase); @@ -114,7 +114,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(200); }, 20000); @@ -133,7 +133,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(100); await game.phaseInterceptor.to(MoveEndPhase); @@ -142,7 +142,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(100); }, 20000); @@ -160,12 +160,12 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(100); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200); }, 20000); @@ -209,22 +209,22 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(100); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(200); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200); }, 20000); @@ -268,22 +268,22 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(100); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(200); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); - await game.phaseInterceptor.to(DamagePhase, false); + await game.phaseInterceptor.to(DamageAnimPhase, false); expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200); }, 20000); }); diff --git a/src/test/moves/glaive_rush.test.ts b/src/test/moves/glaive_rush.test.ts index b36c3e20c7a..9cfbfdd8727 100644 --- a/src/test/moves/glaive_rush.test.ts +++ b/src/test/moves/glaive_rush.test.ts @@ -41,11 +41,11 @@ describe("Moves - Glaive Rush", () => { enemy.hp = 1000; game.move.select(Moves.SHADOW_SNEAK); - await game.phaseInterceptor.to("DamagePhase"); + await game.phaseInterceptor.to("DamageAnimPhase"); const damageDealt = 1000 - enemy.hp; await game.phaseInterceptor.to("TurnEndPhase"); game.move.select(Moves.SHADOW_SNEAK); - await game.phaseInterceptor.to("DamagePhase"); + await game.phaseInterceptor.to("DamageAnimPhase"); expect(enemy.hp).toBeLessThanOrEqual(1001 - (damageDealt * 3)); }); diff --git a/src/test/moves/scale_shot.test.ts b/src/test/moves/scale_shot.test.ts index e4d768fa13a..cbaa6611f3e 100644 --- a/src/test/moves/scale_shot.test.ts +++ b/src/test/moves/scale_shot.test.ts @@ -1,6 +1,6 @@ import { BattlerIndex } from "#app/battle"; import { allMoves } from "#app/data/move"; -import { DamagePhase } from "#app/phases/damage-phase"; +import { DamageAnimPhase } from "#app/phases/damage-anim-phase"; import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import { MoveEndPhase } from "#app/phases/move-end-phase"; import { TurnEndPhase } from "#app/phases/turn-end-phase"; @@ -48,7 +48,7 @@ describe("Moves - Scale Shot", () => { await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); await game.phaseInterceptor.to(MoveEffectPhase); - await game.phaseInterceptor.to(DamagePhase); + await game.phaseInterceptor.to(DamageAnimPhase); //check that stats haven't changed after one or two hits have occurred await game.phaseInterceptor.to(MoveEffectPhase); diff --git a/src/test/moves/shell_side_arm.test.ts b/src/test/moves/shell_side_arm.test.ts index 9646d27f17e..41cbefb186b 100644 --- a/src/test/moves/shell_side_arm.test.ts +++ b/src/test/moves/shell_side_arm.test.ts @@ -26,7 +26,7 @@ describe("Moves - Shell Side Arm", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .moveset([ Moves.SHELL_SIDE_ARM ]) + .moveset([ Moves.SHELL_SIDE_ARM, Moves.SPLASH ]) .battleType("single") .startingLevel(100) .enemyLevel(100) @@ -69,6 +69,9 @@ describe("Moves - Shell Side Arm", () => { vi.spyOn(shellSideArmAttr, "apply"); + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + game.move.select(Moves.SHELL_SIDE_ARM); await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]); await game.phaseInterceptor.to("BerryPhase", false); diff --git a/src/test/moves/whirlwind.test.ts b/src/test/moves/whirlwind.test.ts index c16f38111f2..69232bee43a 100644 --- a/src/test/moves/whirlwind.test.ts +++ b/src/test/moves/whirlwind.test.ts @@ -1,11 +1,15 @@ -import { BattlerTagType } from "#app/enums/battler-tag-type"; +import { BattlerTagType } from "#enums/battler-tag-type"; +import { Challenges } from "#enums/challenges"; +import { Type } from "#enums/type"; import { MoveResult } from "#app/field/pokemon"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { Status } from "#app/data/status-effect"; +import { StatusEffect } from "#enums/status-effect"; describe("Moves - Whirlwind", () => { let phaserGame: Phaser.Game; @@ -25,8 +29,9 @@ describe("Moves - Whirlwind", () => { game = new GameManager(phaserGame); game.override .battleType("single") + .moveset(Moves.SPLASH) .enemyAbility(Abilities.BALL_FETCH) - .enemyMoveset(Moves.WHIRLWIND) + .enemyMoveset([ Moves.SPLASH, Moves.WHIRLWIND ]) .enemySpecies(Species.PIDGEY); }); @@ -41,10 +46,114 @@ describe("Moves - Whirlwind", () => { const staraptor = game.scene.getPlayerPokemon()!; game.move.select(move); + await game.forceEnemyMove(Moves.WHIRLWIND); await game.phaseInterceptor.to("BerryPhase", false); expect(staraptor.findTag((t) => t.tagType === BattlerTagType.FLYING)).toBeDefined(); expect(game.scene.getEnemyPokemon()!.getLastXMoves(1)[0].result).toBe(MoveResult.MISS); }); + + it("should force switches randomly", async () => { + await game.classicMode.startBattle([ Species.BULBASAUR, Species.CHARMANDER, Species.SQUIRTLE ]); + + const [ bulbasaur, charmander, squirtle ] = game.scene.getPlayerParty(); + + // Turn 1: Mock an RNG call that calls for switching to 1st backup Pokemon (Charmander) + vi.spyOn(game.scene, "randBattleSeedInt").mockImplementation((range, min: number = 0) => { + return min; + }); + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.WHIRLWIND); + await game.toNextTurn(); + + expect(bulbasaur.isOnField()).toBe(false); + expect(charmander.isOnField()).toBe(true); + expect(squirtle.isOnField()).toBe(false); + + // Turn 2: Mock an RNG call that calls for switching to 2nd backup Pokemon (Squirtle) + vi.spyOn(game.scene, "randBattleSeedInt").mockImplementation((range, min: number = 0) => { + return min + 1; + }); + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.WHIRLWIND); + await game.toNextTurn(); + + expect(bulbasaur.isOnField()).toBe(false); + expect(charmander.isOnField()).toBe(false); + expect(squirtle.isOnField()).toBe(true); + }); + + it("should not force a switch to a challenge-ineligible Pokemon", async () => { + // Mono-Water challenge, Eevee is ineligible + game.challengeMode.addChallenge(Challenges.SINGLE_TYPE, Type.WATER + 1, 0); + await game.challengeMode.startBattle([ Species.LAPRAS, Species.EEVEE, Species.TOXAPEX, Species.PRIMARINA ]); + + const [ lapras, eevee, toxapex, primarina ] = game.scene.getPlayerParty(); + + // Turn 1: Mock an RNG call that would normally call for switching to Eevee, but it is ineligible + vi.spyOn(game.scene, "randBattleSeedInt").mockImplementation((range, min: number = 0) => { + return min; + }); + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.WHIRLWIND); + await game.toNextTurn(); + + expect(lapras.isOnField()).toBe(false); + expect(eevee.isOnField()).toBe(false); + expect(toxapex.isOnField()).toBe(true); + expect(primarina.isOnField()).toBe(false); + }); + + it("should not force a switch to a fainted Pokemon", async () => { + await game.classicMode.startBattle([ Species.LAPRAS, Species.EEVEE, Species.TOXAPEX, Species.PRIMARINA ]); + + const [ lapras, eevee, toxapex, primarina ] = game.scene.getPlayerParty(); + + // Turn 1: Eevee faints + eevee.hp = 0; + eevee.status = new Status(StatusEffect.FAINT); + expect(eevee.isFainted()).toBe(true); + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.SPLASH); + await game.toNextTurn(); + + // Turn 2: Mock an RNG call that would normally call for switching to Eevee, but it is fainted + vi.spyOn(game.scene, "randBattleSeedInt").mockImplementation((range, min: number = 0) => { + return min; + }); + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.WHIRLWIND); + await game.toNextTurn(); + + expect(lapras.isOnField()).toBe(false); + expect(eevee.isOnField()).toBe(false); + expect(toxapex.isOnField()).toBe(true); + expect(primarina.isOnField()).toBe(false); + }); + + it("should not force a switch if there are no available Pokemon to switch into", async () => { + await game.classicMode.startBattle([ Species.LAPRAS, Species.EEVEE ]); + + const [ lapras, eevee ] = game.scene.getPlayerParty(); + + // Turn 1: Eevee faints + eevee.hp = 0; + eevee.status = new Status(StatusEffect.FAINT); + expect(eevee.isFainted()).toBe(true); + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.SPLASH); + await game.toNextTurn(); + + // Turn 2: Mock an RNG call that would normally call for switching to Eevee, but it is fainted + vi.spyOn(game.scene, "randBattleSeedInt").mockImplementation((range, min: number = 0) => { + return min; + }); + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.WHIRLWIND); + await game.toNextTurn(); + + expect(lapras.isOnField()).toBe(true); + expect(eevee.isOnField()).toBe(false); + }); }); diff --git a/src/test/mystery-encounter/encounter-test-utils.ts b/src/test/mystery-encounter/encounter-test-utils.ts index cd2fd2db042..ee67f1b5d39 100644 --- a/src/test/mystery-encounter/encounter-test-utils.ts +++ b/src/test/mystery-encounter/encounter-test-utils.ts @@ -33,7 +33,7 @@ export async function runMysteryEncounterToEnd(game: GameManager, optionNo: numb }, () => game.isCurrentPhase(MysteryEncounterBattlePhase) || game.isCurrentPhase(MysteryEncounterRewardsPhase)); if (isBattle) { - game.onNextPrompt("DamagePhase", Mode.MESSAGE, () => { + game.onNextPrompt("DamageAnimPhase", Mode.MESSAGE, () => { game.setMode(Mode.MESSAGE); game.endPhase(); }, () => game.isCurrentPhase(CommandPhase)); diff --git a/src/test/mystery-encounter/encounters/safari-zone.test.ts b/src/test/mystery-encounter/encounters/safari-zone.test.ts new file mode 100644 index 00000000000..5699afe254f --- /dev/null +++ b/src/test/mystery-encounter/encounters/safari-zone.test.ts @@ -0,0 +1,173 @@ +import * as MysteryEncounters from "#app/data/mystery-encounters/mystery-encounters"; +import { Biome } from "#enums/biome"; +import { MysteryEncounterType } from "#enums/mystery-encounter-type"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { runMysteryEncounterToEnd, runSelectMysteryEncounterOption } from "#test/mystery-encounter/encounter-test-utils"; +import BattleScene from "#app/battle-scene"; +import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; +import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; +import { initSceneWithoutEncounterPhase } from "#test/utils/gameManagerUtils"; +import MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; +import { MysteryEncounterPhase } from "#app/phases/mystery-encounter-phases"; +import { getSafariSpeciesSpawn, SafariZoneEncounter } from "#app/data/mystery-encounters/encounters/safari-zone-encounter"; +import * as EncounterPhaseUtils from "#app/data/mystery-encounters/utils/encounter-phase-utils"; +import { NON_LEGEND_PARADOX_POKEMON } from "#app/data/balance/special-species-groups"; + +const namespace = "mysteryEncounters/safariZone"; +const defaultParty = [ Species.LAPRAS, Species.GENGAR, Species.ABRA ]; +const defaultBiome = Biome.SWAMP; +const defaultWave = 45; + +describe("Safari Zone - Mystery Encounter", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + let scene: BattleScene; + + beforeAll(() => { + phaserGame = new Phaser.Game({ type: Phaser.HEADLESS }); + }); + + beforeEach(async () => { + game = new GameManager(phaserGame); + scene = game.scene; + game.override.mysteryEncounterChance(100); + game.override.startingWave(defaultWave); + game.override.startingBiome(defaultBiome); + game.override.disableTrainerWaves(); + + const biomeMap = new Map([ + [ Biome.VOLCANO, [ MysteryEncounterType.FIGHT_OR_FLIGHT ]], + [ Biome.FOREST, [ MysteryEncounterType.SAFARI_ZONE ]], + [ Biome.SWAMP, [ MysteryEncounterType.SAFARI_ZONE ]], + [ Biome.JUNGLE, [ MysteryEncounterType.SAFARI_ZONE ]], + ]); + vi.spyOn(MysteryEncounters, "mysteryEncountersByBiome", "get").mockReturnValue(biomeMap); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + vi.clearAllMocks(); + vi.resetAllMocks(); + }); + + it("should have the correct properties", async () => { + await game.runToMysteryEncounter(MysteryEncounterType.SAFARI_ZONE, defaultParty); + + expect(SafariZoneEncounter.encounterType).toBe(MysteryEncounterType.SAFARI_ZONE); + expect(SafariZoneEncounter.encounterTier).toBe(MysteryEncounterTier.GREAT); + expect(SafariZoneEncounter.dialogue).toBeDefined(); + expect(SafariZoneEncounter.dialogue.intro).toStrictEqual([ + { text: `${namespace}:intro` }, + ]); + expect(SafariZoneEncounter.dialogue.encounterOptionsDialogue?.title).toBe(`${namespace}:title`); + expect(SafariZoneEncounter.dialogue.encounterOptionsDialogue?.description).toBe(`${namespace}:description`); + expect(SafariZoneEncounter.dialogue.encounterOptionsDialogue?.query).toBe(`${namespace}:query`); + expect(SafariZoneEncounter.options.length).toBe(2); + }); + + it("should not spawn outside of the forest, swamp, or jungle biomes", async () => { + game.override.mysteryEncounterTier(MysteryEncounterTier.GREAT); + game.override.startingBiome(Biome.VOLCANO); + await game.runToMysteryEncounter(); + + expect(scene.currentBattle?.mysteryEncounter?.encounterType).not.toBe(MysteryEncounterType.SAFARI_ZONE); + }); + + it("should initialize fully", async () => { + initSceneWithoutEncounterPhase(scene, defaultParty); + scene.currentBattle.mysteryEncounter = new MysteryEncounter(SafariZoneEncounter); + const encounter = scene.currentBattle.mysteryEncounter!; + scene.currentBattle.waveIndex = defaultWave; + + const { onInit } = encounter; + + expect(encounter.onInit).toBeDefined(); + + encounter.populateDialogueTokensFromRequirements(scene); + const onInitResult = onInit!(scene); + expect(onInitResult).toBe(true); + }); + + describe("Option 1 - Enter", () => { + it("should have the correct properties", () => { + const option = SafariZoneEncounter.options[0]; + expect(option.optionMode).toBe(MysteryEncounterOptionMode.DISABLED_OR_DEFAULT); + expect(option.dialogue).toBeDefined(); + expect(option.dialogue).toStrictEqual({ + buttonLabel: `${namespace}:option.1.label`, + buttonTooltip: `${namespace}:option.1.tooltip`, + selected: [ + { + text: `${namespace}:option.1.selected`, + }, + ], + }); + }); + + it("should NOT be selectable if the player doesn't have enough money", async () => { + game.scene.money = 0; + await game.runToMysteryEncounter(MysteryEncounterType.SAFARI_ZONE, defaultParty); + await game.phaseInterceptor.to(MysteryEncounterPhase, false); + + const encounterPhase = scene.getCurrentPhase(); + expect(encounterPhase?.constructor.name).toBe(MysteryEncounterPhase.name); + const mysteryEncounterPhase = encounterPhase as MysteryEncounterPhase; + vi.spyOn(mysteryEncounterPhase, "continueEncounter"); + vi.spyOn(mysteryEncounterPhase, "handleOptionSelect"); + vi.spyOn(scene.ui, "playError"); + + await runSelectMysteryEncounterOption(game, 1); + + expect(scene.getCurrentPhase()?.constructor.name).toBe(MysteryEncounterPhase.name); + expect(scene.ui.playError).not.toHaveBeenCalled(); // No error sfx, option is disabled + expect(mysteryEncounterPhase.handleOptionSelect).not.toHaveBeenCalled(); + expect(mysteryEncounterPhase.continueEncounter).not.toHaveBeenCalled(); + }); + + it("should not spawn any Paradox Pokemon", async () => { + const NUM_ROLLS = 2000; // As long as this is greater than total number of species, this should cover all possible RNG rolls + let rngSweepProgress = 0; // Will simulate full range of RNG rolls by steadily increasing from 0 to 1 + + vi.spyOn(Phaser.Math.RND, "realInRange").mockImplementation((min: number, max: number) => { + return rngSweepProgress * (max - min) + min; + }); + vi.spyOn(Phaser.Math.RND, "shuffle").mockImplementation((arr: any[]) => arr); + + for (let i = 0; i < NUM_ROLLS; i++) { + rngSweepProgress = (2 * i + 1) / (2 * NUM_ROLLS); + const simSpecies = getSafariSpeciesSpawn().speciesId; + expect(NON_LEGEND_PARADOX_POKEMON).not.toContain(simSpecies); + } + }); + + // TODO: Tests for player actions inside the Safari Zone (Pokeball, Mud, Bait, Flee) + }); + + describe("Option 2 - Leave", () => { + it("should have the correct properties", () => { + const option = SafariZoneEncounter.options[1]; + expect(option.optionMode).toBe(MysteryEncounterOptionMode.DEFAULT); + expect(option.dialogue).toBeDefined(); + expect(option.dialogue).toStrictEqual({ + buttonLabel: `${namespace}:option.2.label`, + buttonTooltip: `${namespace}:option.2.tooltip`, + selected: [ + { + text: `${namespace}:option.2.selected`, + }, + ], + }); + }); + + it("should leave encounter without battle", async () => { + const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle"); + + await game.runToMysteryEncounter(MysteryEncounterType.SAFARI_ZONE, defaultParty); + await runMysteryEncounterToEnd(game, 2); + + expect(leaveEncounterWithoutBattleSpy).toBeCalled(); + }); + }); +}); diff --git a/src/test/mystery-encounter/encounters/the-pokemon-salesman-encounter.test.ts b/src/test/mystery-encounter/encounters/the-pokemon-salesman-encounter.test.ts index a50c0cf4c9e..91b4a4bcab5 100644 --- a/src/test/mystery-encounter/encounters/the-pokemon-salesman-encounter.test.ts +++ b/src/test/mystery-encounter/encounters/the-pokemon-salesman-encounter.test.ts @@ -9,11 +9,12 @@ import { runMysteryEncounterToEnd, runSelectMysteryEncounterOption } from "#test import BattleScene from "#app/battle-scene"; import { PlayerPokemon } from "#app/field/pokemon"; import { HUMAN_TRANSITABLE_BIOMES } from "#app/data/mystery-encounters/mystery-encounters"; -import { ThePokemonSalesmanEncounter } from "#app/data/mystery-encounters/encounters/the-pokemon-salesman-encounter"; +import { getSalesmanSpeciesOffer, ThePokemonSalesmanEncounter } from "#app/data/mystery-encounters/encounters/the-pokemon-salesman-encounter"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { initSceneWithoutEncounterPhase } from "#test/utils/gameManagerUtils"; import { MysteryEncounterPhase } from "#app/phases/mystery-encounter-phases"; +import { NON_LEGEND_PARADOX_POKEMON } from "#app/data/balance/special-species-groups"; const namespace = "mysteryEncounters/thePokemonSalesman"; const defaultParty = [ Species.LAPRAS, Species.GENGAR, Species.ABRA ]; @@ -172,6 +173,22 @@ describe("The Pokemon Salesman - Mystery Encounter", () => { expect(mysteryEncounterPhase.continueEncounter).not.toHaveBeenCalled(); }); + it("should not offer any Paradox Pokemon", async () => { + const NUM_ROLLS = 2000; // As long as this is greater than total number of species, this should cover all possible RNG rolls + let rngSweepProgress = 0; // Will simulate full range of RNG rolls by steadily increasing from 0 to 1 + + vi.spyOn(Phaser.Math.RND, "realInRange").mockImplementation((min: number, max: number) => { + return rngSweepProgress * (max - min) + min; + }); + vi.spyOn(Phaser.Math.RND, "shuffle").mockImplementation((arr: any[]) => arr); + + for (let i = 0; i < NUM_ROLLS; i++) { + rngSweepProgress = (2 * i + 1) / (2 * NUM_ROLLS); + const simSpecies = getSalesmanSpeciesOffer().speciesId; + expect(NON_LEGEND_PARADOX_POKEMON).not.toContain(simSpecies); + } + }); + it("should leave encounter without battle", async () => { scene.money = 20000; const leaveEncounterWithoutBattleSpy = vi.spyOn(EncounterPhaseUtils, "leaveEncounterWithoutBattle"); diff --git a/src/test/mystery-encounter/mystery-encounter-utils.test.ts b/src/test/mystery-encounter/mystery-encounter-utils.test.ts index ab2d5f052c0..d17b5c8a587 100644 --- a/src/test/mystery-encounter/mystery-encounter-utils.test.ts +++ b/src/test/mystery-encounter/mystery-encounter-utils.test.ts @@ -2,7 +2,7 @@ import BattleScene from "#app/battle-scene"; import { speciesStarterCosts } from "#app/data/balance/starters"; import MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; import { getEncounterText, queueEncounterMessage, showEncounterDialogue, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; -import { getHighestLevelPlayerPokemon, getLowestLevelPlayerPokemon, getRandomPlayerPokemon, getRandomSpeciesByStarterTier, koPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; +import { getHighestLevelPlayerPokemon, getLowestLevelPlayerPokemon, getRandomPlayerPokemon, getRandomSpeciesByStarterCost, koPlayerPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; import { getPokemonSpecies } from "#app/data/pokemon-species"; import { Type } from "#enums/type"; import { MessagePhase } from "#app/phases/message-phase"; @@ -204,9 +204,9 @@ describe("Mystery Encounter Utils", () => { }); }); - describe("getRandomSpeciesByStarterTier", () => { + describe("getRandomSpeciesByStarterCost", () => { it("gets species for a starter tier", () => { - const result = getRandomSpeciesByStarterTier(5); + const result = getRandomSpeciesByStarterCost(5); const pokeSpecies = getPokemonSpecies(result); expect(pokeSpecies.speciesId).toBe(result); @@ -214,7 +214,7 @@ describe("Mystery Encounter Utils", () => { }); it("gets species for a starter tier range", () => { - const result = getRandomSpeciesByStarterTier([ 5, 8 ]); + const result = getRandomSpeciesByStarterCost([ 5, 8 ]); const pokeSpecies = getPokemonSpecies(result); expect(pokeSpecies.speciesId).toBe(result); @@ -224,14 +224,14 @@ describe("Mystery Encounter Utils", () => { it("excludes species from search", () => { // Only 9 tiers are: Koraidon, Miraidon, Arceus, Rayquaza, Kyogre, Groudon, Zacian - const result = getRandomSpeciesByStarterTier(9, [ Species.KORAIDON, Species.MIRAIDON, Species.ARCEUS, Species.RAYQUAZA, Species.KYOGRE, Species.GROUDON ]); + const result = getRandomSpeciesByStarterCost(9, [ Species.KORAIDON, Species.MIRAIDON, Species.ARCEUS, Species.RAYQUAZA, Species.KYOGRE, Species.GROUDON ]); const pokeSpecies = getPokemonSpecies(result); expect(pokeSpecies.speciesId).toBe(Species.ZACIAN); }); it("gets species of specified types", () => { // Only 9 tiers are: Koraidon, Miraidon, Arceus, Rayquaza, Kyogre, Groudon, Zacian - const result = getRandomSpeciesByStarterTier(9, undefined, [ Type.GROUND ]); + const result = getRandomSpeciesByStarterCost(9, undefined, [ Type.GROUND ]); const pokeSpecies = getPokemonSpecies(result); expect(pokeSpecies.speciesId).toBe(Species.GROUDON); }); diff --git a/src/test/utils/phaseInterceptor.ts b/src/test/utils/phaseInterceptor.ts index 4029e5e168c..13750609004 100644 --- a/src/test/utils/phaseInterceptor.ts +++ b/src/test/utils/phaseInterceptor.ts @@ -5,7 +5,7 @@ import { BattleEndPhase } from "#app/phases/battle-end-phase"; import { BerryPhase } from "#app/phases/berry-phase"; import { CheckSwitchPhase } from "#app/phases/check-switch-phase"; import { CommandPhase } from "#app/phases/command-phase"; -import { DamagePhase } from "#app/phases/damage-phase"; +import { DamageAnimPhase } from "#app/phases/damage-anim-phase"; import { EggLapsePhase } from "#app/phases/egg-lapse-phase"; import { EncounterPhase } from "#app/phases/encounter-phase"; import { EndEvolutionPhase } from "#app/phases/end-evolution-phase"; @@ -87,7 +87,7 @@ type PhaseClass = | typeof TurnStartPhase | typeof MovePhase | typeof MoveEffectPhase - | typeof DamagePhase + | typeof DamageAnimPhase | typeof FaintPhase | typeof BerryPhase | typeof TurnEndPhase @@ -146,7 +146,7 @@ type PhaseString = | "TurnStartPhase" | "MovePhase" | "MoveEffectPhase" - | "DamagePhase" + | "DamageAnimPhase" | "FaintPhase" | "BerryPhase" | "TurnEndPhase" @@ -229,7 +229,7 @@ export default class PhaseInterceptor { [ TurnStartPhase, this.startPhase ], [ MovePhase, this.startPhase ], [ MoveEffectPhase, this.startPhase ], - [ DamagePhase, this.startPhase ], + [ DamageAnimPhase, this.startPhase ], [ FaintPhase, this.startPhase ], [ BerryPhase, this.startPhase ], [ TurnEndPhase, this.startPhase ], diff --git a/src/ui/login-form-ui-handler.ts b/src/ui/login-form-ui-handler.ts index bba900aef0a..d3c3663ec4b 100644 --- a/src/ui/login-form-ui-handler.ts +++ b/src/ui/login-form-ui-handler.ts @@ -8,6 +8,7 @@ import { addTextObject, TextStyle } from "./text"; import { addWindow } from "./ui-theme"; import { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler"; import { pokerogueApi } from "#app/plugins/api/pokerogue-api"; +import JSZip from "jszip"; interface BuildInteractableImageOpts { scale?: number; @@ -27,6 +28,7 @@ export default class LoginFormUiHandler extends FormModalUiHandler { private googleImage: Phaser.GameObjects.Image; private discordImage: Phaser.GameObjects.Image; private usernameInfoImage: Phaser.GameObjects.Image; + private saveDownloadImage: Phaser.GameObjects.Image; private externalPartyContainer: Phaser.GameObjects.Container; private infoContainer: Phaser.GameObjects.Container; private externalPartyBg: Phaser.GameObjects.NineSlice; @@ -46,7 +48,13 @@ export default class LoginFormUiHandler extends FormModalUiHandler { scale: 0.5 }); + this.saveDownloadImage = this.buildInteractableImage("saving_icon", "save-download-icon", { + x: 0, + scale: 0.75 + }); + this.infoContainer.add(this.usernameInfoImage); + this.infoContainer.add(this.saveDownloadImage); this.getUi().add(this.infoContainer); this.infoContainer.setVisible(false); this.infoContainer.disableInteractive(); @@ -160,7 +168,7 @@ export default class LoginFormUiHandler extends FormModalUiHandler { this.infoContainer.setVisible(false); this.setMouseCursorStyle("default"); //reset cursor - [ this.discordImage, this.googleImage, this.usernameInfoImage ].forEach((img) => img.off("pointerdown")); + [ this.discordImage, this.googleImage, this.usernameInfoImage, this.saveDownloadImage ].forEach((img) => img.off("pointerdown")); } private processExternalProvider(config: ModalConfig): void { @@ -178,6 +186,7 @@ export default class LoginFormUiHandler extends FormModalUiHandler { this.infoContainer.setVisible(true); this.getUi().moveTo(this.infoContainer, this.getUi().length - 1); this.usernameInfoImage.setPositionRelative(this.infoContainer, 0, 0); + this.saveDownloadImage.setPositionRelative(this.infoContainer, 20, 0); this.discordImage.on("pointerdown", () => { const redirectUri = encodeURIComponent(`${import.meta.env.VITE_SERVER_URL}/auth/discord/callback`); @@ -229,6 +238,34 @@ export default class LoginFormUiHandler extends FormModalUiHandler { } }); + this.saveDownloadImage.on("pointerdown", () => { + // find all data_ and sessionData keys, put them in a .txt file and download everything in a single zip + const localStorageKeys = Object.keys(localStorage); // this gets the keys for localStorage + const keyToFind = "data_"; + const sessionKeyToFind = "sessionData"; + const dataKeys = localStorageKeys.filter(ls => ls.indexOf(keyToFind) >= 0); + const sessionKeys = localStorageKeys.filter(ls => ls.indexOf(sessionKeyToFind) >= 0); + if (dataKeys.length > 0 || sessionKeys.length > 0) { + const zip = new JSZip(); + for (let i = 0; i < dataKeys.length; i++) { + zip.file(dataKeys[i] + ".prsv", localStorage.getItem(dataKeys[i])!); + } + for (let i = 0; i < sessionKeys.length; i++) { + zip.file(sessionKeys[i] + ".prsv", localStorage.getItem(sessionKeys[i])!); + } + zip.generateAsync({ type: "blob" }).then(content => { + const url = URL.createObjectURL(content); + const a = document.createElement("a"); + a.href = url; + a.download = "pokerogue_saves.zip"; + a.click(); + URL.revokeObjectURL(url); + }); + } else { + return onFail(this.ERR_NO_SAVES); + } + }); + this.externalPartyContainer.setAlpha(0); this.scene.tweens.add({ targets: this.externalPartyContainer, diff --git a/src/ui/pokemon-info-container.ts b/src/ui/pokemon-info-container.ts index ead24e6d92f..e0d432265a3 100644 --- a/src/ui/pokemon-info-container.ts +++ b/src/ui/pokemon-info-container.ts @@ -313,6 +313,11 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { this.pokemonShinyNewIcon.setShadowColor(getTextColor(TextStyle.SUMMARY_BLUE, true, this.scene.uiTheme)); const newShinyOrVariant = ((newShiny & caughtAttr) === BigInt(0)) || ((newVariant & caughtAttr) === BigInt(0)); this.pokemonShinyNewIcon.setVisible(!!newShinyOrVariant); + } else if ((caughtAttr & DexAttr.NON_SHINY) === BigInt(0) && ((caughtAttr & DexAttr.SHINY) === DexAttr.SHINY)) { //If the player has *only* caught any shiny variant of this species, not a non-shiny + this.pokemonShinyNewIcon.setVisible(true); + this.pokemonShinyNewIcon.setText("(+)"); + this.pokemonShinyNewIcon.setColor(getTextColor(TextStyle.SUMMARY_BLUE, false, this.scene.uiTheme)); + this.pokemonShinyNewIcon.setShadowColor(getTextColor(TextStyle.SUMMARY_BLUE, true, this.scene.uiTheme)); } else { this.pokemonShinyNewIcon.setVisible(false); } diff --git a/src/ui/settings/abstract-settings-ui-handler.ts b/src/ui/settings/abstract-settings-ui-handler.ts index 83219e1ef5a..cbc93887810 100644 --- a/src/ui/settings/abstract-settings-ui-handler.ts +++ b/src/ui/settings/abstract-settings-ui-handler.ts @@ -1,8 +1,7 @@ import BattleScene from "#app/battle-scene"; -import { hasTouchscreen, isMobile } from "#app/touch-controls"; import { TextStyle, addTextObject } from "#app/ui/text"; import { Mode } from "#app/ui/ui"; -import UiHandler from "#app/ui/ui-handler"; +import MessageUiHandler from "#app/ui/message-ui-handler"; import { addWindow } from "#app/ui/ui-theme"; import { ScrollBar } from "#app/ui/scroll-bar"; import { Button } from "#enums/buttons"; @@ -15,9 +14,10 @@ import i18next from "i18next"; /** * Abstract class for handling UI elements related to settings. */ -export default class AbstractSettingsUiHandler extends UiHandler { +export default class AbstractSettingsUiHandler extends MessageUiHandler { private settingsContainer: Phaser.GameObjects.Container; private optionsContainer: Phaser.GameObjects.Container; + private messageBoxContainer: Phaser.GameObjects.Container; private navigationContainer: NavigationMenu; private scrollCursor: number; @@ -135,6 +135,23 @@ export default class AbstractSettingsUiHandler extends UiHandler { this.scrollBar = new ScrollBar(this.scene, this.optionsBg.width - 9, this.optionsBg.y + 5, 4, this.optionsBg.height - 11, this.rowsToDisplay); this.scrollBar.setTotalRows(this.settings.length); + // Two-lines message box + this.messageBoxContainer = this.scene.add.container(0, this.scene.scaledCanvas.height); + this.messageBoxContainer.setName("settings-message-box"); + this.messageBoxContainer.setVisible(false); + + const settingsMessageBox = addWindow(this.scene, 0, -1, this.scene.scaledCanvas.width - 2, 48); + settingsMessageBox.setOrigin(0, 1); + this.messageBoxContainer.add(settingsMessageBox); + + const messageText = addTextObject(this.scene, 8, -40, "", TextStyle.WINDOW, { maxLines: 2 }); + messageText.setWordWrapWidth(this.scene.game.canvas.width - 60); + messageText.setName("settings-message"); + messageText.setOrigin(0, 0); + + this.messageBoxContainer.add(messageText); + this.message = messageText; + this.settingsContainer.add(this.optionsBg); this.settingsContainer.add(this.scrollBar); this.settingsContainer.add(this.navigationContainer); @@ -144,6 +161,7 @@ export default class AbstractSettingsUiHandler extends UiHandler { this.settingsContainer.add(iconCancel); this.settingsContainer.add(actionText); this.settingsContainer.add(cancelText); + this.settingsContainer.add(this.messageBoxContainer); ui.add(this.settingsContainer); @@ -326,18 +344,16 @@ export default class AbstractSettingsUiHandler extends UiHandler { /** * Set the option cursor to the specified position. * - * @param settingIndex - The index of the setting. + * @param settingIndex - The index of the setting or -1 to change the current setting * @param cursor - The cursor position to set. * @param save - Whether to save the setting to local storage. * @returns `true` if the option cursor was set successfully. */ setOptionCursor(settingIndex: number, cursor: number, save?: boolean): boolean { - const setting = this.settings[settingIndex]; - - if (setting.key === SettingKeys.Touch_Controls && cursor && hasTouchscreen() && isMobile()) { - this.getUi().playError(); - return false; + if (settingIndex === -1) { + settingIndex = this.cursor + this.scrollCursor; } + const setting = this.settings[settingIndex]; const lastCursor = this.optionCursors[settingIndex]; @@ -352,9 +368,33 @@ export default class AbstractSettingsUiHandler extends UiHandler { newValueLabel.setShadowColor(this.getTextColor(TextStyle.SETTINGS_SELECTED, true)); if (save) { - this.scene.gameData.saveSetting(setting.key, cursor); - if (this.reloadSettings.includes(setting)) { - this.reloadRequired = true; + const saveSetting = () => { + this.scene.gameData.saveSetting(setting.key, cursor); + if (setting.requireReload) { + this.reloadRequired = true; + } + }; + + // For settings that ask for confirmation, display confirmation message and a Yes/No prompt before saving the setting + if (setting.options[cursor].needConfirmation) { + const confirmUpdateSetting = () => { + this.scene.ui.revertMode(); + this.showText(""); + saveSetting(); + }; + const cancelUpdateSetting = () => { + this.scene.ui.revertMode(); + this.showText(""); + // Put the cursor back to its previous position without saving or asking for confirmation again + this.setOptionCursor(settingIndex, lastCursor, false); + }; + + const confirmationMessage = setting.options[cursor].confirmationMessage ?? i18next.t("settings:defaultConfirmMessage"); + this.scene.ui.showText(confirmationMessage, null, () => { + this.scene.ui.setOverlayMode(Mode.CONFIRM, confirmUpdateSetting, cancelUpdateSetting, null, null, 1, 750); + }); + } else { + saveSetting(); } } @@ -421,4 +461,9 @@ export default class AbstractSettingsUiHandler extends UiHandler { } this.cursorObj = null; } + + override showText(text: string, delay?: integer, callback?: Function, callbackDelay?: integer, prompt?: boolean, promptDelay?: integer) { + this.messageBoxContainer.setVisible(!!text?.length); + super.showText(text, delay, callback, callbackDelay, prompt, promptDelay); + } }