Merge pull request #23 from PokeRogue-Projects/beta
Transfer Beta to Main
2
.github/old_workflows/eslint.yml
vendored
@ -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"
|
||||||
|
2
.github/old_workflows/github-pages.yml
vendored
@ -8,6 +8,8 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- beta
|
- beta
|
||||||
|
merge_group:
|
||||||
|
types: [checks_requested]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
pages:
|
pages:
|
||||||
|
80
.github/old_workflows/tests.yml
vendored
@ -11,10 +11,12 @@ 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-misc-tests: # Define a job named "run-tests"
|
||||||
name: Run tests # Human-readable name for the job
|
name: Run misc tests # Human-readable name for the job
|
||||||
runs-on: ubuntu-latest # Specify the latest Ubuntu runner for the job
|
runs-on: ubuntu-latest # Specify the latest Ubuntu runner for the job
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@ -29,5 +31,75 @@ jobs:
|
|||||||
- name: Install Node.js dependencies # Step to install Node.js dependencies
|
- name: Install Node.js dependencies # Step to install Node.js dependencies
|
||||||
run: npm ci # Use 'npm ci' to install dependencies
|
run: npm ci # Use 'npm ci' to install dependencies
|
||||||
|
|
||||||
- name: tests # Step to run tests
|
- name: pre-test # pre-test to check overrides
|
||||||
run: npm run test:silent
|
run: npx vitest run --project pre
|
||||||
|
- name: test misc
|
||||||
|
run: npx vitest --project misc
|
||||||
|
|
||||||
|
run-abilities-tests:
|
||||||
|
name: Run abilities tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check out Git repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Set up Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
- name: Install Node.js dependencies
|
||||||
|
run: npm ci
|
||||||
|
- name: pre-test
|
||||||
|
run: npx vitest run --project pre
|
||||||
|
- name: test abilities
|
||||||
|
run: npx vitest --project abilities
|
||||||
|
|
||||||
|
run-items-tests:
|
||||||
|
name: Run items tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check out Git repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Set up Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
- name: Install Node.js dependencies
|
||||||
|
run: npm ci
|
||||||
|
- name: pre-test
|
||||||
|
run: npx vitest run --project pre
|
||||||
|
- name: test items
|
||||||
|
run: npx vitest --project items
|
||||||
|
|
||||||
|
run-moves-tests:
|
||||||
|
name: Run moves tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check out Git repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Set up Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
- name: Install Node.js dependencies
|
||||||
|
run: npm ci
|
||||||
|
- name: pre-test
|
||||||
|
run: npx vitest run --project pre
|
||||||
|
- name: test moves
|
||||||
|
run: npx vitest --project moves
|
||||||
|
|
||||||
|
run-battle-tests:
|
||||||
|
name: Run battle tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check out Git repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Set up Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
- name: Install Node.js dependencies
|
||||||
|
run: npm ci
|
||||||
|
- name: pre-test
|
||||||
|
run: npx vitest run --project pre
|
||||||
|
- name: test battle
|
||||||
|
run: npx vitest --project battle
|
@ -4,7 +4,8 @@ import { fileURLToPath } from 'url';
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This script creates a test boilerplate file for a move or ability.
|
* 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} type - The type of test to create. Either "move", "ability",
|
||||||
|
* or "item".
|
||||||
* @param {string} fileName - The name of the file to create.
|
* @param {string} fileName - The name of the file to create.
|
||||||
* @example npm run create-test move tackle
|
* @example npm run create-test move tackle
|
||||||
*/
|
*/
|
||||||
@ -19,7 +20,7 @@ const type = args[0]; // "move" or "ability"
|
|||||||
let fileName = args[1]; // The file name
|
let fileName = args[1]; // The file name
|
||||||
|
|
||||||
if (!type || !fileName) {
|
if (!type || !fileName) {
|
||||||
console.error('Please provide both a type ("move" or "ability") and a file name.');
|
console.error('Please provide both a type ("move", "ability", or "item") and a file name.');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,8 +41,11 @@ if (type === 'move') {
|
|||||||
} else if (type === 'ability') {
|
} else if (type === 'ability') {
|
||||||
dir = path.join(__dirname, 'src', 'test', 'abilities');
|
dir = path.join(__dirname, 'src', 'test', 'abilities');
|
||||||
description = `Abilities - ${formattedName}`;
|
description = `Abilities - ${formattedName}`;
|
||||||
|
} else if (type === "item") {
|
||||||
|
dir = path.join(__dirname, 'src', 'test', 'items');
|
||||||
|
description = `Items - ${formattedName}`;
|
||||||
} else {
|
} else {
|
||||||
console.error('Invalid type. Please use "move" or "ability".');
|
console.error('Invalid type. Please use "move", "ability", or "item".');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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$
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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 () {
|
||||||
|
11
lefthook.yml
@ -2,6 +2,15 @@ pre-commit:
|
|||||||
parallel: true
|
parallel: true
|
||||||
commands:
|
commands:
|
||||||
eslint:
|
eslint:
|
||||||
glob: '*.{js,jsx,ts,tsx}'
|
glob: "*.{js,jsx,ts,tsx}"
|
||||||
run: npx eslint --fix {staged_files}
|
run: npx eslint --fix {staged_files}
|
||||||
stage_fixed: true
|
stage_fixed: true
|
||||||
|
skip:
|
||||||
|
- merge
|
||||||
|
- rebase
|
||||||
|
|
||||||
|
pre-push:
|
||||||
|
commands:
|
||||||
|
eslint:
|
||||||
|
glob: "*.{js,ts,jsx,tsx}"
|
||||||
|
run: npx eslint --fix {push_files}
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 405 B After Width: | Height: | Size: 405 B |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 12 KiB |
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 30 KiB |
22
public/images/pokemon/variant/465.json
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"1": {
|
||||||
|
"529cc5": "8153c7",
|
||||||
|
"d65a94": "5ad662",
|
||||||
|
"3a73ad": "6b3aad",
|
||||||
|
"bd216b": "21bd69",
|
||||||
|
"5a193a": "195a2a",
|
||||||
|
"193a63": "391963",
|
||||||
|
"295a84": "472984"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"529cc5": "ffedb6",
|
||||||
|
"d65a94": "e67d2f",
|
||||||
|
"3a73ad": "ebc582",
|
||||||
|
"bd216b": "b35131",
|
||||||
|
"31313a": "3d1519",
|
||||||
|
"5a193a": "752e2e",
|
||||||
|
"193a63": "705040",
|
||||||
|
"295a84": "ad875a",
|
||||||
|
"4a4a52": "57211a"
|
||||||
|
}
|
||||||
|
}
|
Before Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 43 KiB |
@ -1017,7 +1017,7 @@
|
|||||||
"279": [
|
"279": [
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
2
|
1
|
||||||
],
|
],
|
||||||
"280": [
|
"280": [
|
||||||
0,
|
0,
|
||||||
@ -1691,8 +1691,8 @@
|
|||||||
],
|
],
|
||||||
"465": [
|
"465": [
|
||||||
0,
|
0,
|
||||||
2,
|
1,
|
||||||
2
|
1
|
||||||
],
|
],
|
||||||
"466": [
|
"466": [
|
||||||
1,
|
1,
|
||||||
@ -3980,6 +3980,11 @@
|
|||||||
1,
|
1,
|
||||||
1
|
1
|
||||||
],
|
],
|
||||||
|
"465": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
"592": [
|
"592": [
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
@ -5690,7 +5695,7 @@
|
|||||||
"465": [
|
"465": [
|
||||||
0,
|
0,
|
||||||
1,
|
1,
|
||||||
2
|
1
|
||||||
],
|
],
|
||||||
"466": [
|
"466": [
|
||||||
2,
|
2,
|
||||||
@ -8008,6 +8013,11 @@
|
|||||||
1,
|
1,
|
||||||
1
|
1
|
||||||
],
|
],
|
||||||
|
"465": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
"592": [
|
"592": [
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
|
@ -8,5 +8,14 @@
|
|||||||
"bd216b": "21bd69",
|
"bd216b": "21bd69",
|
||||||
"31313a": "31313a",
|
"31313a": "31313a",
|
||||||
"d65a94": "5ad662"
|
"d65a94": "5ad662"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"5a193a": "752e2e",
|
||||||
|
"31313a": "3d1519",
|
||||||
|
"d65a94": "e67d2f",
|
||||||
|
"3a73ad": "ebc582",
|
||||||
|
"295a84": "ad875a",
|
||||||
|
"bd216b": "b35131",
|
||||||
|
"193a63": "705040"
|
||||||
}
|
}
|
||||||
}
|
}
|
Before Width: | Height: | Size: 34 KiB |
21
public/images/pokemon/variant/back/female/465.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"1": {
|
||||||
|
"193a63": "391963",
|
||||||
|
"295a84": "472984",
|
||||||
|
"3a73ad": "6b3aad",
|
||||||
|
"000000": "000000",
|
||||||
|
"5a193a": "195a2a",
|
||||||
|
"bd216b": "21bd69",
|
||||||
|
"31313a": "31313a",
|
||||||
|
"d65a94": "5ad662"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"5a193a": "752e2e",
|
||||||
|
"31313a": "3d1519",
|
||||||
|
"d65a94": "e67d2f",
|
||||||
|
"3a73ad": "ebc582",
|
||||||
|
"295a84": "ad875a",
|
||||||
|
"bd216b": "b35131",
|
||||||
|
"193a63": "705040"
|
||||||
|
}
|
||||||
|
}
|
22
public/images/pokemon/variant/female/465.json
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"1": {
|
||||||
|
"529cc5": "8153c7",
|
||||||
|
"d65a94": "5ad662",
|
||||||
|
"3a73ad": "6b3aad",
|
||||||
|
"bd216b": "21bd69",
|
||||||
|
"5a193a": "195a2a",
|
||||||
|
"193a63": "391963",
|
||||||
|
"295a84": "472984"
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"529cc5": "ffedb6",
|
||||||
|
"d65a94": "e67d2f",
|
||||||
|
"3a73ad": "ebc582",
|
||||||
|
"bd216b": "b35131",
|
||||||
|
"31313a": "3d1519",
|
||||||
|
"5a193a": "752e2e",
|
||||||
|
"193a63": "705040",
|
||||||
|
"295a84": "ad875a",
|
||||||
|
"4a4a52": "57211a"
|
||||||
|
}
|
||||||
|
}
|
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 6.9 KiB |
BIN
public/images/ui/egg_summary_bg.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
public/images/ui/egg_summary_bg_blank.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
public/images/ui/icon_egg_move.png
Normal file
After Width: | Height: | Size: 179 B |
BIN
public/images/ui/icon_lock.png
Normal file
After Width: | Height: | Size: 172 B |
BIN
public/images/ui/icon_stop.png
Normal file
After Width: | Height: | Size: 205 B |
BIN
public/images/ui/legacy/egg_summary_bg.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
public/images/ui/legacy/icon_egg_move.png
Normal file
After Width: | Height: | Size: 179 B |
BIN
public/images/ui/legacy/icon_lock.png
Normal file
After Width: | Height: | Size: 172 B |
BIN
public/images/ui/legacy/icon_stop.png
Normal file
After Width: | Height: | Size: 205 B |
BIN
public/images/ui/legacy/settings_icon.png
Normal file
After Width: | Height: | Size: 261 B |
BIN
public/images/ui/settings_icon.png
Normal file
After Width: | Height: | Size: 261 B |
@ -1,3 +1,3 @@
|
|||||||
import BattleScene from "#app/battle-scene.js";
|
import BattleScene from "#app/battle-scene";
|
||||||
|
|
||||||
export type ConditionFn = (scene: BattleScene, args?: any[]) => boolean;
|
export type ConditionFn = (scene: BattleScene, args?: any[]) => boolean;
|
||||||
|
2
src/@types/i18next.d.ts
vendored
@ -1,4 +1,4 @@
|
|||||||
import { type enConfig } from "#app/locales/en/config.js";
|
import { type enConfig } from "#app/locales/en/config";
|
||||||
import { TOptions } from "i18next";
|
import { TOptions } from "i18next";
|
||||||
|
|
||||||
//TODO: this needs to be type properly in the future
|
//TODO: this needs to be type properly in the future
|
||||||
|
@ -63,7 +63,7 @@ import { Moves } from "#enums/moves";
|
|||||||
import { PlayerGender } from "#enums/player-gender";
|
import { PlayerGender } from "#enums/player-gender";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import { UiTheme } from "#enums/ui-theme";
|
import { UiTheme } from "#enums/ui-theme";
|
||||||
import { TimedEventManager } from "#app/timed-event-manager.js";
|
import { TimedEventManager } from "#app/timed-event-manager";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { TrainerType } from "#enums/trainer-type";
|
import { TrainerType } from "#enums/trainer-type";
|
||||||
import { battleSpecDialogue } from "./data/dialogue";
|
import { battleSpecDialogue } from "./data/dialogue";
|
||||||
@ -132,7 +132,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 showTeams: boolean = true;
|
public showTeams: boolean = true;
|
||||||
public showTeamSprites: boolean = false;
|
public showTeamSprites: boolean = false;
|
||||||
@ -865,12 +865,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);
|
||||||
@ -878,7 +879,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
overrideModifiers(this, false);
|
overrideModifiers(this, false);
|
||||||
overrideHeldItems(this, pokemon, false);
|
overrideHeldItems(this, pokemon, false);
|
||||||
if (boss && !dataSource) {
|
if (boss && !dataSource) {
|
||||||
const secondaryIvs = Utils.getIvsFromId(Utils.randSeedInt(4294967295));
|
const secondaryIvs = Utils.getIvsFromId(Utils.randSeedInt(4294967296));
|
||||||
|
|
||||||
for (let s = 0; s < pokemon.ivs.length; s++) {
|
for (let s = 0; s < pokemon.ivs.length; s++) {
|
||||||
pokemon.ivs[s] = Math.round(Phaser.Math.Linear(Math.min(pokemon.ivs[s], secondaryIvs[s]), Math.max(pokemon.ivs[s], secondaryIvs[s]), 0.75));
|
pokemon.ivs[s] = Math.round(Phaser.Math.Linear(Math.min(pokemon.ivs[s], secondaryIvs[s]), Math.max(pokemon.ivs[s], secondaryIvs[s]), 0.75));
|
||||||
@ -976,15 +977,15 @@ export default class BattleScene extends SceneBase {
|
|||||||
|
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
addPkIcon(pokemon: PokemonSpecies, form: integer = 0, x: number, y: number, originX: number = 0.5, originY: number = 0.5, ignoreOverride: boolean = false): Phaser.GameObjects.Container {
|
addPkIcon(pokemon: PokemonSpecies, form: integer = 0, x: number, y: number, originX: number = 0.5, originY: number = 0.5, ignoreOverride: boolean = false, shiny?: boolean, variant?: integer): Phaser.GameObjects.Container {
|
||||||
const container = this.add.container(x, y);
|
const container = this.add.container(x, y);
|
||||||
container.setName(`${pokemon.name}-icon`);
|
container.setName(`${pokemon.name}-icon`);
|
||||||
|
|
||||||
const icon = this.add.sprite(0, 0, pokemon.getIconAtlasKey(form));
|
const icon = this.add.sprite(0, 0, pokemon.getIconAtlasKey(form, shiny, variant));
|
||||||
icon.setName(`sprite-${pokemon.name}-icon`);
|
icon.setName(`sprite-${pokemon.name}-icon`);
|
||||||
icon.setFrame(pokemon.getIconId(true));
|
icon.setFrame(pokemon.getIconId(true, form, shiny, variant));
|
||||||
// Temporary fix to show pokemon's default icon if variant icon doesn't exist
|
// Temporary fix to show pokemon's default icon if variant icon doesn't exist
|
||||||
if (icon.frame.name !== pokemon.getIconId(true)) {
|
if (icon.frame.name !== pokemon.getIconId(true, form, shiny, variant)) {
|
||||||
console.log(`${pokemon.name}'s variant icon does not exist. Replacing with default.`);
|
console.log(`${pokemon.name}'s variant icon does not exist. Replacing with default.`);
|
||||||
icon.setTexture(pokemon.getIconAtlasKey(0));
|
icon.setTexture(pokemon.getIconAtlasKey(0));
|
||||||
icon.setFrame(pokemon.getIconId(true));
|
icon.setFrame(pokemon.getIconId(true));
|
||||||
@ -1011,6 +1012,16 @@ export default class BattleScene extends SceneBase {
|
|||||||
this.offsetGym = this.gameMode.isClassic && this.getGeneratedOffsetGym();
|
this.offsetGym = this.gameMode.isClassic && this.getGeneratedOffsetGym();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a random number using the current battle's seed
|
||||||
|
*
|
||||||
|
* This calls {@linkcode Battle.randSeedInt}(`scene`, {@linkcode range}, {@linkcode min}) in `src/battle.ts`
|
||||||
|
* which calls {@linkcode Utils.randSeedInt randSeedInt}({@linkcode range}, {@linkcode min}) in `src/utils.ts`
|
||||||
|
*
|
||||||
|
* @param range How large of a range of random numbers to choose from. If {@linkcode range} <= 1, returns {@linkcode min}
|
||||||
|
* @param min The minimum integer to pick, default `0`
|
||||||
|
* @returns A random integer between {@linkcode min} and ({@linkcode min} + {@linkcode range} - 1)
|
||||||
|
*/
|
||||||
randBattleSeedInt(range: integer, min: integer = 0, reason?: string): integer {
|
randBattleSeedInt(range: integer, min: integer = 0, reason?: string): integer {
|
||||||
return this.currentBattle?.randSeedInt(this, range, min, reason);
|
return this.currentBattle?.randSeedInt(this, range, min, reason);
|
||||||
}
|
}
|
||||||
@ -1024,6 +1035,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;
|
||||||
|
|
||||||
@ -1231,7 +1243,8 @@ export default class BattleScene extends SceneBase {
|
|||||||
doubleTrainer = false;
|
doubleTrainer = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
newTrainer = trainerData !== undefined ? trainerData.toTrainer(this) : new Trainer(this, trainerType, doubleTrainer ? TrainerVariant.DOUBLE : Utils.randSeedInt(2) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT);
|
const variant = doubleTrainer ? TrainerVariant.DOUBLE : (Utils.randSeedInt(2) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT);
|
||||||
|
newTrainer = trainerData !== undefined ? trainerData.toTrainer(this) : new Trainer(this, trainerType, variant);
|
||||||
this.field.add(newTrainer);
|
this.field.add(newTrainer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1452,6 +1465,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;
|
||||||
}
|
}
|
||||||
@ -2770,7 +2790,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
if (mods.length < 1) {
|
if (mods.length < 1) {
|
||||||
return mods;
|
return mods;
|
||||||
}
|
}
|
||||||
const rand = Math.floor(Utils.randSeedInt(mods.length));
|
const rand = Utils.randSeedInt(mods.length);
|
||||||
return [mods[rand], ...shuffleModifiers(mods.filter((_, i) => i !== rand))];
|
return [mods[rand], ...shuffleModifiers(mods.filter((_, i) => i !== rand))];
|
||||||
};
|
};
|
||||||
modifiers = shuffleModifiers(modifiers);
|
modifiers = shuffleModifiers(modifiers);
|
||||||
@ -2892,6 +2912,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
|
||||||
|
@ -6,7 +6,7 @@ import Trainer, { TrainerVariant } from "./field/trainer";
|
|||||||
import { GameMode } from "./game-mode";
|
import { GameMode } from "./game-mode";
|
||||||
import { MoneyMultiplierModifier, PokemonHeldItemModifier } from "./modifier/modifier";
|
import { MoneyMultiplierModifier, PokemonHeldItemModifier } from "./modifier/modifier";
|
||||||
import { PokeballType } from "./data/pokeball";
|
import { PokeballType } from "./data/pokeball";
|
||||||
import {trainerConfigs} from "#app/data/trainer-config";
|
import { trainerConfigs } from "#app/data/trainer-config";
|
||||||
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";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
@ -31,7 +31,7 @@ export enum BattlerIndex {
|
|||||||
|
|
||||||
export interface TurnCommand {
|
export interface TurnCommand {
|
||||||
command: Command;
|
command: Command;
|
||||||
cursor?: integer;
|
cursor?: number;
|
||||||
move?: QueuedMove;
|
move?: QueuedMove;
|
||||||
targets?: BattlerIndex[];
|
targets?: BattlerIndex[];
|
||||||
skip?: boolean;
|
skip?: boolean;
|
||||||
@ -39,62 +39,49 @@ export interface TurnCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface TurnCommands {
|
interface TurnCommands {
|
||||||
[key: integer]: TurnCommand | null
|
[key: number]: TurnCommand | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Battle {
|
export default class Battle {
|
||||||
protected gameMode: GameMode;
|
protected gameMode: GameMode;
|
||||||
public waveIndex: integer;
|
public waveIndex: number;
|
||||||
public battleType: BattleType;
|
public battleType: BattleType;
|
||||||
public battleSpec: BattleSpec;
|
public battleSpec: BattleSpec;
|
||||||
public trainer: Trainer | undefined;
|
public trainer: Trainer | null;
|
||||||
public enemyLevels: integer[] | undefined;
|
public enemyLevels: number[] | undefined;
|
||||||
public enemyParty: EnemyPokemon[];
|
public enemyParty: EnemyPokemon[] = [];
|
||||||
public seenEnemyPartyMemberIds: Set<integer>;
|
public seenEnemyPartyMemberIds: Set<number> = new Set<number>();
|
||||||
public double: boolean;
|
public double: boolean;
|
||||||
public started: boolean;
|
public started: boolean = false;
|
||||||
public enemySwitchCounter: integer;
|
public enemySwitchCounter: number = 0;
|
||||||
public turn: integer;
|
public turn: number = 0;
|
||||||
public turnCommands: TurnCommands;
|
public turnCommands: TurnCommands;
|
||||||
public playerParticipantIds: Set<integer>;
|
public playerParticipantIds: Set<number> = new Set<number>();
|
||||||
public battleScore: integer;
|
public battleScore: number = 0;
|
||||||
public postBattleLoot: PokemonHeldItemModifier[];
|
public postBattleLoot: PokemonHeldItemModifier[] = [];
|
||||||
public escapeAttempts: integer;
|
public escapeAttempts: number = 0;
|
||||||
public lastMove: Moves;
|
public lastMove: Moves;
|
||||||
public battleSeed: string;
|
public battleSeed: string = Utils.randomString(16, true);
|
||||||
private battleSeedState: string | null;
|
private battleSeedState: string | null = null;
|
||||||
public moneyScattered: number;
|
public moneyScattered: number = 0;
|
||||||
public lastUsedPokeball: PokeballType | null;
|
public lastUsedPokeball: PokeballType | null = null;
|
||||||
public playerFaints: number; // The amount of times pokemon on the players side have fainted
|
/** The number of times a Pokemon on the player's side has fainted this battle */
|
||||||
public enemyFaints: number; // The amount of times pokemon on the enemies side have fainted
|
public playerFaints: number = 0;
|
||||||
|
/** The number of times a Pokemon on the enemy's side has fainted this battle */
|
||||||
|
public enemyFaints: number = 0;
|
||||||
|
|
||||||
private rngCounter: integer = 0;
|
private rngCounter: number = 0;
|
||||||
|
|
||||||
constructor(gameMode: GameMode, waveIndex: integer, battleType: BattleType, trainer?: Trainer, double?: boolean) {
|
constructor(gameMode: GameMode, waveIndex: number, battleType: BattleType, trainer?: Trainer, double?: boolean) {
|
||||||
this.gameMode = gameMode;
|
this.gameMode = gameMode;
|
||||||
this.waveIndex = waveIndex;
|
this.waveIndex = waveIndex;
|
||||||
this.battleType = battleType;
|
this.battleType = battleType;
|
||||||
this.trainer = trainer ?? undefined;
|
this.trainer = trainer ?? null;
|
||||||
this.initBattleSpec();
|
this.initBattleSpec();
|
||||||
this.enemyLevels = battleType !== BattleType.TRAINER
|
this.enemyLevels = battleType !== BattleType.TRAINER
|
||||||
? new Array(double ? 2 : 1).fill(null).map(() => this.getLevelForWave())
|
? new Array(double ? 2 : 1).fill(null).map(() => this.getLevelForWave())
|
||||||
: trainer?.getPartyLevels(this.waveIndex);
|
: trainer?.getPartyLevels(this.waveIndex);
|
||||||
this.enemyParty = [];
|
this.double = double ?? false;
|
||||||
this.seenEnemyPartyMemberIds = new Set<integer>();
|
|
||||||
this.double = !!double;
|
|
||||||
this.enemySwitchCounter = 0;
|
|
||||||
this.turn = 0;
|
|
||||||
this.playerParticipantIds = new Set<integer>();
|
|
||||||
this.battleScore = 0;
|
|
||||||
this.postBattleLoot = [];
|
|
||||||
this.escapeAttempts = 0;
|
|
||||||
this.started = false;
|
|
||||||
this.battleSeed = Utils.randomString(16, true);
|
|
||||||
this.battleSeedState = null;
|
|
||||||
this.moneyScattered = 0;
|
|
||||||
this.lastUsedPokeball = null;
|
|
||||||
this.playerFaints = 0;
|
|
||||||
this.enemyFaints = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private initBattleSpec(): void {
|
private initBattleSpec(): void {
|
||||||
@ -105,7 +92,7 @@ export default class Battle {
|
|||||||
this.battleSpec = spec;
|
this.battleSpec = spec;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getLevelForWave(): integer {
|
private getLevelForWave(): number {
|
||||||
const levelWaveIndex = this.gameMode.getWaveForDifficulty(this.waveIndex);
|
const levelWaveIndex = this.gameMode.getWaveForDifficulty(this.waveIndex);
|
||||||
const baseLevel = 1 + levelWaveIndex / 2 + Math.pow(levelWaveIndex / 25, 2);
|
const baseLevel = 1 + levelWaveIndex / 2 + Math.pow(levelWaveIndex / 25, 2);
|
||||||
const bossMultiplier = 1.2;
|
const bossMultiplier = 1.2;
|
||||||
@ -138,7 +125,7 @@ export default class Battle {
|
|||||||
return rand / value;
|
return rand / value;
|
||||||
}
|
}
|
||||||
|
|
||||||
getBattlerCount(): integer {
|
getBattlerCount(): number {
|
||||||
return this.double ? 2 : 1;
|
return this.double ? 2 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,7 +354,7 @@ export default class Battle {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
multiInt(scene: BattleScene, out: integer[], count: integer, range: integer, min: integer = 0, reason: string = "Unlabeled randSeedInt", offset: integer = 0) {
|
multiInt(scene: BattleScene, out: number[], count: number, range: number, min: number = 0, reason: string = "Unlabeled randSeedInt", offset: number = 0) {
|
||||||
if (range <= 1) {
|
if (range <= 1) {
|
||||||
return min;
|
return min;
|
||||||
}
|
}
|
||||||
@ -394,7 +381,13 @@ export default class Battle {
|
|||||||
scene.rngSeedOverride = tempSeedOverride;
|
scene.rngSeedOverride = tempSeedOverride;
|
||||||
}
|
}
|
||||||
|
|
||||||
randSeedInt(scene: BattleScene, range: integer, min: integer = 0, reason: string = "Unlabeled randSeedInt"): integer {
|
/**
|
||||||
|
* Generates a random number using the current battle's seed. Calls {@linkcode Utils.randSeedInt}
|
||||||
|
* @param range How large of a range of random numbers to choose from. If {@linkcode range} <= 1, returns {@linkcode min}
|
||||||
|
* @param min The minimum integer to pick, default `0`
|
||||||
|
* @returns A random integer between {@linkcode min} and ({@linkcode min} + {@linkcode range} - 1)
|
||||||
|
*/
|
||||||
|
randSeedInt(scene: BattleScene, range: number, min: number = 0, reason: string = "Unlabeled randSeedInt"): number {
|
||||||
if (range <= 1) {
|
if (range <= 1) {
|
||||||
return min;
|
return min;
|
||||||
}
|
}
|
||||||
@ -421,7 +414,7 @@ export default class Battle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class FixedBattle extends Battle {
|
export class FixedBattle extends Battle {
|
||||||
constructor(scene: BattleScene, waveIndex: integer, config: FixedBattleConfig) {
|
constructor(scene: BattleScene, waveIndex: number, config: FixedBattleConfig) {
|
||||||
super(scene.gameMode, waveIndex, config.battleType, config.battleType === BattleType.TRAINER ? config.getTrainer(scene) : undefined, config.double);
|
super(scene.gameMode, waveIndex, config.battleType, config.battleType === BattleType.TRAINER ? config.getTrainer(scene) : undefined, config.double);
|
||||||
if (config.getEnemyParty) {
|
if (config.getEnemyParty) {
|
||||||
this.enemyParty = config.getEnemyParty(scene);
|
this.enemyParty = config.getEnemyParty(scene);
|
||||||
@ -437,7 +430,7 @@ export class FixedBattleConfig {
|
|||||||
public double: boolean;
|
public double: boolean;
|
||||||
public getTrainer: GetTrainerFunc;
|
public getTrainer: GetTrainerFunc;
|
||||||
public getEnemyParty: GetEnemyPartyFunc;
|
public getEnemyParty: GetEnemyPartyFunc;
|
||||||
public seedOffsetWaveIndex: integer;
|
public seedOffsetWaveIndex: number;
|
||||||
|
|
||||||
setBattleType(battleType: BattleType): FixedBattleConfig {
|
setBattleType(battleType: BattleType): FixedBattleConfig {
|
||||||
this.battleType = battleType;
|
this.battleType = battleType;
|
||||||
@ -459,7 +452,7 @@ export class FixedBattleConfig {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
setSeedOffsetWave(seedOffsetWaveIndex: integer): FixedBattleConfig {
|
setSeedOffsetWave(seedOffsetWaveIndex: number): FixedBattleConfig {
|
||||||
this.seedOffsetWaveIndex = seedOffsetWaveIndex;
|
this.seedOffsetWaveIndex = seedOffsetWaveIndex;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -505,7 +498,7 @@ function getRandomTrainerFunc(trainerPool: (TrainerType | TrainerType[])[], rand
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface FixedBattleConfigs {
|
export interface FixedBattleConfigs {
|
||||||
[key: integer]: FixedBattleConfig
|
[key: number]: FixedBattleConfig
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Youngster/Lass on 5
|
* Youngster/Lass on 5
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {SettingGamepad} from "#app/system/settings/settings-gamepad.js";
|
import {SettingGamepad} from "#app/system/settings/settings-gamepad";
|
||||||
import {Button} from "#enums/buttons";
|
import {Button} from "#enums/buttons";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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,
|
||||||
@ -786,8 +786,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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -875,7 +875,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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 });
|
|
||||||
}
|
|
@ -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 {
|
||||||
@ -97,6 +98,127 @@ export interface TerrainBattlerTag {
|
|||||||
terrainTypes: TerrainType[];
|
terrainTypes: TerrainType[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for tags that restrict the usage of moves. This effect is generally referred to as "disabling" a move
|
||||||
|
* in-game. This is not to be confused with {@linkcode Moves.DISABLE}.
|
||||||
|
*
|
||||||
|
* Descendants can override {@linkcode isMoveRestricted} to restrict moves that
|
||||||
|
* match a condition. A restricted move gets cancelled before it is used. Players and enemies should not be allowed
|
||||||
|
* to select restricted moves.
|
||||||
|
*/
|
||||||
|
export abstract class MoveRestrictionBattlerTag extends BattlerTag {
|
||||||
|
constructor(tagType: BattlerTagType, turnCount: integer, sourceMove?: Moves, sourceId?: integer) {
|
||||||
|
super(tagType, [ BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.TURN_END ], turnCount, sourceMove, sourceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
override lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
||||||
|
if (lapseType === BattlerTagLapseType.PRE_MOVE) {
|
||||||
|
// Cancel the affected pokemon's selected move
|
||||||
|
const phase = pokemon.scene.getCurrentPhase() as MovePhase;
|
||||||
|
const move = phase.move;
|
||||||
|
|
||||||
|
if (this.isMoveRestricted(move.moveId)) {
|
||||||
|
pokemon.scene.queueMessage(this.interruptedText(pokemon, move.moveId));
|
||||||
|
phase.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.lapse(pokemon, lapseType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether this tag is restricting a move.
|
||||||
|
*
|
||||||
|
* @param {Moves} move {@linkcode Moves} ID to check restriction for.
|
||||||
|
* @returns {boolean} `true` if the move is restricted by this tag, otherwise `false`.
|
||||||
|
*/
|
||||||
|
abstract isMoveRestricted(move: Moves): boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the text to display when the player attempts to select a move that is restricted by this tag.
|
||||||
|
*
|
||||||
|
* @param {Pokemon} pokemon {@linkcode Pokemon} for which the player is attempting to select the restricted move
|
||||||
|
* @param {Moves} move {@linkcode Moves} ID of the move that is having its selection denied
|
||||||
|
* @returns {string} text to display when the player attempts to select the restricted move
|
||||||
|
*/
|
||||||
|
abstract selectionDeniedText(pokemon: Pokemon, move: Moves): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the text to display when a move's execution is prevented as a result of the restriction.
|
||||||
|
* Because restriction effects also prevent selection of the move, this situation can only arise if a
|
||||||
|
* pokemon first selects a move, then gets outsped by a pokemon using a move that restricts the selected move.
|
||||||
|
*
|
||||||
|
* @param {Pokemon} pokemon {@linkcode Pokemon} attempting to use the restricted move
|
||||||
|
* @param {Moves} move {@linkcode Moves} ID of the move being interrupted
|
||||||
|
* @returns {string} text to display when the move is interrupted
|
||||||
|
*/
|
||||||
|
abstract interruptedText(pokemon: Pokemon, move: Moves): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tag representing the "disabling" effect performed by {@linkcode Moves.DISABLE} and {@linkcode Abilities.CURSED_BODY}.
|
||||||
|
* When the tag is added, the last-used move of the tag holder is set as the disabled move.
|
||||||
|
*/
|
||||||
|
export class DisabledTag extends MoveRestrictionBattlerTag {
|
||||||
|
/** The move being disabled. Gets set when {@linkcode onAdd} is called for this tag. */
|
||||||
|
private moveId: Moves = Moves.NONE;
|
||||||
|
|
||||||
|
constructor(sourceId: number) {
|
||||||
|
super(BattlerTagType.DISABLED, 4, Moves.DISABLE, sourceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
override isMoveRestricted(move: Moves): boolean {
|
||||||
|
return move === this.moveId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*
|
||||||
|
* Ensures that move history exists on `pokemon` and has a valid move. If so, sets the {@link moveId} and shows a message.
|
||||||
|
* Otherwise the move ID will not get assigned and this tag will get removed next turn.
|
||||||
|
*/
|
||||||
|
override onAdd(pokemon: Pokemon): void {
|
||||||
|
super.onAdd(pokemon);
|
||||||
|
|
||||||
|
const move = pokemon.getLastXMoves()
|
||||||
|
.find(m => m.move !== Moves.NONE && m.move !== Moves.STRUGGLE && !m.virtual);
|
||||||
|
if (move === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.moveId = move.move;
|
||||||
|
|
||||||
|
pokemon.scene.queueMessage(i18next.t("battlerTags:disabledOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[this.moveId].name }));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
override onRemove(pokemon: Pokemon): void {
|
||||||
|
super.onRemove(pokemon);
|
||||||
|
|
||||||
|
pokemon.scene.queueMessage(i18next.t("battlerTags:disabledLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[this.moveId].name }));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
override selectionDeniedText(pokemon: Pokemon, move: Moves): string {
|
||||||
|
return i18next.t("battle:moveDisabled", { moveName: allMoves[move].name });
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
override interruptedText(pokemon: Pokemon, move: Moves): string {
|
||||||
|
return i18next.t("battle:disableInterruptedMove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name });
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
override loadTag(source: BattlerTag | any): void {
|
||||||
|
super.loadTag(source);
|
||||||
|
this.moveId = source.moveId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BattlerTag that represents the "recharge" effects of moves like Hyper Beam.
|
* BattlerTag that represents the "recharge" effects of moves like Hyper Beam.
|
||||||
*/
|
*/
|
||||||
@ -207,7 +329,7 @@ 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 {
|
||||||
@ -327,7 +449,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 {
|
||||||
@ -362,9 +484,9 @@ 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, undefined, "Self-hit confusion roll") === 0) {
|
if (pokemon.randSeedInt(3, undefined, "Self-hit confusion roll") === 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, "Damage roll for Confusion") / 100));
|
const damage = Utils.toDmgValue(((((2 * pokemon.level / 5 + 2) * 40 * atk / def) / 50) + 2) * (pokemon.randSeedIntRange(85, 100, "Damage roll for Confusion") / 100));
|
||||||
pokemon.scene.queueMessage(i18next.t("battlerTags:confusedLapseHurtItself"));
|
pokemon.scene.queueMessage(i18next.t("battlerTags:confusedLapseHurtItself"));
|
||||||
pokemon.damageAndUpdate(damage);
|
pokemon.damageAndUpdate(damage);
|
||||||
pokemon.battleData.hitCount++;
|
pokemon.battleData.hitCount++;
|
||||||
@ -387,7 +509,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -506,7 +628,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -773,7 +895,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(), false, [BattleStat.DEF, BattleStat.SPDEF], -1));
|
pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), false, [ Stat.DEF, Stat.SPDEF ], -1));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -783,7 +905,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 {
|
||||||
@ -815,7 +937,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 {
|
||||||
@ -1099,7 +1221,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;
|
||||||
|
|
||||||
@ -1116,7 +1238,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1127,7 +1249,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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1213,7 +1335,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 {
|
||||||
@ -1269,7 +1391,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;
|
||||||
}
|
}
|
||||||
@ -1354,11 +1476,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;
|
||||||
@ -1376,7 +1497,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 {
|
||||||
@ -1446,7 +1567,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;
|
||||||
}
|
}
|
||||||
@ -1510,7 +1631,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 {
|
||||||
@ -1602,7 +1723,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1720,25 +1841,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]++;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1746,8 +1867,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,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1767,9 +1888,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
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1783,15 +1904,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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1933,11 +2054,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:
|
||||||
@ -2001,6 +2122,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source
|
|||||||
return new StockpilingTag(sourceMove);
|
return new StockpilingTag(sourceMove);
|
||||||
case BattlerTagType.OCTOLOCK:
|
case BattlerTagType.OCTOLOCK:
|
||||||
return new OctolockTag(sourceId);
|
return new OctolockTag(sourceId);
|
||||||
|
case BattlerTagType.DISABLED:
|
||||||
|
return new DisabledTag(sourceId);
|
||||||
case BattlerTagType.IGNORE_GHOST:
|
case BattlerTagType.IGNORE_GHOST:
|
||||||
return new ExposedTag(tagType, sourceMove, Type.GHOST, [Type.NORMAL, Type.FIGHTING]);
|
return new ExposedTag(tagType, sourceMove, Type.GHOST, [Type.NORMAL, Type.FIGHTING]);
|
||||||
case BattlerTagType.IGNORE_DARK:
|
case BattlerTagType.IGNORE_DARK:
|
||||||
|
@ -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) => {
|
||||||
|
@ -1,19 +1,18 @@
|
|||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { defaultStarterSpecies, DexAttrProps, GameData } from "#app/system/game-data.js";
|
import { defaultStarterSpecies, DexAttrProps, GameData } from "#app/system/game-data";
|
||||||
import PokemonSpecies, { getPokemonSpecies, getPokemonSpeciesForm, speciesStarters } from "./pokemon-species";
|
import PokemonSpecies, { getPokemonSpecies, getPokemonSpeciesForm, speciesStarters } from "./pokemon-species";
|
||||||
import Pokemon, { PokemonMove } from "#app/field/pokemon.js";
|
import Pokemon, { PokemonMove } from "#app/field/pokemon";
|
||||||
import { BattleType, FixedBattleConfig } from "#app/battle.js";
|
import { BattleType, FixedBattleConfig } from "#app/battle";
|
||||||
import Trainer, { TrainerVariant } from "#app/field/trainer.js";
|
import Trainer, { TrainerVariant } from "#app/field/trainer";
|
||||||
import { GameMode } from "#app/game-mode.js";
|
import { GameMode } from "#app/game-mode";
|
||||||
import { Type } from "./type";
|
import { Type } from "./type";
|
||||||
import { Challenges } from "#enums/challenges";
|
import { Challenges } from "#enums/challenges";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import { TrainerType } from "#enums/trainer-type";
|
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";
|
||||||
import { TypeColor, TypeShadow } from "#app/enums/color.js";
|
import { TypeColor, TypeShadow } from "#app/enums/color";
|
||||||
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;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { BattleSpec } from "#enums/battle-spec";
|
import { BattleSpec } from "#enums/battle-spec";
|
||||||
import { TrainerType } from "#enums/trainer-type";
|
import { TrainerType } from "#enums/trainer-type";
|
||||||
import {trainerConfigs} from "./trainer-config";
|
import { trainerConfigs } from "./trainer-config";
|
||||||
|
|
||||||
export interface TrainerTypeMessages {
|
export interface TrainerTypeMessages {
|
||||||
encounter?: string | string[],
|
encounter?: string | string[],
|
||||||
@ -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: [
|
||||||
|
98
src/data/egg-hatch-data.ts
Normal 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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
144
src/data/egg.ts
@ -8,14 +8,14 @@ import { PlayerPokemon } from "#app/field/pokemon";
|
|||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { EggTier } from "#enums/egg-type";
|
import { EggTier } from "#enums/egg-type";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import { EggSourceType } from "#app/enums/egg-source-types.js";
|
import { EggSourceType } from "#app/enums/egg-source-types";
|
||||||
|
|
||||||
export const EGG_SEED = 1073741824;
|
export const EGG_SEED = 1073741824;
|
||||||
|
|
||||||
// Rates for specific random properties in 1/x
|
// Rates for specific random properties in 1/x
|
||||||
const DEFAULT_SHINY_RATE = 128;
|
const DEFAULT_SHINY_RATE = 128;
|
||||||
const GACHA_SHINY_UP_SHINY_RATE = 64;
|
const GACHA_SHINY_UP_SHINY_RATE = 64;
|
||||||
const SAME_SPECIES_EGG_SHINY_RATE = 24;
|
const SAME_SPECIES_EGG_SHINY_RATE = 12;
|
||||||
const SAME_SPECIES_EGG_HA_RATE = 8;
|
const SAME_SPECIES_EGG_HA_RATE = 8;
|
||||||
const MANAPHY_EGG_MANAPHY_RATE = 8;
|
const MANAPHY_EGG_MANAPHY_RATE = 8;
|
||||||
const GACHA_EGG_HA_RATE = 192;
|
const GACHA_EGG_HA_RATE = 192;
|
||||||
@ -139,46 +139,57 @@ export class Egg {
|
|||||||
////
|
////
|
||||||
|
|
||||||
constructor(eggOptions?: IEggOptions) {
|
constructor(eggOptions?: IEggOptions) {
|
||||||
//if (eggOptions.tier && eggOptions.species) throw Error("Error egg can't have species and tier as option. only choose one of them.")
|
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.")
|
||||||
|
|
||||||
this._sourceType = eggOptions?.sourceType!; // TODO: is this bang correct?
|
this._sourceType = eggOptions?.sourceType!; // TODO: is this bang correct?
|
||||||
// Ensure _sourceType is defined before invoking rollEggTier(), as it is referenced
|
// Ensure _sourceType is defined before invoking rollEggTier(), as it is referenced
|
||||||
this._tier = eggOptions?.tier ?? (Overrides.EGG_TIER_OVERRIDE ?? this.rollEggTier());
|
this._tier = eggOptions?.tier ?? (Overrides.EGG_TIER_OVERRIDE ?? this.rollEggTier());
|
||||||
// If egg was pulled, check if egg pity needs to override the egg tier
|
// If egg was pulled, check if egg pity needs to override the egg tier
|
||||||
if (eggOptions?.pulled) {
|
if (eggOptions?.pulled) {
|
||||||
// Needs this._tier and this._sourceType to work
|
// Needs this._tier and this._sourceType to work
|
||||||
this.checkForPityTierOverrides(eggOptions.scene!); // TODO: is this bang correct?
|
this.checkForPityTierOverrides(eggOptions.scene!); // TODO: is this bang correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
this._id = eggOptions?.id ?? Utils.randInt(EGG_SEED, EGG_SEED * this._tier);
|
this._id = eggOptions?.id ?? Utils.randInt(EGG_SEED, EGG_SEED * this._tier);
|
||||||
|
|
||||||
this._sourceType = eggOptions?.sourceType ?? undefined;
|
this._sourceType = eggOptions?.sourceType ?? undefined;
|
||||||
this._hatchWaves = eggOptions?.hatchWaves ?? this.getEggTierDefaultHatchWaves();
|
this._hatchWaves = eggOptions?.hatchWaves ?? this.getEggTierDefaultHatchWaves();
|
||||||
this._timestamp = eggOptions?.timestamp ?? new Date().getTime();
|
this._timestamp = eggOptions?.timestamp ?? new Date().getTime();
|
||||||
|
|
||||||
// First roll shiny and variant so we can filter if species with an variant exist
|
// First roll shiny and variant so we can filter if species with an variant exist
|
||||||
this._isShiny = eggOptions?.isShiny ?? (Overrides.EGG_SHINY_OVERRIDE || this.rollShiny());
|
this._isShiny = eggOptions?.isShiny ?? (Overrides.EGG_SHINY_OVERRIDE || this.rollShiny());
|
||||||
this._variantTier = eggOptions?.variantTier ?? (Overrides.EGG_VARIANT_OVERRIDE ?? this.rollVariant());
|
this._variantTier = eggOptions?.variantTier ?? (Overrides.EGG_VARIANT_OVERRIDE ?? this.rollVariant());
|
||||||
this._species = eggOptions?.species ?? this.rollSpecies(eggOptions!.scene!)!; // TODO: Are those bangs correct?
|
this._species = eggOptions?.species ?? this.rollSpecies(eggOptions!.scene!)!; // TODO: Are those bangs correct?
|
||||||
|
|
||||||
this._overrideHiddenAbility = eggOptions?.overrideHiddenAbility ?? false;
|
this._overrideHiddenAbility = eggOptions?.overrideHiddenAbility ?? false;
|
||||||
|
|
||||||
// Override egg tier and hatchwaves if species was given
|
// Override egg tier and hatchwaves if species was given
|
||||||
if (eggOptions?.species) {
|
if (eggOptions?.species) {
|
||||||
this._tier = this.getEggTierFromSpeciesStarterValue();
|
this._tier = this.getEggTierFromSpeciesStarterValue();
|
||||||
this._hatchWaves = eggOptions.hatchWaves ?? this.getEggTierDefaultHatchWaves();
|
this._hatchWaves = eggOptions.hatchWaves ?? this.getEggTierDefaultHatchWaves();
|
||||||
}
|
}
|
||||||
// If species has no variant, set variantTier to common. This needs to
|
// If species has no variant, set variantTier to common. This needs to
|
||||||
// be done because species with no variants get filtered at rollSpecies but if the
|
// be done because species with no variants get filtered at rollSpecies but if the
|
||||||
// species is set via options or the legendary gacha pokemon gets choosen the check never happens
|
// species is set via options or the legendary gacha pokemon gets choosen the check never happens
|
||||||
if (this._species && !getPokemonSpecies(this._species).hasVariants()) {
|
if (this._species && !getPokemonSpecies(this._species).hasVariants()) {
|
||||||
this._variantTier = VariantTier.COMMON;
|
this._variantTier = VariantTier.COMMON;
|
||||||
}
|
}
|
||||||
// Needs this._tier so it needs to be generated afer the tier override if bought from same species
|
// Needs this._tier so it needs to be generated afer the tier override if bought from same species
|
||||||
this._eggMoveIndex = eggOptions?.eggMoveIndex ?? this.rollEggMoveIndex();
|
this._eggMoveIndex = eggOptions?.eggMoveIndex ?? this.rollEggMoveIndex();
|
||||||
if (eggOptions?.pulled) {
|
if (eggOptions?.pulled) {
|
||||||
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,37 +211,46 @@ 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 {
|
||||||
// Legacy egg wants to hatch. Generate missing properties
|
let ret: PlayerPokemon;
|
||||||
if (!this._species) {
|
|
||||||
this._isShiny = this.rollShiny();
|
|
||||||
this._species = this.rollSpecies(scene!)!; // TODO: are these bangs correct?
|
|
||||||
}
|
|
||||||
|
|
||||||
let pokemonSpecies = getPokemonSpecies(this._species);
|
const generatePlayerPokemonHelper = (scene: BattleScene) => {
|
||||||
// Special condition to have Phione eggs also have a chance of generating Manaphy
|
// Legacy egg wants to hatch. Generate missing properties
|
||||||
if (this._species === Species.PHIONE) {
|
if (!this._species) {
|
||||||
pokemonSpecies = getPokemonSpecies(Utils.randSeedInt(MANAPHY_EGG_MANAPHY_RATE) ? Species.PHIONE : Species.MANAPHY);
|
this._isShiny = this.rollShiny();
|
||||||
}
|
this._species = this.rollSpecies(scene!)!; // TODO: are these bangs correct?
|
||||||
|
}
|
||||||
|
|
||||||
// Sets the hidden ability if a hidden ability exists and
|
let pokemonSpecies = getPokemonSpecies(this._species);
|
||||||
// the override is set or the egg hits the chance
|
// Special condition to have Phione eggs also have a chance of generating Manaphy
|
||||||
let abilityIndex: number | undefined = undefined;
|
if (this._species === Species.PHIONE) {
|
||||||
const sameSpeciesEggHACheck = (this._sourceType === EggSourceType.SAME_SPECIES_EGG && !Utils.randSeedInt(SAME_SPECIES_EGG_HA_RATE));
|
pokemonSpecies = getPokemonSpecies(Utils.randSeedInt(MANAPHY_EGG_MANAPHY_RATE) ? Species.PHIONE : Species.MANAPHY);
|
||||||
const gachaEggHACheck = (!(this._sourceType === EggSourceType.SAME_SPECIES_EGG) && !Utils.randSeedInt(GACHA_EGG_HA_RATE));
|
}
|
||||||
if (pokemonSpecies.abilityHidden && (this._overrideHiddenAbility || sameSpeciesEggHACheck || gachaEggHACheck)) {
|
|
||||||
abilityIndex = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function has way to many optional parameters
|
// Sets the hidden ability if a hidden ability exists and
|
||||||
const ret: PlayerPokemon = scene.addPlayerPokemon(pokemonSpecies, 1, abilityIndex, undefined, undefined, false);
|
// the override is set or the egg hits the chance
|
||||||
ret.shiny = this._isShiny;
|
let abilityIndex: number | undefined = undefined;
|
||||||
ret.variant = this._variantTier;
|
const sameSpeciesEggHACheck = (this._sourceType === EggSourceType.SAME_SPECIES_EGG && !Utils.randSeedInt(SAME_SPECIES_EGG_HA_RATE));
|
||||||
|
const gachaEggHACheck = (!(this._sourceType === EggSourceType.SAME_SPECIES_EGG) && !Utils.randSeedInt(GACHA_EGG_HA_RATE));
|
||||||
|
if (pokemonSpecies.abilityHidden && (this._overrideHiddenAbility || sameSpeciesEggHACheck || gachaEggHACheck)) {
|
||||||
|
abilityIndex = 2;
|
||||||
|
}
|
||||||
|
|
||||||
const secondaryIvs = Utils.getIvsFromId(Utils.randSeedInt(4294967295));
|
// This function has way to many optional parameters
|
||||||
|
ret = scene.addPlayerPokemon(pokemonSpecies, 1, abilityIndex, undefined, undefined, false);
|
||||||
|
ret.shiny = this._isShiny;
|
||||||
|
ret.variant = this._variantTier;
|
||||||
|
|
||||||
for (let s = 0; s < ret.ivs.length; s++) {
|
const secondaryIvs = Utils.getIvsFromId(Utils.randSeedInt(4294967295));
|
||||||
ret.ivs[s] = Math.max(ret.ivs[s], secondaryIvs[s]);
|
|
||||||
}
|
for (let s = 0; s < ret.ivs.length; 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;
|
||||||
}
|
}
|
||||||
|
940
src/data/move.ts
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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";
|
||||||
|
@ -8,7 +8,7 @@ import { Abilities } from "#enums/abilities";
|
|||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import { TimeOfDay } from "#enums/time-of-day";
|
import { TimeOfDay } from "#enums/time-of-day";
|
||||||
import { getPokemonNameWithAffix } from "#app/messages.js";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { WeatherType } from "./weather";
|
import { WeatherType } from "./weather";
|
||||||
|
|
||||||
@ -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;
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
|
||||||
}
|
|
@ -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";
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,7 +4,7 @@ import { Type } from "./type";
|
|||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import { ChangeMovePriorityAbAttr, applyAbAttrs } from "./ability";
|
import { ChangeMovePriorityAbAttr, applyAbAttrs } from "./ability";
|
||||||
import { ProtectAttr } from "./move";
|
import { ProtectAttr } from "./move";
|
||||||
import { BattlerIndex } from "#app/battle.js";
|
import { BattlerIndex } from "#app/battle";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
|
||||||
export enum TerrainType {
|
export enum TerrainType {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { VariantTier } from "#app/enums/variant-tier.js";
|
import { VariantTier } from "#app/enums/variant-tier";
|
||||||
|
|
||||||
export type Variant = 0 | 1 | 2;
|
export type Variant = 0 | 1 | 2;
|
||||||
|
|
||||||
|
@ -64,6 +64,7 @@ export enum BattlerTagType {
|
|||||||
STOCKPILING = "STOCKPILING",
|
STOCKPILING = "STOCKPILING",
|
||||||
RECEIVE_DOUBLE_DAMAGE = "RECEIVE_DOUBLE_DAMAGE",
|
RECEIVE_DOUBLE_DAMAGE = "RECEIVE_DOUBLE_DAMAGE",
|
||||||
ALWAYS_GET_HIT = "ALWAYS_GET_HIT",
|
ALWAYS_GET_HIT = "ALWAYS_GET_HIT",
|
||||||
|
DISABLED = "DISABLED",
|
||||||
IGNORE_GHOST = "IGNORE_GHOST",
|
IGNORE_GHOST = "IGNORE_GHOST",
|
||||||
IGNORE_DARK = "IGNORE_DARK",
|
IGNORE_DARK = "IGNORE_DARK",
|
||||||
GULP_MISSILE_ARROKUDA = "GULP_MISSILE_ARROKUDA",
|
GULP_MISSILE_ARROKUDA = "GULP_MISSILE_ARROKUDA",
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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`;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { ArenaTagSide } from "#app/data/arena-tag.js";
|
import { ArenaTagSide } from "#app/data/arena-tag";
|
||||||
import { ArenaTagType } from "#enums/arena-tag-type";
|
import { ArenaTagType } from "#enums/arena-tag-type";
|
||||||
import { TerrainType } from "#app/data/terrain.js";
|
import { TerrainType } from "#app/data/terrain";
|
||||||
import { WeatherType } from "#app/data/weather.js";
|
import { WeatherType } from "#app/data/weather";
|
||||||
|
|
||||||
/** Alias for all {@linkcode ArenaEvent} type strings */
|
/** Alias for all {@linkcode ArenaEvent} type strings */
|
||||||
export enum ArenaEventType {
|
export enum ArenaEventType {
|
||||||
|
@ -61,7 +61,7 @@ export class Arena {
|
|||||||
this.scene.arenaBg.setTexture(`${biomeKey}_bg`);
|
this.scene.arenaBg.setTexture(`${biomeKey}_bg`);
|
||||||
this.scene.arenaBgTransition.setTexture(`${biomeKey}_bg`);
|
this.scene.arenaBgTransition.setTexture(`${biomeKey}_bg`);
|
||||||
|
|
||||||
// Redo this on initialise because during save/load the current wave isn't always
|
// Redo this on initialize because during save/load the current wave isn't always
|
||||||
// set correctly during construction
|
// set correctly during construction
|
||||||
this.updatePoolsForTimeOfDay();
|
this.updatePoolsForTimeOfDay();
|
||||||
}
|
}
|
||||||
@ -303,7 +303,7 @@ export class Arena {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets weather to the override specified in overrides.ts
|
* Sets weather to the override specified in overrides.ts
|
||||||
* @param weather new weather to set of type WeatherType
|
* @param weather new {@linkcode WeatherType} to set
|
||||||
* @returns true to force trySetWeather to return true
|
* @returns true to force trySetWeather to return true
|
||||||
*/
|
*/
|
||||||
trySetWeatherOverride(weather: WeatherType): boolean {
|
trySetWeatherOverride(weather: WeatherType): boolean {
|
||||||
@ -315,8 +315,8 @@ export class Arena {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to set a new weather to the battle
|
* Attempts to set a new weather to the battle
|
||||||
* @param weather new weather to set of type WeatherType
|
* @param weather {@linkcode WeatherType} new {@linkcode WeatherType} to set
|
||||||
* @param hasPokemonSource is the new weather from a pokemon
|
* @param hasPokemonSource boolean if the new weather is from a pokemon
|
||||||
* @returns true if new weather set, false if no weather provided or attempting to set the same weather as currently in use
|
* @returns true if new weather set, false if no weather provided or attempting to set the same weather as currently in use
|
||||||
*/
|
*/
|
||||||
trySetWeather(weather: WeatherType, hasPokemonSource: boolean): boolean {
|
trySetWeather(weather: WeatherType, hasPokemonSource: boolean): boolean {
|
||||||
@ -587,6 +587,12 @@ export class Arena {
|
|||||||
this.ignoreAbilities = ignoreAbilities;
|
this.ignoreAbilities = ignoreAbilities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies each `ArenaTag` in this Arena, based on which side (self, enemy, or both) is passed in as a parameter
|
||||||
|
* @param tagType Either an {@linkcode ArenaTagType} string, or an actual {@linkcode ArenaTag} class to filter which ones to apply
|
||||||
|
* @param side {@linkcode ArenaTagSide} which side's arena tags to apply
|
||||||
|
* @param args array of parameters that the called upon tags may need
|
||||||
|
*/
|
||||||
applyTagsForSide(tagType: ArenaTagType | Constructor<ArenaTag>, side: ArenaTagSide, ...args: unknown[]): void {
|
applyTagsForSide(tagType: ArenaTagType | Constructor<ArenaTag>, side: ArenaTagSide, ...args: unknown[]): void {
|
||||||
let tags = typeof tagType === "string"
|
let tags = typeof tagType === "string"
|
||||||
? this.tags.filter(t => t.tagType === tagType)
|
? this.tags.filter(t => t.tagType === tagType)
|
||||||
@ -597,11 +603,28 @@ export class Arena {
|
|||||||
tags.forEach(t => t.apply(this, args));
|
tags.forEach(t => t.apply(this, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the specified tag to both sides (ie: both user and trainer's tag that match the Tag specified)
|
||||||
|
* by calling {@linkcode applyTagsForSide()}
|
||||||
|
* @param tagType Either an {@linkcode ArenaTagType} string, or an actual {@linkcode ArenaTag} class to filter which ones to apply
|
||||||
|
* @param args array of parameters that the called upon tags may need
|
||||||
|
*/
|
||||||
applyTags(tagType: ArenaTagType | Constructor<ArenaTag>, ...args: unknown[]): void {
|
applyTags(tagType: ArenaTagType | Constructor<ArenaTag>, ...args: unknown[]): void {
|
||||||
this.applyTagsForSide(tagType, ArenaTagSide.BOTH, ...args);
|
this.applyTagsForSide(tagType, ArenaTagSide.BOTH, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
addTag(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves | undefined, sourceId: integer, side: ArenaTagSide = ArenaTagSide.BOTH, quiet: boolean = false, targetIndex?: BattlerIndex): boolean {
|
/**
|
||||||
|
* Adds a new tag to the arena
|
||||||
|
* @param tagType {@linkcode ArenaTagType} the tag being added
|
||||||
|
* @param turnCount How many turns the tag lasts
|
||||||
|
* @param sourceMove {@linkcode Moves} the move the tag came from, or `undefined` if not from a move
|
||||||
|
* @param sourceId The ID of the pokemon in play the tag came from (see {@linkcode BattleScene.getPokemonById})
|
||||||
|
* @param side {@linkcode ArenaTagSide} which side(s) the tag applies to
|
||||||
|
* @param quiet If a message should be queued on screen to announce the tag being added
|
||||||
|
* @param targetIndex The {@linkcode BattlerIndex} of the target pokemon
|
||||||
|
* @returns `false` if there already exists a tag of this type in the Arena
|
||||||
|
*/
|
||||||
|
addTag(tagType: ArenaTagType, turnCount: number, sourceMove: Moves | undefined, sourceId: number, side: ArenaTagSide = ArenaTagSide.BOTH, quiet: boolean = false, targetIndex?: BattlerIndex): boolean {
|
||||||
const existingTag = this.getTagOnSide(tagType, side);
|
const existingTag = this.getTagOnSide(tagType, side);
|
||||||
if (existingTag) {
|
if (existingTag) {
|
||||||
existingTag.onOverlap(this);
|
existingTag.onOverlap(this);
|
||||||
@ -614,6 +637,7 @@ export class Arena {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// creates a new tag object
|
||||||
const newTag = getArenaTag(tagType, turnCount || 0, sourceMove, sourceId, targetIndex, side);
|
const newTag = getArenaTag(tagType, turnCount || 0, sourceMove, sourceId, targetIndex, side);
|
||||||
if (newTag) {
|
if (newTag) {
|
||||||
this.tags.push(newTag);
|
this.tags.push(newTag);
|
||||||
@ -627,6 +651,11 @@ export class Arena {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to get a tag from the Arena via {@linkcode getTagOnSide} that applies to both sides
|
||||||
|
* @param tagType The {@linkcode ArenaTagType} or {@linkcode ArenaTag} to get
|
||||||
|
* @returns either the {@linkcode ArenaTag}, or `undefined` if it isn't there
|
||||||
|
*/
|
||||||
getTag(tagType: ArenaTagType | Constructor<ArenaTag>): ArenaTag | undefined {
|
getTag(tagType: ArenaTagType | Constructor<ArenaTag>): ArenaTag | undefined {
|
||||||
return this.getTagOnSide(tagType, ArenaTagSide.BOTH);
|
return this.getTagOnSide(tagType, ArenaTagSide.BOTH);
|
||||||
}
|
}
|
||||||
@ -635,16 +664,35 @@ export class Arena {
|
|||||||
return !!this.getTag(tagType);
|
return !!this.getTag(tagType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to get a tag from the Arena from a specific side (the tag passed in has to either apply to both sides, or the specific side only)
|
||||||
|
*
|
||||||
|
* eg: `MIST` only applies to the user's side, while `MUD_SPORT` applies to both user and enemy side
|
||||||
|
* @param tagType The {@linkcode ArenaTagType} or {@linkcode ArenaTag} to get
|
||||||
|
* @param side The {@linkcode ArenaTagSide} to look at
|
||||||
|
* @returns either the {@linkcode ArenaTag}, or `undefined` if it isn't there
|
||||||
|
*/
|
||||||
getTagOnSide(tagType: ArenaTagType | Constructor<ArenaTag>, side: ArenaTagSide): ArenaTag | undefined {
|
getTagOnSide(tagType: ArenaTagType | Constructor<ArenaTag>, side: ArenaTagSide): ArenaTag | undefined {
|
||||||
return typeof(tagType) === "string"
|
return typeof(tagType) === "string"
|
||||||
? this.tags.find(t => t.tagType === tagType && (side === ArenaTagSide.BOTH || t.side === ArenaTagSide.BOTH || t.side === side))
|
? this.tags.find(t => t.tagType === tagType && (side === ArenaTagSide.BOTH || t.side === ArenaTagSide.BOTH || t.side === side))
|
||||||
: this.tags.find(t => t instanceof tagType && (side === ArenaTagSide.BOTH || t.side === ArenaTagSide.BOTH || t.side === side));
|
: this.tags.find(t => t instanceof tagType && (side === ArenaTagSide.BOTH || t.side === ArenaTagSide.BOTH || t.side === side));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses {@linkcode findTagsOnSide} to filter (using the parameter function) for specific tags that apply to both sides
|
||||||
|
* @param tagPredicate a function mapping {@linkcode ArenaTag}s to `boolean`s
|
||||||
|
* @returns array of {@linkcode ArenaTag}s from which the Arena's tags return true and apply to both sides
|
||||||
|
*/
|
||||||
findTags(tagPredicate: (t: ArenaTag) => boolean): ArenaTag[] {
|
findTags(tagPredicate: (t: ArenaTag) => boolean): ArenaTag[] {
|
||||||
return this.findTagsOnSide(tagPredicate, ArenaTagSide.BOTH);
|
return this.findTagsOnSide(tagPredicate, ArenaTagSide.BOTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns specific tags from the arena that pass the `tagPredicate` function passed in as a parameter, and apply to the given side
|
||||||
|
* @param tagPredicate a function mapping {@linkcode ArenaTag}s to `boolean`s
|
||||||
|
* @param side The {@linkcode ArenaTagSide} to look at
|
||||||
|
* @returns array of {@linkcode ArenaTag}s from which the Arena's tags return `true` and apply to the given side
|
||||||
|
*/
|
||||||
findTagsOnSide(tagPredicate: (t: ArenaTag) => boolean, side: ArenaTagSide): ArenaTag[] {
|
findTagsOnSide(tagPredicate: (t: ArenaTag) => boolean, side: ArenaTagSide): ArenaTag[] {
|
||||||
return this.tags.filter(t => tagPredicate(t) && (side === ArenaTagSide.BOTH || t.side === ArenaTagSide.BOTH || t.side === side));
|
return this.tags.filter(t => tagPredicate(t) && (side === ArenaTagSide.BOTH || t.side === ArenaTagSide.BOTH || t.side === side));
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ import {
|
|||||||
getIconForLatestInput, swap,
|
getIconForLatestInput, swap,
|
||||||
} from "#app/configs/inputs/configHandler";
|
} from "#app/configs/inputs/configHandler";
|
||||||
import BattleScene from "./battle-scene";
|
import BattleScene from "./battle-scene";
|
||||||
import {SettingGamepad} from "#app/system/settings/settings-gamepad.js";
|
import {SettingGamepad} from "#app/system/settings/settings-gamepad";
|
||||||
import {SettingKeyboard} from "#app/system/settings/settings-keyboard";
|
import {SettingKeyboard} from "#app/system/settings/settings-keyboard";
|
||||||
import TouchControl from "#app/touch-controls";
|
import TouchControl from "#app/touch-controls";
|
||||||
import { Button } from "#enums/buttons";
|
import { Button } from "#enums/buttons";
|
||||||
|
@ -38,8 +38,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,
|
||||||
|
@ -207,6 +207,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");
|
||||||
@ -227,6 +228,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");
|
||||||
@ -291,6 +294,7 @@ export class LoadingScene extends SceneBase {
|
|||||||
this.loadImage("saving_icon", "ui");
|
this.loadImage("saving_icon", "ui");
|
||||||
this.loadImage("discord", "ui");
|
this.loadImage("discord", "ui");
|
||||||
this.loadImage("google", "ui");
|
this.loadImage("google", "ui");
|
||||||
|
this.loadImage("settings_icon", "ui");
|
||||||
|
|
||||||
this.loadImage("default_bg", "arenas");
|
this.loadImage("default_bg", "arenas");
|
||||||
// Load arena images
|
// Load arena images
|
||||||
@ -399,6 +403,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");
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
"typeImmunityHeal": "{{abilityName}} von {{pokemonNameWithAffix}} füllte einige KP auf!",
|
"typeImmunityHeal": "{{abilityName}} von {{pokemonNameWithAffix}} füllte einige KP auf!",
|
||||||
"nonSuperEffectiveImmunity": "{{pokemonNameWithAffix}} vermeidet Schaden mit {{abilityName}}!",
|
"nonSuperEffectiveImmunity": "{{pokemonNameWithAffix}} vermeidet Schaden mit {{abilityName}}!",
|
||||||
"disguiseAvoidedDamage": "Die Tarnung von {{pokemonNameWithAffix}} ist aufgeflogen!!",
|
"disguiseAvoidedDamage": "Die Tarnung von {{pokemonNameWithAffix}} ist aufgeflogen!!",
|
||||||
|
"fullHpResistType": "Der Panzer von {{pokemonNameWithAffix}} funkelt und verzerrt die Wechselwirkungen zwischen den Typen!",
|
||||||
"moveImmunity": "Es hat keine Wirkung auf {{pokemonNameWithAffix}}...",
|
"moveImmunity": "Es hat keine Wirkung auf {{pokemonNameWithAffix}}...",
|
||||||
"reverseDrain": "{{pokemonNameWithAffix}} saugt Kloakensoße auf!",
|
"reverseDrain": "{{pokemonNameWithAffix}} saugt Kloakensoße auf!",
|
||||||
"postDefendTypeChange": "{{abilityName}} von {{pokemonNameWithAffix}} macht es zu einem {{typeName}}-Typ!",
|
"postDefendTypeChange": "{{abilityName}} von {{pokemonNameWithAffix}} macht es zu einem {{typeName}}-Typ!",
|
||||||
@ -51,6 +52,7 @@
|
|||||||
"postSummonTeravolt": "{{pokemonNameWithAffix}} strahlt eine knisternde Aura aus!",
|
"postSummonTeravolt": "{{pokemonNameWithAffix}} strahlt eine knisternde Aura aus!",
|
||||||
"postSummonDarkAura": "{{pokemonNameWithAffix}} strahlt eine dunkle Aura aus!",
|
"postSummonDarkAura": "{{pokemonNameWithAffix}} strahlt eine dunkle Aura aus!",
|
||||||
"postSummonFairyAura": "{{pokemonNameWithAffix}} strahlt eine Feenaura aus!",
|
"postSummonFairyAura": "{{pokemonNameWithAffix}} strahlt eine Feenaura aus!",
|
||||||
|
"postSummonAuraBreak": "{{pokemonNameWithAffix}} kehrt die Wirkung aller Aura-Fähigkeiten um!",
|
||||||
"postSummonNeutralizingGas": "Reaktionsgas von {{pokemonNameWithAffix}} hat sich in der Umgebung ausgebreitet!",
|
"postSummonNeutralizingGas": "Reaktionsgas von {{pokemonNameWithAffix}} hat sich in der Umgebung ausgebreitet!",
|
||||||
"postSummonAsOneGlastrier": "{{pokemonNameWithAffix}} verfügt über zwei Fähigkeiten!",
|
"postSummonAsOneGlastrier": "{{pokemonNameWithAffix}} verfügt über zwei Fähigkeiten!",
|
||||||
"postSummonAsOneSpectrier": "{{pokemonNameWithAffix}} verfügt über zwei Fähigkeiten!",
|
"postSummonAsOneSpectrier": "{{pokemonNameWithAffix}} verfügt über zwei Fähigkeiten!",
|
||||||
|
@ -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."
|
||||||
},
|
},
|
||||||
|
@ -36,5 +36,6 @@
|
|||||||
"matBlock": "Tatami-Schild",
|
"matBlock": "Tatami-Schild",
|
||||||
"craftyShield": "Trickschutz",
|
"craftyShield": "Trickschutz",
|
||||||
"tailwind": "Rückenwind",
|
"tailwind": "Rückenwind",
|
||||||
"happyHour": "Goldene Zeiten"
|
"happyHour": "Goldene Zeiten",
|
||||||
|
"safeguard": "Bodyguard"
|
||||||
}
|
}
|
@ -44,6 +44,7 @@
|
|||||||
"moveNotImplemented": "{{moveName}} ist noch nicht implementiert und kann nicht ausgewählt werden.",
|
"moveNotImplemented": "{{moveName}} ist noch nicht implementiert und kann nicht ausgewählt werden.",
|
||||||
"moveNoPP": "Es sind keine AP für diese Attacke mehr übrig!",
|
"moveNoPP": "Es sind keine AP für diese Attacke mehr übrig!",
|
||||||
"moveDisabled": "{{moveName}} ist deaktiviert!",
|
"moveDisabled": "{{moveName}} ist deaktiviert!",
|
||||||
|
"disableInterruptedMove": "{{moveName}} von {{pokemonNameWithAffix}} ist blockiert!",
|
||||||
"noPokeballForce": "Eine unsichtbare Kraft verhindert die Nutzung von Pokébällen.",
|
"noPokeballForce": "Eine unsichtbare Kraft verhindert die Nutzung von Pokébällen.",
|
||||||
"noPokeballTrainer": "Du kannst das Pokémon eines anderen Trainers nicht fangen!",
|
"noPokeballTrainer": "Du kannst das Pokémon eines anderen Trainers nicht fangen!",
|
||||||
"noPokeballMulti": "Du kannst erst einen Pokéball werfen, wenn nur noch ein Pokémon übrig ist!",
|
"noPokeballMulti": "Du kannst erst einen Pokéball werfen, wenn nur noch ein Pokémon übrig ist!",
|
||||||
@ -94,5 +95,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?"
|
||||||
}
|
}
|
@ -67,5 +67,7 @@
|
|||||||
"saltCuredLapse": "{{pokemonNameWithAffix}} wurde durch {{moveName}} verletzt!",
|
"saltCuredLapse": "{{pokemonNameWithAffix}} wurde durch {{moveName}} verletzt!",
|
||||||
"cursedOnAdd": "{{pokemonNameWithAffix}} nimmt einen Teil seiner KP und legt einen Fluch auf {{pokemonName}}!",
|
"cursedOnAdd": "{{pokemonNameWithAffix}} nimmt einen Teil seiner KP und legt einen Fluch auf {{pokemonName}}!",
|
||||||
"cursedLapse": "{{pokemonNameWithAffix}} wurde durch den Fluch verletzt!",
|
"cursedLapse": "{{pokemonNameWithAffix}} wurde durch den Fluch verletzt!",
|
||||||
"stockpilingOnAdd": "{{pokemonNameWithAffix}} hortet {{stockpiledCount}}!"
|
"stockpilingOnAdd": "{{pokemonNameWithAffix}} hortet {{stockpiledCount}}!",
|
||||||
|
"disabledOnAdd": " {{moveName}} von {{pokemonNameWithAffix}} wurde blockiert!",
|
||||||
|
"disabledLapse": "{{moveName}} von {{pokemonNameWithAffix}} ist nicht länger blockiert!"
|
||||||
}
|
}
|
@ -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",
|
||||||
|
@ -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"
|
||||||
}
|
}
|
||||||
|
@ -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"
|
||||||
}
|
}
|
@ -51,5 +51,7 @@
|
|||||||
"renamePokemon": "Pokémon umbennenen",
|
"renamePokemon": "Pokémon umbennenen",
|
||||||
"rename": "Umbenennen",
|
"rename": "Umbenennen",
|
||||||
"nickname": "Spitzname",
|
"nickname": "Spitzname",
|
||||||
"errorServerDown": "Ups! Es gab einen Fehler beim Versuch\nden Server zu kontaktieren\nLasse dieses Fenster offen\nDu wirst automatisch neu verbunden."
|
"errorServerDown": "Ups! Es gab einen Fehler beim Versuch\nden Server zu kontaktieren\nLasse dieses Fenster offen\nDu wirst automatisch neu verbunden.",
|
||||||
|
"noSaves": "Du hast keine gespeicherten Dateien!",
|
||||||
|
"tooManySaves": "Du hast zu viele gespeicherte Dateien!"
|
||||||
}
|
}
|
@ -47,10 +47,14 @@
|
|||||||
"description": "Ändert das Wesen zu {{natureName}}. Schaltet dieses Wesen permanent für diesen Starter frei."
|
"description": "Ändert das Wesen zu {{natureName}}. Schaltet dieses Wesen permanent für diesen Starter frei."
|
||||||
},
|
},
|
||||||
"DoubleBattleChanceBoosterModifierType": {
|
"DoubleBattleChanceBoosterModifierType": {
|
||||||
"description": "Verdoppelt die Wahrscheinlichkeit, dass die nächsten {{battleCount}} Begegnungen mit wilden Pokémon ein Doppelkampf sind."
|
"description": "Vervierfacht die Chance, dass ein Kampf ein Doppelkampf wird, für bis zu {{battleCount}} Kämpfe."
|
||||||
},
|
},
|
||||||
"TempBattleStatBoosterModifierType": {
|
"TempStatStageBoosterModifierType": {
|
||||||
"description": "Erhöht die {{tempBattleStatName}} aller Teammitglieder für 5 Kämpfe um eine Stufe."
|
"description": "Erhöht {{stat}} aller Teammitglieder um {{amount}} für bis zu 5 Kämpfe.",
|
||||||
|
"extra": {
|
||||||
|
"stage": "eine Stufe",
|
||||||
|
"percentage": "30%"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"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 +65,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 +252,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 +421,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 +602,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"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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!",
|
||||||
|
@ -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!",
|
||||||
|
@ -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!"
|
||||||
}
|
}
|
@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"Stat": {
|
"Stat": {
|
||||||
"HP": "KP",
|
"HP": "KP",
|
||||||
"HPStat": "KP",
|
|
||||||
"HPshortened": "KP",
|
"HPshortened": "KP",
|
||||||
"ATK": "Angriff",
|
"ATK": "Angriff",
|
||||||
"ATKshortened": "Ang",
|
"ATKshortened": "Ang",
|
||||||
|
@ -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"
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"badDreams": "{{pokemonName}} is tormented!",
|
"badDreams": "{{pokemonName}} is tormented!",
|
||||||
"costar": "{{pokemonName}} copied {{allyName}}'s stat changes!",
|
"costar": "{{pokemonName}} copied {{allyName}}'s stat changes!",
|
||||||
"iceFaceAvoidedDamage": "{{pokemonNameWithAffix}} avoided\ndamage with {{abilityName}}!",
|
"iceFaceAvoidedDamage": "{{pokemonNameWithAffix}} avoided\ndamage with {{abilityName}}!",
|
||||||
"perishBody": "{{pokemonName}}'s {{abilityName}}\nwill faint both pokemon in 3 turns!",
|
"perishBody": "{{pokemonName}}'s {{abilityName}}\nwill faint both Pokémon in 3 turns!",
|
||||||
"poisonHeal": "{{pokemonName}}'s {{abilityName}}\nrestored its HP a little!",
|
"poisonHeal": "{{pokemonName}}'s {{abilityName}}\nrestored its HP a little!",
|
||||||
"trace": "{{pokemonName}} copied {{targetName}}'s\n{{abilityName}}!",
|
"trace": "{{pokemonName}} copied {{targetName}}'s\n{{abilityName}}!",
|
||||||
"windPowerCharged": "Being hit by {{moveName}} charged {{pokemonName}} with power!",
|
"windPowerCharged": "Being hit by {{moveName}} charged {{pokemonName}} with power!",
|
||||||
@ -52,6 +52,7 @@
|
|||||||
"postSummonTeravolt": "{{pokemonNameWithAffix}} is radiating a bursting aura!",
|
"postSummonTeravolt": "{{pokemonNameWithAffix}} is radiating a bursting aura!",
|
||||||
"postSummonDarkAura": "{{pokemonNameWithAffix}} is radiating a Dark Aura!",
|
"postSummonDarkAura": "{{pokemonNameWithAffix}} is radiating a Dark Aura!",
|
||||||
"postSummonFairyAura": "{{pokemonNameWithAffix}} is radiating a Fairy Aura!",
|
"postSummonFairyAura": "{{pokemonNameWithAffix}} is radiating a Fairy Aura!",
|
||||||
|
"postSummonAuraBreak": "{{pokemonNameWithAffix}} reversed all other Pokémon's auras!",
|
||||||
"postSummonNeutralizingGas": "{{pokemonNameWithAffix}}'s Neutralizing Gas filled the area!",
|
"postSummonNeutralizingGas": "{{pokemonNameWithAffix}}'s Neutralizing Gas filled the area!",
|
||||||
"postSummonAsOneGlastrier": "{{pokemonNameWithAffix}} has two Abilities!",
|
"postSummonAsOneGlastrier": "{{pokemonNameWithAffix}} has two Abilities!",
|
||||||
"postSummonAsOneSpectrier": "{{pokemonNameWithAffix}} has two Abilities!",
|
"postSummonAsOneSpectrier": "{{pokemonNameWithAffix}} has two Abilities!",
|
||||||
|
@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
@ -97,9 +97,9 @@
|
|||||||
"name": "Master League Champion",
|
"name": "Master League Champion",
|
||||||
"name_female": "Master League Champion"
|
"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",
|
||||||
|
@ -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"
|
||||||
}
|
}
|
@ -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!"
|
||||||
}
|
}
|
@ -44,6 +44,7 @@
|
|||||||
"moveNotImplemented": "{{moveName}} is not yet implemented and cannot be selected.",
|
"moveNotImplemented": "{{moveName}} is not yet implemented and cannot be selected.",
|
||||||
"moveNoPP": "There's no PP left for\nthis move!",
|
"moveNoPP": "There's no PP left for\nthis move!",
|
||||||
"moveDisabled": "{{moveName}} is disabled!",
|
"moveDisabled": "{{moveName}} is disabled!",
|
||||||
|
"disableInterruptedMove": "{{pokemonNameWithAffix}}'s {{moveName}}\nis disabled!",
|
||||||
"noPokeballForce": "An unseen force\nprevents using Poké Balls.",
|
"noPokeballForce": "An unseen force\nprevents using Poké Balls.",
|
||||||
"noPokeballTrainer": "You can't catch\nanother trainer's Pokémon!",
|
"noPokeballTrainer": "You can't catch\nanother trainer's Pokémon!",
|
||||||
"noPokeballMulti": "You can only throw a Poké Ball\nwhen there is one Pokémon remaining!",
|
"noPokeballMulti": "You can only throw a Poké Ball\nwhen there is one Pokémon remaining!",
|
||||||
@ -61,6 +62,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}}",
|
||||||
|
@ -67,5 +67,7 @@
|
|||||||
"saltCuredLapse": "{{pokemonNameWithAffix}} is hurt by {{moveName}}!",
|
"saltCuredLapse": "{{pokemonNameWithAffix}} is hurt by {{moveName}}!",
|
||||||
"cursedOnAdd": "{{pokemonNameWithAffix}} cut its own HP and put a curse on the {{pokemonName}}!",
|
"cursedOnAdd": "{{pokemonNameWithAffix}} cut its own HP and put a curse on the {{pokemonName}}!",
|
||||||
"cursedLapse": "{{pokemonNameWithAffix}} is afflicted by the Curse!",
|
"cursedLapse": "{{pokemonNameWithAffix}} is afflicted by the Curse!",
|
||||||
"stockpilingOnAdd": "{{pokemonNameWithAffix}} stockpiled {{stockpiledCount}}!"
|
"stockpilingOnAdd": "{{pokemonNameWithAffix}} stockpiled {{stockpiledCount}}!",
|
||||||
|
"disabledOnAdd": "{{pokemonNameWithAffix}}'s {{moveName}}\nwas disabled!",
|
||||||
|
"disabledLapse": "{{pokemonNameWithAffix}}'s {{moveName}}\nis no longer disabled."
|
||||||
}
|
}
|
@ -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 ineligible 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}}.",
|
||||||
|