Merge branch 'beta' into toxic_spikes

This commit is contained in:
NightKev 2024-09-04 18:41:40 -07:00
commit 63d55abcc9
343 changed files with 11930 additions and 18621 deletions

View File

@ -30,7 +30,7 @@
- [ ] The PR is self-contained and cannot be split into smaller PRs? - [ ] The PR is self-contained and cannot be split into smaller PRs?
- [ ] Have I provided a clear explanation of the changes? - [ ] Have I provided a clear explanation of the changes?
- [ ] Have I considered writing automated tests for the issue? - [ ] Have I considered writing automated tests for the issue?
- [ ] If I have text, did I add make it translatable and added a key in the English language? - [ ] If I have text, did I make it translatable and add a key in the English locale file(s)?
- [ ] Have I tested the changes (manually)? - [ ] Have I tested the changes (manually)?
- [ ] Are all unit tests still passing? (`npm run test`) - [ ] Are all unit tests still passing? (`npm run test`)
- [ ] Are the changes visual? - [ ] Are the changes visual?

View File

@ -11,6 +11,8 @@ on:
branches: branches:
- main # Trigger on pull request events targeting the main branch - main # Trigger on pull request events targeting the main branch
- beta # Trigger on pull request events targeting the beta branch - beta # Trigger on pull request events targeting the beta branch
merge_group:
types: [checks_requested]
jobs: jobs:
run-linters: # Define a job named "run-linters" run-linters: # Define a job named "run-linters"

View File

@ -8,6 +8,8 @@ on:
branches: branches:
- main - main
- beta - beta
merge_group:
types: [checks_requested]
jobs: jobs:
pages: pages:

View File

@ -11,6 +11,8 @@ on:
branches: branches:
- main # Trigger on pull request events targeting the main branch - main # Trigger on pull request events targeting the main branch
- beta # Trigger on pull request events targeting the beta branch - beta # Trigger on pull request events targeting the beta branch
merge_group:
types: [checks_requested]
jobs: jobs:
run-tests: # Define a job named "run-tests" run-tests: # Define a job named "run-tests"

101
create-test-boilerplate.js Normal file
View File

@ -0,0 +1,101 @@
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
/**
* This script creates a test boilerplate file for a move or ability.
* @param {string} type - The type of test to create. Either "move" or "ability".
* @param {string} fileName - The name of the file to create.
* @example npm run create-test move tackle
*/
// Get the directory name of the current module file
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Get the arguments from the command line
const args = process.argv.slice(2);
const type = args[0]; // "move" or "ability"
let fileName = args[1]; // The file name
if (!type || !fileName) {
console.error('Please provide both a type ("move" or "ability") and a file name.');
process.exit(1);
}
// Convert fileName from to snake_case if camelCase is given
fileName = fileName.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase();
// Format the description for the test case
const formattedName = fileName
.replace(/_/g, ' ')
.replace(/\b\w/g, char => char.toUpperCase());
// Determine the directory based on the type
let dir;
let description;
if (type === 'move') {
dir = path.join(__dirname, 'src', 'test', 'moves');
description = `Moves - ${formattedName}`;
} else if (type === 'ability') {
dir = path.join(__dirname, 'src', 'test', 'abilities');
description = `Abilities - ${formattedName}`;
} else {
console.error('Invalid type. Please use "move" or "ability".');
process.exit(1);
}
// Ensure the directory exists
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
// Create the file with the given name
const filePath = path.join(dir, `${fileName}.test.ts`);
if (fs.existsSync(filePath)) {
console.error(`File "${fileName}.test.ts" already exists.`);
process.exit(1);
}
// Define the content template
const content = `import { Abilities } from "#enums/abilities";
import GameManager from "#test/utils/gameManager";
import { SPLASH_ONLY } from "#test/utils/testUtils";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, it } from "vitest";
describe("${description}", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
const TIMEOUT = 20 * 1000;
beforeAll(() => {
phaserGame = new Phaser.Game({
type: Phaser.HEADLESS,
});
});
afterEach(() => {
game.phaseInterceptor.restoreOg();
});
beforeEach(() => {
game = new GameManager(phaserGame);
game.override
.battleType("single")
.enemyAbility(Abilities.BALL_FETCH)
.enemyMoveset(SPLASH_ONLY);
});
it("test case", async () => {
// await game.classicMode.startBattle();
// game.move.select();
}, TIMEOUT);
});
`;
// Write the template content to the file
fs.writeFileSync(filePath, content, 'utf8');
console.log(`File created at: ${filePath}`);

View File

@ -191,15 +191,15 @@ Now that the enemy Pokémon with the best matchup score is on the field (assumin
We then need to apply a 2x multiplier for the move's type effectiveness and a 1.5x multiplier since STAB applies. After applying these multipliers, the final score for this move is **75**. We then need to apply a 2x multiplier for the move's type effectiveness and a 1.5x multiplier since STAB applies. After applying these multipliers, the final score for this move is **75**.
- **Swords Dance**: As a non-attacking move, this move's benefit score is derived entirely from the sum of its attributes' benefit scores. Swords Dance's `StatChangeAttr` has a user benefit score of 0 and a target benefit score that, in this case, simplifies to - **Swords Dance**: As a non-attacking move, this move's benefit score is derived entirely from the sum of its attributes' benefit scores. Swords Dance's `StatStageChangeAttr` has a user benefit score of 0 and a target benefit score that, in this case, simplifies to
$\text{TBS}=4\times \text{levels} + (-2\times \text{sign(levels)})$ $\text{TBS}=4\times \text{levels} + (-2\times \text{sign(levels)})$
where `levels` is the number of stat stages added by the attribute (in this case, +2). The final score for this move is **6** (Note: because this move is self-targeted, we don't flip the sign of TBS when computing the target score). where `levels` is the number of stat stages added by the attribute (in this case, +2). The final score for this move is **6** (Note: because this move is self-targeted, we don't flip the sign of TBS when computing the target score).
- **Crush Claw**: This move is a 75-power Normal-type physical attack with a 50 percent chance to lower the target's Defense by one stage. The additional effect is implemented by the same `StatChangeAttr` as Swords Dance, so we can use the same formulas from before to compute the total TBS and base target score. - **Crush Claw**: This move is a 75-power Normal-type physical attack with a 50 percent chance to lower the target's Defense by one stage. The additional effect is implemented by the same `StatStageChangeAttr` as Swords Dance, so we can use the same formulas from before to compute the total TBS and base target score.
$\text{TBS}=\text{getTargetBenefitScore(StatChangeAttr)}-\text{attackScore}$ $\text{TBS}=\text{getTargetBenefitScore(StatStageChangeAttr)}-\text{attackScore}$
$\text{TBS}=(-4 + 2)-(-2\times 2 + \lfloor \frac{75}{5} \rfloor)=-2-11=-13$ $\text{TBS}=(-4 + 2)-(-2\times 2 + \lfloor \frac{75}{5} \rfloor)=-2-11=-13$

View File

@ -23,15 +23,6 @@ body {
} }
} }
#links {
width: 90%;
text-align: center;
position: fixed;
bottom: 0;
display: flex;
justify-content: space-around;
}
#app { #app {
display: flex; display: flex;
justify-content: center; justify-content: center;

View File

@ -39,7 +39,6 @@
</style> </style>
<link rel="stylesheet" type="text/css" href="./index.css" /> <link rel="stylesheet" type="text/css" href="./index.css" />
<link rel="manifest" href="./manifest.webmanifest"> <link rel="manifest" href="./manifest.webmanifest">
<script type="text/javascript" src="https://app.termly.io/resource-blocker/c5dbfa2f-9723-4c0f-a84b-2895124e851f?autoBlock=on"></script>
<script> <script>
if ("serviceWorker" in navigator) { if ("serviceWorker" in navigator) {
window.addEventListener("load", function () { window.addEventListener("load", function () {
@ -144,13 +143,6 @@
</div> </div>
</div> </div>
<div id="tnc-links">
<a href="#" class="termly-display-preferences" style="display: none;" target="_blank" rel="noreferrer noopener">Consent Preferences</a>
<a href="https://app.termly.io/policy-viewer/policy.html?policyUUID=bc96778b-3f04-4d25-bafc-0deba53e8bec" target="_blank" rel="noreferrer noopener">Privacy Policy</a>
<a href="https://app.termly.io/policy-viewer/policy.html?policyUUID=8b523c05-7ec2-4646-9534-5bd61b386e2a" target="_blank" rel="noreferrer noopener">Cookie Disclaimer</a>
<a href="https://app.termly.io/policy-viewer/policy.html?policyUUID=b01e092a-9721-477f-8356-45576702ff9e" target="_blank" rel="noreferrer noopener">Terms & Conditions</a>
<a href="https://app.termly.io/policy-viewer/policy.html?policyUUID=3b5d1928-3f5b-4ee1-b8df-2d6c276b0bcc" target="_blank" rel="noreferrer noopener">Acceptable Use Policy</a>
</div>
<script type="module" src="./src/main.ts"></script> <script type="module" src="./src/main.ts"></script>
<script src="./src/touch-controls.ts" type="module"></script> <script src="./src/touch-controls.ts" type="module"></script>
<script src="./src/debug.js" type="module"></script> <script src="./src/debug.js" type="module"></script>

View File

@ -18,7 +18,8 @@
"eslint-ci": "eslint .", "eslint-ci": "eslint .",
"docs": "typedoc", "docs": "typedoc",
"depcruise": "depcruise src", "depcruise": "depcruise src",
"depcruise:graph": "depcruise src --output-type dot | node dependency-graph.js > dependency-graph.svg" "depcruise:graph": "depcruise src --output-type dot | node dependency-graph.js > dependency-graph.svg",
"create-test": "node ./create-test-boilerplate.js"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.3.0", "@eslint/js": "^9.3.0",

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View File

@ -1,596 +1,529 @@
{"frames": [ { "frames": {
"0.png": {
{ "frame": { "x": 12, "y": 44, "w": 12, "h": 11 },
"filename": "0.png",
"frame": {"x":0,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "1.png": {
"filename": "1.png", "frame": { "x": 36, "y": 44, "w": 12, "h": 11 },
"frame": {"x":12,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "2.png": {
"filename": "2.png", "frame": { "x": 0, "y": 55, "w": 12, "h": 11 },
"frame": {"x":24,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "3.png": {
"filename": "3.png", "frame": { "x": 12, "y": 55, "w": 12, "h": 11 },
"frame": {"x":36,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "4.png": {
"filename": "4.png", "frame": { "x": 24, "y": 55, "w": 12, "h": 11 },
"frame": {"x":48,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "5.png": {
"filename": "5.png", "frame": { "x": 84, "y": 55, "w": 12, "h": 11 },
"frame": {"x":60,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "6.png": {
"filename": "6.png", "frame": { "x": 96, "y": 55, "w": 12, "h": 11 },
"frame": {"x":72,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "7.png": {
"filename": "7.png", "frame": { "x": 120, "y": 55, "w": 12, "h": 11 },
"frame": {"x":84,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "8.png": {
"filename": "8.png", "frame": { "x": 132, "y": 55, "w": 12, "h": 11 },
"frame": {"x":96,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "9.png": {
"filename": "9.png", "frame": { "x": 52, "y": 33, "w": 12, "h": 11 },
"frame": {"x":108,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "A.png": {
"filename": "A.png", "frame": { "x": 64, "y": 33, "w": 12, "h": 11 },
"frame": {"x":120,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "ALT.png": {
"filename": "ALT.png", "frame": { "x": 0, "y": 22, "w": 16, "h": 11 },
"frame": {"x":132,"y":0,"w":16,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":16,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 11 },
"sourceSize": {"w":16,"h":12} "sourceSize": { "w": 16, "h": 11 }
}, },
{ "B.png": {
"filename": "B.png", "frame": { "x": 76, "y": 33, "w": 12, "h": 11 },
"frame": {"x":148,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "BACK.png": {
"filename": "BACK.png", "frame": { "x": 80, "y": 0, "w": 24, "h": 11 },
"frame": {"x":160,"y":0,"w":24,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":24,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 24, "h": 11 },
"sourceSize": {"w":24,"h":12} "sourceSize": { "w": 24, "h": 11 }
}, },
{ "C.png": {
"filename": "C.png", "frame": { "x": 88, "y": 33, "w": 12, "h": 11 },
"frame": {"x":184,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "CTRL.png": {
"filename": "CTRL.png", "frame": { "x": 0, "y": 11, "w": 22, "h": 11 },
"frame": {"x":196,"y":0,"w":22,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":22,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 22, "h": 11 },
"sourceSize": {"w":22,"h":12} "sourceSize": { "w": 22, "h": 11 }
}, },
{ "D.png": {
"filename": "D.png", "frame": { "x": 100, "y": 33, "w": 12, "h": 11 },
"frame": {"x":218,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "DEL.png": {
"filename": "DEL.png", "frame": { "x": 116, "y": 11, "w": 17, "h": 11 },
"frame": {"x":230,"y":0,"w":17,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":17,"h":12},
"sourceSize": {"w":17,"h":12}
},
{
"filename": "E.png",
"frame": {"x":247,"y":0,"w":12,"h":12},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12},
"sourceSize": {"w":12,"h":12}
},
{
"filename": "END.png",
"frame": {"x":259,"y":0,"w":18,"h":12},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":18,"h":12},
"sourceSize": {"w":18,"h":12}
},
{
"filename": "ENTER.png",
"frame": {"x":277,"y":0,"w":27,"h":11},
"rotated": false,
"trimmed": false,
"spriteSourceSize": {"x":0,"y":0,"w":27,"h":11},
"sourceSize": {"w":27,"h":11}
},
{
"filename": "ESC.png",
"frame": {"x":304,"y":0,"w":17,"h":11},
"rotated": false,
"trimmed": false,
"spriteSourceSize": { "x": 0, "y": 0, "w": 17, "h": 11 }, "spriteSourceSize": { "x": 0, "y": 0, "w": 17, "h": 11 },
"sourceSize": { "w": 17, "h": 11 } "sourceSize": { "w": 17, "h": 11 }
}, },
{ "E.png": {
"filename": "F.png", "frame": { "x": 112, "y": 33, "w": 12, "h": 11 },
"frame": {"x":321,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "END.png": {
"filename": "F1.png", "frame": { "x": 81, "y": 11, "w": 18, "h": 11 },
"frame": {"x":333,"y":0,"w":13,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 18, "h": 11 },
"sourceSize": {"w":13,"h":12} "sourceSize": { "w": 18, "h": 11 }
}, },
{ "ENTER.png": {
"filename": "F2.png", "frame": { "x": 28, "y": 0, "w": 27, "h": 11 },
"frame": {"x":346,"y":0,"w":13,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 27, "h": 11 },
"sourceSize": {"w":13,"h":12} "sourceSize": { "w": 27, "h": 11 }
}, },
{ "ESC.png": {
"filename": "F3.png", "frame": { "x": 99, "y": 11, "w": 17, "h": 11 },
"frame": {"x":359,"y":0,"w":13,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 17, "h": 11 },
"sourceSize": {"w":13,"h":12} "sourceSize": { "w": 17, "h": 11 }
}, },
{ "F.png": {
"filename": "F4.png", "frame": { "x": 124, "y": 33, "w": 12, "h": 11 },
"frame": {"x":372,"y":0,"w":13,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":13,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "F1.png": {
"filename": "F5.png", "frame": { "x": 78, "y": 22, "w": 13, "h": 11 },
"frame": {"x":385,"y":0,"w":13,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 13, "h": 11 },
"sourceSize": {"w":13,"h":12} "sourceSize": { "w": 13, "h": 11 }
}, },
{ "F2.png": {
"filename": "F6.png", "frame": { "x": 91, "y": 22, "w": 13, "h": 11 },
"frame": {"x":398,"y":0,"w":13,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 13, "h": 11 },
"sourceSize": {"w":13,"h":12} "sourceSize": { "w": 13, "h": 11 }
}, },
{ "F3.png": {
"filename": "F7.png", "frame": { "x": 104, "y": 22, "w": 13, "h": 11 },
"frame": {"x":411,"y":0,"w":13,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 13, "h": 11 },
"sourceSize": {"w":13,"h":12} "sourceSize": { "w": 13, "h": 11 }
}, },
{ "F4.png": {
"filename": "F8.png", "frame": { "x": 117, "y": 22, "w": 13, "h": 11 },
"frame": {"x":424,"y":0,"w":13,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 13, "h": 11 },
"sourceSize": {"w":13,"h":12} "sourceSize": { "w": 13, "h": 11 }
}, },
{ "F5.png": {
"filename": "F9.png", "frame": { "x": 130, "y": 22, "w": 13, "h": 11 },
"frame": {"x":437,"y":0,"w":13,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":13,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 13, "h": 11 },
"sourceSize": {"w":13,"h":12} "sourceSize": { "w": 13, "h": 11 }
}, },
{ "F6.png": {
"filename": "F10.png", "frame": { "x": 0, "y": 33, "w": 13, "h": 11 },
"frame": {"x":450,"y":0,"w":16,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":16,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 13, "h": 11 },
"sourceSize": {"w":16,"h":12} "sourceSize": { "w": 13, "h": 11 }
}, },
{ "F7.png": {
"filename": "F11.png", "frame": { "x": 13, "y": 33, "w": 13, "h": 11 },
"frame": {"x":466,"y":0,"w":15,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":15,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 13, "h": 11 },
"sourceSize": {"w":15,"h":12} "sourceSize": { "w": 13, "h": 11 }
}, },
{ "F8.png": {
"filename": "F12.png", "frame": { "x": 26, "y": 33, "w": 13, "h": 11 },
"frame": {"x":481,"y":0,"w":16,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":16,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 13, "h": 11 },
"sourceSize": {"w":16,"h":12} "sourceSize": { "w": 13, "h": 11 }
}, },
{ "F9.png": {
"filename": "G.png", "frame": { "x": 39, "y": 33, "w": 13, "h": 11 },
"frame": {"x":497,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 13, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 13, "h": 11 }
}, },
{ "F10.png": {
"filename": "H.png", "frame": { "x": 16, "y": 22, "w": 16, "h": 11 },
"frame": {"x":509,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 16, "h": 11 }
}, },
{ "F11.png": {
"filename": "HOME.png", "frame": { "x": 48, "y": 22, "w": 15, "h": 11 },
"frame": {"x":521,"y":0,"w":23,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":23,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 15, "h": 11 },
"sourceSize": {"w":23,"h":12} "sourceSize": { "w": 15, "h": 11 }
}, },
{ "F12.png": {
"filename": "I.png", "frame": { "x": 133, "y": 11, "w": 16, "h": 11 },
"frame": {"x":544,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 16, "h": 11 }
}, },
{ "G.png": {
"filename": "INS.png", "frame": { "x": 136, "y": 33, "w": 12, "h": 11 },
"frame": {"x":556,"y":0,"w":16,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":16,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":16,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "H.png": {
"filename": "J.png", "frame": { "x": 0, "y": 44, "w": 12, "h": 11 },
"frame": {"x":572,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "HOME.png": {
"filename": "K.png", "frame": { "x": 104, "y": 0, "w": 23, "h": 11 },
"frame": {"x":584,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 23, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 23, "h": 11 }
}, },
{ "I.png": {
"filename": "KEY_ARROW_DOWN.png", "frame": { "x": 24, "y": 44, "w": 12, "h": 11 },
"frame": {"x":596,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "INS.png": {
"filename": "KEY_ARROW_LEFT.png", "frame": { "x": 32, "y": 22, "w": 16, "h": 11 },
"frame": {"x":608,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 16, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 16, "h": 11 }
}, },
{ "J.png": {
"filename": "KEY_ARROW_RIGHT.png", "frame": { "x": 48, "y": 44, "w": 12, "h": 11 },
"frame": {"x":620,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "K.png": {
"filename": "KEY_ARROW_UP.png", "frame": { "x": 60, "y": 44, "w": 12, "h": 11 },
"frame": {"x":632,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "KEY_ARROW_DOWN.png": {
"filename": "L.png", "frame": { "x": 72, "y": 66, "w": 11, "h": 11 },
"frame": {"x":644,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 11, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 11, "h": 11 }
}, },
{ "KEY_ARROW_LEFT.png": {
"filename": "LEFT_BRACKET.png", "frame": { "x": 72, "y": 44, "w": 12, "h": 11 },
"frame": {"x":656,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "KEY_ARROW_RIGHT.png": {
"filename": "M.png", "frame": { "x": 84, "y": 44, "w": 12, "h": 11 },
"frame": {"x":668,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "KEY_ARROW_UP.png": {
"filename": "MINUS.png", "frame": { "x": 94, "y": 66, "w": 11, "h": 11 },
"frame": {"x":680,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 11, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 11, "h": 11 }
}, },
{ "L.png": {
"filename": "N.png", "frame": { "x": 96, "y": 44, "w": 12, "h": 11 },
"frame": {"x":692,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "LEFT_BRACKET.png": {
"filename": "O.png", "frame": { "x": 127, "y": 66, "w": 10, "h": 11 },
"frame": {"x":704,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 10, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 10, "h": 11 }
}, },
{ "M.png": {
"filename": "P.png", "frame": { "x": 108, "y": 44, "w": 12, "h": 11 },
"frame": {"x":716,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "MINUS.png": {
"filename": "PAGE_DOWN.png", "frame": { "x": 105, "y": 66, "w": 11, "h": 11 },
"frame": {"x":728,"y":0,"w":20,"h":11},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": { "x": 0, "y": 0, "w": 11, "h": 11 },
"sourceSize": { "w": 11, "h": 11 }
},
"N.png": {
"frame": { "x": 120, "y": 44, "w": 12, "h": 11 },
"rotated": false,
"trimmed": true,
"spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": { "w": 12, "h": 11 }
},
"O.png": {
"frame": { "x": 12, "y": 44, "w": 12, "h": 11 },
"rotated": false,
"trimmed": true,
"spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": { "w": 12, "h": 11 }
},
"P.png": {
"frame": { "x": 132, "y": 44, "w": 12, "h": 11 },
"rotated": false,
"trimmed": true,
"spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": { "w": 12, "h": 11 }
},
"PAGE_DOWN.png": {
"frame": { "x": 22, "y": 11, "w": 20, "h": 11 },
"rotated": false,
"trimmed": true,
"spriteSourceSize": { "x": 0, "y": 0, "w": 20, "h": 11 }, "spriteSourceSize": { "x": 0, "y": 0, "w": 20, "h": 11 },
"sourceSize": { "w": 20, "h": 11 } "sourceSize": { "w": 20, "h": 11 }
}, },
{ "PAGE_UP.png": {
"filename": "PAGE_UP.png", "frame": { "x": 42, "y": 11, "w": 20, "h": 11 },
"frame": {"x":748,"y":0,"w":20,"h":11},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": { "x": 0, "y": 0, "w": 20, "h": 11 }, "spriteSourceSize": { "x": 0, "y": 0, "w": 20, "h": 11 },
"sourceSize": { "w": 20, "h": 11 } "sourceSize": { "w": 20, "h": 11 }
}, },
{ "PLUS.png": {
"filename": "PLUS.png", "frame": { "x": 116, "y": 66, "w": 11, "h": 11 },
"frame": {"x":768,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 11, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 11, "h": 11 }
}, },
{ "Q.png": {
"filename": "Q.png", "frame": { "x": 36, "y": 55, "w": 12, "h": 11 },
"frame": {"x":780,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "QUOTE.png": {
"filename": "QUOTE.png", "frame": { "x": 83, "y": 66, "w": 11, "h": 11 },
"frame": {"x":792,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 11, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 11, "h": 11 }
}, },
{ "R.png": {
"filename": "R.png", "frame": { "x": 48, "y": 55, "w": 12, "h": 11 },
"frame": {"x":804,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "RIGHT_BRACKET.png": {
"filename": "RIGHT_BRACKET.png", "frame": { "x": 137, "y": 66, "w": 10, "h": 11 },
"frame": {"x":816,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 10, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 10, "h": 11 }
}, },
{ "S.png": {
"filename": "S.png", "frame": { "x": 60, "y": 55, "w": 12, "h": 11 },
"frame": {"x":828,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "SEMICOLON.png": {
"filename": "SEMICOLON.png", "frame": { "x": 72, "y": 55, "w": 12, "h": 11 },
"frame": {"x":840,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "SHIFT.png": {
"filename": "SHIFT.png", "frame": { "x": 127, "y": 0, "w": 23, "h": 11 },
"frame": {"x":852,"y":0,"w":23,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":23,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 23, "h": 11 },
"sourceSize": {"w":23,"h":12} "sourceSize": { "w": 23, "h": 11 }
}, },
{ "SPACE.png": {
"filename": "SPACE.png", "frame": { "x": 55, "y": 0, "w": 25, "h": 11 },
"frame": {"x":875,"y":0,"w":25,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":25,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 25, "h": 11 },
"sourceSize": {"w":25,"h":12} "sourceSize": { "w": 25, "h": 11 }
}, },
{ "T.png": {
"filename": "T.png", "frame": { "x": 108, "y": 55, "w": 12, "h": 11 },
"frame": {"x":900,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "TAB.png": {
"filename": "TAB.png", "frame": { "x": 62, "y": 11, "w": 19, "h": 11 },
"frame": {"x":912,"y":0,"w":19,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":19,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 19, "h": 11 },
"sourceSize": {"w":19,"h":12} "sourceSize": { "w": 19, "h": 11 }
}, },
{ "TILDE.png": {
"filename": "TILDE.png", "frame": { "x": 63, "y": 22, "w": 15, "h": 11 },
"frame": {"x":931,"y":0,"w":15,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":15,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 15, "h": 11 },
"sourceSize": {"w":15,"h":12} "sourceSize": { "w": 15, "h": 11 }
}, },
{ "U.png": {
"filename": "U.png", "frame": { "x": 0, "y": 66, "w": 12, "h": 11 },
"frame": {"x":946,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "V.png": {
"filename": "V.png", "frame": { "x": 12, "y": 66, "w": 12, "h": 11 },
"frame": {"x":958,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "W.png": {
"filename": "W.png", "frame": { "x": 24, "y": 66, "w": 12, "h": 11 },
"frame": {"x":970,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "X.png": {
"filename": "X.png", "frame": { "x": 36, "y": 66, "w": 12, "h": 11 },
"frame": {"x":982,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "Y.png": {
"filename": "Y.png", "frame": { "x": 48, "y": 66, "w": 12, "h": 11 },
"frame": {"x":994,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}, },
{ "Z.png": {
"filename": "Z.png", "frame": { "x": 60, "y": 66, "w": 12, "h": 11 },
"frame": {"x":1006,"y":0,"w":12,"h":12},
"rotated": false, "rotated": false,
"trimmed": false, "trimmed": true,
"spriteSourceSize": {"x":0,"y":0,"w":12,"h":12}, "spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
"sourceSize": {"w":12,"h":12} "sourceSize": { "w": 12, "h": 11 }
}], },
"ACTION.png": {
"frame": { "x": 0, "y": 0, "w": 28, "h": 11 },
"rotated": false,
"trimmed": true,
"spriteSourceSize": { "x": 0, "y": 0, "w": 28, "h": 11 },
"sourceSize": { "w": 28, "h": 11 }
}
},
"meta": { "meta": {
"app": "https://www.codeandweb.com/texturepacker", "app": "https://www.aseprite.org/",
"version": "1.0", "version": "1.3.7-dev",
"image": "keyboard.png", "image": "keyboard.png",
"format": "RGBA8888", "format": "RGBA8888",
"size": {"w":1018,"h":12}, "size": { "w": 150, "h": 77 },
"scale": "1", "scale": "1"
"smartupdate": "$TexturePacker:SmartUpdate:085d4353a5c4d18c90f82f8926710d72:45908b22b446cf7f4904d4e0b658b16a:bad03abb89ad027d879c383c13fd51bc$"
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 55 KiB

View File

Before

Width:  |  Height:  |  Size: 405 B

After

Width:  |  Height:  |  Size: 405 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -1,38 +1,49 @@
{ {
"0": { "0": {
"bc4524": "af5457",
"31638c": "324a26", "31638c": "324a26",
"101010": "101010",
"5aa5ce": "40683c", "5aa5ce": "40683c",
"a5e6ff": "b6d9ac", "ce4252": "af2c4f",
"7bceef": "789c6e",
"ced6ef": "c09e99",
"737384": "774644",
"ffffff": "f1dcd8", "ffffff": "f1dcd8",
"8c4231": "420b0c", "8c4231": "420b0c",
"ffde4a": "c66f68",
"c57b31": "551917",
"ffffad": "f4bfb6", "ffffad": "f4bfb6",
"ffde4a": "c66f68",
"7bceef": "789c6e",
"a5e6ff": "b6d9ac",
"737384": "774644",
"f7b531": "af5457", "f7b531": "af5457",
"ce4252": "af2c4f", "c57b31": "551917",
"bc4524": "af5457", "ced6ef": "c09e99"
"00e5e7": "00e5e7"
}, },
"1": { "1": {
"bc4524": "3d325e",
"31638c": "143a72", "31638c": "143a72",
"101010": "101010",
"5aa5ce": "4060bc", "5aa5ce": "4060bc",
"a5e6ff": "b4b3ff", "ce4252": "b75558",
"7bceef": "657ddf",
"ced6ef": "a8b5dd",
"737384": "737384",
"ffffff": "e5ecff", "ffffff": "e5ecff",
"8c4231": "17103f", "8c4231": "17103f",
"ffde4a": "534e72",
"c57b31": "2a1f50",
"ffffad": "87879b", "ffffad": "87879b",
"ffde4a": "534e72",
"7bceef": "657ddf",
"a5e6ff": "b4b3ff",
"f7b531": "3d325e", "f7b531": "3d325e",
"ce4252": "b75558", "c57b31": "2a1f50",
"bc4524": "3d325e", "ced6ef": "a8b5dd"
"00e5e7": "00e5e7" },
"2": {
"ce4252": "215991",
"ffde4a": "f16f40",
"ffffad": "ffb274",
"737384": "884c43",
"c57b31": "761c03",
"7bceef": "be3d2f",
"8c4231": "5a0700",
"5aa5ce": "892722",
"8c4232": "761c03",
"ffffff": "f5e1d1",
"a5e6ff": "dd533a",
"f7b531": "bc4524",
"ced6ef": "d19e92",
"31638c": "610f0e"
} }
} }

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

View File

@ -1017,7 +1017,7 @@
"279": [ "279": [
1, 1,
1, 1,
2 1
], ],
"280": [ "280": [
0, 0,

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 B

View File

@ -130,7 +130,7 @@ export default class BattleScene extends SceneBase {
public gameSpeed: integer = 1; public gameSpeed: integer = 1;
public damageNumbersMode: integer = 0; public damageNumbersMode: integer = 0;
public reroll: boolean = false; public reroll: boolean = false;
public shopCursorTarget: number = ShopCursorTarget.CHECK_TEAM; public shopCursorTarget: number = ShopCursorTarget.REWARDS;
public showMovesetFlyout: boolean = true; public showMovesetFlyout: boolean = true;
public showArenaFlyout: boolean = true; public showArenaFlyout: boolean = true;
public showTimeOfDayWidget: boolean = true; public showTimeOfDayWidget: boolean = true;
@ -841,12 +841,13 @@ export default class BattleScene extends SceneBase {
} }
addEnemyPokemon(species: PokemonSpecies, level: integer, trainerSlot: TrainerSlot, boss: boolean = false, dataSource?: PokemonData, postProcess?: (enemyPokemon: EnemyPokemon) => void): EnemyPokemon { addEnemyPokemon(species: PokemonSpecies, level: integer, trainerSlot: TrainerSlot, boss: boolean = false, dataSource?: PokemonData, postProcess?: (enemyPokemon: EnemyPokemon) => void): EnemyPokemon {
if (Overrides.OPP_LEVEL_OVERRIDE > 0) {
level = Overrides.OPP_LEVEL_OVERRIDE;
}
if (Overrides.OPP_SPECIES_OVERRIDE) { if (Overrides.OPP_SPECIES_OVERRIDE) {
species = getPokemonSpecies(Overrides.OPP_SPECIES_OVERRIDE); species = getPokemonSpecies(Overrides.OPP_SPECIES_OVERRIDE);
} // The fact that a Pokemon is a boss or not can change based on its Species and level
boss = this.getEncounterBossSegments(this.currentBattle.waveIndex, level, species) > 1;
if (Overrides.OPP_LEVEL_OVERRIDE !== 0) {
level = Overrides.OPP_LEVEL_OVERRIDE;
} }
const pokemon = new EnemyPokemon(this, species, level, trainerSlot, boss, dataSource); const pokemon = new EnemyPokemon(this, species, level, trainerSlot, boss, dataSource);
@ -973,6 +974,7 @@ export default class BattleScene extends SceneBase {
this.setSeed(Overrides.SEED_OVERRIDE || Utils.randomString(24)); this.setSeed(Overrides.SEED_OVERRIDE || Utils.randomString(24));
console.log("Seed:", this.seed); console.log("Seed:", this.seed);
this.resetSeed(); // Properly resets RNG after saving and quitting a session
this.disableMenu = false; this.disableMenu = false;
@ -1327,6 +1329,13 @@ export default class BattleScene extends SceneBase {
} }
getEncounterBossSegments(waveIndex: integer, level: integer, species?: PokemonSpecies, forceBoss: boolean = false): integer { getEncounterBossSegments(waveIndex: integer, level: integer, species?: PokemonSpecies, forceBoss: boolean = false): integer {
if (Overrides.OPP_HEALTH_SEGMENTS_OVERRIDE > 1) {
return Overrides.OPP_HEALTH_SEGMENTS_OVERRIDE;
} else if (Overrides.OPP_HEALTH_SEGMENTS_OVERRIDE === 1) {
// The rest of the code expects to be returned 0 and not 1 if the enemy is not a boss
return 0;
}
if (this.gameMode.isDaily && this.gameMode.isWaveFinal(waveIndex)) { if (this.gameMode.isDaily && this.gameMode.isWaveFinal(waveIndex)) {
return 5; return 5;
} }
@ -1791,6 +1800,7 @@ export default class BattleScene extends SceneBase {
config = config ?? {}; config = config ?? {};
try { try {
const keyDetails = key.split("/"); const keyDetails = key.split("/");
config["volume"] = config["volume"] ?? 1;
switch (keyDetails[0]) { switch (keyDetails[0]) {
case "level_up_fanfare": case "level_up_fanfare":
case "item_fanfare": case "item_fanfare":
@ -1800,11 +1810,11 @@ export default class BattleScene extends SceneBase {
case "evolution_fanfare": case "evolution_fanfare":
// These sounds are loaded in as BGM, but played as sound effects // These sounds are loaded in as BGM, but played as sound effects
// When these sounds are updated in updateVolume(), they are treated as BGM however because they are placed in the BGM Cache through being called by playSoundWithoutBGM() // When these sounds are updated in updateVolume(), they are treated as BGM however because they are placed in the BGM Cache through being called by playSoundWithoutBGM()
config["volume"] = this.masterVolume * this.bgmVolume; config["volume"] *= (this.masterVolume * this.bgmVolume);
break; break;
case "battle_anims": case "battle_anims":
case "cry": case "cry":
config["volume"] = this.masterVolume * this.fieldVolume; config["volume"] *= (this.masterVolume * this.fieldVolume);
//PRSFX sound files are unusually loud //PRSFX sound files are unusually loud
if (keyDetails[1].startsWith("PRSFX- ")) { if (keyDetails[1].startsWith("PRSFX- ")) {
config["volume"] *= 0.5; config["volume"] *= 0.5;
@ -1812,10 +1822,10 @@ export default class BattleScene extends SceneBase {
break; break;
case "ui": case "ui":
//As of, right now this applies to the "select", "menu_open", "error" sound effects //As of, right now this applies to the "select", "menu_open", "error" sound effects
config["volume"] = this.masterVolume * this.uiVolume; config["volume"] *= (this.masterVolume * this.uiVolume);
break; break;
case "se": case "se":
config["volume"] = this.masterVolume * this.seVolume; config["volume"] *= (this.masterVolume * this.seVolume);
break; break;
} }
this.sound.play(key, config); this.sound.play(key, config);
@ -2732,6 +2742,35 @@ export default class BattleScene extends SceneBase {
(window as any).gameInfo = gameInfo; (window as any).gameInfo = gameInfo;
} }
/**
* This function retrieves the sprite and audio keys for active Pokemon.
* Active Pokemon include both enemy and player Pokemon of the current wave.
* Note: Questions on garbage collection go to @frutescens
* @returns a string array of active sprite and audio keys that should not be deleted
*/
getActiveKeys(): string[] {
const keys: string[] = [];
const playerParty = this.getParty();
playerParty.forEach(p => {
keys.push("pkmn__" + p.species.getSpriteId(p.gender === Gender.FEMALE, p.species.formIndex, p.shiny, p.variant));
keys.push("pkmn__" + p.species.getSpriteId(p.gender === Gender.FEMALE, p.species.formIndex, p.shiny, p.variant, true));
keys.push("cry/" + p.species.getCryKey(p.species.formIndex));
if (p.fusionSpecies && p.getSpeciesForm() !== p.getFusionSpeciesForm()) {
keys.push("cry/"+p.getFusionSpeciesForm().getCryKey(p.fusionSpecies.formIndex));
}
});
// enemyParty has to be operated on separately from playerParty because playerPokemon =/= enemyPokemon
const enemyParty = this.getEnemyParty();
enemyParty.forEach(p => {
keys.push(p.species.getSpriteKey(p.gender === Gender.FEMALE, p.species.formIndex, p.shiny, p.variant));
keys.push("cry/" + p.species.getCryKey(p.species.formIndex));
if (p.fusionSpecies && p.getSpeciesForm() !== p.getFusionSpeciesForm()) {
keys.push("cry/"+p.getFusionSpeciesForm().getCryKey(p.fusionSpecies.formIndex));
}
});
return keys;
}
/** /**
* Initialized the 2nd phase of the final boss (e.g. form-change for Eternatus) * Initialized the 2nd phase of the final boss (e.g. form-change for Eternatus)
* @param pokemon The (enemy) pokemon * @param pokemon The (enemy) pokemon

File diff suppressed because it is too large Load Diff

View File

@ -7,17 +7,17 @@ import Pokemon, { HitResult, PokemonMove } from "../field/pokemon";
import { StatusEffect } from "./status-effect"; import { StatusEffect } from "./status-effect";
import { BattlerIndex } from "../battle"; import { BattlerIndex } from "../battle";
import { BlockNonDirectDamageAbAttr, ChangeMovePriorityAbAttr, ProtectStatAbAttr, applyAbAttrs } from "./ability"; import { BlockNonDirectDamageAbAttr, ChangeMovePriorityAbAttr, ProtectStatAbAttr, applyAbAttrs } from "./ability";
import { BattleStat } from "./battle-stat"; import { Stat } from "#enums/stat";
import { CommonAnim, CommonBattleAnim } from "./battle-anims"; import { CommonAnim, CommonBattleAnim } from "./battle-anims";
import i18next from "i18next"; import i18next from "i18next";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { ArenaTagType } from "#enums/arena-tag-type"; import { ArenaTagType } from "#enums/arena-tag-type";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; import { MoveEffectPhase } from "#app/phases/move-effect-phase";
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase.js"; import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
import { ShowAbilityPhase } from "#app/phases/show-ability-phase.js"; import { ShowAbilityPhase } from "#app/phases/show-ability-phase";
import { StatChangePhase } from "#app/phases/stat-change-phase.js"; import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
export enum ArenaTagSide { export enum ArenaTagSide {
BOTH, BOTH,
@ -804,8 +804,8 @@ class StickyWebTag extends ArenaTrapTag {
applyAbAttrs(ProtectStatAbAttr, pokemon, cancelled); applyAbAttrs(ProtectStatAbAttr, pokemon, cancelled);
if (!cancelled.value) { if (!cancelled.value) {
pokemon.scene.queueMessage(i18next.t("arenaTag:stickyWebActivateTrap", { pokemonName: pokemon.getNameToRender() })); pokemon.scene.queueMessage(i18next.t("arenaTag:stickyWebActivateTrap", { pokemonName: pokemon.getNameToRender() }));
const statLevels = new Utils.NumberHolder(-1); const stages = new Utils.NumberHolder(-1);
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), false, [BattleStat.SPD], statLevels.value)); pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), false, [ Stat.SPD ], stages.value));
} }
} }
@ -893,7 +893,7 @@ class TailwindTag extends ArenaTag {
// Raise attack by one stage if party member has WIND_RIDER ability // Raise attack by one stage if party member has WIND_RIDER ability
if (pokemon.hasAbility(Abilities.WIND_RIDER)) { if (pokemon.hasAbility(Abilities.WIND_RIDER)) {
pokemon.scene.unshiftPhase(new ShowAbilityPhase(pokemon.scene, pokemon.getBattlerIndex())); pokemon.scene.unshiftPhase(new ShowAbilityPhase(pokemon.scene, pokemon.getBattlerIndex()));
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [BattleStat.ATK], 1, true)); pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ Stat.ATK ], 1, true));
} }
} }
} }
@ -923,6 +923,21 @@ class HappyHourTag extends ArenaTag {
} }
} }
class SafeguardTag extends ArenaTag {
constructor(turnCount: integer, sourceId: integer, side: ArenaTagSide) {
super(ArenaTagType.SAFEGUARD, turnCount, Moves.SAFEGUARD, sourceId, side);
}
onAdd(arena: Arena): void {
arena.scene.queueMessage(i18next.t(`arenaTag:safeguardOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
}
onRemove(arena: Arena): void {
arena.scene.queueMessage(i18next.t(`arenaTag:safeguardOnRemove${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`));
}
}
class NoneTag extends ArenaTag { class NoneTag extends ArenaTag {
constructor() { constructor() {
super(ArenaTagType.NONE, 0, undefined, undefined); super(ArenaTagType.NONE, 0, undefined, undefined);
@ -974,6 +989,8 @@ export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMov
return new TailwindTag(turnCount, sourceId, side); return new TailwindTag(turnCount, sourceId, side);
case ArenaTagType.HAPPY_HOUR: case ArenaTagType.HAPPY_HOUR:
return new HappyHourTag(turnCount, sourceId, side); return new HappyHourTag(turnCount, sourceId, side);
case ArenaTagType.SAFEGUARD:
return new SafeguardTag(turnCount, sourceId, side);
default: default:
return null; return null;
} }

View File

@ -788,10 +788,10 @@ export abstract class BattleAnim {
targetSprite.pipelineData["tone"] = [ 0.0, 0.0, 0.0, 0.0 ]; targetSprite.pipelineData["tone"] = [ 0.0, 0.0, 0.0, 0.0 ];
targetSprite.setAngle(0); targetSprite.setAngle(0);
if (!this.isHideUser() && userSprite) { if (!this.isHideUser() && userSprite) {
userSprite.setVisible(true); this.user?.getSprite().setVisible(true); // using this.user to fix context loss due to isOppAnim swap (#481)
} }
if (!this.isHideTarget() && (targetSprite !== userSprite || !this.isHideUser())) { if (!this.isHideTarget() && (targetSprite !== userSprite || !this.isHideUser())) {
targetSprite.setVisible(true); this.target?.getSprite().setVisible(true); // using this.target to fix context loss due to isOppAnim swap (#481)
} }
for (const ms of Object.values(spriteCache).flat()) { for (const ms of Object.values(spriteCache).flat()) {
if (ms) { if (ms) {

View File

@ -1,71 +0,0 @@
import i18next, { ParseKeys } from "i18next";
export enum BattleStat {
ATK,
DEF,
SPATK,
SPDEF,
SPD,
ACC,
EVA,
RAND,
HP
}
export function getBattleStatName(stat: BattleStat) {
switch (stat) {
case BattleStat.ATK:
return i18next.t("pokemonInfo:Stat.ATK");
case BattleStat.DEF:
return i18next.t("pokemonInfo:Stat.DEF");
case BattleStat.SPATK:
return i18next.t("pokemonInfo:Stat.SPATK");
case BattleStat.SPDEF:
return i18next.t("pokemonInfo:Stat.SPDEF");
case BattleStat.SPD:
return i18next.t("pokemonInfo:Stat.SPD");
case BattleStat.ACC:
return i18next.t("pokemonInfo:Stat.ACC");
case BattleStat.EVA:
return i18next.t("pokemonInfo:Stat.EVA");
case BattleStat.HP:
return i18next.t("pokemonInfo:Stat.HPStat");
default:
return "???";
}
}
export function getBattleStatLevelChangeDescription(pokemonNameWithAffix: string, stats: string, levels: integer, up: boolean, count: number = 1) {
const stringKey = (() => {
if (up) {
switch (levels) {
case 1:
return "battle:statRose";
case 2:
return "battle:statSharplyRose";
case 3:
case 4:
case 5:
case 6:
return "battle:statRoseDrastically";
default:
return "battle:statWontGoAnyHigher";
}
} else {
switch (levels) {
case 1:
return "battle:statFell";
case 2:
return "battle:statHarshlyFell";
case 3:
case 4:
case 5:
case 6:
return "battle:statSeverelyFell";
default:
return "battle:statWontGoAnyLower";
}
}
})();
return i18next.t(stringKey as ParseKeys, { pokemonNameWithAffix, stats, count });
}

View File

@ -1,7 +1,6 @@
import { ChargeAnim, CommonAnim, CommonBattleAnim, MoveChargeAnim } from "./battle-anims"; import { ChargeAnim, CommonAnim, CommonBattleAnim, MoveChargeAnim } from "./battle-anims";
import { getPokemonNameWithAffix } from "../messages"; import { getPokemonNameWithAffix } from "../messages";
import Pokemon, { MoveResult, HitResult } from "../field/pokemon"; import Pokemon, { MoveResult, HitResult } from "../field/pokemon";
import { Stat, getStatName } from "./pokemon-stat";
import { StatusEffect } from "./status-effect"; import { StatusEffect } from "./status-effect";
import * as Utils from "../utils"; import * as Utils from "../utils";
import { ChargeAttr, MoveFlags, allMoves } from "./move"; import { ChargeAttr, MoveFlags, allMoves } from "./move";
@ -9,20 +8,20 @@ import { Type } from "./type";
import { BlockNonDirectDamageAbAttr, FlinchEffectAbAttr, ReverseDrainAbAttr, applyAbAttrs } from "./ability"; import { BlockNonDirectDamageAbAttr, FlinchEffectAbAttr, ReverseDrainAbAttr, applyAbAttrs } from "./ability";
import { TerrainType } from "./terrain"; import { TerrainType } from "./terrain";
import { WeatherType } from "./weather"; import { WeatherType } from "./weather";
import { BattleStat } from "./battle-stat";
import { allAbilities } from "./ability"; import { allAbilities } from "./ability";
import { SpeciesFormChangeManualTrigger } from "./pokemon-forms"; import { SpeciesFormChangeManualTrigger } from "./pokemon-forms";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import i18next from "#app/plugins/i18n.js"; import i18next from "#app/plugins/i18n";
import { CommonAnimPhase } from "#app/phases/common-anim-phase.js"; import { Stat, type BattleStat, type EffectiveStat, EFFECTIVE_STATS, getStatKey } from "#app/enums/stat";
import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; import { CommonAnimPhase } from "#app/phases/common-anim-phase";
import { MovePhase } from "#app/phases/move-phase.js"; import { MoveEffectPhase } from "#app/phases/move-effect-phase";
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase.js"; import { MovePhase } from "#app/phases/move-phase";
import { ShowAbilityPhase } from "#app/phases/show-ability-phase.js"; import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
import { StatChangePhase, StatChangeCallback } from "#app/phases/stat-change-phase.js"; import { ShowAbilityPhase } from "#app/phases/show-ability-phase";
import { StatStageChangePhase, StatStageChangeCallback } from "#app/phases/stat-stage-change-phase";
export enum BattlerTagLapseType { export enum BattlerTagLapseType {
FAINT, FAINT,
@ -40,13 +39,15 @@ export class BattlerTag {
public turnCount: number; public turnCount: number;
public sourceMove: Moves; public sourceMove: Moves;
public sourceId?: number; public sourceId?: number;
public isBatonPassable: boolean;
constructor(tagType: BattlerTagType, lapseType: BattlerTagLapseType | BattlerTagLapseType[], turnCount: number, sourceMove?: Moves, sourceId?: number) { constructor(tagType: BattlerTagType, lapseType: BattlerTagLapseType | BattlerTagLapseType[], turnCount: number, sourceMove?: Moves, sourceId?: number, isBatonPassable: boolean = false) {
this.tagType = tagType; this.tagType = tagType;
this.lapseTypes = Array.isArray(lapseType) ? lapseType : [ lapseType ]; this.lapseTypes = Array.isArray(lapseType) ? lapseType : [ lapseType ];
this.turnCount = turnCount; this.turnCount = turnCount;
this.sourceMove = sourceMove!; // TODO: is this bang correct? this.sourceMove = sourceMove!; // TODO: is this bang correct?
this.sourceId = sourceId; this.sourceId = sourceId;
this.isBatonPassable = isBatonPassable;
} }
canAdd(pokemon: Pokemon): boolean { canAdd(pokemon: Pokemon): boolean {
@ -207,12 +208,12 @@ export class ShellTrapTag extends BattlerTag {
export class TrappedTag extends BattlerTag { export class TrappedTag extends BattlerTag {
constructor(tagType: BattlerTagType, lapseType: BattlerTagLapseType, turnCount: number, sourceMove: Moves, sourceId: number) { constructor(tagType: BattlerTagType, lapseType: BattlerTagLapseType, turnCount: number, sourceMove: Moves, sourceId: number) {
super(tagType, lapseType, turnCount, sourceMove, sourceId); super(tagType, lapseType, turnCount, sourceMove, sourceId, true);
} }
canAdd(pokemon: Pokemon): boolean { canAdd(pokemon: Pokemon): boolean {
const isGhost = pokemon.isOfType(Type.GHOST); const isGhost = pokemon.isOfType(Type.GHOST);
const isTrapped = pokemon.getTag(BattlerTagType.TRAPPED); const isTrapped = pokemon.getTag(TrappedTag);
return !isTrapped && !isGhost; return !isTrapped && !isGhost;
} }
@ -245,6 +246,23 @@ export class TrappedTag extends BattlerTag {
} }
} }
/**
* BattlerTag implementing No Retreat's trapping effect.
* This is treated separately from other trapping effects to prevent
* Ghost-type Pokemon from being able to reuse the move.
* @extends TrappedTag
*/
class NoRetreatTag extends TrappedTag {
constructor(sourceId: number) {
super(BattlerTagType.NO_RETREAT, BattlerTagLapseType.CUSTOM, 0, Moves.NO_RETREAT, sourceId);
}
/** overrides {@linkcode TrappedTag.apply}, removing the Ghost-type condition */
canAdd(pokemon: Pokemon): boolean {
return !pokemon.getTag(TrappedTag);
}
}
/** /**
* BattlerTag that represents the {@link https://bulbapedia.bulbagarden.net/wiki/Flinch Flinch} status condition * BattlerTag that represents the {@link https://bulbapedia.bulbagarden.net/wiki/Flinch Flinch} status condition
*/ */
@ -310,7 +328,7 @@ export class InterruptedTag extends BattlerTag {
*/ */
export class ConfusedTag extends BattlerTag { export class ConfusedTag extends BattlerTag {
constructor(turnCount: number, sourceMove: Moves) { constructor(turnCount: number, sourceMove: Moves) {
super(BattlerTagType.CONFUSED, BattlerTagLapseType.MOVE, turnCount, sourceMove); super(BattlerTagType.CONFUSED, BattlerTagLapseType.MOVE, turnCount, sourceMove, undefined, true);
} }
canAdd(pokemon: Pokemon): boolean { canAdd(pokemon: Pokemon): boolean {
@ -345,8 +363,8 @@ export class ConfusedTag extends BattlerTag {
// 1/3 chance of hitting self with a 40 base power move // 1/3 chance of hitting self with a 40 base power move
if (pokemon.randSeedInt(3) === 0) { if (pokemon.randSeedInt(3) === 0) {
const atk = pokemon.getBattleStat(Stat.ATK); const atk = pokemon.getEffectiveStat(Stat.ATK);
const def = pokemon.getBattleStat(Stat.DEF); const def = pokemon.getEffectiveStat(Stat.DEF);
const damage = Utils.toDmgValue(((((2 * pokemon.level / 5 + 2) * 40 * atk / def) / 50) + 2) * (pokemon.randSeedInt(15, 85) / 100)); const damage = Utils.toDmgValue(((((2 * pokemon.level / 5 + 2) * 40 * atk / def) / 50) + 2) * (pokemon.randSeedInt(15, 85) / 100));
pokemon.scene.queueMessage(i18next.t("battlerTags:confusedLapseHurtItself")); pokemon.scene.queueMessage(i18next.t("battlerTags:confusedLapseHurtItself"));
pokemon.damageAndUpdate(damage); pokemon.damageAndUpdate(damage);
@ -370,7 +388,7 @@ export class ConfusedTag extends BattlerTag {
*/ */
export class DestinyBondTag extends BattlerTag { export class DestinyBondTag extends BattlerTag {
constructor(sourceMove: Moves, sourceId: number) { constructor(sourceMove: Moves, sourceId: number) {
super(BattlerTagType.DESTINY_BOND, BattlerTagLapseType.PRE_MOVE, 1, sourceMove, sourceId); super(BattlerTagType.DESTINY_BOND, BattlerTagLapseType.PRE_MOVE, 1, sourceMove, sourceId, true);
} }
/** /**
@ -489,7 +507,7 @@ export class SeedTag extends BattlerTag {
private sourceIndex: number; private sourceIndex: number;
constructor(sourceId: number) { constructor(sourceId: number) {
super(BattlerTagType.SEEDED, BattlerTagLapseType.TURN_END, 1, Moves.LEECH_SEED, sourceId); super(BattlerTagType.SEEDED, BattlerTagLapseType.TURN_END, 1, Moves.LEECH_SEED, sourceId, true);
} }
/** /**
@ -750,7 +768,7 @@ export class OctolockTag extends TrappedTag {
const shouldLapse = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType); const shouldLapse = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
if (shouldLapse) { if (shouldLapse) {
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [BattleStat.DEF, BattleStat.SPDEF], -1)); pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), false, [ Stat.DEF, Stat.SPDEF ], -1));
return true; return true;
} }
@ -760,7 +778,7 @@ export class OctolockTag extends TrappedTag {
export class AquaRingTag extends BattlerTag { export class AquaRingTag extends BattlerTag {
constructor() { constructor() {
super(BattlerTagType.AQUA_RING, BattlerTagLapseType.TURN_END, 1, Moves.AQUA_RING, undefined); super(BattlerTagType.AQUA_RING, BattlerTagLapseType.TURN_END, 1, Moves.AQUA_RING, undefined, true);
} }
onAdd(pokemon: Pokemon): void { onAdd(pokemon: Pokemon): void {
@ -792,7 +810,7 @@ export class AquaRingTag extends BattlerTag {
/** Tag used to allow moves that interact with {@link Moves.MINIMIZE} to function */ /** Tag used to allow moves that interact with {@link Moves.MINIMIZE} to function */
export class MinimizeTag extends BattlerTag { export class MinimizeTag extends BattlerTag {
constructor() { constructor() {
super(BattlerTagType.MINIMIZED, BattlerTagLapseType.TURN_END, 1, Moves.MINIMIZE, undefined); super(BattlerTagType.MINIMIZED, BattlerTagLapseType.TURN_END, 1, Moves.MINIMIZE);
} }
canAdd(pokemon: Pokemon): boolean { canAdd(pokemon: Pokemon): boolean {
@ -864,7 +882,7 @@ export abstract class DamagingTrapTag extends TrappedTag {
} }
canAdd(pokemon: Pokemon): boolean { canAdd(pokemon: Pokemon): boolean {
return !pokemon.isOfType(Type.GHOST) && !pokemon.findTag(t => t instanceof DamagingTrapTag); return !pokemon.getTag(TrappedTag);
} }
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
@ -1076,7 +1094,7 @@ export class ContactDamageProtectedTag extends ProtectedTag {
} }
} }
export class ContactStatChangeProtectedTag extends ProtectedTag { export class ContactStatStageChangeProtectedTag extends ProtectedTag {
private stat: BattleStat; private stat: BattleStat;
private levels: number; private levels: number;
@ -1093,7 +1111,7 @@ export class ContactStatChangeProtectedTag extends ProtectedTag {
*/ */
loadTag(source: BattlerTag | any): void { loadTag(source: BattlerTag | any): void {
super.loadTag(source); super.loadTag(source);
this.stat = source.stat as BattleStat; this.stat = source.stat;
this.levels = source.levels; this.levels = source.levels;
} }
@ -1104,7 +1122,7 @@ export class ContactStatChangeProtectedTag extends ProtectedTag {
const effectPhase = pokemon.scene.getCurrentPhase(); const effectPhase = pokemon.scene.getCurrentPhase();
if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) { if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) {
const attacker = effectPhase.getPokemon(); const attacker = effectPhase.getPokemon();
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, attacker.getBattlerIndex(), true, [ this.stat ], this.levels)); pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, attacker.getBattlerIndex(), true, [ this.stat ], this.levels));
} }
} }
@ -1190,7 +1208,7 @@ export class SturdyTag extends BattlerTag {
export class PerishSongTag extends BattlerTag { export class PerishSongTag extends BattlerTag {
constructor(turnCount: number) { constructor(turnCount: number) {
super(BattlerTagType.PERISH_SONG, BattlerTagLapseType.TURN_END, turnCount, Moves.PERISH_SONG); super(BattlerTagType.PERISH_SONG, BattlerTagLapseType.TURN_END, turnCount, Moves.PERISH_SONG, undefined, true);
} }
canAdd(pokemon: Pokemon): boolean { canAdd(pokemon: Pokemon): boolean {
@ -1246,7 +1264,7 @@ export class AbilityBattlerTag extends BattlerTag {
public ability: Abilities; public ability: Abilities;
constructor(tagType: BattlerTagType, ability: Abilities, lapseType: BattlerTagLapseType, turnCount: number) { constructor(tagType: BattlerTagType, ability: Abilities, lapseType: BattlerTagLapseType, turnCount: number) {
super(tagType, lapseType, turnCount, undefined); super(tagType, lapseType, turnCount);
this.ability = ability; this.ability = ability;
} }
@ -1331,11 +1349,10 @@ export class HighestStatBoostTag extends AbilityBattlerTag {
onAdd(pokemon: Pokemon): void { onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon); super.onAdd(pokemon);
const stats = [ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD ]; let highestStat: EffectiveStat;
let highestStat: Stat; EFFECTIVE_STATS.map(s => pokemon.getEffectiveStat(s)).reduce((highestValue: number, value: number, i: number) => {
stats.map(s => pokemon.getBattleStat(s)).reduce((highestValue: number, value: number, i: number) => {
if (value > highestValue) { if (value > highestValue) {
highestStat = stats[i]; highestStat = EFFECTIVE_STATS[i];
return value; return value;
} }
return highestValue; return highestValue;
@ -1353,7 +1370,7 @@ export class HighestStatBoostTag extends AbilityBattlerTag {
break; break;
} }
pokemon.scene.queueMessage(i18next.t("battlerTags:highestStatBoostOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), statName: getStatName(highestStat) }), null, false, null, true); pokemon.scene.queueMessage(i18next.t("battlerTags:highestStatBoostOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), statName: i18next.t(getStatKey(highestStat)) }), null, false, null, true);
} }
onRemove(pokemon: Pokemon): void { onRemove(pokemon: Pokemon): void {
@ -1423,7 +1440,7 @@ export class TypeImmuneTag extends BattlerTag {
public immuneType: Type; public immuneType: Type;
constructor(tagType: BattlerTagType, sourceMove: Moves, immuneType: Type, length: number = 1) { constructor(tagType: BattlerTagType, sourceMove: Moves, immuneType: Type, length: number = 1) {
super(tagType, BattlerTagLapseType.TURN_END, length, sourceMove); super(tagType, BattlerTagLapseType.TURN_END, length, sourceMove, undefined, true);
this.immuneType = immuneType; this.immuneType = immuneType;
} }
@ -1487,7 +1504,7 @@ export class TypeBoostTag extends BattlerTag {
export class CritBoostTag extends BattlerTag { export class CritBoostTag extends BattlerTag {
constructor(tagType: BattlerTagType, sourceMove: Moves) { constructor(tagType: BattlerTagType, sourceMove: Moves) {
super(tagType, BattlerTagLapseType.TURN_END, 1, sourceMove); super(tagType, BattlerTagLapseType.TURN_END, 1, sourceMove, undefined, true);
} }
onAdd(pokemon: Pokemon): void { onAdd(pokemon: Pokemon): void {
@ -1507,6 +1524,25 @@ export class CritBoostTag extends BattlerTag {
} }
} }
/**
* Tag for the effects of Dragon Cheer, which boosts the critical hit ratio of the user's allies.
* @extends {CritBoostTag}
*/
export class DragonCheerTag extends CritBoostTag {
/** The types of the user's ally when the tag is added */
public typesOnAdd: Type[];
constructor() {
super(BattlerTagType.CRIT_BOOST, Moves.DRAGON_CHEER);
}
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
this.typesOnAdd = pokemon.getTypes(true);
}
}
export class SaltCuredTag extends BattlerTag { export class SaltCuredTag extends BattlerTag {
private sourceIndex: number; private sourceIndex: number;
@ -1560,7 +1596,7 @@ export class CursedTag extends BattlerTag {
private sourceIndex: number; private sourceIndex: number;
constructor(sourceId: number) { constructor(sourceId: number) {
super(BattlerTagType.CURSED, BattlerTagLapseType.TURN_END, 1, Moves.CURSE, sourceId); super(BattlerTagType.CURSED, BattlerTagLapseType.TURN_END, 1, Moves.CURSE, sourceId, true);
} }
/** /**
@ -1678,25 +1714,25 @@ export class IceFaceBlockDamageTag extends FormBlockDamageTag {
*/ */
export class StockpilingTag extends BattlerTag { export class StockpilingTag extends BattlerTag {
public stockpiledCount: number = 0; public stockpiledCount: number = 0;
public statChangeCounts: { [BattleStat.DEF]: number; [BattleStat.SPDEF]: number } = { public statChangeCounts: { [Stat.DEF]: number; [Stat.SPDEF]: number } = {
[BattleStat.DEF]: 0, [Stat.DEF]: 0,
[BattleStat.SPDEF]: 0 [Stat.SPDEF]: 0
}; };
constructor(sourceMove: Moves = Moves.NONE) { constructor(sourceMove: Moves = Moves.NONE) {
super(BattlerTagType.STOCKPILING, BattlerTagLapseType.CUSTOM, 1, sourceMove); super(BattlerTagType.STOCKPILING, BattlerTagLapseType.CUSTOM, 1, sourceMove);
} }
private onStatsChanged: StatChangeCallback = (_, statsChanged, statChanges) => { private onStatStagesChanged: StatStageChangeCallback = (_, statsChanged, statChanges) => {
const defChange = statChanges[statsChanged.indexOf(BattleStat.DEF)] ?? 0; const defChange = statChanges[statsChanged.indexOf(Stat.DEF)] ?? 0;
const spDefChange = statChanges[statsChanged.indexOf(BattleStat.SPDEF)] ?? 0; const spDefChange = statChanges[statsChanged.indexOf(Stat.SPDEF)] ?? 0;
if (defChange) { if (defChange) {
this.statChangeCounts[BattleStat.DEF]++; this.statChangeCounts[Stat.DEF]++;
} }
if (spDefChange) { if (spDefChange) {
this.statChangeCounts[BattleStat.SPDEF]++; this.statChangeCounts[Stat.SPDEF]++;
} }
}; };
@ -1704,8 +1740,8 @@ export class StockpilingTag extends BattlerTag {
super.loadTag(source); super.loadTag(source);
this.stockpiledCount = source.stockpiledCount || 0; this.stockpiledCount = source.stockpiledCount || 0;
this.statChangeCounts = { this.statChangeCounts = {
[ BattleStat.DEF ]: source.statChangeCounts?.[ BattleStat.DEF ] ?? 0, [ Stat.DEF ]: source.statChangeCounts?.[ Stat.DEF ] ?? 0,
[ BattleStat.SPDEF ]: source.statChangeCounts?.[ BattleStat.SPDEF ] ?? 0, [ Stat.SPDEF ]: source.statChangeCounts?.[ Stat.SPDEF ] ?? 0,
}; };
} }
@ -1725,9 +1761,9 @@ export class StockpilingTag extends BattlerTag {
})); }));
// Attempt to increase DEF and SPDEF by one stage, keeping track of successful changes. // Attempt to increase DEF and SPDEF by one stage, keeping track of successful changes.
pokemon.scene.unshiftPhase(new StatChangePhase( pokemon.scene.unshiftPhase(new StatStageChangePhase(
pokemon.scene, pokemon.getBattlerIndex(), true, pokemon.scene, pokemon.getBattlerIndex(), true,
[BattleStat.SPDEF, BattleStat.DEF], 1, true, false, true, this.onStatsChanged [Stat.SPDEF, Stat.DEF], 1, true, false, true, this.onStatStagesChanged
)); ));
} }
} }
@ -1741,15 +1777,15 @@ export class StockpilingTag extends BattlerTag {
* one stage for each stack which had successfully changed that particular stat during onAdd. * one stage for each stack which had successfully changed that particular stat during onAdd.
*/ */
onRemove(pokemon: Pokemon): void { onRemove(pokemon: Pokemon): void {
const defChange = this.statChangeCounts[BattleStat.DEF]; const defChange = this.statChangeCounts[Stat.DEF];
const spDefChange = this.statChangeCounts[BattleStat.SPDEF]; const spDefChange = this.statChangeCounts[Stat.SPDEF];
if (defChange) { if (defChange) {
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [BattleStat.DEF], -defChange, true, false, true)); pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ Stat.DEF ], -defChange, true, false, true));
} }
if (spDefChange) { if (spDefChange) {
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [BattleStat.SPDEF], -spDefChange, true, false, true)); pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ Stat.SPDEF ], -spDefChange, true, false, true));
} }
} }
} }
@ -1864,6 +1900,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source
return new DrowsyTag(); return new DrowsyTag();
case BattlerTagType.TRAPPED: case BattlerTagType.TRAPPED:
return new TrappedTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId); return new TrappedTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);
case BattlerTagType.NO_RETREAT:
return new NoRetreatTag(sourceId);
case BattlerTagType.BIND: case BattlerTagType.BIND:
return new BindTag(turnCount, sourceId); return new BindTag(turnCount, sourceId);
case BattlerTagType.WRAP: case BattlerTagType.WRAP:
@ -1889,11 +1927,11 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source
case BattlerTagType.SPIKY_SHIELD: case BattlerTagType.SPIKY_SHIELD:
return new ContactDamageProtectedTag(sourceMove, 8); return new ContactDamageProtectedTag(sourceMove, 8);
case BattlerTagType.KINGS_SHIELD: case BattlerTagType.KINGS_SHIELD:
return new ContactStatChangeProtectedTag(sourceMove, tagType, BattleStat.ATK, -1); return new ContactStatStageChangeProtectedTag(sourceMove, tagType, Stat.ATK, -1);
case BattlerTagType.OBSTRUCT: case BattlerTagType.OBSTRUCT:
return new ContactStatChangeProtectedTag(sourceMove, tagType, BattleStat.DEF, -2); return new ContactStatStageChangeProtectedTag(sourceMove, tagType, Stat.DEF, -2);
case BattlerTagType.SILK_TRAP: case BattlerTagType.SILK_TRAP:
return new ContactStatChangeProtectedTag(sourceMove, tagType, BattleStat.SPD, -1); return new ContactStatStageChangeProtectedTag(sourceMove, tagType, Stat.SPD, -1);
case BattlerTagType.BANEFUL_BUNKER: case BattlerTagType.BANEFUL_BUNKER:
return new ContactPoisonProtectedTag(sourceMove); return new ContactPoisonProtectedTag(sourceMove);
case BattlerTagType.BURNING_BULWARK: case BattlerTagType.BURNING_BULWARK:
@ -1923,6 +1961,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source
return new TypeBoostTag(tagType, sourceMove, Type.FIRE, 1.5, false); return new TypeBoostTag(tagType, sourceMove, Type.FIRE, 1.5, false);
case BattlerTagType.CRIT_BOOST: case BattlerTagType.CRIT_BOOST:
return new CritBoostTag(tagType, sourceMove); return new CritBoostTag(tagType, sourceMove);
case BattlerTagType.DRAGON_CHEER:
return new DragonCheerTag();
case BattlerTagType.ALWAYS_CRIT: case BattlerTagType.ALWAYS_CRIT:
case BattlerTagType.IGNORE_ACCURACY: case BattlerTagType.IGNORE_ACCURACY:
return new BattlerTag(tagType, BattlerTagLapseType.TURN_END, 2, sourceMove); return new BattlerTag(tagType, BattlerTagLapseType.TURN_END, 2, sourceMove);

View File

@ -1,14 +1,14 @@
import { getPokemonNameWithAffix } from "../messages"; import { getPokemonNameWithAffix } from "../messages";
import Pokemon, { HitResult } from "../field/pokemon"; import Pokemon, { HitResult } from "../field/pokemon";
import { BattleStat } from "./battle-stat";
import { getStatusEffectHealText } from "./status-effect"; import { getStatusEffectHealText } from "./status-effect";
import * as Utils from "../utils"; import * as Utils from "../utils";
import { DoubleBerryEffectAbAttr, ReduceBerryUseThresholdAbAttr, applyAbAttrs } from "./ability"; import { DoubleBerryEffectAbAttr, ReduceBerryUseThresholdAbAttr, applyAbAttrs } from "./ability";
import i18next from "i18next"; import i18next from "i18next";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { BerryType } from "#enums/berry-type"; import { BerryType } from "#enums/berry-type";
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase.js"; import { Stat, type BattleStat } from "#app/enums/stat";
import { StatChangePhase } from "#app/phases/stat-change-phase.js"; import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
export function getBerryName(berryType: BerryType): string { export function getBerryName(berryType: BerryType): string {
return i18next.t(`berry:${BerryType[berryType]}.name`); return i18next.t(`berry:${BerryType[berryType]}.name`);
@ -35,9 +35,10 @@ export function getBerryPredicate(berryType: BerryType): BerryPredicate {
case BerryType.SALAC: case BerryType.SALAC:
return (pokemon: Pokemon) => { return (pokemon: Pokemon) => {
const threshold = new Utils.NumberHolder(0.25); const threshold = new Utils.NumberHolder(0.25);
const battleStat = (berryType - BerryType.LIECHI) as BattleStat; // Offset BerryType such that LIECHI -> Stat.ATK = 1, GANLON -> Stat.DEF = 2, so on and so forth
const stat: BattleStat = berryType - BerryType.ENIGMA;
applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold); applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, false, threshold);
return pokemon.getHpRatio() < threshold.value && pokemon.summonData.battleStats[battleStat] < 6; return pokemon.getHpRatio() < threshold.value && pokemon.getStatStage(stat) < 6;
}; };
case BerryType.LANSAT: case BerryType.LANSAT:
return (pokemon: Pokemon) => { return (pokemon: Pokemon) => {
@ -95,10 +96,11 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
if (pokemon.battleData) { if (pokemon.battleData) {
pokemon.battleData.berriesEaten.push(berryType); pokemon.battleData.berriesEaten.push(berryType);
} }
const battleStat = (berryType - BerryType.LIECHI) as BattleStat; // Offset BerryType such that LIECHI -> Stat.ATK = 1, GANLON -> Stat.DEF = 2, so on and so forth
const statLevels = new Utils.NumberHolder(1); const stat: BattleStat = berryType - BerryType.ENIGMA;
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, statLevels); const statStages = new Utils.NumberHolder(1);
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ battleStat ], statLevels.value)); applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, statStages);
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ stat ], statStages.value));
}; };
case BerryType.LANSAT: case BerryType.LANSAT:
return (pokemon: Pokemon) => { return (pokemon: Pokemon) => {
@ -112,9 +114,10 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
if (pokemon.battleData) { if (pokemon.battleData) {
pokemon.battleData.berriesEaten.push(berryType); pokemon.battleData.berriesEaten.push(berryType);
} }
const statLevels = new Utils.NumberHolder(2); const randStat = Utils.randSeedInt(Stat.SPD, Stat.ATK);
applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, statLevels); const stages = new Utils.NumberHolder(2);
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ BattleStat.RAND ], statLevels.value)); applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, stages);
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ randStat ], stages.value));
}; };
case BerryType.LEPPA: case BerryType.LEPPA:
return (pokemon: Pokemon) => { return (pokemon: Pokemon) => {

View File

@ -46,7 +46,7 @@ export const biomeLinks: BiomeLinks = {
[Biome.SEABED]: [ Biome.CAVE, [ Biome.VOLCANO, 3 ] ], [Biome.SEABED]: [ Biome.CAVE, [ Biome.VOLCANO, 3 ] ],
[Biome.MOUNTAIN]: [ Biome.VOLCANO, [ Biome.WASTELAND, 2 ], [ Biome.SPACE, 3 ] ], [Biome.MOUNTAIN]: [ Biome.VOLCANO, [ Biome.WASTELAND, 2 ], [ Biome.SPACE, 3 ] ],
[Biome.BADLANDS]: [ Biome.DESERT, Biome.MOUNTAIN ], [Biome.BADLANDS]: [ Biome.DESERT, Biome.MOUNTAIN ],
[Biome.CAVE]: [ Biome.BADLANDS, Biome.LAKE [ Biome.LABORATORY, 2 ] ], [Biome.CAVE]: [ Biome.BADLANDS, Biome.LAKE, [ Biome.LABORATORY, 2 ] ],
[Biome.DESERT]: [ Biome.RUINS, [ Biome.CONSTRUCTION_SITE, 2 ] ], [Biome.DESERT]: [ Biome.RUINS, [ Biome.CONSTRUCTION_SITE, 2 ] ],
[Biome.ICE_CAVE]: Biome.SNOWY_FOREST, [Biome.ICE_CAVE]: Biome.SNOWY_FOREST,
[Biome.MEADOW]: [ Biome.PLAINS, Biome.FAIRY_CAVE ], [Biome.MEADOW]: [ Biome.PLAINS, Biome.FAIRY_CAVE ],
@ -7666,7 +7666,7 @@ export function initBiomes() {
if (biome === Biome.END) { if (biome === Biome.END) {
const biomeList = Object.keys(Biome).filter(key => !isNaN(Number(key))); const biomeList = Object.keys(Biome).filter(key => !isNaN(Number(key)));
biomeList.pop(); // Removes Biome.END from the list biomeList.pop(); // Removes Biome.END from the list
const randIndex = Utils.randInt(biomeList.length, 2); // Will never be Biome.TOWN or Biome.PLAINS const randIndex = Utils.randInt(biomeList.length, 1); // Will never be Biome.TOWN
biome = Biome[biomeList[randIndex]]; biome = Biome[biomeList[randIndex]];
} }
const linkedBiomes: (Biome | [ Biome, integer ])[] = Array.isArray(biomeLinks[biome]) const linkedBiomes: (Biome | [ Biome, integer ])[] = Array.isArray(biomeLinks[biome])

View File

@ -13,7 +13,6 @@ import { TrainerType } from "#enums/trainer-type";
import { Nature } from "./nature"; import { Nature } from "./nature";
import { Moves } from "#app/enums/moves.js"; import { Moves } from "#app/enums/moves.js";
import { TypeColor, TypeShadow } from "#app/enums/color.js"; import { TypeColor, TypeShadow } from "#app/enums/color.js";
import { Gender } from "./gender";
import { pokemonEvolutions } from "./pokemon-evolutions"; import { pokemonEvolutions } from "./pokemon-evolutions";
import { pokemonFormChanges } from "./pokemon-forms"; import { pokemonFormChanges } from "./pokemon-forms";
@ -659,7 +658,6 @@ export class FreshStartChallenge extends Challenge {
pokemon.luck = 0; // No luck pokemon.luck = 0; // No luck
pokemon.shiny = false; // Not shiny pokemon.shiny = false; // Not shiny
pokemon.variant = 0; // Not shiny pokemon.variant = 0; // Not shiny
pokemon.gender = Gender.MALE; // Starters default to male
pokemon.formIndex = 0; // Froakie should be base form pokemon.formIndex = 0; // Froakie should be base form
pokemon.ivs = [10, 10, 10, 10, 10, 10]; // Default IVs of 10 for all stats pokemon.ivs = [10, 10, 10, 10, 10, 10]; // Default IVs of 10 for all stats
return true; return true;

View File

@ -707,6 +707,20 @@ export const trainerTypeDialogue: TrainerTypeDialogue = {
] ]
} }
], ],
[TrainerType.ROOD]: [
{
encounter: [
"dialogue:rood.encounter.1",
"dialogue:rood.encounter.2",
"dialogue:rood.encounter.3",
],
victory: [
"dialogue:rood.victory.1",
"dialogue:rood.victory.2",
"dialogue:rood.victory.3",
]
}
],
[TrainerType.FLARE_GRUNT]: [ [TrainerType.FLARE_GRUNT]: [
{ {
encounter: [ encounter: [

View File

@ -0,0 +1,98 @@
import BattleScene from "#app/battle-scene";
import { PlayerPokemon } from "#app/field/pokemon";
import { DexEntry, StarterDataEntry } from "#app/system/game-data";
/**
* Stores data associated with a specific egg and the hatched pokemon
* Allows hatch info to be stored at hatch then retrieved for display during egg summary
*/
export class EggHatchData {
/** the pokemon that hatched from the file (including shiny, IVs, ability) */
public pokemon: PlayerPokemon;
/** index of the egg move from the hatched pokemon (not stored in PlayerPokemon) */
public eggMoveIndex: number;
/** boolean indicating if the egg move for the hatch is new */
public eggMoveUnlocked: boolean;
/** stored copy of the hatched pokemon's dex entry before it was updated due to hatch */
public dexEntryBeforeUpdate: DexEntry;
/** stored copy of the hatched pokemon's starter entry before it was updated due to hatch */
public starterDataEntryBeforeUpdate: StarterDataEntry;
/** reference to the battle scene to get gamedata and update dex */
private scene: BattleScene;
constructor(scene: BattleScene, pokemon: PlayerPokemon, eggMoveIndex: number) {
this.scene = scene;
this.pokemon = pokemon;
this.eggMoveIndex = eggMoveIndex;
}
/**
* Sets the boolean for if the egg move for the hatch is a new unlock
* @param unlocked True if the EM is new
*/
setEggMoveUnlocked(unlocked: boolean) {
this.eggMoveUnlocked = unlocked;
}
/**
* Stores a copy of the current DexEntry of the pokemon and StarterDataEntry of its starter
* Used before updating the dex, so comparing the pokemon to these entries will show the new attributes
*/
setDex() {
const currDexEntry = this.scene.gameData.dexData[this.pokemon.species.speciesId];
const currStarterDataEntry = this.scene.gameData.starterData[this.pokemon.species.getRootSpeciesId()];
this.dexEntryBeforeUpdate = {
seenAttr: currDexEntry.seenAttr,
caughtAttr: currDexEntry.caughtAttr,
natureAttr: currDexEntry.natureAttr,
seenCount: currDexEntry.seenCount,
caughtCount: currDexEntry.caughtCount,
hatchedCount: currDexEntry.hatchedCount,
ivs: [...currDexEntry.ivs]
};
this.starterDataEntryBeforeUpdate = {
moveset: currStarterDataEntry.moveset,
eggMoves: currStarterDataEntry.eggMoves,
candyCount: currStarterDataEntry.candyCount,
friendship: currStarterDataEntry.friendship,
abilityAttr: currStarterDataEntry.abilityAttr,
passiveAttr: currStarterDataEntry.passiveAttr,
valueReduction: currStarterDataEntry.valueReduction,
classicWinCount: currStarterDataEntry.classicWinCount
};
}
/**
* Gets the dex entry before update
* @returns Dex Entry corresponding to this pokemon before the pokemon was added / updated to dex
*/
getDex(): DexEntry {
return this.dexEntryBeforeUpdate;
}
/**
* Gets the starter dex entry before update
* @returns Starter Dex Entry corresponding to this pokemon before the pokemon was added / updated to dex
*/
getStarterEntry(): StarterDataEntry {
return this.starterDataEntryBeforeUpdate;
}
/**
* Update the pokedex data corresponding with the new hatch's pokemon data
* Also sets whether the egg move is a new unlock or not
* @param showMessage boolean to show messages for the new catches and egg moves (false by default)
* @returns
*/
updatePokemon(showMessage : boolean = false) {
return new Promise<void>(resolve => {
this.scene.gameData.setPokemonCaught(this.pokemon, true, true, showMessage).then(() => {
this.scene.gameData.updateSpeciesDexIvs(this.pokemon.species.speciesId, this.pokemon.ivs);
this.scene.gameData.setEggMoveUnlocked(this.pokemon.species, this.eggMoveIndex, showMessage).then((value) => {
this.setEggMoveUnlocked(value);
resolve();
});
});
});
}
}

View File

@ -139,6 +139,7 @@ export class Egg {
//// ////
constructor(eggOptions?: IEggOptions) { constructor(eggOptions?: IEggOptions) {
const generateEggProperties = (eggOptions?: IEggOptions) => {
//if (eggOptions.tier && eggOptions.species) throw Error("Error egg can't have species and tier as option. only choose one of them.") //if (eggOptions.tier && eggOptions.species) throw Error("Error egg can't have species and tier as option. only choose one of them.")
this._sourceType = eggOptions?.sourceType!; // TODO: is this bang correct? this._sourceType = eggOptions?.sourceType!; // TODO: is this bang correct?
@ -180,6 +181,16 @@ export class Egg {
this.increasePullStatistic(eggOptions.scene!); // TODO: is this bang correct? this.increasePullStatistic(eggOptions.scene!); // TODO: is this bang correct?
this.addEggToGameData(eggOptions.scene!); // TODO: is this bang correct? this.addEggToGameData(eggOptions.scene!); // TODO: is this bang correct?
} }
};
if (eggOptions?.scene) {
const seedOverride = Utils.randomString(24);
eggOptions?.scene.executeWithSeedOffset(() => {
generateEggProperties(eggOptions);
}, 0, seedOverride);
} else { // For legacy eggs without scene
generateEggProperties(eggOptions);
}
} }
//// ////
@ -200,6 +211,9 @@ export class Egg {
// Generates a PlayerPokemon from an egg // Generates a PlayerPokemon from an egg
public generatePlayerPokemon(scene: BattleScene): PlayerPokemon { public generatePlayerPokemon(scene: BattleScene): PlayerPokemon {
let ret: PlayerPokemon;
const generatePlayerPokemonHelper = (scene: BattleScene) => {
// Legacy egg wants to hatch. Generate missing properties // Legacy egg wants to hatch. Generate missing properties
if (!this._species) { if (!this._species) {
this._isShiny = this.rollShiny(); this._isShiny = this.rollShiny();
@ -222,7 +236,7 @@ export class Egg {
} }
// This function has way to many optional parameters // This function has way to many optional parameters
const ret: PlayerPokemon = scene.addPlayerPokemon(pokemonSpecies, 1, abilityIndex, undefined, undefined, false); ret = scene.addPlayerPokemon(pokemonSpecies, 1, abilityIndex, undefined, undefined, false);
ret.shiny = this._isShiny; ret.shiny = this._isShiny;
ret.variant = this._variantTier; ret.variant = this._variantTier;
@ -231,6 +245,12 @@ export class Egg {
for (let s = 0; s < ret.ivs.length; s++) { for (let s = 0; s < ret.ivs.length; s++) {
ret.ivs[s] = Math.max(ret.ivs[s], secondaryIvs[s]); ret.ivs[s] = Math.max(ret.ivs[s], secondaryIvs[s]);
} }
};
ret = ret!; // Tell TS compiler it's defined now
scene.executeWithSeedOffset(() => {
generatePlayerPokemonHelper(scene);
}, this._id, EGG_SEED.toString());
return ret; return ret;
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,9 @@
import { Stat, getStatName } from "./pokemon-stat";
import * as Utils from "../utils"; import * as Utils from "../utils";
import { TextStyle, getBBCodeFrag } from "../ui/text"; import { TextStyle, getBBCodeFrag } from "../ui/text";
import { Nature } from "#enums/nature"; import { Nature } from "#enums/nature";
import { UiTheme } from "#enums/ui-theme"; import { UiTheme } from "#enums/ui-theme";
import i18next from "i18next"; import i18next from "i18next";
import { Stat, EFFECTIVE_STATS, getShortenedStatKey } from "#app/enums/stat";
export { Nature }; export { Nature };
@ -14,10 +14,9 @@ export function getNatureName(nature: Nature, includeStatEffects: boolean = fals
ret = i18next.t("nature:" + ret as any); ret = i18next.t("nature:" + ret as any);
} }
if (includeStatEffects) { if (includeStatEffects) {
const stats = Utils.getEnumValues(Stat).slice(1);
let increasedStat: Stat | null = null; let increasedStat: Stat | null = null;
let decreasedStat: Stat | null = null; let decreasedStat: Stat | null = null;
for (const stat of stats) { for (const stat of EFFECTIVE_STATS) {
const multiplier = getNatureStatMultiplier(nature, stat); const multiplier = getNatureStatMultiplier(nature, stat);
if (multiplier > 1) { if (multiplier > 1) {
increasedStat = stat; increasedStat = stat;
@ -28,7 +27,7 @@ export function getNatureName(nature: Nature, includeStatEffects: boolean = fals
const textStyle = forStarterSelect ? TextStyle.SUMMARY_ALT : TextStyle.WINDOW; const textStyle = forStarterSelect ? TextStyle.SUMMARY_ALT : TextStyle.WINDOW;
const getTextFrag = !ignoreBBCode ? (text: string, style: TextStyle) => getBBCodeFrag(text, style, uiTheme) : (text: string, style: TextStyle) => text; const getTextFrag = !ignoreBBCode ? (text: string, style: TextStyle) => getBBCodeFrag(text, style, uiTheme) : (text: string, style: TextStyle) => text;
if (increasedStat && decreasedStat) { if (increasedStat && decreasedStat) {
ret = `${getTextFrag(`${ret}${!forStarterSelect ? "\n" : " "}(`, textStyle)}${getTextFrag(`+${getStatName(increasedStat, true)}`, TextStyle.SUMMARY_PINK)}${getTextFrag("/", textStyle)}${getTextFrag(`-${getStatName(decreasedStat, true)}`, TextStyle.SUMMARY_BLUE)}${getTextFrag(")", textStyle)}`; ret = `${getTextFrag(`${ret}${!forStarterSelect ? "\n" : " "}(`, textStyle)}${getTextFrag(`+${i18next.t(getShortenedStatKey(increasedStat))}`, TextStyle.SUMMARY_PINK)}${getTextFrag("/", textStyle)}${getTextFrag(`-${i18next.t(getShortenedStatKey(decreasedStat))}`, TextStyle.SUMMARY_BLUE)}${getTextFrag(")", textStyle)}`;
} else { } else {
ret = getTextFrag(`${ret}${!forStarterSelect ? "\n" : " "}(-)`, textStyle); ret = getTextFrag(`${ret}${!forStarterSelect ? "\n" : " "}(-)`, textStyle);
} }

View File

@ -1,7 +1,7 @@
import { Gender } from "./gender"; import { Gender } from "./gender";
import { PokeballType } from "./pokeball"; import { PokeballType } from "./pokeball";
import Pokemon from "../field/pokemon"; import Pokemon from "../field/pokemon";
import { Stat } from "./pokemon-stat"; import { Stat } from "#enums/stat";
import { Type } from "./type"; import { Type } from "./type";
import * as Utils from "../utils"; import * as Utils from "../utils";
import { SpeciesFormKey } from "./pokemon-species"; import { SpeciesFormKey } from "./pokemon-species";

View File

@ -66,34 +66,34 @@ export enum FormChangeItem {
BLUE_ORB = 50, BLUE_ORB = 50,
RED_ORB, RED_ORB,
SHARP_METEORITE,
HARD_METEORITE,
SMOOTH_METEORITE,
ADAMANT_CRYSTAL, ADAMANT_CRYSTAL,
LUSTROUS_GLOBE, LUSTROUS_GLOBE,
GRISEOUS_CORE, GRISEOUS_CORE,
REVEAL_GLASS, REVEAL_GLASS,
GRACIDEA,
MAX_MUSHROOMS, MAX_MUSHROOMS,
DARK_STONE, DARK_STONE,
LIGHT_STONE, LIGHT_STONE,
PRISON_BOTTLE, PRISON_BOTTLE,
N_LUNARIZER,
N_SOLARIZER,
RUSTED_SWORD, RUSTED_SWORD,
RUSTED_SHIELD, RUSTED_SHIELD,
ICY_REINS_OF_UNITY, ICY_REINS_OF_UNITY,
SHADOW_REINS_OF_UNITY, SHADOW_REINS_OF_UNITY,
WELLSPRING_MASK, ULTRANECROZIUM_Z,
HEARTHFLAME_MASK,
CORNERSTONE_MASK, SHARP_METEORITE = 100,
HARD_METEORITE,
SMOOTH_METEORITE,
GRACIDEA,
SHOCK_DRIVE, SHOCK_DRIVE,
BURN_DRIVE, BURN_DRIVE,
CHILL_DRIVE, CHILL_DRIVE,
DOUSE_DRIVE, DOUSE_DRIVE,
ULTRANECROZIUM_Z, N_SOLARIZER,
N_LUNARIZER,
FIST_PLATE = 100, WELLSPRING_MASK,
HEARTHFLAME_MASK,
CORNERSTONE_MASK,
FIST_PLATE,
SKY_PLATE, SKY_PLATE,
TOXIC_PLATE, TOXIC_PLATE,
EARTH_PLATE, EARTH_PLATE,
@ -129,7 +129,7 @@ export enum FormChangeItem {
DRAGON_MEMORY, DRAGON_MEMORY,
DARK_MEMORY, DARK_MEMORY,
FAIRY_MEMORY, FAIRY_MEMORY,
BLANK_MEMORY // TODO: Find a potential use for this NORMAL_MEMORY // TODO: Find a potential use for this
} }
export type SpeciesFormChangeConditionPredicate = (p: Pokemon) => boolean; export type SpeciesFormChangeConditionPredicate = (p: Pokemon) => boolean;
@ -359,7 +359,7 @@ export class SpeciesDefaultFormMatchTrigger extends SpeciesFormChangeTrigger {
/** /**
* Class used for triggering form changes based on weather. * Class used for triggering form changes based on weather.
* Used by Castform. * Used by Castform and Cherrim.
* @extends SpeciesFormChangeTrigger * @extends SpeciesFormChangeTrigger
*/ */
export class SpeciesFormChangeWeatherTrigger extends SpeciesFormChangeTrigger { export class SpeciesFormChangeWeatherTrigger extends SpeciesFormChangeTrigger {
@ -392,7 +392,7 @@ export class SpeciesFormChangeWeatherTrigger extends SpeciesFormChangeTrigger {
/** /**
* Class used for reverting to the original form when the weather runs out * Class used for reverting to the original form when the weather runs out
* or when the user loses the ability/is suppressed. * or when the user loses the ability/is suppressed.
* Used by Castform. * Used by Castform and Cherrim.
* @extends SpeciesFormChangeTrigger * @extends SpeciesFormChangeTrigger
*/ */
export class SpeciesFormChangeRevertWeatherFormTrigger extends SpeciesFormChangeTrigger { export class SpeciesFormChangeRevertWeatherFormTrigger extends SpeciesFormChangeTrigger {
@ -930,6 +930,11 @@ export const pokemonFormChanges: PokemonFormChanges = {
new SpeciesFormChange(Species.CASTFORM, "rainy", "", new SpeciesFormChangeActiveTrigger(), true), new SpeciesFormChange(Species.CASTFORM, "rainy", "", new SpeciesFormChangeActiveTrigger(), true),
new SpeciesFormChange(Species.CASTFORM, "snowy", "", new SpeciesFormChangeActiveTrigger(), true), new SpeciesFormChange(Species.CASTFORM, "snowy", "", new SpeciesFormChangeActiveTrigger(), true),
], ],
[Species.CHERRIM]: [
new SpeciesFormChange(Species.CHERRIM, "overcast", "sunshine", new SpeciesFormChangeWeatherTrigger(Abilities.FLOWER_GIFT, [ WeatherType.SUNNY, WeatherType.HARSH_SUN ]), true),
new SpeciesFormChange(Species.CHERRIM, "sunshine", "overcast", new SpeciesFormChangeRevertWeatherFormTrigger(Abilities.FLOWER_GIFT, [ WeatherType.NONE, WeatherType.SANDSTORM, WeatherType.STRONG_WINDS, WeatherType.FOG, WeatherType.HAIL, WeatherType.HEAVY_RAIN, WeatherType.SNOW, WeatherType.RAIN ]), true),
new SpeciesFormChange(Species.CHERRIM, "sunshine", "overcast", new SpeciesFormChangeActiveTrigger(), true),
],
}; };
export function initPokemonForms() { export function initPokemonForms() {

View File

@ -14,7 +14,7 @@ import { GrowthRate } from "./exp";
import { EvolutionLevel, SpeciesWildEvolutionDelay, pokemonEvolutions, pokemonPrevolutions } from "./pokemon-evolutions"; import { EvolutionLevel, SpeciesWildEvolutionDelay, pokemonEvolutions, pokemonPrevolutions } from "./pokemon-evolutions";
import { Type } from "./type"; import { Type } from "./type";
import { LevelMoves, pokemonFormLevelMoves, pokemonFormLevelMoves as pokemonSpeciesFormLevelMoves, pokemonSpeciesLevelMoves } from "./pokemon-level-moves"; import { LevelMoves, pokemonFormLevelMoves, pokemonFormLevelMoves as pokemonSpeciesFormLevelMoves, pokemonSpeciesLevelMoves } from "./pokemon-level-moves";
import { Stat } from "./pokemon-stat"; import { Stat } from "#enums/stat";
import { Variant, VariantSet, variantColorCache, variantData } from "./variant"; import { Variant, VariantSet, variantColorCache, variantData } from "./variant";
export enum Region { export enum Region {
@ -944,7 +944,7 @@ export function initSpecies() {
new PokemonSpecies(Species.METAPOD, 1, false, false, false, "Cocoon Pokémon", Type.BUG, null, 0.7, 9.9, Abilities.SHED_SKIN, Abilities.NONE, Abilities.SHED_SKIN, 205, 50, 20, 55, 25, 25, 30, 120, 50, 72, GrowthRate.MEDIUM_FAST, 50, false), new PokemonSpecies(Species.METAPOD, 1, false, false, false, "Cocoon Pokémon", Type.BUG, null, 0.7, 9.9, Abilities.SHED_SKIN, Abilities.NONE, Abilities.SHED_SKIN, 205, 50, 20, 55, 25, 25, 30, 120, 50, 72, GrowthRate.MEDIUM_FAST, 50, false),
new PokemonSpecies(Species.BUTTERFREE, 1, false, false, false, "Butterfly Pokémon", Type.BUG, Type.FLYING, 1.1, 32, Abilities.COMPOUND_EYES, Abilities.NONE, Abilities.TINTED_LENS, 395, 60, 45, 50, 90, 80, 70, 45, 50, 198, GrowthRate.MEDIUM_FAST, 50, true, true, new PokemonSpecies(Species.BUTTERFREE, 1, false, false, false, "Butterfly Pokémon", Type.BUG, Type.FLYING, 1.1, 32, Abilities.COMPOUND_EYES, Abilities.NONE, Abilities.TINTED_LENS, 395, 60, 45, 50, 90, 80, 70, 45, 50, 198, GrowthRate.MEDIUM_FAST, 50, true, true,
new PokemonForm("Normal", "", Type.BUG, Type.FLYING, 1.1, 32, Abilities.COMPOUND_EYES, Abilities.NONE, Abilities.TINTED_LENS, 395, 60, 45, 50, 90, 80, 70, 45, 50, 198, true, null, true), new PokemonForm("Normal", "", Type.BUG, Type.FLYING, 1.1, 32, Abilities.COMPOUND_EYES, Abilities.NONE, Abilities.TINTED_LENS, 395, 60, 45, 50, 90, 80, 70, 45, 50, 198, true, null, true),
new PokemonForm("G-Max", SpeciesFormKey.GIGANTAMAX, Type.BUG, Type.FLYING, 17, 32, Abilities.TINTED_LENS, Abilities.TINTED_LENS, Abilities.TINTED_LENS, 495, 85, 35, 80, 120, 90, 85, 45, 50, 198, true), new PokemonForm("G-Max", SpeciesFormKey.GIGANTAMAX, Type.BUG, Type.FLYING, 17, 32, Abilities.COMPOUND_EYES, Abilities.COMPOUND_EYES, Abilities.COMPOUND_EYES, 495, 85, 35, 80, 120, 90, 85, 45, 50, 198, true),
), ),
new PokemonSpecies(Species.WEEDLE, 1, false, false, false, "Hairy Bug Pokémon", Type.BUG, Type.POISON, 0.3, 3.2, Abilities.SHIELD_DUST, Abilities.NONE, Abilities.RUN_AWAY, 195, 40, 35, 30, 20, 20, 50, 255, 70, 39, GrowthRate.MEDIUM_FAST, 50, false), new PokemonSpecies(Species.WEEDLE, 1, false, false, false, "Hairy Bug Pokémon", Type.BUG, Type.POISON, 0.3, 3.2, Abilities.SHIELD_DUST, Abilities.NONE, Abilities.RUN_AWAY, 195, 40, 35, 30, 20, 20, 50, 255, 70, 39, GrowthRate.MEDIUM_FAST, 50, false),
new PokemonSpecies(Species.KAKUNA, 1, false, false, false, "Cocoon Pokémon", Type.BUG, Type.POISON, 0.6, 10, Abilities.SHED_SKIN, Abilities.NONE, Abilities.SHED_SKIN, 205, 45, 25, 50, 25, 25, 35, 120, 70, 72, GrowthRate.MEDIUM_FAST, 50, false), new PokemonSpecies(Species.KAKUNA, 1, false, false, false, "Cocoon Pokémon", Type.BUG, Type.POISON, 0.6, 10, Abilities.SHED_SKIN, Abilities.NONE, Abilities.SHED_SKIN, 205, 45, 25, 50, 25, 25, 35, 120, 70, 72, GrowthRate.MEDIUM_FAST, 50, false),

View File

@ -1,29 +0,0 @@
import { Stat } from "#enums/stat";
import i18next from "i18next";
export { Stat };
export function getStatName(stat: Stat, shorten: boolean = false) {
let ret: string = "";
switch (stat) {
case Stat.HP:
ret = !shorten ? i18next.t("pokemonInfo:Stat.HP") : i18next.t("pokemonInfo:Stat.HPshortened");
break;
case Stat.ATK:
ret = !shorten ? i18next.t("pokemonInfo:Stat.ATK") : i18next.t("pokemonInfo:Stat.ATKshortened");
break;
case Stat.DEF:
ret = !shorten ? i18next.t("pokemonInfo:Stat.DEF") : i18next.t("pokemonInfo:Stat.DEFshortened");
break;
case Stat.SPATK:
ret = !shorten ? i18next.t("pokemonInfo:Stat.SPATK") : i18next.t("pokemonInfo:Stat.SPATKshortened");
break;
case Stat.SPDEF:
ret = !shorten ? i18next.t("pokemonInfo:Stat.SPDEF") : i18next.t("pokemonInfo:Stat.SPDEFshortened");
break;
case Stat.SPD:
ret = !shorten ? i18next.t("pokemonInfo:Stat.SPD") : i18next.t("pokemonInfo:Stat.SPDshortened");
break;
}
return ret;
}

View File

@ -1,38 +0,0 @@
import { BattleStat, getBattleStatName } from "./battle-stat";
import i18next from "i18next";
export enum TempBattleStat {
ATK,
DEF,
SPATK,
SPDEF,
SPD,
ACC,
CRIT
}
export function getTempBattleStatName(tempBattleStat: TempBattleStat) {
if (tempBattleStat === TempBattleStat.CRIT) {
return i18next.t("modifierType:TempBattleStatBoosterStatName.CRIT");
}
return getBattleStatName(tempBattleStat as integer as BattleStat);
}
export function getTempBattleStatBoosterItemName(tempBattleStat: TempBattleStat) {
switch (tempBattleStat) {
case TempBattleStat.ATK:
return "X Attack";
case TempBattleStat.DEF:
return "X Defense";
case TempBattleStat.SPATK:
return "X Sp. Atk";
case TempBattleStat.SPDEF:
return "X Sp. Def";
case TempBattleStat.SPD:
return "X Speed";
case TempBattleStat.ACC:
return "X Accuracy";
case TempBattleStat.CRIT:
return "Dire Hit";
}
}

View File

@ -22,5 +22,6 @@ export enum ArenaTagType {
CRAFTY_SHIELD = "CRAFTY_SHIELD", CRAFTY_SHIELD = "CRAFTY_SHIELD",
TAILWIND = "TAILWIND", TAILWIND = "TAILWIND",
HAPPY_HOUR = "HAPPY_HOUR", HAPPY_HOUR = "HAPPY_HOUR",
SAFEGUARD = "SAFEGUARD",
NO_CRIT = "NO_CRIT" NO_CRIT = "NO_CRIT"
} }

View File

@ -69,5 +69,7 @@ export enum BattlerTagType {
GULP_MISSILE_ARROKUDA = "GULP_MISSILE_ARROKUDA", GULP_MISSILE_ARROKUDA = "GULP_MISSILE_ARROKUDA",
GULP_MISSILE_PIKACHU = "GULP_MISSILE_PIKACHU", GULP_MISSILE_PIKACHU = "GULP_MISSILE_PIKACHU",
BEAK_BLAST_CHARGING = "BEAK_BLAST_CHARGING", BEAK_BLAST_CHARGING = "BEAK_BLAST_CHARGING",
SHELL_TRAP = "SHELL_TRAP" SHELL_TRAP = "SHELL_TRAP",
DRAGON_CHEER = "DRAGON_CHEER",
NO_RETREAT = "NO_RETREAT",
} }

View File

@ -1,13 +1,13 @@
/** /**
* Determines the cursor target when entering the shop phase. * Determines the row cursor target when entering the shop phase.
*/ */
export enum ShopCursorTarget { export enum ShopCursorTarget {
/** Cursor points to Reroll */ /** Cursor points to Reroll row */
REROLL, REROLL,
/** Cursor points to Items */ /** Cursor points to Rewards row */
ITEMS, REWARDS,
/** Cursor points to Shop */ /** Cursor points to Shop row */
SHOP, SHOP,
/** Cursor points to Check Team */ /** Cursor points to Check Team row */
CHECK_TEAM CHECK_TEAM
} }

View File

@ -1,8 +1,75 @@
/** Enum that comprises all possible stat-related attributes, in-battle and permanent, of a Pokemon. */
export enum Stat { export enum Stat {
/** Hit Points */
HP = 0, HP = 0,
/** Attack */
ATK, ATK,
/** Defense */
DEF, DEF,
/** Special Attack */
SPATK, SPATK,
/** Special Defense */
SPDEF, SPDEF,
/** Speed */
SPD, SPD,
/** Accuracy */
ACC,
/** Evasiveness */
EVA
}
/** A constant array comprised of the {@linkcode Stat} values that make up {@linkcode PermanentStat}. */
export const PERMANENT_STATS = [ Stat.HP, Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD ] as const;
/** Type used to describe the core, permanent stats of a Pokemon. */
export type PermanentStat = typeof PERMANENT_STATS[number];
/** A constant array comprised of the {@linkcode Stat} values that make up {@linkcode EFfectiveStat}. */
export const EFFECTIVE_STATS = [ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD ] as const;
/** Type used to describe the intersection of core stats and stats that have stages in battle. */
export type EffectiveStat = typeof EFFECTIVE_STATS[number];
/** A constant array comprised of {@linkcode Stat} the values that make up {@linkcode BattleStat}. */
export const BATTLE_STATS = [ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD, Stat.ACC, Stat.EVA ] as const;
/** Type used to describe the stats that have stages which can be incremented and decremented in battle. */
export type BattleStat = typeof BATTLE_STATS[number];
/** A constant array comprised of {@linkcode Stat} the values that make up {@linkcode TempBattleStat}. */
export const TEMP_BATTLE_STATS = [ Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD, Stat.ACC ] as const;
/** Type used to describe the stats that have X item (`TEMP_STAT_STAGE_BOOSTER`) equivalents. */
export type TempBattleStat = typeof TEMP_BATTLE_STATS[number];
/**
* Provides the translation key corresponding to the amount of stat stages and whether those stat stages
* are positive or negative.
* @param stages the amount of stages
* @param isIncrease dictates a negative (`false`) or a positive (`true`) stat stage change
* @returns the translation key fitting the conditions described by {@linkcode stages} and {@linkcode isIncrease}
*/
export function getStatStageChangeDescriptionKey(stages: number, isIncrease: boolean) {
if (stages === 1) {
return isIncrease ? "battle:statRose" : "battle:statFell";
} else if (stages === 2) {
return isIncrease ? "battle:statSharplyRose" : "battle:statHarshlyFell";
} else if (stages <= 6) {
return isIncrease ? "battle:statRoseDrastically" : "battle:statSeverelyFell";
}
return isIncrease ? "battle:statWontGoAnyHigher" : "battle:statWontGoAnyLower";
}
/**
* Provides the translation key corresponding to a given stat which can be translated into its full name.
* @param stat the {@linkcode Stat} to be translated
* @returns the translation key corresponding to the given {@linkcode Stat}
*/
export function getStatKey(stat: Stat) {
return `pokemonInfo:Stat.${Stat[stat]}`;
}
/**
* Provides the translation key corresponding to a given stat which can be translated into its shortened name.
* @param stat the {@linkcode Stat} to be translated
* @returns the translation key corresponding to the given {@linkcode Stat}
*/
export function getShortenedStatKey(stat: PermanentStat) {
return `pokemonInfo:Stat.${Stat[stat]}shortened`;
} }

View File

@ -339,7 +339,10 @@ export class Arena {
*/ */
triggerWeatherBasedFormChanges(): void { triggerWeatherBasedFormChanges(): void {
this.scene.getField(true).forEach( p => { this.scene.getField(true).forEach( p => {
if (p.hasAbility(Abilities.FORECAST) && p.species.speciesId === Species.CASTFORM) { const isCastformWithForecast = (p.hasAbility(Abilities.FORECAST) && p.species.speciesId === Species.CASTFORM);
const isCherrimWithFlowerGift = (p.hasAbility(Abilities.FLOWER_GIFT) && p.species.speciesId === Species.CHERRIM);
if (isCastformWithForecast || isCherrimWithFlowerGift) {
new ShowAbilityPhase(this.scene, p.getBattlerIndex()); new ShowAbilityPhase(this.scene, p.getBattlerIndex());
this.scene.triggerPokemonFormChange(p, SpeciesFormChangeWeatherTrigger); this.scene.triggerPokemonFormChange(p, SpeciesFormChangeWeatherTrigger);
} }
@ -351,7 +354,10 @@ export class Arena {
*/ */
triggerWeatherBasedFormChangesToNormal(): void { triggerWeatherBasedFormChangesToNormal(): void {
this.scene.getField(true).forEach( p => { this.scene.getField(true).forEach( p => {
if (p.hasAbility(Abilities.FORECAST, false, true) && p.species.speciesId === Species.CASTFORM) { const isCastformWithForecast = (p.hasAbility(Abilities.FORECAST, false, true) && p.species.speciesId === Species.CASTFORM);
const isCherrimWithFlowerGift = (p.hasAbility(Abilities.FLOWER_GIFT, false, true) && p.species.speciesId === Species.CHERRIM);
if (isCastformWithForecast || isCherrimWithFlowerGift) {
new ShowAbilityPhase(this.scene, p.getBattlerIndex()); new ShowAbilityPhase(this.scene, p.getBattlerIndex());
return this.scene.triggerPokemonFormChange(p, SpeciesFormChangeRevertWeatherFormTrigger); return this.scene.triggerPokemonFormChange(p, SpeciesFormChangeRevertWeatherFormTrigger);
} }

View File

@ -3,26 +3,24 @@ import BattleScene, { AnySound } from "../battle-scene";
import { Variant, VariantSet, variantColorCache } from "#app/data/variant"; import { Variant, VariantSet, variantColorCache } from "#app/data/variant";
import { variantData } from "#app/data/variant"; import { variantData } from "#app/data/variant";
import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from "../ui/battle-info"; import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from "../ui/battle-info";
import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, VariableMoveTypeAttr, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatChangesAttr, SacrificialAttr, VariableMoveCategoryAttr, CounterDamageAttr, StatChangeAttr, RechargeAttr, ChargeAttr, IgnoreWeatherTypeDebuffAttr, BypassBurnDamageReductionAttr, SacrificialAttrOnHit, OneHitKOAccuracyAttr, RespectAttackTypeImmunityAttr } from "../data/move"; import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, VariableMoveTypeAttr, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatStagesAttr, SacrificialAttr, VariableMoveCategoryAttr, CounterDamageAttr, StatStageChangeAttr, RechargeAttr, ChargeAttr, IgnoreWeatherTypeDebuffAttr, BypassBurnDamageReductionAttr, SacrificialAttrOnHit, OneHitKOAccuracyAttr, RespectAttackTypeImmunityAttr } from "../data/move";
import { default as PokemonSpecies, PokemonSpeciesForm, SpeciesFormKey, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm, getStarterValueFriendshipCap, speciesStarters, starterPassiveAbilities } from "../data/pokemon-species"; import { default as PokemonSpecies, PokemonSpeciesForm, SpeciesFormKey, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm, getStarterValueFriendshipCap, speciesStarters, starterPassiveAbilities } from "../data/pokemon-species";
import { Constructor } from "#app/utils"; import { Constructor } from "#app/utils";
import * as Utils from "../utils"; import * as Utils from "../utils";
import { Type, TypeDamageMultiplier, getTypeDamageMultiplier, getTypeRgb } from "../data/type"; import { Type, TypeDamageMultiplier, getTypeDamageMultiplier, getTypeRgb } from "../data/type";
import { getLevelTotalExp } from "../data/exp"; import { getLevelTotalExp } from "../data/exp";
import { Stat } from "../data/pokemon-stat"; import { Stat, type PermanentStat, type BattleStat, type EffectiveStat, PERMANENT_STATS, BATTLE_STATS, EFFECTIVE_STATS } from "#enums/stat";
import { DamageMoneyRewardModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, EnemyEndureChanceModifier, EnemyFusionChanceModifier, HiddenAbilityRateBoosterModifier, PokemonBaseStatModifier, PokemonFriendshipBoosterModifier, PokemonHeldItemModifier, PokemonNatureWeightModifier, ShinyRateBoosterModifier, SurviveDamageModifier, TempBattleStatBoosterModifier, StatBoosterModifier, CritBoosterModifier, TerastallizeModifier } from "../modifier/modifier"; import { DamageMoneyRewardModifier, EnemyDamageBoosterModifier, EnemyDamageReducerModifier, EnemyEndureChanceModifier, EnemyFusionChanceModifier, HiddenAbilityRateBoosterModifier, BaseStatModifier, PokemonFriendshipBoosterModifier, PokemonHeldItemModifier, PokemonNatureWeightModifier, ShinyRateBoosterModifier, SurviveDamageModifier, TempStatStageBoosterModifier, TempCritBoosterModifier, StatBoosterModifier, CritBoosterModifier, TerastallizeModifier } from "../modifier/modifier";
import { PokeballType } from "../data/pokeball"; import { PokeballType } from "../data/pokeball";
import { Gender } from "../data/gender"; import { Gender } from "../data/gender";
import { initMoveAnim, loadMoveAnimAssets } from "../data/battle-anims"; import { initMoveAnim, loadMoveAnimAssets } from "../data/battle-anims";
import { Status, StatusEffect, getRandomStatus } from "../data/status-effect"; import { Status, StatusEffect, getRandomStatus } from "../data/status-effect";
import { pokemonEvolutions, pokemonPrevolutions, SpeciesFormEvolution, SpeciesEvolutionCondition, FusionSpeciesFormEvolution } from "../data/pokemon-evolutions"; import { pokemonEvolutions, pokemonPrevolutions, SpeciesFormEvolution, SpeciesEvolutionCondition, FusionSpeciesFormEvolution } from "../data/pokemon-evolutions";
import { reverseCompatibleTms, tmSpecies, tmPoolTiers } from "../data/tms"; import { reverseCompatibleTms, tmSpecies, tmPoolTiers } from "../data/tms";
import { BattleStat } from "../data/battle-stat"; import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoostTag, TypeImmuneTag, getBattlerTag, SemiInvulnerableTag, TypeBoostTag, ExposedTag, DragonCheerTag, CritBoostTag, TrappedTag } from "../data/battler-tags";
import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoostTag, TypeImmuneTag, getBattlerTag, SemiInvulnerableTag, TypeBoostTag, ExposedTag } from "../data/battler-tags";
import { WeatherType } from "../data/weather"; import { WeatherType } from "../data/weather";
import { TempBattleStat } from "../data/temp-battle-stat";
import { ArenaTagSide, NoCritTag, WeakenMoveScreenTag } from "../data/arena-tag"; import { ArenaTagSide, NoCritTag, WeakenMoveScreenTag } from "../data/arena-tag";
import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldBattleStatMultiplierAbAttrs, FieldMultiplyBattleStatAbAttr, AddSecondStrikeAbAttr, IgnoreOpponentEvasionAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr, MoveTypeChangeAbAttr } from "../data/ability"; import { Ability, AbAttr, StatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatStagesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldStatMultiplierAbAttrs, FieldMultiplyStatAbAttr, AddSecondStrikeAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr, MoveTypeChangeAbAttr, FullHpResistTypeAbAttr, applyCheckTrappedAbAttrs, CheckTrappedAbAttr } from "../data/ability";
import PokemonData from "../system/pokemon-data"; import PokemonData from "../system/pokemon-data";
import { BattlerIndex } from "../battle"; import { BattlerIndex } from "../battle";
import { Mode } from "../ui/ui"; import { Mode } from "../ui/ui";
@ -40,7 +38,7 @@ import Overrides from "#app/overrides";
import i18next from "i18next"; import i18next from "i18next";
import { speciesEggMoves } from "../data/egg-moves"; import { speciesEggMoves } from "../data/egg-moves";
import { ModifierTier } from "../modifier/modifier-tier"; import { ModifierTier } from "../modifier/modifier-tier";
import { applyChallenges, ChallengeType } from "#app/data/challenge.js"; import { applyChallenges, ChallengeType } from "#app/data/challenge";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import { ArenaTagType } from "#enums/arena-tag-type"; import { ArenaTagType } from "#enums/arena-tag-type";
import { BattleSpec } from "#enums/battle-spec"; import { BattleSpec } from "#enums/battle-spec";
@ -49,17 +47,17 @@ import { BerryType } from "#enums/berry-type";
import { Biome } from "#enums/biome"; import { Biome } from "#enums/biome";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import { getPokemonNameWithAffix } from "#app/messages";
import { DamagePhase } from "#app/phases/damage-phase";
import { FaintPhase } from "#app/phases/faint-phase";
import { LearnMovePhase } from "#app/phases/learn-move-phase";
import { MoveEffectPhase } from "#app/phases/move-effect-phase";
import { MoveEndPhase } from "#app/phases/move-end-phase";
import { ObtainStatusEffectPhase } from "#app/phases/obtain-status-effect-phase";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { SwitchSummonPhase } from "#app/phases/switch-summon-phase";
import { ToggleDoublePositionPhase } from "#app/phases/toggle-double-position-phase";
import { Challenges } from "#enums/challenges"; import { Challenges } from "#enums/challenges";
import { getPokemonNameWithAffix } from "#app/messages.js";
import { DamagePhase } from "#app/phases/damage-phase.js";
import { FaintPhase } from "#app/phases/faint-phase.js";
import { LearnMovePhase } from "#app/phases/learn-move-phase.js";
import { MoveEffectPhase } from "#app/phases/move-effect-phase.js";
import { MoveEndPhase } from "#app/phases/move-end-phase.js";
import { ObtainStatusEffectPhase } from "#app/phases/obtain-status-effect-phase.js";
import { StatChangePhase } from "#app/phases/stat-change-phase.js";
import { SwitchSummonPhase } from "#app/phases/switch-summon-phase.js";
import { ToggleDoublePositionPhase } from "#app/phases/toggle-double-position-phase.js";
export enum FieldPosition { export enum FieldPosition {
CENTER, CENTER,
@ -119,6 +117,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
public maskEnabled: boolean; public maskEnabled: boolean;
public maskSprite: Phaser.GameObjects.Sprite | null; public maskSprite: Phaser.GameObjects.Sprite | null;
public usedTMs: Moves[];
private shinySparkle: Phaser.GameObjects.Sprite; private shinySparkle: Phaser.GameObjects.Sprite;
constructor(scene: BattleScene, x: number, y: number, species: PokemonSpecies, level: integer, abilityIndex?: integer, formIndex?: integer, gender?: Gender, shiny?: boolean, variant?: Variant, ivs?: integer[], nature?: Nature, dataSource?: Pokemon | PokemonData) { constructor(scene: BattleScene, x: number, y: number, species: PokemonSpecies, level: integer, abilityIndex?: integer, formIndex?: integer, gender?: Gender, shiny?: boolean, variant?: Variant, ivs?: integer[], nature?: Nature, dataSource?: Pokemon | PokemonData) {
@ -133,9 +133,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.scene.applyModifiers(HiddenAbilityRateBoosterModifier, true, hiddenAbilityChance); this.scene.applyModifiers(HiddenAbilityRateBoosterModifier, true, hiddenAbilityChance);
} }
const hasHiddenAbility = !Utils.randSeedInt(hiddenAbilityChance.value);
const randAbilityIndex = Utils.randSeedInt(2);
this.species = species; this.species = species;
this.pokeball = dataSource?.pokeball || PokeballType.POKEBALL; this.pokeball = dataSource?.pokeball || PokeballType.POKEBALL;
this.level = level; this.level = level;
@ -146,6 +143,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.abilityIndex = abilityIndex; // Use the provided ability index if it is defined this.abilityIndex = abilityIndex; // Use the provided ability index if it is defined
} else { } else {
// If abilityIndex is not provided, determine it based on species and hidden ability // If abilityIndex is not provided, determine it based on species and hidden ability
const hasHiddenAbility = !Utils.randSeedInt(hiddenAbilityChance.value);
const randAbilityIndex = Utils.randSeedInt(2);
if (species.abilityHidden && hasHiddenAbility) { if (species.abilityHidden && hasHiddenAbility) {
// If the species has a hidden ability and the hidden ability is present // If the species has a hidden ability and the hidden ability is present
this.abilityIndex = 2; this.abilityIndex = 2;
@ -196,6 +195,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.fusionVariant = dataSource.fusionVariant || 0; this.fusionVariant = dataSource.fusionVariant || 0;
this.fusionGender = dataSource.fusionGender; this.fusionGender = dataSource.fusionGender;
this.fusionLuck = dataSource.fusionLuck; this.fusionLuck = dataSource.fusionLuck;
this.usedTMs = dataSource.usedTMs ?? [];
} else { } else {
this.id = Utils.randSeedInt(4294967296); this.id = Utils.randSeedInt(4294967296);
this.ivs = ivs || Utils.getIvsFromId(this.id); this.ivs = ivs || Utils.getIvsFromId(this.id);
@ -674,49 +674,139 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}); });
} }
getStat(stat: Stat): integer { /**
* Retrieves the entire set of stats of the {@linkcode Pokemon}.
* @param bypassSummonData prefer actual stats (`true` by default) or in-battle overriden stats (`false`)
* @returns the numeric values of the {@linkcode Pokemon}'s stats
*/
getStats(bypassSummonData: boolean = true): number[] {
if (!bypassSummonData && this.summonData?.stats) {
return this.summonData.stats;
}
return this.stats;
}
/**
* Retrieves the corresponding {@linkcode PermanentStat} of the {@linkcode Pokemon}.
* @param stat the desired {@linkcode PermanentStat}
* @param bypassSummonData prefer actual stats (`true` by default) or in-battle overridden stats (`false`)
* @returns the numeric value of the desired {@linkcode Stat}
*/
getStat(stat: PermanentStat, bypassSummonData: boolean = true): number {
if (!bypassSummonData && this.summonData && (this.summonData.stats[stat] !== 0)) {
return this.summonData.stats[stat];
}
return this.stats[stat]; return this.stats[stat];
} }
getBattleStat(stat: Stat, opponent?: Pokemon, move?: Move, isCritical: boolean = false): integer { /**
if (stat === Stat.HP) { * Writes the value to the corrseponding {@linkcode PermanentStat} of the {@linkcode Pokemon}.
return this.getStat(Stat.HP); *
} * Note that this does nothing if {@linkcode value} is less than 0.
const battleStat = (stat - 1) as BattleStat; * @param stat the desired {@linkcode PermanentStat} to be overwritten
const statLevel = new Utils.IntegerHolder(this.summonData.battleStats[battleStat]); * @param value the desired numeric value
if (opponent) { * @param bypassSummonData write to actual stats (`true` by default) or in-battle overridden stats (`false`)
if (isCritical) { */
switch (stat) { setStat(stat: PermanentStat, value: number, bypassSummonData: boolean = true): void {
case Stat.ATK: if (value >= 0) {
case Stat.SPATK: if (!bypassSummonData && this.summonData) {
statLevel.value = Math.max(statLevel.value, 0); this.summonData.stats[stat] = value;
break; } else {
case Stat.DEF: this.stats[stat] = value;
case Stat.SPDEF:
statLevel.value = Math.min(statLevel.value, 0);
break;
} }
} }
applyAbAttrs(IgnoreOpponentStatChangesAbAttr, opponent, null, false, statLevel); }
if (move) {
applyMoveAttrs(IgnoreOpponentStatChangesAttr, this, opponent, move, statLevel); /**
* Retrieves the entire set of in-battle stat stages of the {@linkcode Pokemon}.
* @returns the numeric values of the {@linkcode Pokemon}'s in-battle stat stages if available, a fresh stat stage array otherwise
*/
getStatStages(): number[] {
return this.summonData ? this.summonData.statStages : [ 0, 0, 0, 0, 0, 0, 0 ];
}
/**
* Retrieves the in-battle stage of the specified {@linkcode BattleStat}.
* @param stat the {@linkcode BattleStat} whose stage is desired
* @returns the stage of the desired {@linkcode BattleStat} if available, 0 otherwise
*/
getStatStage(stat: BattleStat): number {
return this.summonData ? this.summonData.statStages[stat - 1] : 0;
}
/**
* Writes the value to the in-battle stage of the corresponding {@linkcode BattleStat} of the {@linkcode Pokemon}.
*
* Note that, if the value is not within a range of [-6, 6], it will be forced to the closest range bound.
* @param stat the {@linkcode BattleStat} whose stage is to be overwritten
* @param value the desired numeric value
*/
setStatStage(stat: BattleStat, value: number): void {
if (this.summonData) {
if (value >= -6) {
this.summonData.statStages[stat - 1] = Math.min(value, 6);
} else {
this.summonData.statStages[stat - 1] = Math.max(value, -6);
} }
} }
if (this.isPlayer()) {
this.scene.applyModifiers(TempBattleStatBoosterModifier, this.isPlayer(), battleStat as integer as TempBattleStat, statLevel);
} }
const statValue = new Utils.NumberHolder(this.getStat(stat));
/**
* Retrieves the critical-hit stage considering the move used and the Pokemon
* who used it.
* @param source the {@linkcode Pokemon} who using the move
* @param move the {@linkcode Move} being used
* @returns the final critical-hit stage value
*/
getCritStage(source: Pokemon, move: Move): number {
const critStage = new Utils.IntegerHolder(0);
applyMoveAttrs(HighCritAttr, source, this, move, critStage);
this.scene.applyModifiers(CritBoosterModifier, source.isPlayer(), source, critStage);
this.scene.applyModifiers(TempCritBoosterModifier, source.isPlayer(), critStage);
const bonusCrit = new Utils.BooleanHolder(false);
//@ts-ignore
if (applyAbAttrs(BonusCritAbAttr, source, null, false, bonusCrit)) { // TODO: resolve ts-ignore. This is a promise. Checking a promise is bogus.
if (bonusCrit.value) {
critStage.value += 1;
}
}
const critBoostTag = source.getTag(CritBoostTag);
if (critBoostTag) {
if (critBoostTag instanceof DragonCheerTag) {
critStage.value += critBoostTag.typesOnAdd.includes(Type.DRAGON) ? 2 : 1;
} else {
critStage.value += 2;
}
}
console.log(`crit stage: +${critStage.value}`);
return critStage.value;
}
/**
* Calculates and retrieves the final value of a stat considering any held
* items, move effects, opponent abilities, and whether there was a critical
* hit.
* @param stat the desired {@linkcode EffectiveStat}
* @param opponent the target {@linkcode Pokemon}
* @param move the {@linkcode Move} being used
* @param isCritical determines whether a critical hit has occurred or not (`false` by default)
* @returns the final in-battle value of a stat
*/
getEffectiveStat(stat: EffectiveStat, opponent?: Pokemon, move?: Move, isCritical: boolean = false): integer {
const statValue = new Utils.NumberHolder(this.getStat(stat, false));
this.scene.applyModifiers(StatBoosterModifier, this.isPlayer(), this, stat, statValue); this.scene.applyModifiers(StatBoosterModifier, this.isPlayer(), this, stat, statValue);
const fieldApplied = new Utils.BooleanHolder(false); const fieldApplied = new Utils.BooleanHolder(false);
for (const pokemon of this.scene.getField(true)) { for (const pokemon of this.scene.getField(true)) {
applyFieldBattleStatMultiplierAbAttrs(FieldMultiplyBattleStatAbAttr, pokemon, stat, statValue, this, fieldApplied); applyFieldStatMultiplierAbAttrs(FieldMultiplyStatAbAttr, pokemon, stat, statValue, this, fieldApplied);
if (fieldApplied.value) { if (fieldApplied.value) {
break; break;
} }
} }
applyBattleStatMultiplierAbAttrs(BattleStatMultiplierAbAttr, this, battleStat, statValue); applyStatMultiplierAbAttrs(StatMultiplierAbAttr, this, stat, statValue);
let ret = statValue.value * (Math.max(2, 2 + statLevel.value) / Math.max(2, 2 - statLevel.value)); let ret = statValue.value * this.getStatStageMultiplier(stat, opponent, move, isCritical);
switch (stat) { switch (stat) {
case Stat.ATK: case Stat.ATK:
if (this.getTag(BattlerTagType.SLOW_START)) { if (this.getTag(BattlerTagType.SLOW_START)) {
@ -763,24 +853,25 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (!this.stats) { if (!this.stats) {
this.stats = [ 0, 0, 0, 0, 0, 0 ]; this.stats = [ 0, 0, 0, 0, 0, 0 ];
} }
const baseStats = this.getSpeciesForm().baseStats.slice(0);
if (this.fusionSpecies) { // Get and manipulate base stats
const fusionBaseStats = this.getFusionSpeciesForm().baseStats; const baseStats = this.getSpeciesForm(true).baseStats.slice();
for (let s = 0; s < this.stats.length; s++) { if (this.isFusion()) {
const fusionBaseStats = this.getFusionSpeciesForm(true).baseStats;
for (const s of PERMANENT_STATS) {
baseStats[s] = Math.ceil((baseStats[s] + fusionBaseStats[s]) / 2); baseStats[s] = Math.ceil((baseStats[s] + fusionBaseStats[s]) / 2);
} }
} else if (this.scene.gameMode.isSplicedOnly) { } else if (this.scene.gameMode.isSplicedOnly) {
for (let s = 0; s < this.stats.length; s++) { for (const s of PERMANENT_STATS) {
baseStats[s] = Math.ceil(baseStats[s] / 2); baseStats[s] = Math.ceil(baseStats[s] / 2);
} }
} }
this.scene.applyModifiers(PokemonBaseStatModifier, this.isPlayer(), this, baseStats); this.scene.applyModifiers(BaseStatModifier, this.isPlayer(), this, baseStats);
const stats = Utils.getEnumValues(Stat);
for (const s of stats) { // Using base stats, calculate and store stats one by one
const isHp = s === Stat.HP; for (const s of PERMANENT_STATS) {
const baseStat = baseStats[s]; let value = Math.floor(((2 * baseStats[s] + this.ivs[s]) * this.level) * 0.01);
let value = Math.floor(((2 * baseStat + this.ivs[s]) * this.level) * 0.01); if (s === Stat.HP) {
if (isHp) {
value = value + this.level + 10; value = value + this.level + 10;
if (this.hasAbility(Abilities.WONDER_GUARD, false, true)) { if (this.hasAbility(Abilities.WONDER_GUARD, false, true)) {
value = 1; value = 1;
@ -801,7 +892,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
value = Math.max(Math[natureStatMultiplier.value > 1 ? "ceil" : "floor"](value * natureStatMultiplier.value), 1); value = Math.max(Math[natureStatMultiplier.value > 1 ? "ceil" : "floor"](value * natureStatMultiplier.value), 1);
} }
} }
this.stats[s] = value;
this.setStat(s, value);
} }
} }
@ -936,7 +1028,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (this.metBiome === -1 && !this.scene.gameMode.isFreshStartChallenge() && !this.scene.gameMode.isDaily) { if (this.metBiome === -1 && !this.scene.gameMode.isFreshStartChallenge() && !this.scene.gameMode.isDaily) {
levelMoves = this.getUnlockedEggMoves().concat(levelMoves); levelMoves = this.getUnlockedEggMoves().concat(levelMoves);
} }
return levelMoves.filter(lm => !this.moveset.some(m => m?.moveId === lm)); if (Array.isArray(this.usedTMs) && this.usedTMs.length > 0) {
levelMoves = this.usedTMs.filter(m => !levelMoves.includes(m)).concat(levelMoves);
}
levelMoves = levelMoves.filter(lm => !this.moveset.some(m => m?.moveId === lm));
return levelMoves;
} }
/** /**
@ -1210,6 +1306,28 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return !!this.getTag(GroundedTag) || (!this.isOfType(Type.FLYING, true, true) && !this.hasAbility(Abilities.LEVITATE) && !this.getTag(BattlerTagType.MAGNET_RISEN) && !this.getTag(SemiInvulnerableTag)); return !!this.getTag(GroundedTag) || (!this.isOfType(Type.FLYING, true, true) && !this.hasAbility(Abilities.LEVITATE) && !this.getTag(BattlerTagType.MAGNET_RISEN) && !this.getTag(SemiInvulnerableTag));
} }
/**
* Determines whether this Pokemon is prevented from running or switching due
* to effects from moves and/or abilities.
* @param trappedAbMessages `string[]` If defined, ability trigger messages
* (e.g. from Shadow Tag) are forwarded through this array.
* @param simulated `boolean` if `true`, applies abilities via simulated calls.
* @returns
*/
isTrapped(trappedAbMessages: string[] = [], simulated: boolean = true): boolean {
if (this.isOfType(Type.GHOST)) {
return false;
}
const trappedByAbility = new Utils.BooleanHolder(false);
this.scene.getEnemyField()!.forEach(enemyPokemon =>
applyCheckTrappedAbAttrs(CheckTrappedAbAttr, enemyPokemon, trappedByAbility, this, trappedAbMessages, simulated)
);
return (trappedByAbility.value || !!this.getTag(TrappedTag));
}
/** /**
* Calculates the type of a move when used by this Pokemon after * Calculates the type of a move when used by this Pokemon after
* type-changing move and ability attributes have applied. * type-changing move and ability attributes have applied.
@ -1276,6 +1394,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
} }
// Apply Tera Shell's effect to attacks after all immunities are accounted for
if (!ignoreAbility && move.category !== MoveCategory.STATUS) {
applyPreDefendAbAttrs(FullHpResistTypeAbAttr, this, source, move, cancelledHolder, simulated, typeMultiplier);
}
return (!cancelledHolder.value ? typeMultiplier.value : 0) as TypeDamageMultiplier; return (!cancelledHolder.value ? typeMultiplier.value : 0) as TypeDamageMultiplier;
} }
@ -1345,7 +1468,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const types = this.getTypes(true); const types = this.getTypes(true);
const enemyTypes = opponent.getTypes(true, true); const enemyTypes = opponent.getTypes(true, true);
/** Is this Pokemon faster than the opponent? */ /** Is this Pokemon faster than the opponent? */
const outspeed = (this.isActive(true) ? this.getBattleStat(Stat.SPD, opponent) : this.getStat(Stat.SPD)) >= opponent.getBattleStat(Stat.SPD, this); const outspeed = (this.isActive(true) ? this.getEffectiveStat(Stat.SPD, opponent) : this.getStat(Stat.SPD, false)) >= opponent.getEffectiveStat(Stat.SPD, this);
/** /**
* Based on how effective this Pokemon's types are offensively against the opponent's types. * Based on how effective this Pokemon's types are offensively against the opponent's types.
* This score is increased by 25 percent if this Pokemon is faster than the opponent. * This score is increased by 25 percent if this Pokemon is faster than the opponent.
@ -1501,13 +1624,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
/** /**
* Function that tries to set a Pokemon shiny based on the trainer's trainer ID and secret ID * Function that tries to set a Pokemon shiny based on the trainer's trainer ID and secret ID.
* Endless Pokemon in the end biome are unable to be set to shiny * Endless Pokemon in the end biome are unable to be set to shiny
* *
* The exact mechanic is that it calculates E as the XOR of the player's trainer ID and secret ID * The exact mechanic is that it calculates E as the XOR of the player's trainer ID and secret ID.
* F is calculated as the XOR of the first 16 bits of the Pokemon's ID with the last 16 bits * F is calculated as the XOR of the first 16 bits of the Pokemon's ID with the last 16 bits.
* The XOR of E and F are then compared to the thresholdOverride (default case 32) to see whether or not to generate a shiny * The XOR of E and F are then compared to the {@linkcode shinyThreshold} (or {@linkcode thresholdOverride} if set) to see whether or not to generate a shiny.
* @param thresholdOverride number that is divided by 2^16 (65536) to get the shiny chance * The base shiny odds are {@linkcode baseShinyChance} / 65536
* @param thresholdOverride number that is divided by 2^16 (65536) to get the shiny chance, overrides {@linkcode shinyThreshold} if set (bypassing shiny rate modifiers such as Shiny Charm)
* @returns true if the Pokemon has been set as a shiny, false otherwise * @returns true if the Pokemon has been set as a shiny, false otherwise
*/ */
trySetShiny(thresholdOverride?: integer): boolean { trySetShiny(thresholdOverride?: integer): boolean {
@ -1522,7 +1646,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const E = this.scene.gameData.trainerId ^ this.scene.gameData.secretId; const E = this.scene.gameData.trainerId ^ this.scene.gameData.secretId;
const F = rand1 ^ rand2; const F = rand1 ^ rand2;
const shinyThreshold = new Utils.IntegerHolder(32); /** `64/65536 -> 1/1024` */
const baseShinyChance = 64;
const shinyThreshold = new Utils.IntegerHolder(baseShinyChance);
if (thresholdOverride === undefined) { if (thresholdOverride === undefined) {
if (this.scene.eventManager.isEventActive()) { if (this.scene.eventManager.isEventActive()) {
shinyThreshold.value *= this.scene.eventManager.getShinyMultiplier(); shinyThreshold.value *= this.scene.eventManager.getShinyMultiplier();
@ -1535,9 +1661,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
this.shiny = (E ^ F) < shinyThreshold.value; this.shiny = (E ^ F) < shinyThreshold.value;
if ((E ^ F) < 32) {
console.log("REAL SHINY!!");
}
if (this.shiny) { if (this.shiny) {
this.initShinySparkle(); this.initShinySparkle();
@ -1724,7 +1847,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
movePool = movePool.map(m => [m[0], m[1] * (!!allMoves[m[0]].hasAttr(SacrificialAttr) ? 0.5 : 1)]); movePool = movePool.map(m => [m[0], m[1] * (!!allMoves[m[0]].hasAttr(SacrificialAttr) ? 0.5 : 1)]);
movePool = movePool.map(m => [m[0], m[1] * (!!allMoves[m[0]].hasAttr(SacrificialAttrOnHit) ? 0.5 : 1)]); movePool = movePool.map(m => [m[0], m[1] * (!!allMoves[m[0]].hasAttr(SacrificialAttrOnHit) ? 0.5 : 1)]);
// Trainers get a weight bump to stat buffing moves // Trainers get a weight bump to stat buffing moves
movePool = movePool.map(m => [m[0], m[1] * (allMoves[m[0]].getAttrs(StatChangeAttr).some(a => a.levels > 1 && a.selfTarget) ? 1.25 : 1)]); movePool = movePool.map(m => [m[0], m[1] * (allMoves[m[0]].getAttrs(StatStageChangeAttr).some(a => a.stages > 1 && a.selfTarget) ? 1.25 : 1)]);
// Trainers get a weight decrease to multiturn moves // Trainers get a weight decrease to multiturn moves
movePool = movePool.map(m => [m[0], m[1] * (!!allMoves[m[0]].hasAttr(ChargeAttr) || !!allMoves[m[0]].hasAttr(RechargeAttr) ? 0.7 : 1)]); movePool = movePool.map(m => [m[0], m[1] * (!!allMoves[m[0]].hasAttr(ChargeAttr) || !!allMoves[m[0]].hasAttr(RechargeAttr) ? 0.7 : 1)]);
} }
@ -1736,8 +1859,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
movePool = movePool.map(m => [m[0], m[1] * (allMoves[m[0]].category === MoveCategory.STATUS ? 1 : Math.max(Math.min(allMoves[m[0]].power/maxPower, 1), 0.5))]); movePool = movePool.map(m => [m[0], m[1] * (allMoves[m[0]].category === MoveCategory.STATUS ? 1 : Math.max(Math.min(allMoves[m[0]].power/maxPower, 1), 0.5))]);
// Weight damaging moves against the lower stat // Weight damaging moves against the lower stat
const worseCategory: MoveCategory = this.stats[Stat.ATK] > this.stats[Stat.SPATK] ? MoveCategory.SPECIAL : MoveCategory.PHYSICAL; const atk = this.getStat(Stat.ATK);
const statRatio = worseCategory === MoveCategory.PHYSICAL ? this.stats[Stat.ATK]/this.stats[Stat.SPATK] : this.stats[Stat.SPATK]/this.stats[Stat.ATK]; const spAtk = this.getStat(Stat.SPATK);
const worseCategory: MoveCategory = atk > spAtk ? MoveCategory.SPECIAL : MoveCategory.PHYSICAL;
const statRatio = worseCategory === MoveCategory.PHYSICAL ? atk / spAtk : spAtk / atk;
movePool = movePool.map(m => [m[0], m[1] * (allMoves[m[0]].category === worseCategory ? statRatio : 1)]); movePool = movePool.map(m => [m[0], m[1] * (allMoves[m[0]].category === worseCategory ? statRatio : 1)]);
let weightMultiplier = 0.9; // The higher this is the more the game weights towards higher level moves. At 0 all moves are equal weight. let weightMultiplier = 0.9; // The higher this is the more the game weights towards higher level moves. At 0 all moves are equal weight.
@ -1923,6 +2048,48 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return this instanceof PlayerPokemon ? this.scene.getPlayerField() : this.scene.getEnemyField(); return this instanceof PlayerPokemon ? this.scene.getPlayerField() : this.scene.getEnemyField();
} }
/**
* Calculates the stat stage multiplier of the user against an opponent.
*
* Note that this does not apply to evasion or accuracy
* @see {@linkcode getAccuracyMultiplier}
* @param stat the desired {@linkcode EffectiveStat}
* @param opponent the target {@linkcode Pokemon}
* @param move the {@linkcode Move} being used
* @param isCritical determines whether a critical hit has occurred or not (`false` by default)
* @return the stat stage multiplier to be used for effective stat calculation
*/
getStatStageMultiplier(stat: EffectiveStat, opponent?: Pokemon, move?: Move, isCritical: boolean = false): number {
const statStage = new Utils.IntegerHolder(this.getStatStage(stat));
const ignoreStatStage = new Utils.BooleanHolder(false);
if (opponent) {
if (isCritical) {
switch (stat) {
case Stat.ATK:
case Stat.SPATK:
statStage.value = Math.max(statStage.value, 0);
break;
case Stat.DEF:
case Stat.SPDEF:
statStage.value = Math.min(statStage.value, 0);
break;
}
}
applyAbAttrs(IgnoreOpponentStatStagesAbAttr, opponent, null, false, stat, ignoreStatStage);
if (move) {
applyMoveAttrs(IgnoreOpponentStatStagesAttr, this, opponent, move, ignoreStatStage);
}
}
if (!ignoreStatStage.value) {
const statStageMultiplier = new Utils.NumberHolder(Math.max(2, 2 + statStage.value) / Math.max(2, 2 - statStage.value));
this.scene.applyModifiers(TempStatStageBoosterModifier, this.isPlayer(), stat, statStageMultiplier);
return Math.min(statStageMultiplier.value, 4);
}
return 1;
}
/** /**
* Calculates the accuracy multiplier of the user against a target. * Calculates the accuracy multiplier of the user against a target.
* *
@ -1939,34 +2106,38 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return 1; return 1;
} }
const userAccuracyLevel = new Utils.IntegerHolder(this.summonData.battleStats[BattleStat.ACC]); const userAccStage = new Utils.IntegerHolder(this.getStatStage(Stat.ACC));
const targetEvasionLevel = new Utils.IntegerHolder(target.summonData.battleStats[BattleStat.EVA]); const targetEvaStage = new Utils.IntegerHolder(target.getStatStage(Stat.EVA));
applyAbAttrs(IgnoreOpponentStatChangesAbAttr, target, null, false, userAccuracyLevel); const ignoreAccStatStage = new Utils.BooleanHolder(false);
applyAbAttrs(IgnoreOpponentStatChangesAbAttr, this, null, false, targetEvasionLevel); const ignoreEvaStatStage = new Utils.BooleanHolder(false);
applyAbAttrs(IgnoreOpponentEvasionAbAttr, this, null, false, targetEvasionLevel);
applyMoveAttrs(IgnoreOpponentStatChangesAttr, this, target, sourceMove, targetEvasionLevel); applyAbAttrs(IgnoreOpponentStatStagesAbAttr, target, null, false, Stat.ACC, ignoreAccStatStage);
this.scene.applyModifiers(TempBattleStatBoosterModifier, this.isPlayer(), TempBattleStat.ACC, userAccuracyLevel); applyAbAttrs(IgnoreOpponentStatStagesAbAttr, this, null, false, Stat.EVA, ignoreEvaStatStage);
applyMoveAttrs(IgnoreOpponentStatStagesAttr, this, target, sourceMove, ignoreEvaStatStage);
this.scene.applyModifiers(TempStatStageBoosterModifier, this.isPlayer(), Stat.ACC, userAccStage);
userAccStage.value = ignoreAccStatStage.value ? 0 : Math.min(userAccStage.value, 6);
targetEvaStage.value = ignoreEvaStatStage.value ? 0 : targetEvaStage.value;
if (target.findTag(t => t instanceof ExposedTag)) { if (target.findTag(t => t instanceof ExposedTag)) {
targetEvasionLevel.value = Math.min(0, targetEvasionLevel.value); targetEvaStage.value = Math.min(0, targetEvaStage.value);
} }
const accuracyMultiplier = new Utils.NumberHolder(1); const accuracyMultiplier = new Utils.NumberHolder(1);
if (userAccuracyLevel.value !== targetEvasionLevel.value) { if (userAccStage.value !== targetEvaStage.value) {
accuracyMultiplier.value = userAccuracyLevel.value > targetEvasionLevel.value accuracyMultiplier.value = userAccStage.value > targetEvaStage.value
? (3 + Math.min(userAccuracyLevel.value - targetEvasionLevel.value, 6)) / 3 ? (3 + Math.min(userAccStage.value - targetEvaStage.value, 6)) / 3
: 3 / (3 + Math.min(targetEvasionLevel.value - userAccuracyLevel.value, 6)); : 3 / (3 + Math.min(targetEvaStage.value - userAccStage.value, 6));
} }
applyBattleStatMultiplierAbAttrs(BattleStatMultiplierAbAttr, this, BattleStat.ACC, accuracyMultiplier, false, sourceMove); applyStatMultiplierAbAttrs(StatMultiplierAbAttr, this, Stat.ACC, accuracyMultiplier, false, sourceMove);
const evasionMultiplier = new Utils.NumberHolder(1); const evasionMultiplier = new Utils.NumberHolder(1);
applyBattleStatMultiplierAbAttrs(BattleStatMultiplierAbAttr, target, BattleStat.EVA, evasionMultiplier); applyStatMultiplierAbAttrs(StatMultiplierAbAttr, target, Stat.EVA, evasionMultiplier);
accuracyMultiplier.value /= evasionMultiplier.value; return accuracyMultiplier.value / evasionMultiplier.value;
return accuracyMultiplier.value;
} }
/** /**
@ -2053,22 +2224,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (critOnly.value || critAlways) { if (critOnly.value || critAlways) {
isCritical = true; isCritical = true;
} else { } else {
const critLevel = new Utils.IntegerHolder(0); const critChance = [24, 8, 2, 1][Math.max(0, Math.min(this.getCritStage(source, move), 3))];
applyMoveAttrs(HighCritAttr, source, this, move, critLevel);
this.scene.applyModifiers(CritBoosterModifier, source.isPlayer(), source, critLevel);
this.scene.applyModifiers(TempBattleStatBoosterModifier, source.isPlayer(), TempBattleStat.CRIT, critLevel);
const bonusCrit = new Utils.BooleanHolder(false);
//@ts-ignore
if (applyAbAttrs(BonusCritAbAttr, source, null, false, bonusCrit)) { // TODO: resolve ts-ignore. This is a promise. Checking a promise is bogus.
if (bonusCrit.value) {
critLevel.value += 1;
}
}
if (source.getTag(BattlerTagType.CRIT_BOOST)) {
critLevel.value += 2;
}
console.log(`crit stage: +${critLevel.value}`);
const critChance = [24, 8, 2, 1][Math.max(0, Math.min(critLevel.value, 3))];
isCritical = critChance === 1 || !this.scene.randBattleSeedInt(critChance); isCritical = critChance === 1 || !this.scene.randBattleSeedInt(critChance);
if (Overrides.NEVER_CRIT_OVERRIDE) { if (Overrides.NEVER_CRIT_OVERRIDE) {
isCritical = false; isCritical = false;
@ -2082,8 +2238,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
isCritical = false; isCritical = false;
} }
} }
const sourceAtk = new Utils.IntegerHolder(source.getBattleStat(isPhysical ? Stat.ATK : Stat.SPATK, this, undefined, isCritical)); const sourceAtk = new Utils.IntegerHolder(source.getEffectiveStat(isPhysical ? Stat.ATK : Stat.SPATK, this, undefined, isCritical));
const targetDef = new Utils.IntegerHolder(this.getBattleStat(isPhysical ? Stat.DEF : Stat.SPDEF, source, move, isCritical)); const targetDef = new Utils.IntegerHolder(this.getEffectiveStat(isPhysical ? Stat.DEF : Stat.SPDEF, source, move, isCritical));
const criticalMultiplier = new Utils.NumberHolder(isCritical ? 1.5 : 1); const criticalMultiplier = new Utils.NumberHolder(isCritical ? 1.5 : 1);
applyAbAttrs(MultCritAbAttr, source, null, false, criticalMultiplier); applyAbAttrs(MultCritAbAttr, source, null, false, criticalMultiplier);
const screenMultiplier = new Utils.NumberHolder(1); const screenMultiplier = new Utils.NumberHolder(1);
@ -2494,24 +2650,23 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
* @param source {@linkcode Pokemon} the pokemon whose stats/Tags are to be passed on from, ie: the Pokemon using Baton Pass * @param source {@linkcode Pokemon} the pokemon whose stats/Tags are to be passed on from, ie: the Pokemon using Baton Pass
*/ */
transferSummon(source: Pokemon): void { transferSummon(source: Pokemon): void {
const battleStats = Utils.getEnumValues(BattleStat); // Copy all stat stages
for (const stat of battleStats) { for (const s of BATTLE_STATS) {
this.summonData.battleStats[stat] = source.summonData.battleStats[stat]; const sourceStage = source.getStatStage(s);
if ((this instanceof PlayerPokemon) && (sourceStage === 6)) {
this.scene.validateAchv(achvs.TRANSFER_MAX_STAT_STAGE);
} }
this.setStatStage(s, sourceStage);
}
for (const tag of source.summonData.tags) { for (const tag of source.summonData.tags) {
if (!tag.isBatonPassable) {
// bypass those can not be passed via Baton Pass
const excludeTagTypes = new Set([BattlerTagType.DROWSY, BattlerTagType.INFATUATED, BattlerTagType.FIRE_BOOST]);
if (excludeTagTypes.has(tag.tagType)) {
continue; continue;
} }
this.summonData.tags.push(tag); this.summonData.tags.push(tag);
} }
if (this instanceof PlayerPokemon && source.summonData.battleStats.find(bs => bs === 6)) {
this.scene.validateAchv(achvs.TRANSFER_MAX_BATTLE_STAT);
}
this.updateInfo(); this.updateInfo();
} }
@ -2754,6 +2909,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const types = this.getTypes(true, true); const types = this.getTypes(true, true);
const defendingSide = this.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
if (sourcePokemon && sourcePokemon !== this && this.scene.arena.getTagOnSide(ArenaTagType.SAFEGUARD, defendingSide)) {
return false;
}
switch (effect) { switch (effect) {
case StatusEffect.POISON: case StatusEffect.POISON:
case StatusEffect.TOXIC: case StatusEffect.TOXIC:
@ -3319,6 +3479,7 @@ export default interface Pokemon {
export class PlayerPokemon extends Pokemon { export class PlayerPokemon extends Pokemon {
public compatibleTms: Moves[]; public compatibleTms: Moves[];
public usedTms: Moves[];
constructor(scene: BattleScene, species: PokemonSpecies, level: integer, abilityIndex?: integer, formIndex?: integer, gender?: Gender, shiny?: boolean, variant?: Variant, ivs?: integer[], nature?: Nature, dataSource?: Pokemon | PokemonData) { constructor(scene: BattleScene, species: PokemonSpecies, level: integer, abilityIndex?: integer, formIndex?: integer, gender?: Gender, shiny?: boolean, variant?: Variant, ivs?: integer[], nature?: Nature, dataSource?: Pokemon | PokemonData) {
super(scene, 106, 148, species, level, abilityIndex, formIndex, gender, shiny, variant, ivs, nature, dataSource); super(scene, 106, 148, species, level, abilityIndex, formIndex, gender, shiny, variant, ivs, nature, dataSource);
@ -3342,6 +3503,7 @@ export class PlayerPokemon extends Pokemon {
} }
} }
this.generateCompatibleTms(); this.generateCompatibleTms();
this.usedTms = [];
} }
initBattleInfo(): void { initBattleInfo(): void {
@ -3600,6 +3762,9 @@ export class PlayerPokemon extends Pokemon {
newPokemon.moveset = this.moveset.slice(); newPokemon.moveset = this.moveset.slice();
newPokemon.moveset = this.copyMoveset(); newPokemon.moveset = this.copyMoveset();
newPokemon.luck = this.luck; newPokemon.luck = this.luck;
newPokemon.metLevel = this.metLevel;
newPokemon.metBiome = this.metBiome;
newPokemon.metSpecies = this.metSpecies;
newPokemon.fusionSpecies = this.fusionSpecies; newPokemon.fusionSpecies = this.fusionSpecies;
newPokemon.fusionFormIndex = this.fusionFormIndex; newPokemon.fusionFormIndex = this.fusionFormIndex;
newPokemon.fusionAbilityIndex = this.fusionAbilityIndex; newPokemon.fusionAbilityIndex = this.fusionAbilityIndex;
@ -3679,16 +3844,17 @@ export class PlayerPokemon extends Pokemon {
this.scene.gameData.gameStats.pokemonFused++; this.scene.gameData.gameStats.pokemonFused++;
// Store the average HP% that each Pokemon has // Store the average HP% that each Pokemon has
const newHpPercent = ((pokemon.hp / pokemon.stats[Stat.HP]) + (this.hp / this.stats[Stat.HP])) / 2; const maxHp = this.getMaxHp();
const newHpPercent = ((pokemon.hp / pokemon.getMaxHp()) + (this.hp / maxHp)) / 2;
this.generateName(); this.generateName();
this.calculateStats(); this.calculateStats();
// Set this Pokemon's HP to the average % of both fusion components // Set this Pokemon's HP to the average % of both fusion components
this.hp = Math.round(this.stats[Stat.HP] * newHpPercent); this.hp = Math.round(maxHp * newHpPercent);
if (!this.isFainted()) { if (!this.isFainted()) {
// If this Pokemon hasn't fainted, make sure the HP wasn't set over the new maximum // If this Pokemon hasn't fainted, make sure the HP wasn't set over the new maximum
this.hp = Math.min(this.hp, this.stats[Stat.HP]); this.hp = Math.min(this.hp, maxHp);
this.status = getRandomStatus(this.status, pokemon.status); // Get a random valid status between the two this.status = getRandomStatus(this.status, pokemon.status); // Get a random valid status between the two
} else if (!pokemon.isFainted()) { } else if (!pokemon.isFainted()) {
// If this Pokemon fainted but the other hasn't, make sure the HP wasn't set to zero // If this Pokemon fainted but the other hasn't, make sure the HP wasn't set to zero
@ -4138,7 +4304,7 @@ export class EnemyPokemon extends Pokemon {
//console.log('damage', damage, 'segment', segmentsBypassed + 1, 'segment size', segmentSize, 'damage needed', Math.round(segmentSize * Math.pow(2, segmentsBypassed + 1))); //console.log('damage', damage, 'segment', segmentsBypassed + 1, 'segment size', segmentSize, 'damage needed', Math.round(segmentSize * Math.pow(2, segmentsBypassed + 1)));
} }
damage = hpRemainder + Math.round(segmentSize * segmentsBypassed); damage = Utils.toDmgValue(this.hp - hpThreshold + segmentSize * segmentsBypassed);
clearedBossSegmentIndex = s - segmentsBypassed; clearedBossSegmentIndex = s - segmentsBypassed;
} }
break; break;
@ -4181,43 +4347,40 @@ export class EnemyPokemon extends Pokemon {
handleBossSegmentCleared(segmentIndex: integer): void { handleBossSegmentCleared(segmentIndex: integer): void {
while (segmentIndex - 1 < this.bossSegmentIndex) { while (segmentIndex - 1 < this.bossSegmentIndex) {
let boostedStat = BattleStat.RAND; // Filter out already maxed out stat stages and weigh the rest based on existing stats
const leftoverStats = EFFECTIVE_STATS.filter((s: EffectiveStat) => this.getStatStage(s) < 6);
const statWeights = leftoverStats.map((s: EffectiveStat) => this.getStat(s, false));
const battleStats = Utils.getEnumValues(BattleStat).slice(0, -3); let boostedStat: EffectiveStat;
const statWeights = new Array().fill(battleStats.length).filter((bs: BattleStat) => this.summonData.battleStats[bs] < 6).map((bs: BattleStat) => this.getStat(bs + 1)); const statThresholds: number[] = [];
const statThresholds: integer[] = [];
let totalWeight = 0; let totalWeight = 0;
for (const bs of battleStats) {
totalWeight += statWeights[bs]; for (const i in statWeights) {
totalWeight += statWeights[i];
statThresholds.push(totalWeight); statThresholds.push(totalWeight);
} }
// Pick a random stat from the leftover stats to increase its stages
const randInt = Utils.randSeedInt(totalWeight); const randInt = Utils.randSeedInt(totalWeight);
for (const i in statThresholds) {
for (const bs of battleStats) { if (randInt < statThresholds[i]) {
if (randInt < statThresholds[bs]) { boostedStat = leftoverStats[i];
boostedStat = bs;
break; break;
} }
} }
let statLevels = 1; let stages = 1;
switch (segmentIndex) { // increase the boost if the boss has at least 3 segments and we passed last shield
case 1: if (this.bossSegments >= 3 && this.bossSegmentIndex === 1) {
if (this.bossSegments >= 3) { stages++;
statLevels++;
} }
break; // increase the boost if the boss has at least 5 segments and we passed the second to last shield
case 2: if (this.bossSegments >= 5 && this.bossSegmentIndex === 2) {
if (this.bossSegments >= 5) { stages++;
statLevels++;
}
break;
} }
this.scene.unshiftPhase(new StatChangePhase(this.scene, this.getBattlerIndex(), true, [ boostedStat ], statLevels, true, true)); this.scene.unshiftPhase(new StatStageChangePhase(this.scene, this.getBattlerIndex(), true, [ boostedStat! ], stages, true, true));
this.bossSegmentIndex--; this.bossSegmentIndex--;
} }
} }
@ -4274,7 +4437,7 @@ export interface TurnMove {
targets?: BattlerIndex[]; targets?: BattlerIndex[];
result: MoveResult; result: MoveResult;
virtual?: boolean; virtual?: boolean;
turn?: integer; turn?: number;
} }
export interface QueuedMove { export interface QueuedMove {
@ -4286,17 +4449,17 @@ export interface QueuedMove {
export interface AttackMoveResult { export interface AttackMoveResult {
move: Moves; move: Moves;
result: DamageResult; result: DamageResult;
damage: integer; damage: number;
critical: boolean; critical: boolean;
sourceId: integer; sourceId: number;
sourceBattlerIndex: BattlerIndex; sourceBattlerIndex: BattlerIndex;
} }
export class PokemonSummonData { export class PokemonSummonData {
public battleStats: integer[] = [ 0, 0, 0, 0, 0, 0, 0 ]; public statStages: number[] = [ 0, 0, 0, 0, 0, 0, 0 ];
public moveQueue: QueuedMove[] = []; public moveQueue: QueuedMove[] = [];
public disabledMove: Moves = Moves.NONE; public disabledMove: Moves = Moves.NONE;
public disabledTurns: integer = 0; public disabledTurns: number = 0;
public tags: BattlerTag[] = []; public tags: BattlerTag[] = [];
public abilitySuppressed: boolean = false; public abilitySuppressed: boolean = false;
public abilitiesApplied: Abilities[] = []; public abilitiesApplied: Abilities[] = [];
@ -4306,14 +4469,14 @@ export class PokemonSummonData {
public ability: Abilities = Abilities.NONE; public ability: Abilities = Abilities.NONE;
public gender: Gender; public gender: Gender;
public fusionGender: Gender; public fusionGender: Gender;
public stats: integer[]; public stats: number[] = [ 0, 0, 0, 0, 0, 0 ];
public moveset: (PokemonMove | null)[]; public moveset: (PokemonMove | null)[];
// If not initialized this value will not be populated from save data. // If not initialized this value will not be populated from save data.
public types: Type[] = []; public types: Type[] = [];
} }
export class PokemonBattleData { export class PokemonBattleData {
public hitCount: integer = 0; public hitCount: number = 0;
public endured: boolean = false; public endured: boolean = false;
public berriesEaten: BerryType[] = []; public berriesEaten: BerryType[] = [];
public abilitiesApplied: Abilities[] = []; public abilitiesApplied: Abilities[] = [];
@ -4322,21 +4485,23 @@ export class PokemonBattleData {
export class PokemonBattleSummonData { export class PokemonBattleSummonData {
/** The number of turns the pokemon has passed since entering the battle */ /** The number of turns the pokemon has passed since entering the battle */
public turnCount: integer = 1; public turnCount: number = 1;
/** The list of moves the pokemon has used since entering the battle */ /** The list of moves the pokemon has used since entering the battle */
public moveHistory: TurnMove[] = []; public moveHistory: TurnMove[] = [];
} }
export class PokemonTurnData { export class PokemonTurnData {
public flinched: boolean; public flinched: boolean = false;
public acted: boolean; public acted: boolean = false;
public hitCount: integer; public hitCount: number;
public hitsLeft: integer; public hitsLeft: number;
public damageDealt: integer = 0; public damageDealt: number = 0;
public currDamageDealt: integer = 0; public currDamageDealt: number = 0;
public damageTaken: integer = 0; public damageTaken: number = 0;
public attacksReceived: AttackMoveResult[] = []; public attacksReceived: AttackMoveResult[] = [];
public order: number; public order: number;
public statStagesIncreased: boolean = false;
public statStagesDecreased: boolean = false;
} }
export enum AiType { export enum AiType {

View File

@ -37,8 +37,7 @@ export interface ModifierTypeTranslationEntries {
ModifierType: { [key: string]: ModifierTypeTranslationEntry }, ModifierType: { [key: string]: ModifierTypeTranslationEntry },
SpeciesBoosterItem: { [key: string]: ModifierTypeTranslationEntry }, SpeciesBoosterItem: { [key: string]: ModifierTypeTranslationEntry },
AttackTypeBoosterItem: SimpleTranslationEntries, AttackTypeBoosterItem: SimpleTranslationEntries,
TempBattleStatBoosterItem: SimpleTranslationEntries, TempStatStageBoosterItem: SimpleTranslationEntries,
TempBattleStatBoosterStatName: SimpleTranslationEntries,
BaseStatBoosterItem: SimpleTranslationEntries, BaseStatBoosterItem: SimpleTranslationEntries,
EvolutionItem: SimpleTranslationEntries, EvolutionItem: SimpleTranslationEntries,
FormChangeItem: SimpleTranslationEntries, FormChangeItem: SimpleTranslationEntries,

View File

@ -41,8 +41,6 @@ export class LoadingScene extends SceneBase {
this.loadImage("loading_bg", "arenas"); this.loadImage("loading_bg", "arenas");
this.loadImage("logo", ""); this.loadImage("logo", "");
// this.loadImage("pride-update", "events");
this.loadImage("august-variant-update", "events");
// Load menu images // Load menu images
this.loadAtlas("bg", "ui"); this.loadAtlas("bg", "ui");
@ -80,6 +78,7 @@ export class LoadingScene extends SceneBase {
this.loadAtlas("overlay_hp_boss", "ui"); this.loadAtlas("overlay_hp_boss", "ui");
this.loadImage("overlay_exp", "ui"); this.loadImage("overlay_exp", "ui");
this.loadImage("icon_owned", "ui"); this.loadImage("icon_owned", "ui");
this.loadImage("icon_egg_move", "ui");
this.loadImage("ability_bar_left", "ui"); this.loadImage("ability_bar_left", "ui");
this.loadImage("bgm_bar", "ui"); this.loadImage("bgm_bar", "ui");
this.loadImage("party_exp_bar", "ui"); this.loadImage("party_exp_bar", "ui");
@ -100,6 +99,8 @@ export class LoadingScene extends SceneBase {
this.loadImage("ha_capsule", "ui", "ha_capsule.png"); this.loadImage("ha_capsule", "ui", "ha_capsule.png");
this.loadImage("champion_ribbon", "ui", "champion_ribbon.png"); this.loadImage("champion_ribbon", "ui", "champion_ribbon.png");
this.loadImage("icon_spliced", "ui"); this.loadImage("icon_spliced", "ui");
this.loadImage("icon_lock", "ui", "icon_lock.png");
this.loadImage("icon_stop", "ui", "icon_stop.png");
this.loadImage("icon_tera", "ui"); this.loadImage("icon_tera", "ui");
this.loadImage("type_tera", "ui"); this.loadImage("type_tera", "ui");
this.loadAtlas("type_bgs", "ui"); this.loadAtlas("type_bgs", "ui");
@ -246,7 +247,12 @@ export class LoadingScene extends SceneBase {
} else { } else {
this.loadAtlas("types", ""); this.loadAtlas("types", "");
} }
const availableLangs = ["en", "de", "it", "fr", "ja", "ko", "es", "pt-BR", "zh-CN"];
if (lang && availableLangs.includes(lang)) {
this.loadImage("september-update-"+lang, "events");
} else {
this.loadImage("september-update-en", "events");
}
this.loadAtlas("statuses", ""); this.loadAtlas("statuses", "");
this.loadAtlas("categories", ""); this.loadAtlas("categories", "");
@ -267,6 +273,7 @@ export class LoadingScene extends SceneBase {
this.loadImage("gacha_knob", "egg"); this.loadImage("gacha_knob", "egg");
this.loadImage("egg_list_bg", "ui"); this.loadImage("egg_list_bg", "ui");
this.loadImage("egg_summary_bg", "ui");
this.loadImage("end_m", "cg"); this.loadImage("end_m", "cg");
this.loadImage("end_f", "cg"); this.loadImage("end_f", "cg");

View File

@ -89,7 +89,7 @@
"name": "Bänder-Meister", "name": "Bänder-Meister",
"name_female": "Bänder-Meisterin" "name_female": "Bänder-Meisterin"
}, },
"TRANSFER_MAX_BATTLE_STAT": { "TRANSFER_MAX_STAT_STAGE": {
"name": "Teamwork", "name": "Teamwork",
"description": "Nutze Staffette, während der Anwender mindestens eines Statuswertes maximiert hat." "description": "Nutze Staffette, während der Anwender mindestens eines Statuswertes maximiert hat."
}, },

View File

@ -47,5 +47,11 @@
"tailwindOnRemovePlayer": "Der Rückenwind auf deiner Seite hat sich gelegt!", "tailwindOnRemovePlayer": "Der Rückenwind auf deiner Seite hat sich gelegt!",
"tailwindOnRemoveEnemy": "Der Rückenwind auf gegnerischer Seite hat sich gelegt!", "tailwindOnRemoveEnemy": "Der Rückenwind auf gegnerischer Seite hat sich gelegt!",
"happyHourOnAdd": "Goldene Zeiten sind angebrochen!", "happyHourOnAdd": "Goldene Zeiten sind angebrochen!",
"happyHourOnRemove": "Die goldenen Zeiten sind vorbei!" "happyHourOnRemove": "Die goldenen Zeiten sind vorbei!",
"safeguardOnAdd": "Das ganze Feld wird von einem Schleier umhüllt!",
"safeguardOnAddPlayer": "Das Team des Anwenders wird von einem Schleier umhüllt!",
"safeguardOnAddEnemy": "Das gegnerische Team wird von einem Schleier umhüllt!",
"safeguardOnRemove": "Der mystische Schleier, der das ganze Feld umgab, hat sich gelüftet!",
"safeguardOnRemovePlayer": "Der mystische Schleier, der dein Team umgab, hat sich gelüftet!",
"safeguardOnRemoveEnemy": "Der mystische Schleier, der das gegnerische Team umgab, hat sich gelüftet!"
} }

View File

@ -94,5 +94,6 @@
"retryBattle": "Möchtest du vom Beginn des Kampfes neustarten?", "retryBattle": "Möchtest du vom Beginn des Kampfes neustarten?",
"unlockedSomething": "{{unlockedThing}} wurde freigeschaltet.", "unlockedSomething": "{{unlockedThing}} wurde freigeschaltet.",
"congratulations": "Glückwunsch!", "congratulations": "Glückwunsch!",
"beatModeFirstTime": "{{speciesName}} hat den {{gameMode}} Modus zum ersten Mal beendet! Du erhältst {{newModifier}}!" "beatModeFirstTime": "{{speciesName}} hat den {{gameMode}} Modus zum ersten Mal beendet! Du erhältst {{newModifier}}!",
"eggSkipPrompt": "Zur Ei-Zusammenfassung springen?"
} }

View File

@ -1,10 +1,11 @@
{ {
"noneSelected": "Keine ausgewählt",
"title": "Herausforderungsmodifikatoren", "title": "Herausforderungsmodifikatoren",
"illegalEvolution": "{{pokemon}} hat sich in ein Pokémon verwandelt, dass für diese Herausforderung nicht zulässig ist!", "illegalEvolution": "{{pokemon}} hat sich in ein Pokémon verwandelt, dass für diese Herausforderung nicht zulässig ist!",
"singleGeneration": { "singleGeneration": {
"name": "Mono-Generation", "name": "Mono-Generation",
"desc": "Du kannst nur Pokémon aus der {{gen}} Generation verwenden.", "desc": "Du kannst nur Pokémon aus der {{gen}} Generation verwenden.",
"desc_default": "Du kannst nur Pokémon gewählten Generation verwenden.", "desc_default": "Du kannst nur Pokémon aus der gewählten Generation verwenden.",
"gen_1": "ersten", "gen_1": "ersten",
"gen_2": "zweiten", "gen_2": "zweiten",
"gen_3": "dritten", "gen_3": "dritten",

View File

@ -1,6 +1,6 @@
{ {
"ending": "@c{smile}Oh? Du hast gewonnen?@d{96} @c{smile_eclosed}Ich schätze, das hätte ich wissen sollen.\n$Aber, du bist jetzt zurück.\n$@c{smile}Es ist vorbei.@d{64} Du hast die Schleife beendet.\n$@c{serious_smile_fists}Du hast auch deinen Traum erfüllt, nicht wahr?\nDu hast nicht einmal verloren.\n$@c{neutral}Ich bin der Einzige, der sich daran erinnern wird, was du getan hast.@d{96}\n$Ich schätze, das ist in Ordnung, oder?\n$@c{serious_smile_fists}Deine Legende wird immer in unseren Herzen weiterleben.\n$@c{smile_eclosed}Wie auch immer, ich habe genug von diesem Ort, oder nicht? Lass uns nach Hause gehen.\n$@c{serious_smile_fists}Vielleicht können wir, wenn wir zurück sind, noch einen Kampf haben?\n$Wenn du dazu bereit bist.", "ending": "@c{shock}Du bist zurück?@d{32} Bedeutet das…@d{96} du hast gewonnen?!\n$@c{smile_ehalf}Ich hätte wissen sollen, dass du es in dir hast.\n$@c{smile_eclosed}Natürlich… ich hatte immer dieses Gefühl.\n$@c{smile}Es ist jetzt vorbei, richtig? Du hast die Schleife beendet.\n$@c{smile_ehalf}Du hast auch deinen Traum erfüllt, nicht wahr?\n$Du hast nicht einmal verloren.\n$Ich werde die Einzige sein, die sich daran erinnert, was du getan hast.\n$@c{angry_mopen}Ich werde versuchen, es nicht zu vergessen!\n$@c{smile_wave_wink}Nur ein Scherz!@d{64} @c{smile}Ich würde es nie vergessen.@d{32}\n$Deine Legende wird in unseren Herzen weiterleben.\n$@c{smile_wave}Wie auch immer,@d{64} es wird spät…@d{96} denke ich?\nEs ist schwer zu sagen an diesem Ort.\n$Lass uns nach Hause gehen. \n$@c{smile_wave_wink}Vielleicht können wir morgen noch einen Kampf haben, der alten Zeiten willen?",
"ending_female": "@c{shock}Du bist zurück?@d{32} Bedeutet das…@d{96} du hast gewonnen?!\n$@c{smile_ehalf}Ich hätte wissen sollen, dass du es in dir hast.\n$@c{smile_eclosed}Natürlich… ich hatte immer dieses Gefühl.\n$@c{smile}Es ist jetzt vorbei, richtig? Du hast die Schleife beendet.\n$@c{smile_ehalf}Du hast auch deinen Traum erfüllt, nicht wahr?\n$Du hast nicht einmal verloren.\n$Ich werde die Einzige sein, die sich daran erinnert, was du getan hast.\n$@c{angry_mopen}Ich werde versuchen, es nicht zu vergessen!\n$@c{smile_wave_wink}Nur ein Scherz!@d{64} @c{smile}Ich würde es nie vergessen.@d{32}\n$Deine Legende wird in unseren Herzen weiterleben.\n$@c{smile_wave}Wie auch immer,@d{64} es wird spät…@d{96} denke ich?\nEs ist schwer zu sagen an diesem Ort.\n$Lass uns nach Hause gehen. \n$@c{smile_wave_wink}Vielleicht können wir morgen noch einen Kampf haben, der alten Zeiten willen?", "ending_female": "@c{smile}Oh? Du hast gewonnen?@d{96} @c{smile_eclosed}Ich schätze, das hätte ich wissen sollen.\n$Aber, du bist jetzt zurück.\n$@c{smile}Es ist vorbei.@d{64} Du hast die Schleife beendet.\n$@c{serious_smile_fists}Du hast auch deinen Traum erfüllt, nicht wahr?\nDu hast nicht einmal verloren.\n$@c{neutral}Ich bin der Einzige, der sich daran erinnern wird, was du getan hast.@d{96}\n$Ich schätze, das ist in Ordnung, oder?\n$@c{serious_smile_fists}Deine Legende wird immer in unseren Herzen weiterleben.\n$@c{smile_eclosed}Wie auch immer, ich habe genug von diesem Ort, oder nicht? Lass uns nach Hause gehen.\n$@c{serious_smile_fists}Vielleicht können wir, wenn wir zurück sind, noch einen Kampf haben?\n$Wenn du dazu bereit bist.",
"ending_endless": "Glückwunsch! Du hast das aktuelle Ende erreicht!\nWir arbeiten an mehr Spielinhalten.", "ending_endless": "Glückwunsch! Du hast das aktuelle Ende erreicht!\nWir arbeiten an mehr Spielinhalten.",
"ending_name": "Entwickler" "ending_name": "Entwickler"
} }

View File

@ -1403,19 +1403,19 @@
"1": "Ich muss dein Potenzial als Trainer und die Stärke der Pokémon sehen, die mit dir kämpfen!", "1": "Ich muss dein Potenzial als Trainer und die Stärke der Pokémon sehen, die mit dir kämpfen!",
"2": "Los geht's! Dies sind meine Gesteins-Pokémon, mein ganzer Stolz!", "2": "Los geht's! Dies sind meine Gesteins-Pokémon, mein ganzer Stolz!",
"3": "Gesteins-Pokémon sind einfach die besten!", "3": "Gesteins-Pokémon sind einfach die besten!",
"4": "Ich muss dein Potenzial als Trainer und die Stärke der Pokémon sehen, die mit dir kämpfen!" "4": "Tag für Tag grabe ich hier nach Fossilien.\n$Die viele Arbeit hat meine Pokémon felsenfest gemacht\nund das wirst du jetzt im Kampf zu spüren bekommen!"
}, },
"victory": { "victory": {
"1": "W-was? Das kann nicht sein! Meine total tranierten Pokémon!", "1": "W-was? Das kann nicht sein! Meine total tranierten Pokémon!",
"2": "…Wir haben die Kontrolle verloren. Beim nächsten Mal fordere ich dich\n$zu einem Fossilien-Ausgrabungswettbewerb heraus.", "2": "…Wir haben die Kontrolle verloren. Beim nächsten Mal fordere ich dich\n$zu einem Fossilien-Ausgrabungswettbewerb heraus.",
"3": "Mit deinem Können ist es nur natürlich, dass du gewinnst.", "3": "Mit deinem Können ist es nur natürlich, dass du gewinnst.",
"4": "W-was?! Das kann nicht sein! Selbst das war nicht genug?", "4": "W-was?! Das kann nicht sein! Selbst das war nicht genug?"
"5": "Ich habe es vermasselt."
}, },
"defeat": { "defeat": {
"1": "Siehst du? Ich bin stolz auf meinen steinigen Kampfstil!", "1": "Siehst du? Ich bin stolz auf meinen steinigen Kampfstil!",
"2": "Danke! Der Kampf hat mir Vertrauen gegeben, dass ich vielleicht meinen Vater besiegen kann!", "2": "Danke! Der Kampf hat mir Vertrauen gegeben, dass ich vielleicht meinen Vater besiegen kann!",
"3": "Ich fühle mich, als hätte ich gerade einen wirklich hartnäckigen Felsen durchbrochen!" "3": "Na, was sagst du jetzt? Meine felsenfesten Pokémon waren hart genug für dich, was?",
"4": "Ich wusste, dass ich gewinnen würde!"
} }
}, },
"morty": { "morty": {

View File

@ -25,5 +25,6 @@
"unlinkGoogle": "Google trennen", "unlinkGoogle": "Google trennen",
"cancel": "Abbrechen", "cancel": "Abbrechen",
"losingProgressionWarning": "Du wirst jeglichen Fortschritt seit Anfang dieses Kampfes verlieren. Fortfahren?", "losingProgressionWarning": "Du wirst jeglichen Fortschritt seit Anfang dieses Kampfes verlieren. Fortfahren?",
"noEggs": "Du brütest aktuell keine Eier aus!" "noEggs": "Du brütest aktuell keine Eier aus!",
"donate": "Spenden"
} }

View File

@ -49,8 +49,8 @@
"DoubleBattleChanceBoosterModifierType": { "DoubleBattleChanceBoosterModifierType": {
"description": "Verdoppelt die Wahrscheinlichkeit, dass die nächsten {{battleCount}} Begegnungen mit wilden Pokémon ein Doppelkampf sind." "description": "Verdoppelt die Wahrscheinlichkeit, dass die nächsten {{battleCount}} Begegnungen mit wilden Pokémon ein Doppelkampf sind."
}, },
"TempBattleStatBoosterModifierType": { "TempStatStageBoosterModifierType": {
"description": "Erhöht die {{tempBattleStatName}} aller Teammitglieder für 5 Kämpfe um eine Stufe." "description": "Erhöht die {{stat}} aller Teammitglieder für 5 Kämpfe um eine Stufe."
}, },
"AttackTypeBoosterModifierType": { "AttackTypeBoosterModifierType": {
"description": "Erhöht die Stärke aller {{moveType}}-Attacken eines Pokémon um 20%." "description": "Erhöht die Stärke aller {{moveType}}-Attacken eines Pokémon um 20%."
@ -61,8 +61,8 @@
"AllPokemonLevelIncrementModifierType": { "AllPokemonLevelIncrementModifierType": {
"description": "Erhöht das Level aller Teammitglieder um {{levels}}." "description": "Erhöht das Level aller Teammitglieder um {{levels}}."
}, },
"PokemonBaseStatBoosterModifierType": { "BaseStatBoosterModifierType": {
"description": "Erhöht den {{statName}} Basiswert des Trägers um 10%. Das Stapellimit erhöht sich, je höher dein IS-Wert ist." "description": "Erhöht den {{stat}} Basiswert des Trägers um 10%. Das Stapellimit erhöht sich, je höher dein IS-Wert ist."
}, },
"AllPokemonFullHpRestoreModifierType": { "AllPokemonFullHpRestoreModifierType": {
"description": "Stellt 100% der KP aller Pokémon her." "description": "Stellt 100% der KP aller Pokémon her."
@ -248,6 +248,12 @@
"name": "Scope-Linse", "name": "Scope-Linse",
"description": "Ein Item zum Tragen. Es erhöht die Volltrefferquote." "description": "Ein Item zum Tragen. Es erhöht die Volltrefferquote."
}, },
"DIRE_HIT": {
"name": "X-Volltreffer",
"extra": {
"raises": "Volltrefferquote"
}
},
"LEEK": { "LEEK": {
"name": "Lauchstange", "name": "Lauchstange",
"description": "Ein Item, das von Porenta getragen werden kann. Diese lange Lauchstange erhöht die Volltrefferquote stark." "description": "Ein Item, das von Porenta getragen werden kann. Diese lange Lauchstange erhöht die Volltrefferquote stark."
@ -411,25 +417,13 @@
"description": "Ein Item, das Ditto zum Tragen gegeben werden kann. Fein und doch hart, erhöht dieses sonderbare Pulver die Initiative." "description": "Ein Item, das Ditto zum Tragen gegeben werden kann. Fein und doch hart, erhöht dieses sonderbare Pulver die Initiative."
} }
}, },
"TempBattleStatBoosterItem": { "TempStatStageBoosterItem": {
"x_attack": "X-Angriff", "x_attack": "X-Angriff",
"x_defense": "X-Verteidigung", "x_defense": "X-Verteidigung",
"x_sp_atk": "X-Sp.-Ang.", "x_sp_atk": "X-Sp.-Ang.",
"x_sp_def": "X-Sp.-Vert.", "x_sp_def": "X-Sp.-Vert.",
"x_speed": "X-Tempo", "x_speed": "X-Tempo",
"x_accuracy": "X-Treffer", "x_accuracy": "X-Treffer"
"dire_hit": "X-Volltreffer"
},
"TempBattleStatBoosterStatName": {
"ATK": "Angriff",
"DEF": "Verteidigung",
"SPATK": "Sp. Ang",
"SPDEF": "Sp. Vert",
"SPD": "Initiative",
"ACC": "Genauigkeit",
"CRIT": "Volltrefferquote",
"EVA": "Fluchtwert",
"DEFAULT": "???"
}, },
"AttackTypeBoosterItem": { "AttackTypeBoosterItem": {
"silk_scarf": "Seidenschal", "silk_scarf": "Seidenschal",
@ -604,6 +598,6 @@
"DRAGON_MEMORY": "Drachen-Disc", "DRAGON_MEMORY": "Drachen-Disc",
"DARK_MEMORY": "Unlicht-Disc", "DARK_MEMORY": "Unlicht-Disc",
"FAIRY_MEMORY": "Feen-Disc", "FAIRY_MEMORY": "Feen-Disc",
"BLANK_MEMORY": "Leere-Disc" "NORMAL_MEMORY": "Normal-Disc"
} }
} }

View File

@ -3,7 +3,7 @@
"turnHealApply": "{{typeName}} von {{pokemonNameWithAffix}} füllt einige KP auf!", "turnHealApply": "{{typeName}} von {{pokemonNameWithAffix}} füllt einige KP auf!",
"hitHealApply": "{{typeName}} von {{pokemonNameWithAffix}} füllt einige KP auf!", "hitHealApply": "{{typeName}} von {{pokemonNameWithAffix}} füllt einige KP auf!",
"pokemonInstantReviveApply": "{{pokemonNameWithAffix}} wurde durch {{typeName}} wiederbelebt!", "pokemonInstantReviveApply": "{{pokemonNameWithAffix}} wurde durch {{typeName}} wiederbelebt!",
"pokemonResetNegativeStatStageApply": "Die negative Statuswertveränderung von {{pokemonNameWithAffix}} wurde durch {{typeName}} aufgehoben!", "resetNegativeStatStageApply": "Die negative Statuswertveränderung von {{pokemonNameWithAffix}} wurde durch {{typeName}} aufgehoben!",
"moneyInterestApply": "Du erhählst {{moneyAmount}} ₽ durch das Item {{typeName}}!", "moneyInterestApply": "Du erhählst {{moneyAmount}} ₽ durch das Item {{typeName}}!",
"turnHeldItemTransferApply": "{{itemName}} von {{pokemonNameWithAffix}} wurde durch {{typeName}} von {{pokemonName}} absorbiert!", "turnHeldItemTransferApply": "{{itemName}} von {{pokemonNameWithAffix}} wurde durch {{typeName}} von {{pokemonName}} absorbiert!",
"contactHeldItemTransferApply": "{{itemName}} von {{pokemonNameWithAffix}} wurde durch {{typeName}} von {{pokemonName}} geklaut!", "contactHeldItemTransferApply": "{{itemName}} von {{pokemonNameWithAffix}} wurde durch {{typeName}} von {{pokemonName}} geklaut!",

View File

@ -3,6 +3,10 @@
"cutHpPowerUpMove": "{{pokemonName}} nutzt seine KP um seine Attacke zu verstärken!", "cutHpPowerUpMove": "{{pokemonName}} nutzt seine KP um seine Attacke zu verstärken!",
"absorbedElectricity": "{{pokemonName}} absorbiert elektrische Energie!", "absorbedElectricity": "{{pokemonName}} absorbiert elektrische Energie!",
"switchedStatChanges": "{{pokemonName}} tauschte die Statuswerteveränderungen mit dem Ziel!", "switchedStatChanges": "{{pokemonName}} tauschte die Statuswerteveränderungen mit dem Ziel!",
"switchedTwoStatChanges": "{{pokemonName}} tauscht Veränderungen an {{firstStat}} und {{secondStat}} mit dem Ziel!",
"switchedStat": "{{pokemonName}} tauscht seinen {{stat}}-Wert mit dem des Zieles!",
"sharedGuard": "{{pokemonName}} addiert seine Schutzkräfte mit jenen des Zieles und teilt sie gerecht auf!",
"sharedPower": "{{pokemonName}} addiert seine Kräfte mit jenen des Zieles und teilt sie gerecht auf!",
"goingAllOutForAttack": "{{pokemonName}} legt sich ins Zeug!", "goingAllOutForAttack": "{{pokemonName}} legt sich ins Zeug!",
"regainedHealth": "{{pokemonName}} erholt sich!", "regainedHealth": "{{pokemonName}} erholt sich!",
"keptGoingAndCrashed": "{{pokemonName}} springt daneben und verletzt sich!", "keptGoingAndCrashed": "{{pokemonName}} springt daneben und verletzt sich!",
@ -61,5 +65,6 @@
"suppressAbilities": "Die Fähigkeit von {{pokemonName}} wirkt nicht mehr!", "suppressAbilities": "Die Fähigkeit von {{pokemonName}} wirkt nicht mehr!",
"revivalBlessing": "{{pokemonName}} ist wieder fit und kampfbereit!", "revivalBlessing": "{{pokemonName}} ist wieder fit und kampfbereit!",
"swapArenaTags": "{{pokemonName}} hat die Effekte, die auf den beiden Seiten des Kampffeldes wirken, miteinander getauscht!", "swapArenaTags": "{{pokemonName}} hat die Effekte, die auf den beiden Seiten des Kampffeldes wirken, miteinander getauscht!",
"exposedMove": "{{pokemonName}} erkennt {{targetPokemonName}}!" "exposedMove": "{{pokemonName}} erkennt {{targetPokemonName}}!",
"safeguard": "{{targetName}} wird durch Bodyguard geschützt!"
} }

View File

@ -10,5 +10,5 @@
"eternamaxChange": "{{preName}} hat sich zu {{pokemonName}} unendynamaximiert!", "eternamaxChange": "{{preName}} hat sich zu {{pokemonName}} unendynamaximiert!",
"revertChange": "{{pokemonName}} hat seine ursprüngliche Form zurückerlangt!", "revertChange": "{{pokemonName}} hat seine ursprüngliche Form zurückerlangt!",
"formChange": "{{preName}} hat seine Form geändert!", "formChange": "{{preName}} hat seine Form geändert!",
"disguiseChange": "Its disguise served it as a decoy!" "disguiseChange": "Sein Kostüm hat die Attacke absorbiert!"
} }

View File

@ -1,7 +1,6 @@
{ {
"Stat": { "Stat": {
"HP": "KP", "HP": "KP",
"HPStat": "KP",
"HPshortened": "KP", "HPshortened": "KP",
"ATK": "Angriff", "ATK": "Angriff",
"ATKshortened": "Ang", "ATKshortened": "Ang",

View File

@ -100,7 +100,7 @@
"moveTouchControls": "Bewegung Touch Steuerung", "moveTouchControls": "Bewegung Touch Steuerung",
"shopOverlayOpacity": "Shop Overlay Deckkraft", "shopOverlayOpacity": "Shop Overlay Deckkraft",
"shopCursorTarget": "Shop-Cursor Ziel", "shopCursorTarget": "Shop-Cursor Ziel",
"items": "Items", "rewards": "Items",
"reroll": "Neu rollen", "reroll": "Neu rollen",
"shop": "Shop", "shop": "Shop",
"checkTeam": "Team überprüfen" "checkTeam": "Team überprüfen"

View File

@ -12,6 +12,7 @@
"blockItemTheft": "{{pokemonNameWithAffix}}'s {{abilityName}}\nprevents item theft!", "blockItemTheft": "{{pokemonNameWithAffix}}'s {{abilityName}}\nprevents item theft!",
"typeImmunityHeal": "{{pokemonNameWithAffix}}'s {{abilityName}}\nrestored its HP a little!", "typeImmunityHeal": "{{pokemonNameWithAffix}}'s {{abilityName}}\nrestored its HP a little!",
"nonSuperEffectiveImmunity": "{{pokemonNameWithAffix}} avoided damage\nwith {{abilityName}}!", "nonSuperEffectiveImmunity": "{{pokemonNameWithAffix}} avoided damage\nwith {{abilityName}}!",
"fullHpResistType": "{{pokemonNameWithAffix}} made its shell gleam!\nIt's distorting type matchups!",
"moveImmunity": "It doesn't affect {{pokemonNameWithAffix}}!", "moveImmunity": "It doesn't affect {{pokemonNameWithAffix}}!",
"reverseDrain": "{{pokemonNameWithAffix}} sucked up the liquid ooze!", "reverseDrain": "{{pokemonNameWithAffix}} sucked up the liquid ooze!",
"postDefendTypeChange": "{{pokemonNameWithAffix}}'s {{abilityName}}\nmade it the {{typeName}} type!", "postDefendTypeChange": "{{pokemonNameWithAffix}}'s {{abilityName}}\nmade it the {{typeName}} type!",

View File

@ -1,268 +0,0 @@
{
"Achievements": {
"name": "Achievements"
},
"Locked": {
"name": "Locked"
},
"MoneyAchv": {
"description": "Accumulate a total of ₽{{moneyAmount}}"
},
"10K_MONEY": {
"name": "Money Haver"
},
"100K_MONEY": {
"name": "Rich"
},
"1M_MONEY": {
"name": "Millionaire"
},
"10M_MONEY": {
"name": "One Percenter"
},
"DamageAchv": {
"description": "Inflict {{damageAmount}} damage in one hit"
},
"250_DMG": {
"name": "Hard Hitter"
},
"1000_DMG": {
"name": "Harder Hitter"
},
"2500_DMG": {
"name": "That's a Lotta Damage!"
},
"10000_DMG": {
"name": "One Punch Man"
},
"HealAchv": {
"description": "Heal {{healAmount}} {{HP}} at once with a move, ability, or held item"
},
"250_HEAL": {
"name": "Novice Healer"
},
"1000_HEAL": {
"name": "Big Healer"
},
"2500_HEAL": {
"name": "Cleric"
},
"10000_HEAL": {
"name": "Recovery Master"
},
"LevelAchv": {
"description": "Level up a Pokémon to Lv{{level}}"
},
"LV_100": {
"name": "But Wait, There's More!"
},
"LV_250": {
"name": "Elite"
},
"LV_1000": {
"name": "To Go Even Further Beyond"
},
"RibbonAchv": {
"description": "Accumulate a total of {{ribbonAmount}} Ribbons"
},
"10_RIBBONS": {
"name": "Pokémon League Champion"
},
"25_RIBBONS": {
"name": "Great League Champion"
},
"50_RIBBONS": {
"name": "Ultra League Champion"
},
"75_RIBBONS": {
"name": "Rogue League Champion"
},
"100_RIBBONS": {
"name": "Master League Champion"
},
"TRANSFER_MAX_BATTLE_STAT": {
"name": "Teamwork",
"description": "Baton pass to another party member with at least one stat maxed out"
},
"MAX_FRIENDSHIP": {
"name": "Friendmaxxing",
"description": "Reach max friendship on a Pokémon"
},
"MEGA_EVOLVE": {
"name": "Megamorph",
"description": "Mega evolve a Pokémon"
},
"GIGANTAMAX": {
"name": "Absolute Unit",
"description": "Gigantamax a Pokémon"
},
"TERASTALLIZE": {
"name": "STAB Enthusiast",
"description": "Terastallize a Pokémon"
},
"STELLAR_TERASTALLIZE": {
"name": "The Hidden Type",
"description": "Stellar Terastallize a Pokémon"
},
"SPLICE": {
"name": "Infinite Fusion",
"description": "Splice two Pokémon together with DNA Splicers"
},
"MINI_BLACK_HOLE": {
"name": "A Hole Lot of Items",
"description": "Acquire a Mini Black Hole"
},
"CATCH_MYTHICAL": {
"name": "Mythical",
"description": "Catch a mythical Pokémon"
},
"CATCH_SUB_LEGENDARY": {
"name": "(Sub-)Legendary",
"description": "Catch a sub-legendary Pokémon"
},
"CATCH_LEGENDARY": {
"name": "Legendary",
"description": "Catch a legendary Pokémon"
},
"SEE_SHINY": {
"name": "Shiny",
"description": "Find a shiny Pokémon in the wild"
},
"SHINY_PARTY": {
"name": "That's Dedication",
"description": "Have a full party of shiny Pokémon"
},
"HATCH_MYTHICAL": {
"name": "Mythical Egg",
"description": "Hatch a mythical Pokémon from an egg"
},
"HATCH_SUB_LEGENDARY": {
"name": "Sub-Legendary Egg",
"description": "Hatch a sub-legendary Pokémon from an egg"
},
"HATCH_LEGENDARY": {
"name": "Legendary Egg",
"description": "Hatch a legendary Pokémon from an egg"
},
"HATCH_SHINY": {
"name": "Shiny Egg",
"description": "Hatch a shiny Pokémon from an egg"
},
"HIDDEN_ABILITY": {
"name": "Hidden Potential",
"description": "Catch a Pokémon with a hidden ability"
},
"PERFECT_IVS": {
"name": "Certificate of Authenticity",
"description": "Get perfect IVs on a Pokémon"
},
"CLASSIC_VICTORY": {
"name": "Undefeated",
"description": "Beat the game in classic mode"
},
"UNEVOLVED_CLASSIC_VICTORY": {
"name": "Bring Your Child To Work Day",
"description": "Beat the game in Classic Mode with at least one unevolved party member."
},
"MONO_GEN_ONE": {
"name": "The Original Rival",
"description": "Complete the generation one only challenge."
},
"MONO_GEN_TWO": {
"name": "Generation 1.5",
"description": "Complete the generation two only challenge."
},
"MONO_GEN_THREE": {
"name": "Too much water?",
"description": "Complete the generation three only challenge."
},
"MONO_GEN_FOUR": {
"name": "Is she really the hardest?",
"description": "Complete the generation four only challenge."
},
"MONO_GEN_FIVE": {
"name": "All Original",
"description": "Complete the generation five only challenge."
},
"MONO_GEN_SIX": {
"name": "Almost Royalty",
"description": "Complete the generation six only challenge."
},
"MONO_GEN_SEVEN": {
"name": "Only Technically",
"description": "Complete the generation seven only challenge."
},
"MONO_GEN_EIGHT": {
"name": "A Champion Time!",
"description": "Complete the generation eight only challenge."
},
"MONO_GEN_NINE": {
"name": "She was going easy on you",
"description": "Complete the generation nine only challenge."
},
"MonoType": {
"description": "Complete the {{type}} monotype challenge."
},
"MONO_NORMAL": {
"name": "Extra Ordinary"
},
"MONO_FIGHTING": {
"name": "I Know Kung Fu"
},
"MONO_FLYING": {
"name": "Angry Birds"
},
"MONO_POISON": {
"name": "Kanto's Favourite"
},
"MONO_GROUND": {
"name": "Forecast: Earthquakes"
},
"MONO_ROCK": {
"name": "Brock Hard"
},
"MONO_BUG": {
"name": "You Like Jazz?"
},
"MONO_GHOST": {
"name": "Who You Gonna Call?"
},
"MONO_STEEL": {
"name": "Iron Giant"
},
"MONO_FIRE": {
"name": "I Cast Fireball!"
},
"MONO_WATER": {
"name": "When It Rains, It Pours"
},
"MONO_GRASS": {
"name": "Can't Touch This"
},
"MONO_ELECTRIC": {
"name": "Aim For The Horn!"
},
"MONO_PSYCHIC": {
"name": "Big Brain Energy"
},
"MONO_ICE": {
"name": "Walking On Thin Ice"
},
"MONO_DRAGON": {
"name": "Pseudo-Legend Club"
},
"MONO_DARK": {
"name": "It's Just A Phase"
},
"MONO_FAIRY": {
"name": "Hey! Listen!"
},
"FRESH_START": {
"name": "First Try!",
"description": "Complete the Fresh Start challenge."
},
"INVERSE_BATTLE": {
"name": "Mirror rorriM",
"description": "Complete the Inverse Battle challenge.\n.egnellahc elttaB esrevnI eht etelpmoC"
}
}

View File

@ -10,19 +10,19 @@
}, },
"10K_MONEY": { "10K_MONEY": {
"name": "Money Haver", "name": "Money Haver",
"name_female": null "name_female": "Money Haver"
}, },
"100K_MONEY": { "100K_MONEY": {
"name": "Rich", "name": "Rich",
"name_female": null "name_female": "Rich"
}, },
"1M_MONEY": { "1M_MONEY": {
"name": "Millionaire", "name": "Millionaire",
"name_female": null "name_female": "Millionaire"
}, },
"10M_MONEY": { "10M_MONEY": {
"name": "One Percenter", "name": "One Percenter",
"name_female": null "name_female": "One Percenter"
}, },
"DamageAchv": { "DamageAchv": {
"description": "Inflict {{damageAmount}} damage in one hit" "description": "Inflict {{damageAmount}} damage in one hit"
@ -32,11 +32,11 @@
}, },
"1000_DMG": { "1000_DMG": {
"name": "Harder Hitter", "name": "Harder Hitter",
"name_female": null "name_female": "Harder Hitter"
}, },
"2500_DMG": { "2500_DMG": {
"name": "That's a Lotta Damage!", "name": "That's a Lotta Damage!",
"name_female": null "name_female": "That's a Lotta Damage!"
}, },
"10000_DMG": { "10000_DMG": {
"name": "One Punch Man", "name": "One Punch Man",
@ -47,19 +47,19 @@
}, },
"250_HEAL": { "250_HEAL": {
"name": "Novice Healer", "name": "Novice Healer",
"name_female": null "name_female": "Novice Healer"
}, },
"1000_HEAL": { "1000_HEAL": {
"name": "Big Healer", "name": "Big Healer",
"name_female": null "name_female": "Big Healer"
}, },
"2500_HEAL": { "2500_HEAL": {
"name": "Cleric", "name": "Cleric",
"name_female": null "name_female": "Cleric"
}, },
"10000_HEAL": { "10000_HEAL": {
"name": "Recovery Master", "name": "Recovery Master",
"name_female": null "name_female": "Recovery Master"
}, },
"LevelAchv": { "LevelAchv": {
"description": "Level up a Pokémon to Lv{{level}}" "description": "Level up a Pokémon to Lv{{level}}"
@ -69,7 +69,7 @@
}, },
"LV_250": { "LV_250": {
"name": "Elite", "name": "Elite",
"name_female": null "name_female": "Elite"
}, },
"LV_1000": { "LV_1000": {
"name": "To Go Even Further Beyond" "name": "To Go Even Further Beyond"
@ -79,27 +79,27 @@
}, },
"10_RIBBONS": { "10_RIBBONS": {
"name": "Pokémon League Champion", "name": "Pokémon League Champion",
"name_female": null "name_female": "Pokémon League Champion"
}, },
"25_RIBBONS": { "25_RIBBONS": {
"name": "Great League Champion", "name": "Great League Champion",
"name_female": null "name_female": "Great League Champion"
}, },
"50_RIBBONS": { "50_RIBBONS": {
"name": "Ultra League Champion", "name": "Ultra League Champion",
"name_female": null "name_female": "Ultra League Champion"
}, },
"75_RIBBONS": { "75_RIBBONS": {
"name": "Rogue League Champion", "name": "Rogue League Champion",
"name_female": null "name_female": "Rogue League Champion"
}, },
"100_RIBBONS": { "100_RIBBONS": {
"name": "Master League Champion", "name": "Master League Champion",
"name_female": null "name_female": "Master League Champion"
}, },
"TRANSFER_MAX_BATTLE_STAT": { "TRANSFER_MAX_STAT_STAGE": {
"name": "Teamwork", "name": "Teamwork",
"description": "Baton pass to another party member with at least one stat maxed out" "description": "Baton pass to another party member with at least one stat stage maxed out"
}, },
"MAX_FRIENDSHIP": { "MAX_FRIENDSHIP": {
"name": "Friendmaxxing", "name": "Friendmaxxing",
@ -147,7 +147,7 @@
}, },
"SHINY_PARTY": { "SHINY_PARTY": {
"name": "That's Dedication", "name": "That's Dedication",
"name_female": null, "name_female": "That's Dedication",
"description": "Have a full party of shiny Pokémon" "description": "Have a full party of shiny Pokémon"
}, },
"HATCH_MYTHICAL": { "HATCH_MYTHICAL": {
@ -176,7 +176,7 @@
}, },
"CLASSIC_VICTORY": { "CLASSIC_VICTORY": {
"name": "Undefeated", "name": "Undefeated",
"name_female": null, "name_female": "Undefeated",
"description": "Beat the game in classic mode" "description": "Beat the game in classic mode"
}, },
"UNEVOLVED_CLASSIC_VICTORY": { "UNEVOLVED_CLASSIC_VICTORY": {

View File

@ -39,5 +39,6 @@
"matBlock": "Mat Block", "matBlock": "Mat Block",
"craftyShield": "Crafty Shield", "craftyShield": "Crafty Shield",
"tailwind": "Tailwind", "tailwind": "Tailwind",
"happyHour": "Happy Hour" "happyHour": "Happy Hour",
"safeguard": "Safeguard"
} }

View File

@ -47,5 +47,11 @@
"tailwindOnRemovePlayer": "Your team's Tailwind petered out!", "tailwindOnRemovePlayer": "Your team's Tailwind petered out!",
"tailwindOnRemoveEnemy": "The opposing team's Tailwind petered out!", "tailwindOnRemoveEnemy": "The opposing team's Tailwind petered out!",
"happyHourOnAdd": "Everyone is caught up in the happy atmosphere!", "happyHourOnAdd": "Everyone is caught up in the happy atmosphere!",
"happyHourOnRemove": "The atmosphere returned to normal." "happyHourOnRemove": "The atmosphere returned to normal.",
"safeguardOnAdd": "The whole field is cloaked in a mystical veil!",
"safeguardOnAddPlayer": "Your team cloaked itself in a mystical veil!",
"safeguardOnAddEnemy": "The opposing team cloaked itself in a mystical veil!",
"safeguardOnRemove": "The field is no longer protected by Safeguard!",
"safeguardOnRemovePlayer": "Your team is no longer protected by Safeguard!",
"safeguardOnRemoveEnemy": "The opposing team is no longer protected by Safeguard!"
} }

View File

@ -61,6 +61,7 @@
"skipItemQuestion": "Are you sure you want to skip taking an item?", "skipItemQuestion": "Are you sure you want to skip taking an item?",
"itemStackFull": "The stack for {{fullItemName}} is full.\nYou will receive {{itemName}} instead.", "itemStackFull": "The stack for {{fullItemName}} is full.\nYou will receive {{itemName}} instead.",
"eggHatching": "Oh?", "eggHatching": "Oh?",
"eggSkipPrompt": "Skip to egg summary?",
"ivScannerUseQuestion": "Use IV Scanner on {{pokemonName}}?", "ivScannerUseQuestion": "Use IV Scanner on {{pokemonName}}?",
"wildPokemonWithAffix": "Wild {{pokemonName}}", "wildPokemonWithAffix": "Wild {{pokemonName}}",
"foePokemonWithAffix": "Foe {{pokemonName}}", "foePokemonWithAffix": "Foe {{pokemonName}}",

View File

@ -1,6 +1,7 @@
{ {
"title": "Challenge Modifiers", "title": "Challenge Modifiers",
"illegalEvolution": "{{pokemon}} changed into an ineligble pokémon\nfor this challenge!", "illegalEvolution": "{{pokemon}} changed into an ineligble pokémon\nfor this challenge!",
"noneSelected": "None Selected",
"singleGeneration": { "singleGeneration": {
"name": "Mono Gen", "name": "Mono Gen",
"desc": "You can only use Pokémon from Generation {{gen}}.", "desc": "You can only use Pokémon from Generation {{gen}}.",

View File

@ -58,7 +58,7 @@
"iris_alder_double": { "iris_alder_double": {
"encounter": { "encounter": {
"1": "Iris: Welcome Challenger! I am THE Unova Champion!\n$Alder: Iris, aren't you a bit too excited?", "1": "Iris: Welcome Challenger! I am THE Unova Champion!\n$Alder: Iris, aren't you a bit too excited?",
"1_female": null "1_female": "Iris: Welcome Challenger! I am THE Unova Champion!\n$Alder: Iris, aren't you a bit too excited?"
}, },
"victory": { "victory": {
"1": "Iris: A loss like this is not easy to take...\n$Alder: But we will only get stronger with every loss!" "1": "Iris: A loss like this is not easy to take...\n$Alder: But we will only get stronger with every loss!"
@ -75,7 +75,7 @@
"marnie_piers_double": { "marnie_piers_double": {
"encounter": { "encounter": {
"1": "Piers: Ready for a concert?\n$Marnie: Brother... They are here to fight, not to sing...", "1": "Piers: Ready for a concert?\n$Marnie: Brother... They are here to fight, not to sing...",
"1_female": null "1_female": "Piers: Ready for a concert?\n$Marnie: Brother... They are here to fight, not to sing..."
}, },
"victory": { "victory": {
"1": "Piers: Now that was a great concert!\n$Marnie: Brother..." "1": "Piers: Now that was a great concert!\n$Marnie: Brother..."

View File

@ -1,6 +1,6 @@
{ {
"encounter": "It appears the time has finally come once again.\nYou know why you have come here, do you not?\n$You were drawn here, because you have been here before.\nCountless times.\n$Though, perhaps it can be counted.\nTo be precise, this is in fact your {{cycleCount}} cycle.\n$Each cycle your mind reverts to its former state.\nEven so, somehow, remnants of your former selves remain.\n$Until now you have yet to succeed, but I sense a different presence in you this time.\n\n$You are the only one here, though it is as if there is… another.\n$Will you finally prove a formidable challenge to me?\nThe challenge I have longed after for millennia?\n$We begin.", "encounter": "It appears the time has finally come once again.\nYou know why you have come here, do you not?\n$You were drawn here, because you have been here before.\nCountless times.\n$Though, perhaps it can be counted.\nTo be precise, this is in fact your {{cycleCount}} cycle.\n$Each cycle your mind reverts to its former state.\nEven so, somehow, remnants of your former selves remain.\n$Until now you have yet to succeed, but I sense a different presence in you this time.\n\n$You are the only one here, though it is as if there is… another.\n$Will you finally prove a formidable challenge to me?\nThe challenge I have longed after for millennia?\n$We begin.",
"encounter_female": null, "encounter_female": "It appears the time has finally come once again.\nYou know why you have come here, do you not?\n$You were drawn here, because you have been here before.\nCountless times.\n$Though, perhaps it can be counted.\nTo be precise, this is in fact your {{cycleCount}} cycle.\n$Each cycle your mind reverts to its former state.\nEven so, somehow, remnants of your former selves remain.\n$Until now you have yet to succeed, but I sense a different presence in you this time.\n\n$You are the only one here, though it is as if there is… another.\n$Will you finally prove a formidable challenge to me?\nThe challenge I have longed after for millennia?\n$We begin.",
"firstStageWin": "I see. The presence I felt was indeed real.\nIt appears I no longer need to hold back.\n$Do not disappoint me.", "firstStageWin": "I see. The presence I felt was indeed real.\nIt appears I no longer need to hold back.\n$Do not disappoint me.",
"secondStageWin": "…Magnificent.", "secondStageWin": "…Magnificent.",
"key_ordinal_one": "st", "key_ordinal_one": "st",

View File

@ -1,6 +1,6 @@
{ {
"ending": "@c{smile}Oh? You won?@d{96} @c{smile_eclosed}I guess I should've known.\nBut, you're back now.\n$@c{smile}It's over.@d{64} You ended the loop.\n$@c{serious_smile_fists}You fulfilled your dream too, didn't you?\nYou didn't lose even once.\n$@c{neutral}I'm the only one who'll remember what you did.@d{96}\nI guess that's okay, isn't it?\n$@c{serious_smile_fists}Your legend will always live on in our hearts.\n$@c{smile_eclosed}Anyway, I've had about enough of this place, haven't you? Let's head home.\n$@c{serious_smile_fists}Maybe when we get back, we can have another battle?\nIf you're up to it.", "ending": "@c{shock}You're back?@d{32} Does that mean…@d{96} you won?!\n@c{smile_ehalf}I should have known you had it in you.\n$@c{smile_eclosed}Of course… I always had that feeling.\n@c{smile}It's over now, right? You ended the loop.\n$@c{smile_ehalf}You fulfilled your dream too, didn't you?\nYou didn't lose even once.\n$I'll be the only one to remember what you did.\n@c{angry_mopen}I'll try not to forget!\n$@c{smile_wave_wink}Just kidding!@d{64} @c{smile}I'd never forget.@d{32}\nYour legend will live on in our hearts.\n$@c{smile_wave}Anyway,@d{64} it's getting late…@d{96} I think?\nIt's hard to tell in this place.\n$Let's go home. @c{smile_wave_wink}Maybe tomorrow, we can have another battle, for old time's sake?",
"ending_female": "@c{shock}You're back?@d{32} Does that mean…@d{96} you won?!\n@c{smile_ehalf}I should have known you had it in you.\n$@c{smile_eclosed}Of course… I always had that feeling.\n@c{smile}It's over now, right? You ended the loop.\n$@c{smile_ehalf}You fulfilled your dream too, didn't you?\nYou didn't lose even once.\n$I'll be the only one to remember what you did.\n@c{angry_mopen}I'll try not to forget!\n$@c{smile_wave_wink}Just kidding!@d{64} @c{smile}I'd never forget.@d{32}\nYour legend will live on in our hearts.\n$@c{smile_wave}Anyway,@d{64} it's getting late…@d{96} I think?\nIt's hard to tell in this place.\n$Let's go home. @c{smile_wave_wink}Maybe tomorrow, we can have another battle, for old time's sake?", "ending_female": "@c{smile}Oh? You won?@d{96} @c{smile_eclosed}I guess I should've known.\nBut, you're back now.\n$@c{smile}It's over.@d{64} You ended the loop.\n$@c{serious_smile_fists}You fulfilled your dream too, didn't you?\nYou didn't lose even once.\n$@c{neutral}I'm the only one who'll remember what you did.@d{96}\nI guess that's okay, isn't it?\n$@c{serious_smile_fists}Your legend will always live on in our hearts.\n$@c{smile_eclosed}Anyway, I've had about enough of this place, haven't you? Let's head home.\n$@c{serious_smile_fists}Maybe when we get back, we can have another battle?\nIf you're up to it.",
"ending_endless": "Congratulations on reaching the current end!\nMore content is coming soon.", "ending_endless": "Congratulations on reaching the current end!\nMore content is coming soon.",
"ending_name": "Devs" "ending_name": "Devs"
} }

View File

@ -3,31 +3,31 @@
"encounter": { "encounter": {
"1": "Hey, wanna battle?", "1": "Hey, wanna battle?",
"2": "Are you a new trainer too?", "2": "Are you a new trainer too?",
"2_female": null, "2_female": "Are you a new trainer too?",
"3": "Hey, I haven't seen you before. Let's battle!", "3": "Hey, I haven't seen you before. Let's battle!",
"4": "I just lost, so I'm trying to find more Pokémon.\nWait! You look weak! Come on, let's battle!", "4": "I just lost, so I'm trying to find more Pokémon.\nWait! You look weak! Come on, let's battle!",
"4_female": null, "4_female": "I just lost, so I'm trying to find more Pokémon.\nWait! You look weak! Come on, let's battle!",
"5": "Have we met or not? I don't really remember. Well, I guess it's nice to meet you anyway!", "5": "Have we met or not? I don't really remember. Well, I guess it's nice to meet you anyway!",
"6": "All right! Let's go!", "6": "All right! Let's go!",
"7": "All right! Here I come! I'll show you my power!", "7": "All right! Here I come! I'll show you my power!",
"8": "Haw haw haw... I'll show you how hawesome my Pokémon are!", "8": "Haw haw haw... I'll show you how hawesome my Pokémon are!",
"9": "No need to waste time saying hello. Bring it on whenever you're ready!", "9": "No need to waste time saying hello. Bring it on whenever you're ready!",
"9_female": null, "9_female": "No need to waste time saying hello. Bring it on whenever you're ready!",
"10": "Don't let your guard down, or you may be crying when a kid beats you.", "10": "Don't let your guard down, or you may be crying when a kid beats you.",
"11": "I've raised my Pokémon with great care. You're not allowed to hurt them!", "11": "I've raised my Pokémon with great care. You're not allowed to hurt them!",
"12": "Glad you made it! It won't be an easy job from here.", "12": "Glad you made it! It won't be an easy job from here.",
"12_female": null, "12_female": "Glad you made it! It won't be an easy job from here.",
"13": "The battles continue forever! Welcome to the world with no end!", "13": "The battles continue forever! Welcome to the world with no end!",
"13_female": null "13_female": "The battles continue forever! Welcome to the world with no end!"
}, },
"victory": { "victory": {
"1": "Wow! You're strong!", "1": "Wow! You're strong!",
"1_female": null, "1_female": "Wow! You're strong!",
"2": "I didn't stand a chance, huh?", "2": "I didn't stand a chance, huh?",
"3": "I'll find you again when I'm older and beat you!", "3": "I'll find you again when I'm older and beat you!",
"4": "Ugh. I don't have any more Pokémon.", "4": "Ugh. I don't have any more Pokémon.",
"5": "No way… NO WAY! How could I lose again…", "5": "No way… NO WAY! How could I lose again…",
"5_female": null, "5_female": "No way… NO WAY! How could I lose again…",
"6": "No! I lost!", "6": "No! I lost!",
"7": "Whoa! You are incredible! I'm amazed and surprised!", "7": "Whoa! You are incredible! I'm amazed and surprised!",
"8": "Could it be… How… My Pokémon and I are the strongest, though…", "8": "Could it be… How… My Pokémon and I are the strongest, though…",
@ -42,12 +42,12 @@
"encounter": { "encounter": {
"1": "Let's have a battle, shall we?", "1": "Let's have a battle, shall we?",
"2": "You look like a new trainer. Let's have a battle!", "2": "You look like a new trainer. Let's have a battle!",
"2_female": null, "2_female": "You look like a new trainer. Let's have a battle!",
"3": "I don't recognize you. How about a battle?", "3": "I don't recognize you. How about a battle?",
"4": "Let's have a fun Pokémon battle!", "4": "Let's have a fun Pokémon battle!",
"5": "I'll show you the ropes of how to really use Pokémon!", "5": "I'll show you the ropes of how to really use Pokémon!",
"6": "A serious battle starts from a serious beginning! Are you sure you're ready?", "6": "A serious battle starts from a serious beginning! Are you sure you're ready?",
"6_female": null, "6_female": "A serious battle starts from a serious beginning! Are you sure you're ready?",
"7": "You're only young once. And you only get one shot at a given battle. Soon, you'll be nothing but a memory.", "7": "You're only young once. And you only get one shot at a given battle. Soon, you'll be nothing but a memory.",
"8": "You'd better go easy on me, OK? Though I'll be seriously fighting!", "8": "You'd better go easy on me, OK? Though I'll be seriously fighting!",
"9": "School is boring. I've got nothing to do. Yawn. I'm only battling to kill the time." "9": "School is boring. I've got nothing to do. Yawn. I'm only battling to kill the time."
@ -55,15 +55,15 @@
"victory": { "victory": {
"1": "That was impressive! I've got a lot to learn.", "1": "That was impressive! I've got a lot to learn.",
"2": "I didn't think you'd beat me that bad…", "2": "I didn't think you'd beat me that bad…",
"2_female": null, "2_female": "I didn't think you'd beat me that bad…",
"3": "I hope we get to have a rematch some day.", "3": "I hope we get to have a rematch some day.",
"4": "That was pretty amazingly fun! You've totally exhausted me…", "4": "That was pretty amazingly fun! You've totally exhausted me…",
"5": "You actually taught me a lesson! You're pretty amazing!", "5": "You actually taught me a lesson! You're pretty amazing!",
"6": "Seriously, I lost. That is, like, seriously depressing, but you were seriously cool.", "6": "Seriously, I lost. That is, like, seriously depressing, but you were seriously cool.",
"6_female": null, "6_female": "Seriously, I lost. That is, like, seriously depressing, but you were seriously cool.",
"7": "I don't need memories like this. Deleting memory…", "7": "I don't need memories like this. Deleting memory…",
"8": "Hey! I told you to go easy on me! Still, you're pretty cool when you're serious.", "8": "Hey! I told you to go easy on me! Still, you're pretty cool when you're serious.",
"8_female": null, "8_female": "Hey! I told you to go easy on me! Still, you're pretty cool when you're serious.",
"9": "I'm actually getting tired of battling… There's gotta be something new to do…" "9": "I'm actually getting tired of battling… There's gotta be something new to do…"
} }
}, },
@ -154,7 +154,7 @@
"ace_trainer": { "ace_trainer": {
"encounter": { "encounter": {
"1": "You seem quite confident.", "1": "You seem quite confident.",
"1_female": null, "1_female": "You seem quite confident.",
"2": "Your Pokémon… Show them to me…", "2": "Your Pokémon… Show them to me…",
"3": "Because I'm an Ace Trainer, people think I'm strong.", "3": "Because I'm an Ace Trainer, people think I'm strong.",
"4": "Are you aware of what it takes to be an Ace Trainer?" "4": "Are you aware of what it takes to be an Ace Trainer?"
@ -163,9 +163,9 @@
"1": "Yes… You have good Pokémon…", "1": "Yes… You have good Pokémon…",
"2": "What?! But I'm a battling genius!", "2": "What?! But I'm a battling genius!",
"3": "Of course, you are the main character!", "3": "Of course, you are the main character!",
"3_female": null, "3_female": "Of course, you are the main character!",
"4": "OK! OK! You could be an Ace Trainer!", "4": "OK! OK! You could be an Ace Trainer!",
"4_female": null "4_female": "OK! OK! You could be an Ace Trainer!"
}, },
"defeat": { "defeat": {
"1": "I am devoting my body and soul to Pokémon battles!", "1": "I am devoting my body and soul to Pokémon battles!",
@ -187,7 +187,7 @@
"1": "Get ready, because when we team up, it's double the trouble!", "1": "Get ready, because when we team up, it's double the trouble!",
"2": "Two hearts, one strategy let's see if you can keep up with our twin power!", "2": "Two hearts, one strategy let's see if you can keep up with our twin power!",
"3": "Hope you're ready for double trouble, because we're about to bring the heat!", "3": "Hope you're ready for double trouble, because we're about to bring the heat!",
"3_female": null "3_female": "Hope you're ready for double trouble, because we're about to bring the heat!"
}, },
"victory": { "victory": {
"1": "We may have lost this round, but our bond remains unbreakable!", "1": "We may have lost this round, but our bond remains unbreakable!",
@ -216,7 +216,7 @@
"encounter": { "encounter": {
"1": "I praise your courage in challenging me! For I am the one with the strongest kick!", "1": "I praise your courage in challenging me! For I am the one with the strongest kick!",
"2": "Oh, I see. Would you like to be cut to pieces? Or do you prefer the role of punching bag?", "2": "Oh, I see. Would you like to be cut to pieces? Or do you prefer the role of punching bag?",
"2_female": null "2_female": "Oh, I see. Would you like to be cut to pieces? Or do you prefer the role of punching bag?"
}, },
"victory": { "victory": {
"1": "Oh. The Pokémon did the fighting. My strong kick didn't help a bit.", "1": "Oh. The Pokémon did the fighting. My strong kick didn't help a bit.",
@ -328,7 +328,7 @@
"defeat": { "defeat": {
"1": "New age simply refers to twentieth century classical composers, right?", "1": "New age simply refers to twentieth century classical composers, right?",
"2": "Don't get hung up on sadness or frustration. You can use your grudges to motivate yourself.", "2": "Don't get hung up on sadness or frustration. You can use your grudges to motivate yourself.",
"2_female": null "2_female": "Don't get hung up on sadness or frustration. You can use your grudges to motivate yourself."
} }
}, },
"psychic": { "psychic": {
@ -360,7 +360,7 @@
"baker": { "baker": {
"encounter": { "encounter": {
"1": "Hope you're ready to taste defeat!", "1": "Hope you're ready to taste defeat!",
"1_female": null "1_female": "Hope you're ready to taste defeat!"
}, },
"victory": { "victory": {
"1": "I'll bake a comeback." "1": "I'll bake a comeback."
@ -391,7 +391,7 @@
"1": "Matey, you're walking the plank if you lose!", "1": "Matey, you're walking the plank if you lose!",
"2": "Come on then! My sailor's pride is at stake!", "2": "Come on then! My sailor's pride is at stake!",
"3": "Ahoy there! Are you seasick?", "3": "Ahoy there! Are you seasick?",
"3_female": null "3_female": "Ahoy there! Are you seasick?"
}, },
"victory": { "victory": {
"1": "Argh! Beaten by a kid!", "1": "Argh! Beaten by a kid!",
@ -413,13 +413,13 @@
}, },
"ariana": { "ariana": {
"encounter": { "encounter": {
"1": "Hold it right there! We can't someone on the loose.\n$It's harmful to Team Rocket's pride, you see.", "1": "Hold it right there!\nWe can't have someone on the loose.\n$It's harmful to Team Rocket's pride, you see.",
"2": "I don't know or care if what I'm doing is right or wrong...\n$I just put my faith in Giovanni and do as I am told", "2": "I don't know or care if what I'm doing is right or wrong...\n$I just put my faith in Giovanni and do as I am told",
"3": "Your trip ends here. I'm going to take you down!" "3": "Your trip ends here. I'm going to take you down!"
}, },
"victory": { "victory": {
"1": "Tch, you really are strong. It's too bad.\n$If you were to join Team Rocket, you could become an Executive.", "1": "Tch, you really are strong. It's too bad.\n$If you were to join Team Rocket, you could become an Executive.",
"1_female": null, "1_female": "Tch, you really are strong. It's too bad.\n$If you were to join Team Rocket, you could become an Executive.",
"2": "I... I'm shattered...", "2": "I... I'm shattered...",
"3": "Aaaieeeee! This can't be happening! I fought hard, but I still lost…" "3": "Aaaieeeee! This can't be happening! I fought hard, but I still lost…"
} }
@ -458,7 +458,7 @@
"1": "Hehehe! You might have beaten me, but you don't stand a chance against the boss!\n$If you get lost now, you won't have to face a sound whipping!", "1": "Hehehe! You might have beaten me, but you don't stand a chance against the boss!\n$If you get lost now, you won't have to face a sound whipping!",
"2": "Hehehe... So, I lost, too...", "2": "Hehehe... So, I lost, too...",
"3": "Ahya! How could this be? For an Admin like me to lose to some random trainer...", "3": "Ahya! How could this be? For an Admin like me to lose to some random trainer...",
"3_female": null "3_female": "Ahya! How could this be? For an Admin like me to lose to some random trainer..."
} }
}, },
"courtney": { "courtney": {
@ -478,13 +478,13 @@
"1": "Ahahahaha! You're going to meddle in Team Aqua's affairs?\n$You're either absolutely fearless, simply ignorant, or both!\n$You're so cute, you're disgusting! I'll put you down", "1": "Ahahahaha! You're going to meddle in Team Aqua's affairs?\n$You're either absolutely fearless, simply ignorant, or both!\n$You're so cute, you're disgusting! I'll put you down",
"2": "What's this? Who's this spoiled brat?", "2": "What's this? Who's this spoiled brat?",
"3": "Cool your jets. Be patient. I'll crush you shortly.", "3": "Cool your jets. Be patient. I'll crush you shortly.",
"3_female": null "3_female": "Cool your jets. Be patient. I'll crush you shortly."
}, },
"victory": { "victory": {
"1": "Ahahahaha! We got meddled with unexpectedly! We're out of options.\n$We'll have to pull out. But this isn't the last you'll see of Team Aqua!\n$We have other plans! Don't you forget it!", "1": "Ahahahaha! We got meddled with unexpectedly! We're out of options.\n$We'll have to pull out. But this isn't the last you'll see of Team Aqua!\n$We have other plans! Don't you forget it!",
"2": "Ahhh?! Did I go too easy on you?!", "2": "Ahhh?! Did I go too easy on you?!",
"3": "Uh. Are you telling me you've upped your game even more during the fight?\n$You're a brat with a bright future… My Pokémon and I don't have any strength left to fight…\n$Go on… Go and be destroyed by Archie.", "3": "Uh. Are you telling me you've upped your game even more during the fight?\n$You're a brat with a bright future… My Pokémon and I don't have any strength left to fight…\n$Go on… Go and be destroyed by Archie.",
"3_female": null "3_female": "Uh. Are you telling me you've upped your game even more during the fight?\n$You're a brat with a bright future… My Pokémon and I don't have any strength left to fight…\n$Go on… Go and be destroyed by Archie."
} }
}, },
"matt": { "matt": {
@ -497,7 +497,7 @@
"1": "Muwuhahaha! That battle was fun even though I lost!", "1": "Muwuhahaha! That battle was fun even though I lost!",
"2": "I can feel it! I can feel it, all right! The strength coming offa you!\n$More! I still want more! But looks like we're outta time...", "2": "I can feel it! I can feel it, all right! The strength coming offa you!\n$More! I still want more! But looks like we're outta time...",
"3": "Oho! That's a loss I can be proud of!", "3": "Oho! That's a loss I can be proud of!",
"3_female": null "3_female": "Oho! That's a loss I can be proud of!"
} }
}, },
"mars": { "mars": {
@ -505,7 +505,7 @@
"1": "I'm Mars, one of Team Galactic's top Commanders.", "1": "I'm Mars, one of Team Galactic's top Commanders.",
"2": "Team Galactic's vision for the future is unwavering. Opposition will be crushed without mercy!", "2": "Team Galactic's vision for the future is unwavering. Opposition will be crushed without mercy!",
"3": "Feeling nervous? You should be!", "3": "Feeling nervous? You should be!",
"3_female": null "3_female": "Feeling nervous? You should be!"
}, },
"victory": { "victory": {
"1": "This can't be happening! How did I lose?!", "1": "This can't be happening! How did I lose?!",
@ -540,25 +540,25 @@
"zinzolin": { "zinzolin": {
"encounter": { "encounter": {
"1": "You could become a threat to Team Plasma, so we will eliminate you here and now!", "1": "You could become a threat to Team Plasma, so we will eliminate you here and now!",
"1_female": null, "1_female": "You could become a threat to Team Plasma, so we will eliminate you here and now!",
"2": "You don't have the sense to know when to quit, it seems. It's an act of mercy on my part to bring an end to this now!", "2": "You don't have the sense to know when to quit, it seems. It's an act of mercy on my part to bring an end to this now!",
"3": "You're an impressive Trainer to have made it this far. But it ends here.", "3": "You're an impressive Trainer to have made it this far. But it ends here.",
"3_female": null "3_female": "You're an impressive Trainer to have made it this far. But it ends here."
}, },
"victory": { "victory": {
"1": "Ghetsis... I have failed you...", "1": "Ghetsis... I have failed you...",
"2": "It's bitter cold. I'm shivering. I'm suffering. Yet, we will stand victorious.", "2": "It's bitter cold. I'm shivering. I'm suffering. Yet, we will stand victorious.",
"3": "Hmph. You're a smarter Trainer than I expected, but not smart enough.", "3": "Hmph. You're a smarter Trainer than I expected, but not smart enough.",
"3_female": null "3_female": "Hmph. You're a smarter Trainer than I expected, but not smart enough."
} }
}, },
"rood": { "rood": {
"encounter": { "encounter": {
"1": "You are a threat to Team Plasma. We cannot let you walk away from here and now!", "1": "You are a threat to Team Plasma. We cannot let you walk away from here and now!",
"1_female": null, "1_female": "You are a threat to Team Plasma. We cannot let you walk away from here and now!",
"2": "It seems you don't know when to give up. I'll make sure no one interferes with our plans!", "2": "It seems you don't know when to give up. I'll make sure no one interferes with our plans!",
"3": "You are a remarkable Trainer to have made it this far. But this is where it ends.", "3": "You are a remarkable Trainer to have made it this far. But this is where it ends.",
"3_female": null "3_female": "You are a remarkable Trainer to have made it this far. But this is where it ends."
}, },
"victory": { "victory": {
"1": "Ghetsis... I have failed my mission...", "1": "Ghetsis... I have failed my mission...",
@ -569,15 +569,15 @@
"xerosic": { "xerosic": {
"encounter": { "encounter": {
"1": "Ah ha ha! It would be my pleasure. Come on, little Trainer! Let's see what you've got!", "1": "Ah ha ha! It would be my pleasure. Come on, little Trainer! Let's see what you've got!",
"1_female": null, "1_female": "Ah ha ha! It would be my pleasure. Come on, little Trainer! Let's see what you've got!",
"2": "Hmm... You're more powerful than you look. I wonder how much energy there is inside you.", "2": "Hmm... You're more powerful than you look. I wonder how much energy there is inside you.",
"2_female": null, "2_female": "Hmm... You're more powerful than you look. I wonder how much energy there is inside you.",
"3": "I've been waiting for you! I need to do a little research on you! Come, let us begin!" "3": "I've been waiting for you! I need to do a little research on you! Come, let us begin!"
}, },
"victory": { "victory": {
"1": "Ah, you're quite strong. Oh yes—very strong, indeed.", "1": "Ah, you're quite strong. Oh yes—very strong, indeed.",
"2": "Ding-ding-ding! You did it! To the victor go the spoils!", "2": "Ding-ding-ding! You did it! To the victor go the spoils!",
"2_female": null, "2_female": "Ding-ding-ding! You did it! To the victor go the spoils!",
"3": "Wonderful! Amazing! You have tremendous skill and bravery!" "3": "Wonderful! Amazing! You have tremendous skill and bravery!"
} }
}, },
@ -585,7 +585,7 @@
"encounter": { "encounter": {
"1": "I am Bryony, and it would be my pleasure to battle you. Show me what you've got.", "1": "I am Bryony, and it would be my pleasure to battle you. Show me what you've got.",
"2": "Impressive... You're more powerful than you appear. Let's see the true extent of your energy.", "2": "Impressive... You're more powerful than you appear. Let's see the true extent of your energy.",
"2_female": null, "2_female": "Impressive... You're more powerful than you appear. Let's see the true extent of your energy.",
"3": "I've anticipated your arrival. It's time for a little test. Shall we begin?" "3": "I've anticipated your arrival. It's time for a little test. Shall we begin?"
}, },
"victory": { "victory": {
@ -598,11 +598,11 @@
"encounter": { "encounter": {
"1": "Prepare for trouble!", "1": "Prepare for trouble!",
"2": "We're pulling a big job here! Get lost, kid!", "2": "We're pulling a big job here! Get lost, kid!",
"2_female": null, "2_female": "We're pulling a big job here! Get lost, kid!",
"3": "Hand over your Pokémon, or face the wrath of Team Rocket!", "3": "Hand over your Pokémon, or face the wrath of Team Rocket!",
"4": "You're about to experience the true terror of Team Rocket!", "4": "You're about to experience the true terror of Team Rocket!",
"5": "Hey, kid! Me am a Team Rocket member kind of guy!", "5": "Hey, kid! Me am a Team Rocket member kind of guy!",
"5_female": null "5_female": "Hey, kid! Me am a Team Rocket member kind of guy!"
}, },
"victory": { "victory": {
"1": "Team Rocket blasting off again!", "1": "Team Rocket blasting off again!",
@ -624,7 +624,7 @@
"1": "Huh? I lost?!", "1": "Huh? I lost?!",
"2": "I can't believe I lost! I even skipped lunch for this", "2": "I can't believe I lost! I even skipped lunch for this",
"3": "No way! You're just a kid!", "3": "No way! You're just a kid!",
"3_female": null, "3_female": "No way! You're just a kid!",
"4": "Urrrgh... I should've ducked into our hideout right away...", "4": "Urrrgh... I should've ducked into our hideout right away...",
"5": "You beat me... Do you think the boss will dock my pay for this?" "5": "You beat me... Do you think the boss will dock my pay for this?"
} }
@ -652,7 +652,7 @@
"3": "In the name of Team Galactic, I'll eliminate anyone who stands in our way!", "3": "In the name of Team Galactic, I'll eliminate anyone who stands in our way!",
"4": "Get ready to lose!", "4": "Get ready to lose!",
"5": "Hope you're ready for a cosmic beatdown!", "5": "Hope you're ready for a cosmic beatdown!",
"5_female": null "5_female": "Hope you're ready for a cosmic beatdown!"
}, },
"victory": { "victory": {
"1": "Shut down...", "1": "Shut down...",
@ -682,7 +682,7 @@
"encounter": { "encounter": {
"1": "Your Pokémon are no match for the elegance of Team Flare.", "1": "Your Pokémon are no match for the elegance of Team Flare.",
"2": "Hope you brought your sunglasses, because things are about to get bright!", "2": "Hope you brought your sunglasses, because things are about to get bright!",
"2_female": null, "2_female": "Hope you brought your sunglasses, because things are about to get bright!",
"3": "Team Flare will cleanse the world of imperfection!", "3": "Team Flare will cleanse the world of imperfection!",
"4": "Prepare to face the brilliance of Team Flare!", "4": "Prepare to face the brilliance of Team Flare!",
"5": "Fashion is most important to us!" "5": "Fashion is most important to us!"
@ -699,6 +699,7 @@
"encounter": { "encounter": {
"1": "I'll fight you with all I have to wipe you out!", "1": "I'll fight you with all I have to wipe you out!",
"2": "I don't care if you're a kid or what. I'll send you flying if you threaten us!", "2": "I don't care if you're a kid or what. I'll send you flying if you threaten us!",
"2_female": "I don't care if you're a kid or what. I'll send you flying if you threaten us!",
"3": "I was told to turn away Trainers, whomever they might be!", "3": "I was told to turn away Trainers, whomever they might be!",
"4": "I'll show you the power of Aether Paradise!", "4": "I'll show you the power of Aether Paradise!",
"5": "Now that you've learned of the darkness at the heart of Aether Paradise, we'll need you to conveniently disappear!" "5": "Now that you've learned of the darkness at the heart of Aether Paradise, we'll need you to conveniently disappear!"
@ -715,11 +716,13 @@
"encounter": { "encounter": {
"1": "I, Branch Chief Faba, shall show you the harshness of the real world!", "1": "I, Branch Chief Faba, shall show you the harshness of the real world!",
"2": "The man who is called Aether Paradise's last line of defense is to battle a mere child?", "2": "The man who is called Aether Paradise's last line of defense is to battle a mere child?",
"2_female": "The man who is called Aether Paradise's last line of defense is to battle a mere child?",
"3": "I, Faba, am the Aether Branch Chief. The only one in the world, I'm irreplaceable." "3": "I, Faba, am the Aether Branch Chief. The only one in the world, I'm irreplaceable."
}, },
"victory": { "victory": {
"1": "Aiyee!", "1": "Aiyee!",
"2": "H-h-how can this be?! How could this child...", "2": "H-h-how can this be?! How could this child...",
"2_female": "H-h-how can this be?! How could this child...",
"3": "This is why... This is why I can't bring myself to like children." "3": "This is why... This is why I can't bring myself to like children."
} }
}, },
@ -727,9 +730,12 @@
"encounter": { "encounter": {
"1": "We're not bad-we're just hard!", "1": "We're not bad-we're just hard!",
"2": "You want some? That's how we say hello! Nice knowing you, punks!", "2": "You want some? That's how we say hello! Nice knowing you, punks!",
"2_female": "You want some? That's how we say hello! Nice knowing you, punks!",
"3": "We're just a bunch of guys and gals with a great interest in other people's Pokémon!", "3": "We're just a bunch of guys and gals with a great interest in other people's Pokémon!",
"4": "Why you trying to act hard when we're already hard as bones out here, homie?", "4": "Why you trying to act hard when we're already hard as bones out here, homie?",
"5": "Team Skull represent! We can't pay the rent! Had a lot of fun, but our youth was misspent!" "4_female": "Why you trying to act hard when we're already hard as bones out here, homie?",
"5": "Team Skull represent! We can't pay the rent! Had a lot of fun, but our youth was misspent!",
"5_female": "Team Skull represent! We can't pay the rent! Had a lot of fun, but our youth was misspent!"
}, },
"victory": { "victory": {
"1": "Huh? Is it over already?", "1": "Huh? Is it over already?",
@ -742,11 +748,13 @@
"plumeria": { "plumeria": {
"encounter": { "encounter": {
"1": " ...Hmph. You don't look like anything special to me.", "1": " ...Hmph. You don't look like anything special to me.",
"2": "It takes these dumb Grunts way too long to deal with you kids..", "1_female": " ...Hmph. You don't look like anything special to me.",
"2": "It takes these dumb Grunts way too long to deal with you kids...",
"3": "Mess with anyone in Team Skull, and I'll show you how serious I can get." "3": "Mess with anyone in Team Skull, and I'll show you how serious I can get."
}, },
"victory": { "victory": {
"1": "Hmmph! You're pretty strong. I'll give you that.", "1": "Hmmph! You're pretty strong. I'll give you that.",
"1_female": "Hmmph! You're pretty strong. I'll give you that.",
"2": "Hmmph. Guess you are pretty tough. Now I understand why my Grunts waste so much time battling kids.", "2": "Hmmph. Guess you are pretty tough. Now I understand why my Grunts waste so much time battling kids.",
"3": "Hmmph! I guess I just have to hold that loss." "3": "Hmmph! I guess I just have to hold that loss."
} }
@ -755,6 +763,7 @@
"encounter": { "encounter": {
"1": "It looks like this is the end of the line for you!", "1": "It looks like this is the end of the line for you!",
"2": "You are a trainer aren't you? I'm afraid that doesn't give you the right to interfere in our work.", "2": "You are a trainer aren't you? I'm afraid that doesn't give you the right to interfere in our work.",
"2_female": "You are a trainer aren't you? I'm afraid that doesn't give you the right to interfere in our work.",
"3": "I'm from Macro Cosmos Insurance! Do you have a life insurance policy?" "3": "I'm from Macro Cosmos Insurance! Do you have a life insurance policy?"
}, },
"victory": { "victory": {
@ -772,6 +781,7 @@
"victory": { "victory": {
"1": "*sigh* I wasn't able to win... Oleana...you really are a hopeless woman.", "1": "*sigh* I wasn't able to win... Oleana...you really are a hopeless woman.",
"2": "Arghhh! This is inexcusable... What was I thinking... Any trainer who's made it this far would be no pushover..", "2": "Arghhh! This is inexcusable... What was I thinking... Any trainer who's made it this far would be no pushover..",
"2_female": "Arghhh! This is inexcusable... What was I thinking... Any trainer who's made it this far would be no pushover..",
"3": "*sigh* I am one tired Oleana..." "3": "*sigh* I am one tired Oleana..."
} }
}, },
@ -784,7 +794,7 @@
}, },
"defeat": { "defeat": {
"1": "Mark my words. Not being able to measure your own strength shows that you are still a child.", "1": "Mark my words. Not being able to measure your own strength shows that you are still a child.",
"1_female": null "1_female": "Mark my words. Not being able to measure your own strength shows that you are still a child."
} }
}, },
"rocket_boss_giovanni_2": { "rocket_boss_giovanni_2": {
@ -845,7 +855,7 @@
"galactic_boss_cyrus_1": { "galactic_boss_cyrus_1": {
"encounter": { "encounter": {
"1": "You were compelled to come here by such vacuous sentimentality.\n$I will make you regret paying heed to your heart!", "1": "You were compelled to come here by such vacuous sentimentality.\n$I will make you regret paying heed to your heart!",
"1_female": null "1_female": "You were compelled to come here by such vacuous sentimentality.\n$I will make you regret paying heed to your heart!"
}, },
"victory": { "victory": {
"1": "Interesting. And quite curious." "1": "Interesting. And quite curious."
@ -995,7 +1005,7 @@
"misty": { "misty": {
"encounter": { "encounter": {
"1": "My policy is an all out offensive with Water-type Pokémon!", "1": "My policy is an all out offensive with Water-type Pokémon!",
"1_female": null, "1_female": "My policy is an all out offensive with Water-type Pokémon!",
"2": "Hiya, I'll show you the strength of my aquatic Pokémon!", "2": "Hiya, I'll show you the strength of my aquatic Pokémon!",
"3": "My dream was to go on a journey and battle powerful trainers…\nWill you be a sufficient challenge?" "3": "My dream was to go on a journey and battle powerful trainers…\nWill you be a sufficient challenge?"
}, },
@ -1013,14 +1023,14 @@
"lt_surge": { "lt_surge": {
"encounter": { "encounter": {
"1": "My Electric Pokémon saved me during the war! I'll show you how!", "1": "My Electric Pokémon saved me during the war! I'll show you how!",
"1_female": null, "1_female": "My Electric Pokémon saved me during the war! I'll show you how!",
"2": "Ten-hut! I'll shock you into surrender!", "2": "Ten-hut! I'll shock you into surrender!",
"3": "I'll zap you just like I do to all my enemies in battle!" "3": "I'll zap you just like I do to all my enemies in battle!"
}, },
"victory": { "victory": {
"1": "Whoa! Your team's the real deal, kid!", "1": "Whoa! Your team's the real deal, kid!",
"2": "Aaargh, you're strong! Even my electric tricks lost against you.", "2": "Aaargh, you're strong! Even my electric tricks lost against you.",
"2_female": null, "2_female": "Aaargh, you're strong! Even my electric tricks lost against you.",
"3": "That was an absolutely shocking loss!" "3": "That was an absolutely shocking loss!"
}, },
"defeat": { "defeat": {
@ -1045,7 +1055,7 @@
"defeat": { "defeat": {
"1": "I was afraid I would doze off…", "1": "I was afraid I would doze off…",
"2": "Oh my, it seems my Grass Pokémon overwhelmed you.", "2": "Oh my, it seems my Grass Pokémon overwhelmed you.",
"2_female": null, "2_female": "Oh my, it seems my Grass Pokémon overwhelmed you.",
"3": "That battle was such a soothing experience.", "3": "That battle was such a soothing experience.",
"4": "Oh… Is that all?" "4": "Oh… Is that all?"
} }
@ -1106,7 +1116,7 @@
"1": "I, the leader of Team Rocket, will make you feel a world of pain!", "1": "I, the leader of Team Rocket, will make you feel a world of pain!",
"2": "My training here will be vital before I am to face my old associates again.", "2": "My training here will be vital before I am to face my old associates again.",
"3": "I do not think you are prepared for the level of failure you are about to experience!", "3": "I do not think you are prepared for the level of failure you are about to experience!",
"3_female": null "3_female": "I do not think you are prepared for the level of failure you are about to experience!"
}, },
"victory": { "victory": {
"1": "WHAT! Me, lose?! There is nothing I wish to say to you!", "1": "WHAT! Me, lose?! There is nothing I wish to say to you!",
@ -1139,7 +1149,7 @@
"brawly": { "brawly": {
"encounter": { "encounter": {
"1": "Oh man, a challenger!\nLet's see what you can do!", "1": "Oh man, a challenger!\nLet's see what you can do!",
"1_female": null, "1_female": "Oh man, a challenger!\nLet's see what you can do!",
"2": "You seem like a big splash.\nLet's battle!", "2": "You seem like a big splash.\nLet's battle!",
"3": "Time to create a storm!\nLet's go!" "3": "Time to create a storm!\nLet's go!"
}, },
@ -1167,7 +1177,7 @@
}, },
"defeat": { "defeat": {
"1": "Recharge your batteries and challenge me again sometime!\nWahahahaha!", "1": "Recharge your batteries and challenge me again sometime!\nWahahahaha!",
"1_female": null, "1_female": "Recharge your batteries and challenge me again sometime!\nWahahahaha!",
"2": "I hope you found our battle electrifying!\nWahahahaha!", "2": "I hope you found our battle electrifying!\nWahahahaha!",
"3": "Aren't you shocked I won?\nWahahahaha!" "3": "Aren't you shocked I won?\nWahahahaha!"
} }
@ -1214,7 +1224,7 @@
}, },
"victory": { "victory": {
"1": "You're the first Trainer I've seen with more grace than I.\nExcellently played.", "1": "You're the first Trainer I've seen with more grace than I.\nExcellently played.",
"1_female": null, "1_female": "You're the first Trainer I've seen with more grace than I.\nExcellently played.",
"2": "Oh, my Flying Pokémon have plummeted!\nVery well.", "2": "Oh, my Flying Pokémon have plummeted!\nVery well.",
"3": "Though I may have fallen, my Pokémon will continue to fly!" "3": "Though I may have fallen, my Pokémon will continue to fly!"
}, },
@ -1227,7 +1237,7 @@
"tate": { "tate": {
"encounter": { "encounter": {
"1": "Hehehe…\nWere you surprised to see me without my sister?", "1": "Hehehe…\nWere you surprised to see me without my sister?",
"1_female": null, "1_female": "Hehehe…\nWere you surprised to see me without my sister?",
"2": "I can see what you're thinking…\nYou want to battle!", "2": "I can see what you're thinking…\nYou want to battle!",
"3": "How can you defeat someone…\nWho knows your every move?" "3": "How can you defeat someone…\nWho knows your every move?"
}, },
@ -1245,7 +1255,7 @@
"liza": { "liza": {
"encounter": { "encounter": {
"1": "Fufufu…\nWere you surprised to see me without my brother?", "1": "Fufufu…\nWere you surprised to see me without my brother?",
"1_female": null, "1_female": "Fufufu…\nWere you surprised to see me without my brother?",
"2": "I can determine what you desire…\nYou want to battle, don't you?", "2": "I can determine what you desire…\nYou want to battle, don't you?",
"3": "How can you defeat someone…\nWho's one with their Pokémon?" "3": "How can you defeat someone…\nWho's one with their Pokémon?"
}, },
@ -1317,10 +1327,10 @@
"nessa": { "nessa": {
"encounter": { "encounter": {
"1": "No matter what kind of plan your refined mind may be plotting, my partner and I will be sure to sink it.", "1": "No matter what kind of plan your refined mind may be plotting, my partner and I will be sure to sink it.",
"1_female": null, "1_female": "No matter what kind of plan your refined mind may be plotting, my partner and I will be sure to sink it.",
"2": "I'm not here to chat. I'm here to win!", "2": "I'm not here to chat. I'm here to win!",
"3": "This is a little gift from my Pokémon… I hope you can take it!", "3": "This is a little gift from my Pokémon… I hope you can take it!",
"3_female": null "3_female": "This is a little gift from my Pokémon… I hope you can take it!"
}, },
"victory": { "victory": {
"1": "You and your Pokémon are just too much…", "1": "You and your Pokémon are just too much…",
@ -1341,7 +1351,7 @@
}, },
"victory": { "victory": {
"1": "You… You're pretty good, huh?", "1": "You… You're pretty good, huh?",
"1_female": null, "1_female": "You… You're pretty good, huh?",
"2": "If you find Gordie around, be sure to give him a right trashing, would you?", "2": "If you find Gordie around, be sure to give him a right trashing, would you?",
"3": "I think you took breaking the ice a little too literally…" "3": "I think you took breaking the ice a little too literally…"
}, },
@ -1355,12 +1365,12 @@
"encounter": { "encounter": {
"1": "You look strong! Shoots! Let's start!", "1": "You look strong! Shoots! Let's start!",
"2": "I'm strong like the ocean's wide. You're gonna get swept away, fo' sho'.", "2": "I'm strong like the ocean's wide. You're gonna get swept away, fo' sho'.",
"2_female": null, "2_female": "I'm strong like the ocean's wide. You're gonna get swept away, fo' sho'.",
"3": "Oh ho, so I'm facing you! That's off the wall." "3": "Oh ho, so I'm facing you! That's off the wall."
}, },
"victory": { "victory": {
"1": "You totally rocked that! You're raising some wicked Pokémon. You got this Trainer thing down!", "1": "You totally rocked that! You're raising some wicked Pokémon. You got this Trainer thing down!",
"1_female": null, "1_female": "You totally rocked that! You're raising some wicked Pokémon. You got this Trainer thing down!",
"2": "You don't just look strong, you're strong fo' reals! Eh, I was swept away, too!", "2": "You don't just look strong, you're strong fo' reals! Eh, I was swept away, too!",
"3": "You're strong as a gnarly wave!" "3": "You're strong as a gnarly wave!"
}, },
@ -1373,7 +1383,7 @@
"shauntal": { "shauntal": {
"encounter": { "encounter": {
"1": "Excuse me. You're a challenger, right?\nI'm the Elite Four's Ghost-type Pokémon user, Shauntal, and I shall be your opponent.", "1": "Excuse me. You're a challenger, right?\nI'm the Elite Four's Ghost-type Pokémon user, Shauntal, and I shall be your opponent.",
"1_female": null, "1_female": "Excuse me. You're a challenger, right?\nI'm the Elite Four's Ghost-type Pokémon user, Shauntal, and I shall be your opponent.",
"2": "I absolutely love writing about Trainers who come here and the Pokémon they train.\nCould I use you and your Pokémon as a subject?", "2": "I absolutely love writing about Trainers who come here and the Pokémon they train.\nCould I use you and your Pokémon as a subject?",
"3": "Every person who works with Pokémon has a story to tell.\nWhat story is about to be told?" "3": "Every person who works with Pokémon has a story to tell.\nWhat story is about to be told?"
}, },
@ -1391,7 +1401,7 @@
"marshal": { "marshal": {
"encounter": { "encounter": {
"1": "My mentor, Alder, sees your potential as a Trainer and is taking an interest in you.\nIt is my intention to test you--to take you to the limits of your strength. Kiai!", "1": "My mentor, Alder, sees your potential as a Trainer and is taking an interest in you.\nIt is my intention to test you--to take you to the limits of your strength. Kiai!",
"1_female": null, "1_female": "My mentor, Alder, sees your potential as a Trainer and is taking an interest in you.\nIt is my intention to test you--to take you to the limits of your strength. Kiai!",
"2": "Victory, decisive victory, is my intention! Challenger, here I come!", "2": "Victory, decisive victory, is my intention! Challenger, here I come!",
"3": "In myself, I seek to develop the strength of a fighter and shatter any weakness in myself!\nPrevailing with the force of my convictions!" "3": "In myself, I seek to develop the strength of a fighter and shatter any weakness in myself!\nPrevailing with the force of my convictions!"
}, },
@ -1411,7 +1421,7 @@
"1": "You remind me of an old friend. That makes me excited about this Pokémon battle!", "1": "You remind me of an old friend. That makes me excited about this Pokémon battle!",
"2": "Pokémon battles have no meaning if you don't think why you battle.\n$Or better said, it makes battling together with Pokémon meaningless.", "2": "Pokémon battles have no meaning if you don't think why you battle.\n$Or better said, it makes battling together with Pokémon meaningless.",
"3": "My name's Cheren! I'm a Gym Leader and a teacher! Pleasure to meet you.", "3": "My name's Cheren! I'm a Gym Leader and a teacher! Pleasure to meet you.",
"3_female": null "3_female": "My name's Cheren! I'm a Gym Leader and a teacher! Pleasure to meet you."
}, },
"victory": { "victory": {
"1": "Thank you! I saw what was missing in me.", "1": "Thank you! I saw what was missing in me.",
@ -1427,73 +1437,73 @@
"chili": { "chili": {
"encounter": { "encounter": {
"1": "Yeeeeooow! Time to play with FIRE!! I'm the strongest of us brothers!", "1": "Yeeeeooow! Time to play with FIRE!! I'm the strongest of us brothers!",
"1_female": null, "1_female": "Yeeeeooow! Time to play with FIRE!! I'm the strongest of us brothers!",
"2": "Ta-da! The Fire-type scorcher Chili--that's me--will be your opponent!", "2": "Ta-da! The Fire-type scorcher Chili--that's me--will be your opponent!",
"2_female": null, "2_female": "Ta-da! The Fire-type scorcher Chili--that's me--will be your opponent!",
"3": "I'm going to show you what me and my blazing Fire types can do!", "3": "I'm going to show you what me and my blazing Fire types can do!",
"3_female": null "3_female": "I'm going to show you what me and my blazing Fire types can do!"
}, },
"victory": { "victory": {
"1": "You got me. I am… burned… out…", "1": "You got me. I am… burned… out…",
"1_female": null, "1_female": "You got me. I am… burned… out…",
"2": "Whoa ho! You're on fire!", "2": "Whoa ho! You're on fire!",
"2_female": null, "2_female": "Whoa ho! You're on fire!",
"3": "Augh! You got me!" "3": "Augh! You got me!"
}, },
"defeat": { "defeat": {
"1": "I'm on fire! Play with me, and you'll get burned!", "1": "I'm on fire! Play with me, and you'll get burned!",
"1_female": null, "1_female": "I'm on fire! Play with me, and you'll get burned!",
"2": "When you play with fire, you get burned!", "2": "When you play with fire, you get burned!",
"3": "I mean, c'mon, your opponent was me! You didn't have a chance!", "3": "I mean, c'mon, your opponent was me! You didn't have a chance!",
"3_female": null "3_female": "I mean, c'mon, your opponent was me! You didn't have a chance!"
} }
}, },
"cilan": { "cilan": {
"encounter": { "encounter": {
"1": "Nothing personal... No hard feelings... Me and my Grass-type Pokémon will...\n$Um... We're gonna battle come what may.", "1": "Nothing personal... No hard feelings... Me and my Grass-type Pokémon will...\n$Um... We're gonna battle come what may.",
"1_female": null, "1_female": "Nothing personal... No hard feelings... Me and my Grass-type Pokémon will...\n$Um... We're gonna battle come what may.",
"2": "So, um, if you're OK with me, I'll, um, put everything I've got into being, er, you know, your opponent.", "2": "So, um, if you're OK with me, I'll, um, put everything I've got into being, er, you know, your opponent.",
"2_female": null, "2_female": "So, um, if you're OK with me, I'll, um, put everything I've got into being, er, you know, your opponent.",
"3": "OK… So, um, I'm Cilan, I like Grass-type Pokémon.", "3": "OK… So, um, I'm Cilan, I like Grass-type Pokémon.",
"3_female": null "3_female": "OK… So, um, I'm Cilan, I like Grass-type Pokémon."
}, },
"victory": { "victory": {
"1": "Er… Is it over now?", "1": "Er… Is it over now?",
"1_female": null, "1_female": "Er… Is it over now?",
"2": "…What a surprise. You are very strong, aren't you? \n$I guess my brothers wouldn't have been able to defeat you either…", "2": "…What a surprise. You are very strong, aren't you? \n$I guess my brothers wouldn't have been able to defeat you either…",
"2_female": null, "2_female": "…What a surprise. You are very strong, aren't you? \n$I guess my brothers wouldn't have been able to defeat you either…",
"3": "…Huh. Looks like my timing was, um, off?" "3": "…Huh. Looks like my timing was, um, off?"
}, },
"defeat": { "defeat": {
"1": "Huh? Did I win?", "1": "Huh? Did I win?",
"1_female": null, "1_female": "Huh? Did I win?",
"2": "I guess… \n$I suppose I won, because I've been competing with my brothers Chili and Cress, and we all were able to get tougher.", "2": "I guess… \n$I suppose I won, because I've been competing with my brothers Chili and Cress, and we all were able to get tougher.",
"2_female": null, "2_female": "I guess… \n$I suppose I won, because I've been competing with my brothers Chili and Cress, and we all were able to get tougher.",
"3": "It…it was quite a thrilling experience…", "3": "It…it was quite a thrilling experience…",
"3_female": null "3_female": "It…it was quite a thrilling experience…"
} }
}, },
"roark": { "roark": {
"encounter": { "encounter": {
"1": "I need to see your potential as a Trainer. And, I'll need to see the toughness of the Pokémon that battle with you!", "1": "I need to see your potential as a Trainer. And, I'll need to see the toughness of the Pokémon that battle with you!",
"1_female": null, "1_female": "I need to see your potential as a Trainer. And, I'll need to see the toughness of the Pokémon that battle with you!",
"2": "Here goes! These are my rocking Pokémon, my pride and joy!", "2": "Here goes! These are my rocking Pokémon, my pride and joy!",
"3": "Rock-type Pokémon are simply the best!", "3": "Rock-type Pokémon are simply the best!",
"4": "I need to see your potential as a Trainer. And, I'll need to see the toughness of the Pokémon that battle with you!", "4": "Every day, I toughened up my Pokémon by digging up Fossils nonstop.\n$Could I show you how tough I made them in a battle?",
"4_female": null "4_female": "Every day, I toughened up my Pokémon by digging up Fossils nonstop.\n$Could I show you how tough I made them in a battle?"
}, },
"victory": { "victory": {
"1": "W-what? That can't be! My buffed-up Pokémon!", "1": "W-what? That can't be! My buffed-up Pokémon!",
"2": "…We lost control there. Next time I'd like to challenge you to a Fossil-digging race underground.", "2": "…We lost control there. Next time I'd like to challenge you to a Fossil-digging race underground.",
"2_female": null, "2_female": "…We lost control there. Next time I'd like to challenge you to a Fossil-digging race underground.",
"3": "With skill like yours, it's natural for you to win.", "3": "With skill like yours, it's natural for you to win.",
"4": "Wh-what?! It can't be! Even that wasn't enough?", "4": "Wh-what?! It can't be! Even that wasn't enough?"
"5": "I blew it."
}, },
"defeat": { "defeat": {
"1": "See? I'm proud of my rocking battle style!", "1": "See? I'm proud of my rocking battle style!",
"2": "Thanks! The battle gave me confidence that I may be able to beat my dad!", "2": "Thanks! The battle gave me confidence that I may be able to beat my dad!",
"3": "I feel like I just smashed through a really stubborn boulder!" "3": "See? These are my rocking Pokémon, my pride and joy!",
"4": "I knew I would win!"
} }
}, },
"morty": { "morty": {
@ -1508,7 +1518,7 @@
"victory": { "victory": {
"1": "I'm not good enough yet…", "1": "I'm not good enough yet…",
"2": "I see… Your journey has taken you to far-away places and you have witnessed much more than I.\n$I envy you for that…", "2": "I see… Your journey has taken you to far-away places and you have witnessed much more than I.\n$I envy you for that…",
"2_female": null, "2_female": "I see… Your journey has taken you to far-away places and you have witnessed much more than I.\n$I envy you for that…",
"3": "How is this possible…", "3": "How is this possible…",
"4": "I don't think our potentials are so different.\n$But you seem to have something more than that… So be it.", "4": "I don't think our potentials are so different.\n$But you seem to have something more than that… So be it.",
"5": "Guess I need more training.", "5": "Guess I need more training.",
@ -1568,13 +1578,13 @@
}, },
"defeat": { "defeat": {
"1": "Heh heh! Don't mind me, just scooping up a W over here. I get it if you're upset, but don't go full Kieran on me, OK?", "1": "Heh heh! Don't mind me, just scooping up a W over here. I get it if you're upset, but don't go full Kieran on me, OK?",
"1_female": null "1_female": "Heh heh! Don't mind me, just scooping up a W over here. I get it if you're upset, but don't go full Kieran on me, OK?"
} }
}, },
"ramos": { "ramos": {
"encounter": { "encounter": {
"1": "Did yeh enjoy the garden playground I made with all these sturdy plants o' mine?\n$Their strength is a sign o' my strength as a gardener and a Gym Leader! Yeh sure yer up to facing all that?", "1": "Did yeh enjoy the garden playground I made with all these sturdy plants o' mine?\n$Their strength is a sign o' my strength as a gardener and a Gym Leader! Yeh sure yer up to facing all that?",
"1_female": null "1_female": "Did yeh enjoy the garden playground I made with all these sturdy plants o' mine?\n$Their strength is a sign o' my strength as a gardener and a Gym Leader! Yeh sure yer up to facing all that?"
}, },
"victory": { "victory": {
"1": "Yeh believe in yer Pokémon… And they believe in yeh, too… It was a fine battle, sprout." "1": "Yeh believe in yer Pokémon… And they believe in yeh, too… It was a fine battle, sprout."
@ -1605,7 +1615,7 @@
"victory": { "victory": {
"1": "I must say, I'm warmed up to you! I might even admire you a little.", "1": "I must say, I'm warmed up to you! I might even admire you a little.",
"2": "Wow! You're great! You've earned my respect! \n$I think your focus and will bowled us over totally. ", "2": "Wow! You're great! You've earned my respect! \n$I think your focus and will bowled us over totally. ",
"2_female": null "2_female": "Wow! You're great! You've earned my respect! \n$I think your focus and will bowled us over totally. "
}, },
"defeat": { "defeat": {
"1": "I sensed your will to win, but I don't lose!", "1": "I sensed your will to win, but I don't lose!",
@ -1618,7 +1628,7 @@
}, },
"victory": { "victory": {
"1": "Amazing! You're very good, aren't you?", "1": "Amazing! You're very good, aren't you?",
"1_female": null "1_female": "Amazing! You're very good, aren't you?"
}, },
"defeat": { "defeat": {
"1": "Yes! My Pokémon and I are perfectly good!" "1": "Yes! My Pokémon and I are perfectly good!"
@ -1660,7 +1670,7 @@
"clay": { "clay": {
"encounter": { "encounter": {
"1": "Harrumph! Kept me waitin', didn't ya, kid? All right, time to see what ya can do!", "1": "Harrumph! Kept me waitin', didn't ya, kid? All right, time to see what ya can do!",
"1_female": null "1_female": "Harrumph! Kept me waitin', didn't ya, kid? All right, time to see what ya can do!"
}, },
"victory": { "victory": {
"1": "Man oh man… It feels good to go all out and still be defeated!" "1": "Man oh man… It feels good to go all out and still be defeated!"
@ -1675,7 +1685,7 @@
}, },
"victory": { "victory": {
"1": "Vaultin' Veluza! Yer a lively one, aren't ya! A little TOO lively, if I do say so myself!", "1": "Vaultin' Veluza! Yer a lively one, aren't ya! A little TOO lively, if I do say so myself!",
"1_female": null "1_female": "Vaultin' Veluza! Yer a lively one, aren't ya! A little TOO lively, if I do say so myself!"
}, },
"defeat": { "defeat": {
"1": "You come back to see me again now, ya hear?" "1": "You come back to see me again now, ya hear?"
@ -1742,7 +1752,7 @@
}, },
"victory": { "victory": {
"1": "Bravo. I realize now your authenticity and magnificence as a Pokémon Trainer. \n$I find much joy in having met you and your Pokémon. You have proven yourself worthy.", "1": "Bravo. I realize now your authenticity and magnificence as a Pokémon Trainer. \n$I find much joy in having met you and your Pokémon. You have proven yourself worthy.",
"1_female": null "1_female": "Bravo. I realize now your authenticity and magnificence as a Pokémon Trainer. \n$I find much joy in having met you and your Pokémon. You have proven yourself worthy."
}, },
"defeat": { "defeat": {
"1": "A grand illusion!" "1": "A grand illusion!"
@ -1751,14 +1761,14 @@
"lorelei": { "lorelei": {
"encounter": { "encounter": {
"1": "No one can best me when it comes to icy Pokémon! Freezing moves are powerful!\n$Your Pokémon will be at my mercy when they are frozen solid! Hahaha! Are you ready?", "1": "No one can best me when it comes to icy Pokémon! Freezing moves are powerful!\n$Your Pokémon will be at my mercy when they are frozen solid! Hahaha! Are you ready?",
"1_female": null "1_female": "No one can best me when it comes to icy Pokémon! Freezing moves are powerful!\n$Your Pokémon will be at my mercy when they are frozen solid! Hahaha! Are you ready?"
}, },
"victory": { "victory": {
"1": "How dare you!" "1": "How dare you!"
}, },
"defeat": { "defeat": {
"1": "There's nothing you can do once you're frozen.", "1": "There's nothing you can do once you're frozen.",
"1_female": null "1_female": "There's nothing you can do once you're frozen."
} }
}, },
"will": { "will": {
@ -1775,11 +1785,11 @@
"malva": { "malva": {
"encounter": { "encounter": {
"1": "I feel like my heart might just burst into flames. \n$I'm burning up with my hatred for you, runt!", "1": "I feel like my heart might just burst into flames. \n$I'm burning up with my hatred for you, runt!",
"1_female": null "1_female": "I feel like my heart might just burst into flames. \n$I'm burning up with my hatred for you, runt!"
}, },
"victory": { "victory": {
"1": "What news… So a new challenger has defeated Malva!", "1": "What news… So a new challenger has defeated Malva!",
"1_female": null "1_female": "What news… So a new challenger has defeated Malva!"
}, },
"defeat": { "defeat": {
"1": "I am delighted! Yes, delighted that I could squash you beneath my heel." "1": "I am delighted! Yes, delighted that I could squash you beneath my heel."
@ -1802,7 +1812,7 @@
}, },
"victory": { "victory": {
"1": "I certainly found an interesting Trainer to face!", "1": "I certainly found an interesting Trainer to face!",
"1_female": null "1_female": "I certainly found an interesting Trainer to face!"
}, },
"defeat": { "defeat": {
"1": "Ahaha. What an interesting battle." "1": "Ahaha. What an interesting battle."
@ -1814,11 +1824,11 @@
}, },
"victory": { "victory": {
"1": "Not bad, kiddo.", "1": "Not bad, kiddo.",
"1_female": null "1_female": "Not bad, kiddo."
}, },
"defeat": { "defeat": {
"1": "Nahahaha! You really are something else, kiddo!", "1": "Nahahaha! You really are something else, kiddo!",
"1_female": null "1_female": "Nahahaha! You really are something else, kiddo!"
} }
}, },
"bruno": { "bruno": {
@ -1838,7 +1848,7 @@
}, },
"victory": { "victory": {
"1": "Whoa, amazing! You're an expert on Pokémon!\nMy research isn't complete yet. OK, you win.", "1": "Whoa, amazing! You're an expert on Pokémon!\nMy research isn't complete yet. OK, you win.",
"1_female": null "1_female": "Whoa, amazing! You're an expert on Pokémon!\nMy research isn't complete yet. OK, you win."
}, },
"defeat": { "defeat": {
"1": "Thanks! Thanks to our battle, I was also able to make progress in my research!" "1": "Thanks! Thanks to our battle, I was also able to make progress in my research!"
@ -1869,11 +1879,11 @@
"lenora": { "lenora": {
"encounter": { "encounter": {
"1": "Well then, challenger, I'm going to research how you battle with the Pokémon you've so lovingly raised!", "1": "Well then, challenger, I'm going to research how you battle with the Pokémon you've so lovingly raised!",
"1_female": null "1_female": "Well then, challenger, I'm going to research how you battle with the Pokémon you've so lovingly raised!"
}, },
"victory": { "victory": {
"1": "My theory about you was correct. You're more than just talented… You're motivated! I salute you!", "1": "My theory about you was correct. You're more than just talented… You're motivated! I salute you!",
"1_female": null "1_female": "My theory about you was correct. You're more than just talented… You're motivated! I salute you!"
}, },
"defeat": { "defeat": {
"1": "Ah ha ha! If you lose, make sure to analyze why, and use that knowledge in your next battle!" "1": "Ah ha ha! If you lose, make sure to analyze why, and use that knowledge in your next battle!"
@ -1899,7 +1909,7 @@
}, },
"defeat": { "defeat": {
"1": "Hey, c'mon! Get serious! You gotta put more out there!", "1": "Hey, c'mon! Get serious! You gotta put more out there!",
"1_female": null "1_female": "Hey, c'mon! Get serious! You gotta put more out there!"
} }
}, },
"olivia": { "olivia": {
@ -1938,7 +1948,7 @@
"flint": { "flint": {
"encounter": { "encounter": {
"1": "Hope you're warmed up, cause here comes the Big Bang!", "1": "Hope you're warmed up, cause here comes the Big Bang!",
"1_female": null "1_female": "Hope you're warmed up, cause here comes the Big Bang!"
}, },
"victory": { "victory": {
"1": "Incredible! Your moves are so hot, they make mine look lukewarm!" "1": "Incredible! Your moves are so hot, they make mine look lukewarm!"
@ -1961,7 +1971,7 @@
"caitlin": { "caitlin": {
"encounter": { "encounter": {
"1": "It's me who appeared when the flower opened up. You who have been waiting…\n$You look like a Pokémon Trainer with refined strength and deepened kindness. \n$What I look for in my opponent is superb strength… \n$Please unleash your power to the fullest!", "1": "It's me who appeared when the flower opened up. You who have been waiting…\n$You look like a Pokémon Trainer with refined strength and deepened kindness. \n$What I look for in my opponent is superb strength… \n$Please unleash your power to the fullest!",
"1_female": null "1_female": "It's me who appeared when the flower opened up. You who have been waiting…\n$You look like a Pokémon Trainer with refined strength and deepened kindness. \n$What I look for in my opponent is superb strength… \n$Please unleash your power to the fullest!"
}, },
"victory": { "victory": {
"1": "My Pokémon and I learned so much! I offer you my thanks." "1": "My Pokémon and I learned so much! I offer you my thanks."
@ -1984,15 +1994,15 @@
"wikstrom": { "wikstrom": {
"encounter": { "encounter": {
"1": "Well met, young challenger! Verily am I the famed blade of hardened steel, Duke Wikstrom! \n$Let the battle begin! En garde!", "1": "Well met, young challenger! Verily am I the famed blade of hardened steel, Duke Wikstrom! \n$Let the battle begin! En garde!",
"1_female": null "1_female": "Well met, young challenger! Verily am I the famed blade of hardened steel, Duke Wikstrom! \n$Let the battle begin! En garde!"
}, },
"victory": { "victory": {
"1": "Glorious! The trust that you share with your honorable Pokémon surpasses even mine!", "1": "Glorious! The trust that you share with your honorable Pokémon surpasses even mine!",
"1_female": null "1_female": "Glorious! The trust that you share with your honorable Pokémon surpasses even mine!"
}, },
"defeat": { "defeat": {
"1": "What manner of magic is this? My heart, it doth hammer ceaselessly in my breast! \n$Winning against such a worthy opponent doth give my soul wings--thus do I soar!", "1": "What manner of magic is this? My heart, it doth hammer ceaselessly in my breast! \n$Winning against such a worthy opponent doth give my soul wings--thus do I soar!",
"1_female": null "1_female": "What manner of magic is this? My heart, it doth hammer ceaselessly in my breast! \n$Winning against such a worthy opponent doth give my soul wings--thus do I soar!"
} }
}, },
"acerola": { "acerola": {
@ -2024,14 +2034,14 @@
}, },
"victory": { "victory": {
"1": "You got me. You are magnificent!", "1": "You got me. You are magnificent!",
"1_female": null, "1_female": "You got me. You are magnificent!",
"2": "I never expected another trainer to beat me… I'm surprised.", "2": "I never expected another trainer to beat me… I'm surprised.",
"2_female": null "2_female": "I never expected another trainer to beat me… I'm surprised."
}, },
"defeat": { "defeat": {
"1": "That was close. Want to try again?", "1": "That was close. Want to try again?",
"2": "It's not that you are weak. Don't let it bother you.", "2": "It's not that you are weak. Don't let it bother you.",
"2_female": null "2_female": "It's not that you are weak. Don't let it bother you."
} }
}, },
"karen": { "karen": {
@ -2057,7 +2067,7 @@
}, },
"victory": { "victory": {
"1": "The power of Grass has wilted… What an incredible Challenger!", "1": "The power of Grass has wilted… What an incredible Challenger!",
"1_female": null "1_female": "The power of Grass has wilted… What an incredible Challenger!"
}, },
"defeat": { "defeat": {
"1": "This'll really leave you in shock and awe." "1": "This'll really leave you in shock and awe."
@ -2077,7 +2087,7 @@
"drasna": { "drasna": {
"encounter": { "encounter": {
"1": "You must be a strong Trainer. Yes, quite strong indeed…\n$That's just wonderful news! Facing opponents like you and your team will make my Pokémon grow like weeds!", "1": "You must be a strong Trainer. Yes, quite strong indeed…\n$That's just wonderful news! Facing opponents like you and your team will make my Pokémon grow like weeds!",
"1_female": null "1_female": "You must be a strong Trainer. Yes, quite strong indeed…\n$That's just wonderful news! Facing opponents like you and your team will make my Pokémon grow like weeds!"
}, },
"victory": { "victory": {
"1": "Oh, dear me. That sure was a quick battle… I do hope you'll come back again sometime!" "1": "Oh, dear me. That sure was a quick battle… I do hope you'll come back again sometime!"
@ -2111,7 +2121,7 @@
"blue": { "blue": {
"encounter": { "encounter": {
"1": "You must be pretty good to get this far.", "1": "You must be pretty good to get this far.",
"1_female": null "1_female": "You must be pretty good to get this far."
}, },
"victory": { "victory": {
"1": "I've only lost to him and now to you… Him? Hee, hee…" "1": "I've only lost to him and now to you… Him? Hee, hee…"
@ -2159,7 +2169,7 @@
}, },
"victory": { "victory": {
"1": "This is the emergence of a new Champion.", "1": "This is the emergence of a new Champion.",
"1_female": null "1_female": "This is the emergence of a new Champion."
}, },
"defeat": { "defeat": {
"1": "I successfully defended my Championship." "1": "I successfully defended my Championship."
@ -2248,7 +2258,7 @@
}, },
"victory": { "victory": {
"1": "Waaah! Waaah! You're so mean!", "1": "Waaah! Waaah! You're so mean!",
"1_female": null "1_female": "Waaah! Waaah! You're so mean!"
}, },
"defeat": { "defeat": {
"1": "And that's that!" "1": "And that's that!"
@ -2257,7 +2267,7 @@
"chuck": { "chuck": {
"encounter": { "encounter": {
"1": "Hah! You want to challenge me? Are you brave or just ignorant?", "1": "Hah! You want to challenge me? Are you brave or just ignorant?",
"1_female": null "1_female": "Hah! You want to challenge me? Are you brave or just ignorant?"
}, },
"victory": { "victory": {
"1": "You're strong! Would you please make me your apprentice?" "1": "You're strong! Would you please make me your apprentice?"
@ -2269,7 +2279,7 @@
"katy": { "katy": {
"encounter": { "encounter": {
"1": "Don't let your guard down unless you would like to find yourself knocked off your feet!", "1": "Don't let your guard down unless you would like to find yourself knocked off your feet!",
"1_female": null "1_female": "Don't let your guard down unless you would like to find yourself knocked off your feet!"
}, },
"victory": { "victory": {
"1": "All of my sweet little Pokémon dropped like flies!" "1": "All of my sweet little Pokémon dropped like flies!"
@ -2303,7 +2313,7 @@
"maylene": { "maylene": {
"encounter": { "encounter": {
"1": "I've come to challenge you now, and I won't hold anything back. \n$Please prepare yourself for battle!", "1": "I've come to challenge you now, and I won't hold anything back. \n$Please prepare yourself for battle!",
"1_female": null "1_female": "I've come to challenge you now, and I won't hold anything back. \n$Please prepare yourself for battle!"
}, },
"victory": { "victory": {
"1": "I admit defeat…" "1": "I admit defeat…"
@ -2326,7 +2336,7 @@
"byron": { "byron": {
"encounter": { "encounter": {
"1": "Trainer! You're young, just like my son, Roark. \n$With more young Trainers taking charge, the future of Pokémon is bright! \n$So, as a wall for young people, I'll take your challenge!", "1": "Trainer! You're young, just like my son, Roark. \n$With more young Trainers taking charge, the future of Pokémon is bright! \n$So, as a wall for young people, I'll take your challenge!",
"1_female": null "1_female": "Trainer! You're young, just like my son, Roark. \n$With more young Trainers taking charge, the future of Pokémon is bright! \n$So, as a wall for young people, I'll take your challenge!"
}, },
"victory": { "victory": {
"1": "Hmm! My sturdy Pokémon--defeated!" "1": "Hmm! My sturdy Pokémon--defeated!"
@ -2349,7 +2359,7 @@
"volkner": { "volkner": {
"encounter": { "encounter": {
"1": "Since you've come this far, you must be quite strong…\n$I hope you're the Trainer who'll make me remember how fun it is to battle!", "1": "Since you've come this far, you must be quite strong…\n$I hope you're the Trainer who'll make me remember how fun it is to battle!",
"1_female": null "1_female": "Since you've come this far, you must be quite strong…\n$I hope you're the Trainer who'll make me remember how fun it is to battle!"
}, },
"victory": { "victory": {
"1": "You've got me beat…\n$Your desire and the noble way your Pokémon battled for you… \n$I even felt thrilled during our match. That was a very good battle." "1": "You've got me beat…\n$Your desire and the noble way your Pokémon battled for you… \n$I even felt thrilled during our match. That was a very good battle."
@ -2452,7 +2462,7 @@
"valerie": { "valerie": {
"encounter": { "encounter": {
"1": "Oh, if it isn't a young Trainer… It is lovely to get to meet you like this. \n$Then I suppose you have earned yourself the right to a battle, as a reward for your efforts. \n$The elusive Fairy may appear frail as the breeze and delicate as a bloom, but it is strong.", "1": "Oh, if it isn't a young Trainer… It is lovely to get to meet you like this. \n$Then I suppose you have earned yourself the right to a battle, as a reward for your efforts. \n$The elusive Fairy may appear frail as the breeze and delicate as a bloom, but it is strong.",
"1_female": null "1_female": "Oh, if it isn't a young Trainer… It is lovely to get to meet you like this. \n$Then I suppose you have earned yourself the right to a battle, as a reward for your efforts. \n$The elusive Fairy may appear frail as the breeze and delicate as a bloom, but it is strong."
}, },
"victory": { "victory": {
"1": "I hope that you will find things worth smiling about tomorrow…" "1": "I hope that you will find things worth smiling about tomorrow…"
@ -2500,7 +2510,7 @@
}, },
"victory": { "victory": {
"1": "Your pink is still lacking, but you're an excellent Trainer with excellent Pokémon.", "1": "Your pink is still lacking, but you're an excellent Trainer with excellent Pokémon.",
"1_female": null "1_female": "Your pink is still lacking, but you're an excellent Trainer with excellent Pokémon."
}, },
"defeat": { "defeat": {
"1": "Too bad for you, I guess." "1": "Too bad for you, I guess."
@ -2509,7 +2519,7 @@
"bede": { "bede": {
"encounter": { "encounter": {
"1": "I suppose I should prove beyond doubt just how pathetic you are and how strong I am.", "1": "I suppose I should prove beyond doubt just how pathetic you are and how strong I am.",
"1_female": null "1_female": "I suppose I should prove beyond doubt just how pathetic you are and how strong I am."
}, },
"victory": { "victory": {
"1": "I see… Well, that's fine. I wasn't really trying all that hard anyway." "1": "I see… Well, that's fine. I wasn't really trying all that hard anyway."
@ -2554,7 +2564,7 @@
"brassius": { "brassius": {
"encounter": { "encounter": {
"1": "I assume you are ready? Let our collaborative work of art begin!", "1": "I assume you are ready? Let our collaborative work of art begin!",
"1_female": null "1_female": "I assume you are ready? Let our collaborative work of art begin!"
}, },
"victory": { "victory": {
"1": "Ahhh…vant-garde!" "1": "Ahhh…vant-garde!"
@ -2566,11 +2576,11 @@
"iono": { "iono": {
"encounter": { "encounter": {
"1": "How're ya feelin' about this battle?\n$...\n$Let's get this show on the road! How strong is our challenger? \n$I 'unno! Let's find out together!", "1": "How're ya feelin' about this battle?\n$...\n$Let's get this show on the road! How strong is our challenger? \n$I 'unno! Let's find out together!",
"1_female": null "1_female": "How're ya feelin' about this battle?\n$...\n$Let's get this show on the road! How strong is our challenger? \n$I 'unno! Let's find out together!"
}, },
"victory": { "victory": {
"1": "You're as flashy and bright as a 10,000,000-volt Thunderbolt, friendo!", "1": "You're as flashy and bright as a 10,000,000-volt Thunderbolt, friendo!",
"1_female": null "1_female": "You're as flashy and bright as a 10,000,000-volt Thunderbolt, friendo!"
}, },
"defeat": { "defeat": {
"1": "Your eyeballs are MINE!" "1": "Your eyeballs are MINE!"
@ -2593,7 +2603,7 @@
}, },
"victory": { "victory": {
"1": "You're cool, my friend—you move my SOUL!", "1": "You're cool, my friend—you move my SOUL!",
"1_female": null "1_female": "You're cool, my friend—you move my SOUL!"
}, },
"defeat": { "defeat": {
"1": "Later, baby!" "1": "Later, baby!"
@ -2627,9 +2637,9 @@
"nessa_elite": { "nessa_elite": {
"encounter": { "encounter": {
"1": "The tides are turning in my favor. Ready to get swept away?", "1": "The tides are turning in my favor. Ready to get swept away?",
"1_female": null, "1_female": "The tides are turning in my favor. Ready to get swept away?",
"2": "Let's make some waves with this battle! I hope you're prepared!", "2": "Let's make some waves with this battle! I hope you're prepared!",
"2_female": null "2_female": "Let's make some waves with this battle! I hope you're prepared!"
}, },
"victory": { "victory": {
"1": "You navigated those waters perfectly... Well done!", "1": "You navigated those waters perfectly... Well done!",
@ -2657,7 +2667,7 @@
"allister_elite": { "allister_elite": {
"encounter": { "encounter": {
"1": "Shadows fall... Are you ready to face your fears?", "1": "Shadows fall... Are you ready to face your fears?",
"1_female": null, "1_female": "Shadows fall... Are you ready to face your fears?",
"2": "Let's see if you can handle the darkness that I command." "2": "Let's see if you can handle the darkness that I command."
}, },
"victory": { "victory": {
@ -2681,7 +2691,7 @@
"defeat": { "defeat": {
"1": "Another storm weathered, another victory claimed! Well fought!", "1": "Another storm weathered, another victory claimed! Well fought!",
"2": "You got caught in my storm! Better luck next time!", "2": "You got caught in my storm! Better luck next time!",
"2_female": null "2_female": "You got caught in my storm! Better luck next time!"
} }
}, },
"alder": { "alder": {

View File

@ -24,6 +24,7 @@
"linkGoogle": "Link Google", "linkGoogle": "Link Google",
"unlinkGoogle": "Unlink Google", "unlinkGoogle": "Unlink Google",
"cancel": "Cancel", "cancel": "Cancel",
"donate": "Donate",
"losingProgressionWarning": "You will lose any progress since the beginning of the battle. Proceed?", "losingProgressionWarning": "You will lose any progress since the beginning of the battle. Proceed?",
"noEggs": "You are not hatching\nany eggs at the moment!" "noEggs": "You are not hatching\nany eggs at the moment!"
} }

View File

@ -49,8 +49,8 @@
"DoubleBattleChanceBoosterModifierType": { "DoubleBattleChanceBoosterModifierType": {
"description": "Doubles the chance of an encounter being a double battle for {{battleCount}} battles." "description": "Doubles the chance of an encounter being a double battle for {{battleCount}} battles."
}, },
"TempBattleStatBoosterModifierType": { "TempStatStageBoosterModifierType": {
"description": "Increases the {{tempBattleStatName}} of all party members by 1 stage for 5 battles." "description": "Increases the {{stat}} of all party members by 1 stage for 5 battles."
}, },
"AttackTypeBoosterModifierType": { "AttackTypeBoosterModifierType": {
"description": "Increases the power of a Pokémon's {{moveType}}-type moves by 20%." "description": "Increases the power of a Pokémon's {{moveType}}-type moves by 20%."
@ -61,8 +61,8 @@
"AllPokemonLevelIncrementModifierType": { "AllPokemonLevelIncrementModifierType": {
"description": "Increases all party members' level by {{levels}}." "description": "Increases all party members' level by {{levels}}."
}, },
"PokemonBaseStatBoosterModifierType": { "BaseStatBoosterModifierType": {
"description": "Increases the holder's base {{statName}} by 10%. The higher your IVs, the higher the stack limit." "description": "Increases the holder's base {{stat}} by 10%. The higher your IVs, the higher the stack limit."
}, },
"AllPokemonFullHpRestoreModifierType": { "AllPokemonFullHpRestoreModifierType": {
"description": "Restores 100% HP for all Pokémon." "description": "Restores 100% HP for all Pokémon."
@ -183,6 +183,7 @@
"SOOTHE_BELL": { "name": "Soothe Bell" }, "SOOTHE_BELL": { "name": "Soothe Bell" },
"SCOPE_LENS": { "name": "Scope Lens", "description": "It's a lens for scoping out weak points. It boosts the holder's critical-hit ratio."}, "SCOPE_LENS": { "name": "Scope Lens", "description": "It's a lens for scoping out weak points. It boosts the holder's critical-hit ratio."},
"DIRE_HIT": { "name": "Dire Hit", "extra": { "raises": "Critical Hit Ratio" } },
"LEEK": { "name": "Leek", "description": "This very long and stiff stalk of leek boosts the critical-hit ratio of Farfetch'd's moves."}, "LEEK": { "name": "Leek", "description": "This very long and stiff stalk of leek boosts the critical-hit ratio of Farfetch'd's moves."},
"EVIOLITE": { "name": "Eviolite", "description": "This mysterious evolutionary lump boosts the Defense and Sp. Def stats when held by a Pokémon that can still evolve." }, "EVIOLITE": { "name": "Eviolite", "description": "This mysterious evolutionary lump boosts the Defense and Sp. Def stats when held by a Pokémon that can still evolve." },
@ -250,28 +251,14 @@
"METAL_POWDER": { "name": "Metal Powder", "description": "Extremely fine yet hard, this odd powder boosts Ditto's Defense stat." }, "METAL_POWDER": { "name": "Metal Powder", "description": "Extremely fine yet hard, this odd powder boosts Ditto's Defense stat." },
"QUICK_POWDER": { "name": "Quick Powder", "description": "Extremely fine yet hard, this odd powder boosts Ditto's Speed stat." } "QUICK_POWDER": { "name": "Quick Powder", "description": "Extremely fine yet hard, this odd powder boosts Ditto's Speed stat." }
}, },
"TempBattleStatBoosterItem": { "TempStatStageBoosterItem": {
"x_attack": "X Attack", "x_attack": "X Attack",
"x_defense": "X Defense", "x_defense": "X Defense",
"x_sp_atk": "X Sp. Atk", "x_sp_atk": "X Sp. Atk",
"x_sp_def": "X Sp. Def", "x_sp_def": "X Sp. Def",
"x_speed": "X Speed", "x_speed": "X Speed",
"x_accuracy": "X Accuracy", "x_accuracy": "X Accuracy"
"dire_hit": "Dire Hit"
}, },
"TempBattleStatBoosterStatName": {
"ATK": "Attack",
"DEF": "Defense",
"SPATK": "Sp. Atk",
"SPDEF": "Sp. Def",
"SPD": "Speed",
"ACC": "Accuracy",
"CRIT": "Critical Hit Ratio",
"EVA": "Evasiveness",
"DEFAULT": "???"
},
"AttackTypeBoosterItem": { "AttackTypeBoosterItem": {
"silk_scarf": "Silk Scarf", "silk_scarf": "Silk Scarf",
"black_belt": "Black Belt", "black_belt": "Black Belt",
@ -450,6 +437,6 @@
"DRAGON_MEMORY": "Dragon Memory", "DRAGON_MEMORY": "Dragon Memory",
"DARK_MEMORY": "Dark Memory", "DARK_MEMORY": "Dark Memory",
"FAIRY_MEMORY": "Fairy Memory", "FAIRY_MEMORY": "Fairy Memory",
"BLANK_MEMORY": "Blank Memory" "NORMAL_MEMORY": "Normal Memory"
} }
} }

View File

@ -3,7 +3,7 @@
"turnHealApply": "{{pokemonNameWithAffix}} restored a little HP using\nits {{typeName}}!", "turnHealApply": "{{pokemonNameWithAffix}} restored a little HP using\nits {{typeName}}!",
"hitHealApply": "{{pokemonNameWithAffix}} restored a little HP using\nits {{typeName}}!", "hitHealApply": "{{pokemonNameWithAffix}} restored a little HP using\nits {{typeName}}!",
"pokemonInstantReviveApply": "{{pokemonNameWithAffix}} was revived\nby its {{typeName}}!", "pokemonInstantReviveApply": "{{pokemonNameWithAffix}} was revived\nby its {{typeName}}!",
"pokemonResetNegativeStatStageApply": "{{pokemonNameWithAffix}}'s lowered stats were restored\nby its {{typeName}}!", "resetNegativeStatStageApply": "{{pokemonNameWithAffix}}'s lowered stats were restored\nby its {{typeName}}!",
"moneyInterestApply": "You received interest of ₽{{moneyAmount}}\nfrom the {{typeName}}!", "moneyInterestApply": "You received interest of ₽{{moneyAmount}}\nfrom the {{typeName}}!",
"turnHeldItemTransferApply": "{{pokemonNameWithAffix}}'s {{itemName}} was absorbed\nby {{pokemonName}}'s {{typeName}}!", "turnHeldItemTransferApply": "{{pokemonNameWithAffix}}'s {{itemName}} was absorbed\nby {{pokemonName}}'s {{typeName}}!",
"contactHeldItemTransferApply": "{{pokemonNameWithAffix}}'s {{itemName}} was snatched\nby {{pokemonName}}'s {{typeName}}!", "contactHeldItemTransferApply": "{{pokemonNameWithAffix}}'s {{itemName}} was snatched\nby {{pokemonName}}'s {{typeName}}!",

View File

@ -3,6 +3,10 @@
"cutHpPowerUpMove": "{{pokemonName}} cut its own HP to power up its move!", "cutHpPowerUpMove": "{{pokemonName}} cut its own HP to power up its move!",
"absorbedElectricity": "{{pokemonName}} absorbed electricity!", "absorbedElectricity": "{{pokemonName}} absorbed electricity!",
"switchedStatChanges": "{{pokemonName}} switched stat changes with the target!", "switchedStatChanges": "{{pokemonName}} switched stat changes with the target!",
"switchedTwoStatChanges": "{{pokemonName}} switched all changes to its {{firstStat}}\nand {{secondStat}} with its target!",
"switchedStat": "{{pokemonName}} switched {{stat}} with its target!",
"sharedGuard": "{{pokemonName}} shared its guard with the target!",
"sharedPower": "{{pokemonName}} shared its power with the target!",
"goingAllOutForAttack": "{{pokemonName}} is going all out for this attack!", "goingAllOutForAttack": "{{pokemonName}} is going all out for this attack!",
"regainedHealth": "{{pokemonName}} regained\nhealth!", "regainedHealth": "{{pokemonName}} regained\nhealth!",
"keptGoingAndCrashed": "{{pokemonName}} kept going\nand crashed!", "keptGoingAndCrashed": "{{pokemonName}} kept going\nand crashed!",
@ -61,5 +65,6 @@
"suppressAbilities": "{{pokemonName}}'s ability\nwas suppressed!", "suppressAbilities": "{{pokemonName}}'s ability\nwas suppressed!",
"revivalBlessing": "{{pokemonName}} was revived!", "revivalBlessing": "{{pokemonName}} was revived!",
"swapArenaTags": "{{pokemonName}} swapped the battle effects affecting each side of the field!", "swapArenaTags": "{{pokemonName}} swapped the battle effects affecting each side of the field!",
"exposedMove": "{{pokemonName}} identified\n{{targetPokemonName}}!" "exposedMove": "{{pokemonName}} identified\n{{targetPokemonName}}!",
"safeguard": "{{targetName}} is protected by Safeguard!"
} }

Some files were not shown because too many files have changed in this diff Show More