Merge branch 'beta' into implSynchronize
This commit is contained in:
commit
0157eba750
|
@ -0,0 +1,30 @@
|
||||||
|
name: Test Template
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
project:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
shard:
|
||||||
|
required: true
|
||||||
|
type: number
|
||||||
|
totalShards:
|
||||||
|
required: true
|
||||||
|
type: number
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
name: Shard ${{ inputs.shard }} of ${{ inputs.totalShards }}
|
||||||
|
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: Run tests
|
||||||
|
run: npx vitest --project ${{ inputs.project }} --shard=${{ inputs.shard }}/${{ inputs.totalShards }} ${{ !runner.debug && '--silent' || '' }}
|
|
@ -15,91 +15,33 @@ on:
|
||||||
types: [checks_requested]
|
types: [checks_requested]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
run-misc-tests: # Define a job named "run-tests"
|
pre-test:
|
||||||
name: Run misc tests # Human-readable name for the job
|
name: Run Pre-test
|
||||||
runs-on: ubuntu-latest # Specify the latest Ubuntu runner for the job
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Check out Git repository # Step to check out the repository
|
|
||||||
uses: actions/checkout@v4 # Use the checkout action version 4
|
|
||||||
|
|
||||||
- name: Set up Node.js # Step to set up Node.js environment
|
|
||||||
uses: actions/setup-node@v4 # Use the setup-node action version 4
|
|
||||||
with:
|
|
||||||
node-version: 20 # Specify Node.js version 20
|
|
||||||
|
|
||||||
- name: Install Node.js dependencies # Step to install Node.js dependencies
|
|
||||||
run: npm ci # Use 'npm ci' to install dependencies
|
|
||||||
|
|
||||||
- name: pre-test # pre-test to check overrides
|
|
||||||
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
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Check out Git repository
|
- name: Check out Git repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
path: tests-action
|
||||||
- name: Set up Node.js
|
- name: Set up Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 20
|
||||||
- name: Install Node.js dependencies
|
- name: Install Node.js dependencies
|
||||||
|
working-directory: tests-action
|
||||||
run: npm ci
|
run: npm ci
|
||||||
- name: pre-test
|
- name: Run Pre-test
|
||||||
run: npx vitest run --project pre
|
working-directory: tests-action
|
||||||
- name: test abilities
|
run: npx vitest run --project pre ${{ !runner.debug && '--silent' || '' }}
|
||||||
run: npx vitest --project abilities
|
|
||||||
|
|
||||||
run-items-tests:
|
run-tests:
|
||||||
name: Run items tests
|
name: Run Tests
|
||||||
runs-on: ubuntu-latest
|
needs: [pre-test]
|
||||||
steps:
|
strategy:
|
||||||
- name: Check out Git repository
|
matrix:
|
||||||
uses: actions/checkout@v4
|
shard: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||||
- name: Set up Node.js
|
uses: ./.github/workflows/test-shard-template.yml
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
project: main
|
||||||
- name: Install Node.js dependencies
|
shard: ${{ matrix.shard }}
|
||||||
run: npm ci
|
totalShards: 10
|
||||||
- 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
|
|
|
@ -20,12 +20,15 @@ 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", "ability", or "item") and a file name.');
|
console.error('Please provide a type ("move", "ability", or "item") and a file name.');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert fileName from to snake_case if camelCase is given
|
// Convert fileName from kebab-case or camelCase to snake_case
|
||||||
fileName = fileName.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase();
|
fileName = fileName
|
||||||
|
.replace(/-+/g, '_') // Convert kebab-case (dashes) to underscores
|
||||||
|
.replace(/([a-z])([A-Z])/g, '$1_$2') // Convert camelCase to snake_case
|
||||||
|
.toLowerCase(); // Ensure all lowercase
|
||||||
|
|
||||||
// Format the description for the test case
|
// Format the description for the test case
|
||||||
const formattedName = fileName
|
const formattedName = fileName
|
||||||
|
@ -64,10 +67,11 @@ if (fs.existsSync(filePath)) {
|
||||||
|
|
||||||
// Define the content template
|
// Define the content template
|
||||||
const content = `import { Abilities } from "#enums/abilities";
|
const content = `import { Abilities } from "#enums/abilities";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, it, expect } from "vitest";
|
||||||
|
|
||||||
describe("${description}", () => {
|
describe("${description}", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
|
@ -87,14 +91,15 @@ describe("${description}", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
game = new GameManager(phaserGame);
|
game = new GameManager(phaserGame);
|
||||||
game.override
|
game.override
|
||||||
|
.moveset([Moves.SPLASH])
|
||||||
.battleType("single")
|
.battleType("single")
|
||||||
.enemyAbility(Abilities.BALL_FETCH)
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
.enemyMoveset(SPLASH_ONLY);
|
.enemyMoveset(Moves.SPLASH);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("test case", async () => {
|
it("test case", async () => {
|
||||||
// await game.classicMode.startBattle();
|
// await game.classicMode.startBattle([Species.MAGIKARP]);
|
||||||
// game.move.select();
|
// game.move.select(Moves.SPLASH);
|
||||||
}, TIMEOUT);
|
}, TIMEOUT);
|
||||||
});
|
});
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import tseslint from '@typescript-eslint/eslint-plugin';
|
import tseslint from '@typescript-eslint/eslint-plugin';
|
||||||
import stylisticTs from '@stylistic/eslint-plugin-ts'
|
import stylisticTs from '@stylistic/eslint-plugin-ts'
|
||||||
import parser from '@typescript-eslint/parser';
|
import parser from '@typescript-eslint/parser';
|
||||||
// import imports from 'eslint-plugin-import'; // Disabled due to not being compatible with eslint v9
|
import importX from 'eslint-plugin-import-x';
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
|
@ -11,7 +11,7 @@ export default [
|
||||||
parser: parser
|
parser: parser
|
||||||
},
|
},
|
||||||
plugins: {
|
plugins: {
|
||||||
// imports: imports.configs.recommended // Disabled due to not being compatible with eslint v9
|
"import-x": importX,
|
||||||
'@stylistic/ts': stylisticTs,
|
'@stylistic/ts': stylisticTs,
|
||||||
'@typescript-eslint': tseslint
|
'@typescript-eslint': tseslint
|
||||||
},
|
},
|
||||||
|
@ -39,7 +39,8 @@ export default [
|
||||||
}],
|
}],
|
||||||
"space-before-blocks": ["error", "always"], // Enforces a space before blocks
|
"space-before-blocks": ["error", "always"], // Enforces a space before blocks
|
||||||
"keyword-spacing": ["error", { "before": true, "after": true }], // Enforces spacing before and after keywords
|
"keyword-spacing": ["error", { "before": true, "after": true }], // Enforces spacing before and after keywords
|
||||||
"comma-spacing": ["error", { "before": false, "after": true }] // Enforces spacing after comma
|
"comma-spacing": ["error", { "before": false, "after": true }], // Enforces spacing after comma
|
||||||
|
"import-x/extensions": ["error", "never", { "json": "always" }], // Enforces no extension for imports unless json
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
"@vitest/coverage-istanbul": "^2.0.4",
|
"@vitest/coverage-istanbul": "^2.0.4",
|
||||||
"dependency-cruiser": "^16.3.10",
|
"dependency-cruiser": "^16.3.10",
|
||||||
"eslint": "^9.7.0",
|
"eslint": "^9.7.0",
|
||||||
|
"eslint-plugin-import-x": "^4.2.1",
|
||||||
"jsdom": "^24.0.0",
|
"jsdom": "^24.0.0",
|
||||||
"lefthook": "^1.6.12",
|
"lefthook": "^1.6.12",
|
||||||
"phaser3spectorjs": "^0.0.8",
|
"phaser3spectorjs": "^0.0.8",
|
||||||
|
@ -2505,6 +2506,19 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/doctrine": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"esutils": "^2.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/eastasianwidth": {
|
"node_modules/eastasianwidth": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
||||||
|
@ -2687,6 +2701,155 @@
|
||||||
"url": "https://opencollective.com/eslint"
|
"url": "https://opencollective.com/eslint"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/eslint-import-resolver-node": {
|
||||||
|
"version": "0.3.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
|
||||||
|
"integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "^3.2.7",
|
||||||
|
"is-core-module": "^2.13.0",
|
||||||
|
"resolve": "^1.22.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/eslint-import-resolver-node/node_modules/debug": {
|
||||||
|
"version": "3.2.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
|
||||||
|
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "^2.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/eslint-plugin-import-x": {
|
||||||
|
"version": "4.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/eslint-plugin-import-x/-/eslint-plugin-import-x-4.2.1.tgz",
|
||||||
|
"integrity": "sha512-WWi2GedccIJa0zXxx3WDnTgouGQTtdYK1nhXMwywbqqAgB0Ov+p1pYBsWh3VaB0bvBOwLse6OfVII7jZD9xo5Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/utils": "^8.1.0",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"doctrine": "^3.0.0",
|
||||||
|
"eslint-import-resolver-node": "^0.3.9",
|
||||||
|
"get-tsconfig": "^4.7.3",
|
||||||
|
"is-glob": "^4.0.3",
|
||||||
|
"minimatch": "^9.0.3",
|
||||||
|
"semver": "^7.6.3",
|
||||||
|
"stable-hash": "^0.0.4",
|
||||||
|
"tslib": "^2.6.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"eslint": "^8.57.0 || ^9.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/eslint-plugin-import-x/node_modules/@typescript-eslint/scope-manager": {
|
||||||
|
"version": "8.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.5.0.tgz",
|
||||||
|
"integrity": "sha512-06JOQ9Qgj33yvBEx6tpC8ecP9o860rsR22hWMEd12WcTRrfaFgHr2RB/CA/B+7BMhHkXT4chg2MyboGdFGawYg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/types": "8.5.0",
|
||||||
|
"@typescript-eslint/visitor-keys": "8.5.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/eslint-plugin-import-x/node_modules/@typescript-eslint/types": {
|
||||||
|
"version": "8.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.5.0.tgz",
|
||||||
|
"integrity": "sha512-qjkormnQS5wF9pjSi6q60bKUHH44j2APxfh9TQRXK8wbYVeDYYdYJGIROL87LGZZ2gz3Rbmjc736qyL8deVtdw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/eslint-plugin-import-x/node_modules/@typescript-eslint/typescript-estree": {
|
||||||
|
"version": "8.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.5.0.tgz",
|
||||||
|
"integrity": "sha512-vEG2Sf9P8BPQ+d0pxdfndw3xIXaoSjliG0/Ejk7UggByZPKXmJmw3GW5jV2gHNQNawBUyfahoSiCFVov0Ruf7Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/types": "8.5.0",
|
||||||
|
"@typescript-eslint/visitor-keys": "8.5.0",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"fast-glob": "^3.3.2",
|
||||||
|
"is-glob": "^4.0.3",
|
||||||
|
"minimatch": "^9.0.4",
|
||||||
|
"semver": "^7.6.0",
|
||||||
|
"ts-api-utils": "^1.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"typescript": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/eslint-plugin-import-x/node_modules/@typescript-eslint/utils": {
|
||||||
|
"version": "8.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.5.0.tgz",
|
||||||
|
"integrity": "sha512-6yyGYVL0e+VzGYp60wvkBHiqDWOpT63pdMV2CVG4LVDd5uR6q1qQN/7LafBZtAtNIn/mqXjsSeS5ggv/P0iECw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@eslint-community/eslint-utils": "^4.4.0",
|
||||||
|
"@typescript-eslint/scope-manager": "8.5.0",
|
||||||
|
"@typescript-eslint/types": "8.5.0",
|
||||||
|
"@typescript-eslint/typescript-estree": "8.5.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"eslint": "^8.57.0 || ^9.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/eslint-plugin-import-x/node_modules/@typescript-eslint/visitor-keys": {
|
||||||
|
"version": "8.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.5.0.tgz",
|
||||||
|
"integrity": "sha512-yTPqMnbAZJNy2Xq2XU8AdtOW9tJIr+UQb64aXB9f3B1498Zx9JorVgFJcZpEc9UBuCCrdzKID2RGAMkYcDtZOw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/types": "8.5.0",
|
||||||
|
"eslint-visitor-keys": "^3.4.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/eslint-scope": {
|
"node_modules/eslint-scope": {
|
||||||
"version": "8.0.2",
|
"version": "8.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz",
|
||||||
|
@ -3143,6 +3306,19 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/get-tsconfig": {
|
||||||
|
"version": "4.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.0.tgz",
|
||||||
|
"integrity": "sha512-Pgba6TExTZ0FJAn1qkJAjIeKoDJ3CsI2ChuLohJnZl/tTU8MVrq3b+2t5UOPfRa4RMsorClBjJALkJUMjG1PAw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"resolve-pkg-maps": "^1.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/glob-parent": {
|
"node_modules/glob-parent": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
||||||
|
@ -4854,6 +5030,16 @@
|
||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/resolve-pkg-maps": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/reusify": {
|
"node_modules/reusify": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
|
||||||
|
@ -5069,6 +5255,13 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/stable-hash": {
|
||||||
|
"version": "0.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.4.tgz",
|
||||||
|
"integrity": "sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/stackback": {
|
"node_modules/stackback": {
|
||||||
"version": "0.0.2",
|
"version": "0.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
|
||||||
|
@ -5460,6 +5653,13 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tslib": {
|
||||||
|
"version": "2.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
|
||||||
|
"integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "0BSD"
|
||||||
|
},
|
||||||
"node_modules/type-check": {
|
"node_modules/type-check": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
"@vitest/coverage-istanbul": "^2.0.4",
|
"@vitest/coverage-istanbul": "^2.0.4",
|
||||||
"dependency-cruiser": "^16.3.10",
|
"dependency-cruiser": "^16.3.10",
|
||||||
"eslint": "^9.7.0",
|
"eslint": "^9.7.0",
|
||||||
|
"eslint-plugin-import-x": "^4.2.1",
|
||||||
"jsdom": "^24.0.0",
|
"jsdom": "^24.0.0",
|
||||||
"lefthook": "^1.6.12",
|
"lefthook": "^1.6.12",
|
||||||
"phaser3spectorjs": "^0.0.8",
|
"phaser3spectorjs": "^0.0.8",
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 799 B |
Binary file not shown.
Before Width: | Height: | Size: 807 B |
Binary file not shown.
Before Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
Before Width: | Height: | Size: 799 B |
Binary file not shown.
Before Width: | Height: | Size: 800 B |
Binary file not shown.
Before Width: | Height: | Size: 799 B |
|
@ -2193,8 +2193,14 @@ export default class BattleScene extends SceneBase {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
findPhase(phaseFilter: (phase: Phase) => boolean): Phase | undefined {
|
/**
|
||||||
return this.phaseQueue.find(phaseFilter);
|
* Find a specific {@linkcode Phase} in the phase queue.
|
||||||
|
*
|
||||||
|
* @param phaseFilter filter function to use to find the wanted phase
|
||||||
|
* @returns the found phase or undefined if none found
|
||||||
|
*/
|
||||||
|
findPhase<P extends Phase = Phase>(phaseFilter: (phase: P) => boolean): P | undefined {
|
||||||
|
return this.phaseQueue.find(phaseFilter) as P;
|
||||||
}
|
}
|
||||||
|
|
||||||
tryReplacePhase(phaseFilter: (phase: Phase) => boolean, phase: Phase): boolean {
|
tryReplacePhase(phaseFilter: (phase: Phase) => boolean, phase: Phase): boolean {
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
export const PLAYER_PARTY_MAX_SIZE = 6;
|
|
@ -1595,8 +1595,8 @@ export class PostAttackAbAttr extends AbAttr {
|
||||||
private attackCondition: PokemonAttackCondition;
|
private attackCondition: PokemonAttackCondition;
|
||||||
|
|
||||||
/** The default attackCondition requires that the selected move is a damaging move */
|
/** The default attackCondition requires that the selected move is a damaging move */
|
||||||
constructor(attackCondition: PokemonAttackCondition = (user, target, move) => (move.category !== MoveCategory.STATUS)) {
|
constructor(attackCondition: PokemonAttackCondition = (user, target, move) => (move.category !== MoveCategory.STATUS), showAbility: boolean = true) {
|
||||||
super();
|
super(showAbility);
|
||||||
|
|
||||||
this.attackCondition = attackCondition;
|
this.attackCondition = attackCondition;
|
||||||
}
|
}
|
||||||
|
@ -1624,6 +1624,40 @@ export class PostAttackAbAttr extends AbAttr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ability attribute for Gorilla Tactics
|
||||||
|
* @extends PostAttackAbAttr
|
||||||
|
*/
|
||||||
|
export class GorillaTacticsAbAttr extends PostAttackAbAttr {
|
||||||
|
constructor() {
|
||||||
|
super((user, target, move) => true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Pokemon} pokemon the {@linkcode Pokemon} with this ability
|
||||||
|
* @param passive n/a
|
||||||
|
* @param simulated whether the ability is being simulated
|
||||||
|
* @param defender n/a
|
||||||
|
* @param move n/a
|
||||||
|
* @param hitResult n/a
|
||||||
|
* @param args n/a
|
||||||
|
* @returns `true` if the ability is applied
|
||||||
|
*/
|
||||||
|
applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean | Promise<boolean> {
|
||||||
|
if (simulated) {
|
||||||
|
return simulated;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pokemon.getTag(BattlerTagType.GORILLA_TACTICS)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pokemon.addTag(BattlerTagType.GORILLA_TACTICS);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr {
|
export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr {
|
||||||
private stealCondition: PokemonAttackCondition | null;
|
private stealCondition: PokemonAttackCondition | null;
|
||||||
|
|
||||||
|
@ -3978,7 +4012,7 @@ export class PostBattleLootAbAttr extends PostBattleAbAttr {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PostFaintAbAttr extends AbAttr {
|
export class PostFaintAbAttr extends AbAttr {
|
||||||
applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
|
applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): boolean {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4029,7 +4063,7 @@ export class PostFaintClearWeatherAbAttr extends PostFaintAbAttr {
|
||||||
* @param args N/A
|
* @param args N/A
|
||||||
* @returns {boolean} Returns true if the weather clears, otherwise false.
|
* @returns {boolean} Returns true if the weather clears, otherwise false.
|
||||||
*/
|
*/
|
||||||
applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
|
applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): boolean {
|
||||||
const weatherType = pokemon.scene.arena.weather?.weatherType;
|
const weatherType = pokemon.scene.arena.weather?.weatherType;
|
||||||
let turnOffWeather = false;
|
let turnOffWeather = false;
|
||||||
|
|
||||||
|
@ -4077,8 +4111,8 @@ export class PostFaintContactDamageAbAttr extends PostFaintAbAttr {
|
||||||
this.damageRatio = damageRatio;
|
this.damageRatio = damageRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
|
applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): boolean {
|
||||||
if (move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) {
|
if (move !== undefined && attacker !== undefined && move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) { //If the mon didn't die to indirect damage
|
||||||
const cancelled = new Utils.BooleanHolder(false);
|
const cancelled = new Utils.BooleanHolder(false);
|
||||||
pokemon.scene.getField(true).map(p => applyAbAttrs(FieldPreventExplosiveMovesAbAttr, p, cancelled, simulated));
|
pokemon.scene.getField(true).map(p => applyAbAttrs(FieldPreventExplosiveMovesAbAttr, p, cancelled, simulated));
|
||||||
if (cancelled.value || attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) {
|
if (cancelled.value || attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) {
|
||||||
|
@ -4107,8 +4141,8 @@ export class PostFaintHPDamageAbAttr extends PostFaintAbAttr {
|
||||||
super ();
|
super ();
|
||||||
}
|
}
|
||||||
|
|
||||||
applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
|
applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): boolean {
|
||||||
if (!simulated) {
|
if (move !== undefined && attacker !== undefined && !simulated) { //If the mon didn't die to indirect damage
|
||||||
const damage = pokemon.turnData.attacksReceived[0].damage;
|
const damage = pokemon.turnData.attacksReceived[0].damage;
|
||||||
attacker.damageAndUpdate((damage), HitResult.OTHER);
|
attacker.damageAndUpdate((damage), HitResult.OTHER);
|
||||||
attacker.turnData.damageTaken += damage;
|
attacker.turnData.damageTaken += damage;
|
||||||
|
@ -4770,7 +4804,7 @@ export function applyPostBattleAbAttrs(attrType: Constructor<PostBattleAbAttr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPostFaintAbAttrs(attrType: Constructor<PostFaintAbAttr>,
|
export function applyPostFaintAbAttrs(attrType: Constructor<PostFaintAbAttr>,
|
||||||
pokemon: Pokemon, attacker: Pokemon, move: Move, hitResult: HitResult, simulated: boolean = false, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, attacker?: Pokemon, move?: Move, hitResult?: HitResult, simulated: boolean = false, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PostFaintAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostFaint(pokemon, passive, simulated, attacker, move, hitResult, args), args, false, simulated);
|
return applyAbAttrsInternal<PostFaintAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostFaint(pokemon, passive, simulated, attacker, move, hitResult, args), args, false, simulated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5657,7 +5691,7 @@ export function initAbilities() {
|
||||||
.bypassFaint()
|
.bypassFaint()
|
||||||
.partial(),
|
.partial(),
|
||||||
new Ability(Abilities.GORILLA_TACTICS, 8)
|
new Ability(Abilities.GORILLA_TACTICS, 8)
|
||||||
.unimplemented(),
|
.attr(GorillaTacticsAbAttr),
|
||||||
new Ability(Abilities.NEUTRALIZING_GAS, 8)
|
new Ability(Abilities.NEUTRALIZING_GAS, 8)
|
||||||
.attr(SuppressFieldAbilitiesAbAttr)
|
.attr(SuppressFieldAbilitiesAbAttr)
|
||||||
.attr(UncopiableAbilityAbAttr)
|
.attr(UncopiableAbilityAbAttr)
|
||||||
|
|
|
@ -107,8 +107,8 @@ export interface TerrainBattlerTag {
|
||||||
* to select restricted moves.
|
* to select restricted moves.
|
||||||
*/
|
*/
|
||||||
export abstract class MoveRestrictionBattlerTag extends BattlerTag {
|
export abstract class MoveRestrictionBattlerTag extends BattlerTag {
|
||||||
constructor(tagType: BattlerTagType, turnCount: integer, sourceMove?: Moves, sourceId?: integer) {
|
constructor(tagType: BattlerTagType, lapseType: BattlerTagLapseType | BattlerTagLapseType[], turnCount: integer, sourceMove?: Moves, sourceId?: integer) {
|
||||||
super(tagType, [ BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.TURN_END ], turnCount, sourceMove, sourceId);
|
super(tagType, lapseType, turnCount, sourceMove, sourceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
|
@ -119,7 +119,9 @@ export abstract class MoveRestrictionBattlerTag extends BattlerTag {
|
||||||
const move = phase.move;
|
const move = phase.move;
|
||||||
|
|
||||||
if (this.isMoveRestricted(move.moveId)) {
|
if (this.isMoveRestricted(move.moveId)) {
|
||||||
|
if (this.interruptedText(pokemon, move.moveId)) {
|
||||||
pokemon.scene.queueMessage(this.interruptedText(pokemon, move.moveId));
|
pokemon.scene.queueMessage(this.interruptedText(pokemon, move.moveId));
|
||||||
|
}
|
||||||
phase.cancel();
|
phase.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +157,52 @@ export abstract class MoveRestrictionBattlerTag extends BattlerTag {
|
||||||
* @param {Moves} move {@linkcode Moves} ID of the move being interrupted
|
* @param {Moves} move {@linkcode Moves} ID of the move being interrupted
|
||||||
* @returns {string} text to display when the move is interrupted
|
* @returns {string} text to display when the move is interrupted
|
||||||
*/
|
*/
|
||||||
abstract interruptedText(pokemon: Pokemon, move: Moves): string;
|
interruptedText(pokemon: Pokemon, move: Moves): string {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tag representing the "Throat Chop" effect. Pokemon with this tag cannot use sound-based moves.
|
||||||
|
* @see {@link https://bulbapedia.bulbagarden.net/wiki/Throat_Chop_(move) | Throat Chop}
|
||||||
|
* @extends MoveRestrictionBattlerTag
|
||||||
|
*/
|
||||||
|
export class ThroatChoppedTag extends MoveRestrictionBattlerTag {
|
||||||
|
constructor() {
|
||||||
|
super(BattlerTagType.THROAT_CHOPPED, [ BattlerTagLapseType.TURN_END, BattlerTagLapseType.PRE_MOVE ], 2, Moves.THROAT_CHOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a {@linkcode Moves | move} is restricted by Throat Chop.
|
||||||
|
* @override
|
||||||
|
* @param {Moves} move the {@linkcode Moves | move} to check for sound-based restriction
|
||||||
|
* @returns true if the move is sound-based
|
||||||
|
*/
|
||||||
|
override isMoveRestricted(move: Moves): boolean {
|
||||||
|
return allMoves[move].hasFlag(MoveFlags.SOUND_BASED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a message when the player attempts to select a move that is restricted by Throat Chop.
|
||||||
|
* @override
|
||||||
|
* @param {Pokemon} pokemon the {@linkcode Pokemon} that is attempting to select the restricted move
|
||||||
|
* @param {Moves} move the {@linkcode Moves | move} that is being restricted
|
||||||
|
* @returns the message to display when the player attempts to select the restricted move
|
||||||
|
*/
|
||||||
|
override selectionDeniedText(pokemon: Pokemon, move: Moves): string {
|
||||||
|
return i18next.t("battle:moveCannotBeSelected", { moveName: allMoves[move].name });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a message when a move is interrupted by Throat Chop.
|
||||||
|
* @override
|
||||||
|
* @param {Pokemon} pokemon the interrupted {@linkcode Pokemon}
|
||||||
|
* @param {Moves} move the {@linkcode Moves | move} that was interrupted
|
||||||
|
* @returns the message to display when the move is interrupted
|
||||||
|
*/
|
||||||
|
override interruptedText(pokemon: Pokemon, move: Moves): string {
|
||||||
|
return i18next.t("battle:throatChopInterruptedMove", { pokemonName: getPokemonNameWithAffix(pokemon) });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -167,7 +214,7 @@ export class DisabledTag extends MoveRestrictionBattlerTag {
|
||||||
private moveId: Moves = Moves.NONE;
|
private moveId: Moves = Moves.NONE;
|
||||||
|
|
||||||
constructor(sourceId: number) {
|
constructor(sourceId: number) {
|
||||||
super(BattlerTagType.DISABLED, 4, Moves.DISABLE, sourceId);
|
super(BattlerTagType.DISABLED, [ BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.TURN_END ], 4, Moves.DISABLE, sourceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
|
@ -178,7 +225,7 @@ export class DisabledTag extends MoveRestrictionBattlerTag {
|
||||||
/**
|
/**
|
||||||
* @override
|
* @override
|
||||||
*
|
*
|
||||||
* Ensures that move history exists on `pokemon` and has a valid move. If so, sets the {@link moveId} and shows a message.
|
* Ensures that move history exists on `pokemon` and has a valid move. If so, sets the {@linkcode moveId} and shows a message.
|
||||||
* Otherwise the move ID will not get assigned and this tag will get removed next turn.
|
* Otherwise the move ID will not get assigned and this tag will get removed next turn.
|
||||||
*/
|
*/
|
||||||
override onAdd(pokemon: Pokemon): void {
|
override onAdd(pokemon: Pokemon): void {
|
||||||
|
@ -207,7 +254,12 @@ export class DisabledTag extends MoveRestrictionBattlerTag {
|
||||||
return i18next.t("battle:moveDisabled", { moveName: allMoves[move].name });
|
return i18next.t("battle:moveDisabled", { moveName: allMoves[move].name });
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @override */
|
/**
|
||||||
|
* @override
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
override interruptedText(pokemon: Pokemon, move: Moves): string {
|
override interruptedText(pokemon: Pokemon, move: Moves): string {
|
||||||
return i18next.t("battle:disableInterruptedMove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name });
|
return i18next.t("battle:disableInterruptedMove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: allMoves[move].name });
|
||||||
}
|
}
|
||||||
|
@ -219,6 +271,72 @@ export class DisabledTag extends MoveRestrictionBattlerTag {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tag used by Gorilla Tactics to restrict the user to using only one move.
|
||||||
|
* @extends MoveRestrictionBattlerTag
|
||||||
|
*/
|
||||||
|
export class GorillaTacticsTag extends MoveRestrictionBattlerTag {
|
||||||
|
private moveId = Moves.NONE;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(BattlerTagType.GORILLA_TACTICS, BattlerTagLapseType.CUSTOM, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
override isMoveRestricted(move: Moves): boolean {
|
||||||
|
return move !== this.moveId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
* @param {Pokemon} pokemon the {@linkcode Pokemon} to check if the tag can be added
|
||||||
|
* @returns `true` if the pokemon has a valid move and no existing {@linkcode GorillaTacticsTag}; `false` otherwise
|
||||||
|
*/
|
||||||
|
override canAdd(pokemon: Pokemon): boolean {
|
||||||
|
return (this.getLastValidMove(pokemon) !== undefined) && !pokemon.getTag(GorillaTacticsTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that move history exists on {@linkcode Pokemon} and has a valid move.
|
||||||
|
* If so, sets the {@linkcode moveId} and increases the user's Attack by 50%.
|
||||||
|
* @override
|
||||||
|
* @param {Pokemon} pokemon the {@linkcode Pokemon} to add the tag to
|
||||||
|
*/
|
||||||
|
override onAdd(pokemon: Pokemon): void {
|
||||||
|
const lastValidMove = this.getLastValidMove(pokemon);
|
||||||
|
|
||||||
|
if (!lastValidMove) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.moveId = lastValidMove;
|
||||||
|
pokemon.setStat(Stat.ATK, pokemon.getStat(Stat.ATK, false) * 1.5, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @override
|
||||||
|
* @param {Pokemon} pokemon n/a
|
||||||
|
* @param {Moves} move {@linkcode Moves} ID of the move being denied
|
||||||
|
* @returns {string} text to display when the move is denied
|
||||||
|
*/
|
||||||
|
override selectionDeniedText(pokemon: Pokemon, move: Moves): string {
|
||||||
|
return i18next.t("battle:canOnlyUseMove", { moveName: allMoves[this.moveId].name, pokemonName: getPokemonNameWithAffix(pokemon) });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the last valid move from the pokemon's move history.
|
||||||
|
* @param {Pokemon} pokemon {@linkcode Pokemon} to get the last valid move from
|
||||||
|
* @returns {Moves | undefined} the last valid move from the pokemon's move history
|
||||||
|
*/
|
||||||
|
getLastValidMove(pokemon: Pokemon): Moves | undefined {
|
||||||
|
const move = pokemon.getLastXMoves()
|
||||||
|
.find(m => m.move !== Moves.NONE && m.move !== Moves.STRUGGLE && !m.virtual);
|
||||||
|
|
||||||
|
return move?.move;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BattlerTag that represents the "recharge" effects of moves like Hyper Beam.
|
* BattlerTag that represents the "recharge" effects of moves like Hyper Beam.
|
||||||
*/
|
*/
|
||||||
|
@ -1984,7 +2102,38 @@ export class ExposedTag extends BattlerTag {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tag that doubles the type effectiveness of Fire-type moves.
|
||||||
|
* @extends BattlerTag
|
||||||
|
*/
|
||||||
|
export class TarShotTag extends BattlerTag {
|
||||||
|
constructor() {
|
||||||
|
super(BattlerTagType.TAR_SHOT, BattlerTagLapseType.CUSTOM, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the Pokemon is terastallized, the tag cannot be added.
|
||||||
|
* @param {Pokemon} pokemon the {@linkcode Pokemon} to which the tag is added
|
||||||
|
* @returns whether the tag is applied
|
||||||
|
*/
|
||||||
|
override canAdd(pokemon: Pokemon): boolean {
|
||||||
|
return !pokemon.isTerastallized();
|
||||||
|
}
|
||||||
|
|
||||||
|
override onAdd(pokemon: Pokemon): void {
|
||||||
|
pokemon.scene.queueMessage(i18next.t("battlerTags:tarShotOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a {@linkcode BattlerTag} based on the provided tag type, turn count, source move, and source ID.
|
||||||
|
*
|
||||||
|
* @param {BattlerTagType} tagType the type of the {@linkcode BattlerTagType}.
|
||||||
|
* @param turnCount the turn count.
|
||||||
|
* @param {Moves} sourceMove the source {@linkcode Moves}.
|
||||||
|
* @param sourceId the source ID.
|
||||||
|
* @returns {BattlerTag} the corresponding {@linkcode BattlerTag} object.
|
||||||
|
*/
|
||||||
export function getBattlerTag(tagType: BattlerTagType, turnCount: number, sourceMove: Moves, sourceId: number): BattlerTag {
|
export function getBattlerTag(tagType: BattlerTagType, turnCount: number, sourceMove: Moves, sourceId: number): BattlerTag {
|
||||||
switch (tagType) {
|
switch (tagType) {
|
||||||
case BattlerTagType.RECHARGING:
|
case BattlerTagType.RECHARGING:
|
||||||
|
@ -2125,6 +2274,12 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source
|
||||||
case BattlerTagType.GULP_MISSILE_ARROKUDA:
|
case BattlerTagType.GULP_MISSILE_ARROKUDA:
|
||||||
case BattlerTagType.GULP_MISSILE_PIKACHU:
|
case BattlerTagType.GULP_MISSILE_PIKACHU:
|
||||||
return new GulpMissileTag(tagType, sourceMove);
|
return new GulpMissileTag(tagType, sourceMove);
|
||||||
|
case BattlerTagType.TAR_SHOT:
|
||||||
|
return new TarShotTag();
|
||||||
|
case BattlerTagType.THROAT_CHOPPED:
|
||||||
|
return new ThroatChoppedTag();
|
||||||
|
case BattlerTagType.GORILLA_TACTICS:
|
||||||
|
return new GorillaTacticsTag();
|
||||||
case BattlerTagType.NONE:
|
case BattlerTagType.NONE:
|
||||||
default:
|
default:
|
||||||
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);
|
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);
|
||||||
|
|
|
@ -222,7 +222,7 @@ export class Egg {
|
||||||
|
|
||||||
let pokemonSpecies = getPokemonSpecies(this._species);
|
let pokemonSpecies = getPokemonSpecies(this._species);
|
||||||
// Special condition to have Phione eggs also have a chance of generating Manaphy
|
// Special condition to have Phione eggs also have a chance of generating Manaphy
|
||||||
if (this._species === Species.PHIONE) {
|
if (this._species === Species.PHIONE && this._sourceType === EggSourceType.SAME_SPECIES_EGG) {
|
||||||
pokemonSpecies = getPokemonSpecies(Utils.randSeedInt(MANAPHY_EGG_MANAPHY_RATE) ? Species.PHIONE : Species.MANAPHY);
|
pokemonSpecies = getPokemonSpecies(Utils.randSeedInt(MANAPHY_EGG_MANAPHY_RATE) ? Species.PHIONE : Species.MANAPHY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,7 +326,8 @@ export class Egg {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Utils.randSeedInt(baseChance * Math.pow(2, 3 - this.tier)) ? Utils.randSeedInt(3) : 3;
|
const tierMultiplier = this.isManaphyEgg() ? 2 : Math.pow(2, 3 - this.tier);
|
||||||
|
return Utils.randSeedInt(baseChance * tierMultiplier) ? Utils.randSeedInt(3) : 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getEggTierDefaultHatchWaves(eggTier?: EggTier): number {
|
private getEggTierDefaultHatchWaves(eggTier?: EggTier): number {
|
||||||
|
@ -361,7 +362,12 @@ export class Egg {
|
||||||
* the species that was the legendary focus at the time
|
* the species that was the legendary focus at the time
|
||||||
*/
|
*/
|
||||||
if (this.isManaphyEgg()) {
|
if (this.isManaphyEgg()) {
|
||||||
const rand = Utils.randSeedInt(MANAPHY_EGG_MANAPHY_RATE);
|
/**
|
||||||
|
* Adding a technicality to make unit tests easier: By making this check pass
|
||||||
|
* when Utils.randSeedInt(8) = 1, and by making the generatePlayerPokemon() species
|
||||||
|
* check pass when Utils.randSeedInt(8) = 0, we can tell them apart during tests.
|
||||||
|
*/
|
||||||
|
const rand = (Utils.randSeedInt(MANAPHY_EGG_MANAPHY_RATE) !== 1);
|
||||||
return rand ? Species.PHIONE : Species.MANAPHY;
|
return rand ? Species.PHIONE : Species.MANAPHY;
|
||||||
} else if (this.tier === EggTier.MASTER
|
} else if (this.tier === EggTier.MASTER
|
||||||
&& this._sourceType === EggSourceType.GACHA_LEGENDARY) {
|
&& this._sourceType === EggSourceType.GACHA_LEGENDARY) {
|
||||||
|
|
103
src/data/move.ts
103
src/data/move.ts
|
@ -5986,9 +5986,8 @@ export class SwapStatAttr extends MoveEffectAttr {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes the average of the user's and target's corresponding current
|
* Swaps the user's and target's corresponding current
|
||||||
* {@linkcode stat} values and sets that stat to the average for both
|
* {@linkcode EffectiveStat | stat} values
|
||||||
* temporarily.
|
|
||||||
* @param user the {@linkcode Pokemon} that used the move
|
* @param user the {@linkcode Pokemon} that used the move
|
||||||
* @param target the {@linkcode Pokemon} that the move was used on
|
* @param target the {@linkcode Pokemon} that the move was used on
|
||||||
* @param move N/A
|
* @param move N/A
|
||||||
|
@ -6012,6 +6011,62 @@ export class SwapStatAttr extends MoveEffectAttr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attribute used to switch the user's own stats.
|
||||||
|
* Used by Power Shift.
|
||||||
|
* @extends MoveEffectAttr
|
||||||
|
*/
|
||||||
|
export class ShiftStatAttr extends MoveEffectAttr {
|
||||||
|
private statToSwitch: EffectiveStat;
|
||||||
|
private statToSwitchWith: EffectiveStat;
|
||||||
|
|
||||||
|
constructor(statToSwitch: EffectiveStat, statToSwitchWith: EffectiveStat) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.statToSwitch = statToSwitch;
|
||||||
|
this.statToSwitchWith = statToSwitchWith;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switches the user's stats based on the {@linkcode statToSwitch} and {@linkcode statToSwitchWith} attributes.
|
||||||
|
* @param {Pokemon} user the {@linkcode Pokemon} that used the move
|
||||||
|
* @param target n/a
|
||||||
|
* @param move n/a
|
||||||
|
* @param args n/a
|
||||||
|
* @returns whether the effect was applied
|
||||||
|
*/
|
||||||
|
override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
|
if (!super.apply(user, target, move, args)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstStat = user.getStat(this.statToSwitch, false);
|
||||||
|
const secondStat = user.getStat(this.statToSwitchWith, false);
|
||||||
|
|
||||||
|
user.setStat(this.statToSwitch, secondStat, false);
|
||||||
|
user.setStat(this.statToSwitchWith, firstStat, false);
|
||||||
|
|
||||||
|
user.scene.queueMessage(i18next.t("moveTriggers:shiftedStats", {
|
||||||
|
pokemonName: getPokemonNameWithAffix(user),
|
||||||
|
statToSwitch: i18next.t(getStatKey(this.statToSwitch)),
|
||||||
|
statToSwitchWith: i18next.t(getStatKey(this.statToSwitchWith))
|
||||||
|
}));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encourages the user to use the move if the stat to switch with is greater than the stat to switch.
|
||||||
|
* @param {Pokemon} user the {@linkcode Pokemon} that used the move
|
||||||
|
* @param target n/a
|
||||||
|
* @param move n/a
|
||||||
|
* @returns number of points to add to the user's benefit score
|
||||||
|
*/
|
||||||
|
override getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer {
|
||||||
|
return user.getStat(this.statToSwitchWith, false) > user.getStat(this.statToSwitch, false) ? 10 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attribute used for status moves, namely Power Split and Guard Split,
|
* Attribute used for status moves, namely Power Split and Guard Split,
|
||||||
* that take the average of a user's and target's corresponding
|
* that take the average of a user's and target's corresponding
|
||||||
|
@ -6216,12 +6271,42 @@ export class VariableTargetAttr extends MoveAttr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attribute for {@linkcode Moves.AFTER_YOU}
|
||||||
|
*
|
||||||
|
* [After You - Move | Bulbapedia](https://bulbapedia.bulbagarden.net/wiki/After_You_(move))
|
||||||
|
*/
|
||||||
|
export class AfterYouAttr extends MoveEffectAttr {
|
||||||
|
/**
|
||||||
|
* Allows the target of this move to act right after the user.
|
||||||
|
*
|
||||||
|
* @param user {@linkcode Pokemon} that is using the move.
|
||||||
|
* @param target {@linkcode Pokemon} that will move right after this move is used.
|
||||||
|
* @param move {@linkcode Move} {@linkcode Moves.AFTER_YOU}
|
||||||
|
* @param _args N/A
|
||||||
|
* @returns true
|
||||||
|
*/
|
||||||
|
override apply(user: Pokemon, target: Pokemon, _move: Move, _args: any[]): boolean {
|
||||||
|
user.scene.queueMessage(i18next.t("moveTriggers:afterYou", {targetName: getPokemonNameWithAffix(target)}));
|
||||||
|
|
||||||
|
//Will find next acting phase of the targeted pokémon, delete it and queue it next on successful delete.
|
||||||
|
const nextAttackPhase = target.scene.findPhase<MovePhase>((phase) => phase.pokemon === target);
|
||||||
|
if (nextAttackPhase && target.scene.tryRemovePhase((phase: MovePhase) => phase.pokemon === target)) {
|
||||||
|
target.scene.prependToPhase(new MovePhase(target.scene, target, [...nextAttackPhase.targets], nextAttackPhase.move), MovePhase);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const failOnGravityCondition: MoveConditionFunc = (user, target, move) => !user.scene.arena.getTag(ArenaTagType.GRAVITY);
|
const failOnGravityCondition: MoveConditionFunc = (user, target, move) => !user.scene.arena.getTag(ArenaTagType.GRAVITY);
|
||||||
|
|
||||||
const failOnBossCondition: MoveConditionFunc = (user, target, move) => !target.isBossImmune();
|
const failOnBossCondition: MoveConditionFunc = (user, target, move) => !target.isBossImmune();
|
||||||
|
|
||||||
const failOnMaxCondition: MoveConditionFunc = (user, target, move) => !target.isMax();
|
const failOnMaxCondition: MoveConditionFunc = (user, target, move) => !target.isMax();
|
||||||
|
|
||||||
|
const failIfSingleBattle: MoveConditionFunc = (user, target, move) => user.scene.currentBattle.double;
|
||||||
|
|
||||||
const failIfDampCondition: MoveConditionFunc = (user, target, move) => {
|
const failIfDampCondition: MoveConditionFunc = (user, target, move) => {
|
||||||
const cancelled = new Utils.BooleanHolder(false);
|
const cancelled = new Utils.BooleanHolder(false);
|
||||||
user.scene.getField(true).map(p=>applyAbAttrs(FieldPreventExplosiveMovesAbAttr, p, cancelled));
|
user.scene.getField(true).map(p=>applyAbAttrs(FieldPreventExplosiveMovesAbAttr, p, cancelled));
|
||||||
|
@ -7869,7 +7954,10 @@ export function initMoves() {
|
||||||
.attr(AbilityGiveAttr),
|
.attr(AbilityGiveAttr),
|
||||||
new StatusMove(Moves.AFTER_YOU, Type.NORMAL, -1, 15, -1, 0, 5)
|
new StatusMove(Moves.AFTER_YOU, Type.NORMAL, -1, 15, -1, 0, 5)
|
||||||
.ignoresProtect()
|
.ignoresProtect()
|
||||||
.unimplemented(),
|
.target(MoveTarget.NEAR_OTHER)
|
||||||
|
.condition(failIfSingleBattle)
|
||||||
|
.condition((user, target, move) => !target.turnData.acted)
|
||||||
|
.attr(AfterYouAttr),
|
||||||
new AttackMove(Moves.ROUND, Type.NORMAL, MoveCategory.SPECIAL, 60, 100, 15, -1, 0, 5)
|
new AttackMove(Moves.ROUND, Type.NORMAL, MoveCategory.SPECIAL, 60, 100, 15, -1, 0, 5)
|
||||||
.soundBased()
|
.soundBased()
|
||||||
.partial(),
|
.partial(),
|
||||||
|
@ -8403,7 +8491,7 @@ export function initMoves() {
|
||||||
.target(MoveTarget.USER_AND_ALLIES)
|
.target(MoveTarget.USER_AND_ALLIES)
|
||||||
.condition((user, target, move) => !![ user, user.getAlly() ].filter(p => p?.isActive()).find(p => !![ Abilities.PLUS, Abilities.MINUS].find(a => p.hasAbility(a, false)))),
|
.condition((user, target, move) => !![ user, user.getAlly() ].filter(p => p?.isActive()).find(p => !![ Abilities.PLUS, Abilities.MINUS].find(a => p.hasAbility(a, false)))),
|
||||||
new AttackMove(Moves.THROAT_CHOP, Type.DARK, MoveCategory.PHYSICAL, 80, 100, 15, 100, 0, 7)
|
new AttackMove(Moves.THROAT_CHOP, Type.DARK, MoveCategory.PHYSICAL, 80, 100, 15, 100, 0, 7)
|
||||||
.partial(),
|
.attr(AddBattlerTagAttr, BattlerTagType.THROAT_CHOPPED),
|
||||||
new AttackMove(Moves.POLLEN_PUFF, Type.BUG, MoveCategory.SPECIAL, 90, 100, 15, -1, 0, 7)
|
new AttackMove(Moves.POLLEN_PUFF, Type.BUG, MoveCategory.SPECIAL, 90, 100, 15, -1, 0, 7)
|
||||||
.attr(StatusCategoryOnAllyAttr)
|
.attr(StatusCategoryOnAllyAttr)
|
||||||
.attr(HealOnAllyAttr, 0.5, true, false)
|
.attr(HealOnAllyAttr, 0.5, true, false)
|
||||||
|
@ -8643,7 +8731,7 @@ export function initMoves() {
|
||||||
.condition((user, target, move) => user.getTag(TrappedTag)?.sourceMove !== Moves.NO_RETREAT), // fails if the user is currently trapped by No Retreat
|
.condition((user, target, move) => user.getTag(TrappedTag)?.sourceMove !== Moves.NO_RETREAT), // fails if the user is currently trapped by No Retreat
|
||||||
new StatusMove(Moves.TAR_SHOT, Type.ROCK, 100, 15, -1, 0, 8)
|
new StatusMove(Moves.TAR_SHOT, Type.ROCK, 100, 15, -1, 0, 8)
|
||||||
.attr(StatStageChangeAttr, [ Stat.SPD ], -1)
|
.attr(StatStageChangeAttr, [ Stat.SPD ], -1)
|
||||||
.partial(),
|
.attr(AddBattlerTagAttr, BattlerTagType.TAR_SHOT, false),
|
||||||
new StatusMove(Moves.MAGIC_POWDER, Type.PSYCHIC, 100, 20, -1, 0, 8)
|
new StatusMove(Moves.MAGIC_POWDER, Type.PSYCHIC, 100, 20, -1, 0, 8)
|
||||||
.attr(ChangeTypeAttr, Type.PSYCHIC)
|
.attr(ChangeTypeAttr, Type.PSYCHIC)
|
||||||
.powderMove(),
|
.powderMove(),
|
||||||
|
@ -8893,7 +8981,8 @@ export function initMoves() {
|
||||||
new AttackMove(Moves.PSYSHIELD_BASH, Type.PSYCHIC, MoveCategory.PHYSICAL, 70, 90, 10, 100, 0, 8)
|
new AttackMove(Moves.PSYSHIELD_BASH, Type.PSYCHIC, MoveCategory.PHYSICAL, 70, 90, 10, 100, 0, 8)
|
||||||
.attr(StatStageChangeAttr, [ Stat.DEF ], 1, true),
|
.attr(StatStageChangeAttr, [ Stat.DEF ], 1, true),
|
||||||
new SelfStatusMove(Moves.POWER_SHIFT, Type.NORMAL, -1, 10, -1, 0, 8)
|
new SelfStatusMove(Moves.POWER_SHIFT, Type.NORMAL, -1, 10, -1, 0, 8)
|
||||||
.unimplemented(),
|
.target(MoveTarget.USER)
|
||||||
|
.attr(ShiftStatAttr, Stat.ATK, Stat.DEF),
|
||||||
new AttackMove(Moves.STONE_AXE, Type.ROCK, MoveCategory.PHYSICAL, 65, 90, 15, 100, 0, 8)
|
new AttackMove(Moves.STONE_AXE, Type.ROCK, MoveCategory.PHYSICAL, 65, 90, 15, 100, 0, 8)
|
||||||
.attr(AddArenaTrapTagHitAttr, ArenaTagType.STEALTH_ROCK)
|
.attr(AddArenaTrapTagHitAttr, ArenaTagType.STEALTH_ROCK)
|
||||||
.slicingMove(),
|
.slicingMove(),
|
||||||
|
|
|
@ -73,4 +73,7 @@ export enum BattlerTagType {
|
||||||
SHELL_TRAP = "SHELL_TRAP",
|
SHELL_TRAP = "SHELL_TRAP",
|
||||||
DRAGON_CHEER = "DRAGON_CHEER",
|
DRAGON_CHEER = "DRAGON_CHEER",
|
||||||
NO_RETREAT = "NO_RETREAT",
|
NO_RETREAT = "NO_RETREAT",
|
||||||
|
GORILLA_TACTICS = "GORILLA_TACTICS",
|
||||||
|
THROAT_CHOPPED = "THROAT_CHOPPED",
|
||||||
|
TAR_SHOT = "TAR_SHOT",
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ import { initMoveAnim, loadMoveAnimAssets } from "../data/battle-anims";
|
||||||
import { Status, StatusEffect, getRandomStatus } from "../data/status-effect";
|
import { Status, StatusEffect, getRandomStatus } from "../data/status-effect";
|
||||||
import { pokemonEvolutions, pokemonPrevolutions, SpeciesFormEvolution, SpeciesEvolutionCondition, FusionSpeciesFormEvolution } from "../data/pokemon-evolutions";
|
import { pokemonEvolutions, pokemonPrevolutions, SpeciesFormEvolution, SpeciesEvolutionCondition, FusionSpeciesFormEvolution } from "../data/pokemon-evolutions";
|
||||||
import { reverseCompatibleTms, tmSpecies, tmPoolTiers } from "../data/tms";
|
import { reverseCompatibleTms, tmSpecies, tmPoolTiers } from "../data/tms";
|
||||||
import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoostTag, TypeImmuneTag, getBattlerTag, SemiInvulnerableTag, TypeBoostTag, MoveRestrictionBattlerTag, ExposedTag, DragonCheerTag, CritBoostTag, TrappedTag } from "../data/battler-tags";
|
import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoostTag, TypeImmuneTag, getBattlerTag, SemiInvulnerableTag, TypeBoostTag, MoveRestrictionBattlerTag, ExposedTag, DragonCheerTag, CritBoostTag, TrappedTag, TarShotTag } from "../data/battler-tags";
|
||||||
import { WeatherType } from "../data/weather";
|
import { WeatherType } from "../data/weather";
|
||||||
import { ArenaTagSide, NoCritTag, WeakenMoveScreenTag } from "../data/arena-tag";
|
import { ArenaTagSide, NoCritTag, WeakenMoveScreenTag } from "../data/arena-tag";
|
||||||
import { Ability, AbAttr, StatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatStagesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldStatMultiplierAbAttrs, FieldMultiplyStatAbAttr, AddSecondStrikeAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr, MoveTypeChangeAbAttr, FullHpResistTypeAbAttr, applyCheckTrappedAbAttrs, CheckTrappedAbAttr, PostSetStatusAbAttr, applyPostSetStatusAbAttrs } from "../data/ability";
|
import { Ability, AbAttr, StatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatStagesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldStatMultiplierAbAttrs, FieldMultiplyStatAbAttr, AddSecondStrikeAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr, MoveTypeChangeAbAttr, FullHpResistTypeAbAttr, applyCheckTrappedAbAttrs, CheckTrappedAbAttr, PostSetStatusAbAttr, applyPostSetStatusAbAttrs } from "../data/ability";
|
||||||
|
@ -58,6 +58,7 @@ import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
||||||
import { SwitchSummonPhase } from "#app/phases/switch-summon-phase";
|
import { SwitchSummonPhase } from "#app/phases/switch-summon-phase";
|
||||||
import { ToggleDoublePositionPhase } from "#app/phases/toggle-double-position-phase";
|
import { ToggleDoublePositionPhase } from "#app/phases/toggle-double-position-phase";
|
||||||
import { Challenges } from "#enums/challenges";
|
import { Challenges } from "#enums/challenges";
|
||||||
|
import { PLAYER_PARTY_MAX_SIZE } from "#app/constants";
|
||||||
|
|
||||||
export enum FieldPosition {
|
export enum FieldPosition {
|
||||||
CENTER,
|
CENTER,
|
||||||
|
@ -983,10 +984,16 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||||
: this.moveset;
|
: this.moveset;
|
||||||
|
|
||||||
// Overrides moveset based on arrays specified in overrides.ts
|
// Overrides moveset based on arrays specified in overrides.ts
|
||||||
const overrideArray: Array<Moves> = this.isPlayer() ? Overrides.MOVESET_OVERRIDE : Overrides.OPP_MOVESET_OVERRIDE;
|
let overrideArray: Moves | Array<Moves> = this.isPlayer() ? Overrides.MOVESET_OVERRIDE : Overrides.OPP_MOVESET_OVERRIDE;
|
||||||
|
if (!Array.isArray(overrideArray)) {
|
||||||
|
overrideArray = [overrideArray];
|
||||||
|
}
|
||||||
if (overrideArray.length > 0) {
|
if (overrideArray.length > 0) {
|
||||||
|
if (!this.isPlayer()) {
|
||||||
|
this.moveset = [];
|
||||||
|
}
|
||||||
overrideArray.forEach((move: Moves, index: number) => {
|
overrideArray.forEach((move: Moves, index: number) => {
|
||||||
const ppUsed = this.moveset[index]?.ppUsed || 0;
|
const ppUsed = this.moveset[index]?.ppUsed ?? 0;
|
||||||
this.moveset[index] = new PokemonMove(move, Math.min(ppUsed, allMoves[move].pp));
|
this.moveset[index] = new PokemonMove(move, Math.min(ppUsed, allMoves[move].pp));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1323,9 +1330,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||||
}
|
}
|
||||||
|
|
||||||
const trappedByAbility = new Utils.BooleanHolder(false);
|
const trappedByAbility = new Utils.BooleanHolder(false);
|
||||||
|
const opposingField = this.isPlayer() ? this.scene.getEnemyField() : this.scene.getPlayerField();
|
||||||
|
|
||||||
this.scene.getEnemyField()!.forEach(enemyPokemon =>
|
opposingField.forEach(opponent =>
|
||||||
applyCheckTrappedAbAttrs(CheckTrappedAbAttr, enemyPokemon, trappedByAbility, this, trappedAbMessages, simulated)
|
applyCheckTrappedAbAttrs(CheckTrappedAbAttr, opponent, trappedByAbility, this, trappedAbMessages, simulated)
|
||||||
);
|
);
|
||||||
|
|
||||||
return (trappedByAbility.value || !!this.getTag(TrappedTag));
|
return (trappedByAbility.value || !!this.getTag(TrappedTag));
|
||||||
|
@ -1351,7 +1359,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the effectiveness of a move against the Pokémon.
|
* Calculates the effectiveness of a move against the Pokémon.
|
||||||
*
|
* This includes modifiers from move and ability attributes.
|
||||||
* @param source {@linkcode Pokemon} The attacking Pokémon.
|
* @param source {@linkcode Pokemon} The attacking Pokémon.
|
||||||
* @param move {@linkcode Move} The move being used by the attacking Pokémon.
|
* @param move {@linkcode Move} The move being used by the attacking Pokémon.
|
||||||
* @param ignoreAbility Whether to ignore abilities that might affect type effectiveness or immunity (defaults to `false`).
|
* @param ignoreAbility Whether to ignore abilities that might affect type effectiveness or immunity (defaults to `false`).
|
||||||
|
@ -1375,6 +1383,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||||
typeMultiplier.value = 0;
|
typeMultiplier.value = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.getTag(TarShotTag) && (this.getMoveType(move) === Type.FIRE)) {
|
||||||
|
typeMultiplier.value *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
const cancelledHolder = cancelled ?? new Utils.BooleanHolder(false);
|
const cancelledHolder = cancelled ?? new Utils.BooleanHolder(false);
|
||||||
if (!ignoreAbility) {
|
if (!ignoreAbility) {
|
||||||
applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelledHolder, simulated, typeMultiplier);
|
applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelledHolder, simulated, typeMultiplier);
|
||||||
|
@ -1406,7 +1418,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the type effectiveness multiplier for an attack type
|
* Calculates the move's type effectiveness multiplier based on the target's type/s.
|
||||||
* @param moveType {@linkcode Type} the type of the move being used
|
* @param moveType {@linkcode Type} the type of the move being used
|
||||||
* @param source {@linkcode Pokemon} the Pokemon using the move
|
* @param source {@linkcode Pokemon} the Pokemon using the move
|
||||||
* @param ignoreStrongWinds whether or not this ignores strong winds (anticipation, forewarn, stealth rocks)
|
* @param ignoreStrongWinds whether or not this ignores strong winds (anticipation, forewarn, stealth rocks)
|
||||||
|
@ -4466,17 +4478,29 @@ export class EnemyPokemon extends Pokemon {
|
||||||
return BattlerIndex.ENEMY + this.getFieldIndex();
|
return BattlerIndex.ENEMY + this.getFieldIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
addToParty(pokeballType: PokeballType) {
|
/**
|
||||||
|
* Add a new pokemon to the player's party (at `slotIndex` if set).
|
||||||
|
* @param pokeballType the type of pokeball the pokemon was caught with
|
||||||
|
* @param slotIndex an optional index to place the pokemon in the party
|
||||||
|
* @returns the pokemon that was added or null if the pokemon could not be added
|
||||||
|
*/
|
||||||
|
addToParty(pokeballType: PokeballType, slotIndex: number = -1) {
|
||||||
const party = this.scene.getParty();
|
const party = this.scene.getParty();
|
||||||
let ret: PlayerPokemon | null = null;
|
let ret: PlayerPokemon | null = null;
|
||||||
|
|
||||||
if (party.length < 6) {
|
if (party.length < PLAYER_PARTY_MAX_SIZE) {
|
||||||
this.pokeball = pokeballType;
|
this.pokeball = pokeballType;
|
||||||
this.metLevel = this.level;
|
this.metLevel = this.level;
|
||||||
this.metBiome = this.scene.arena.biomeType;
|
this.metBiome = this.scene.arena.biomeType;
|
||||||
this.metSpecies = this.species.speciesId;
|
this.metSpecies = this.species.speciesId;
|
||||||
const newPokemon = this.scene.addPlayerPokemon(this.species, this.level, this.abilityIndex, this.formIndex, this.gender, this.shiny, this.variant, this.ivs, this.nature, this);
|
const newPokemon = this.scene.addPlayerPokemon(this.species, this.level, this.abilityIndex, this.formIndex, this.gender, this.shiny, this.variant, this.ivs, this.nature, this);
|
||||||
|
|
||||||
|
if (Utils.isBetween(slotIndex, 0, PLAYER_PARTY_MAX_SIZE - 1)) {
|
||||||
|
party.splice(slotIndex, 0, newPokemon);
|
||||||
|
} else {
|
||||||
party.push(newPokemon);
|
party.push(newPokemon);
|
||||||
|
}
|
||||||
|
|
||||||
ret = newPokemon;
|
ret = newPokemon;
|
||||||
this.scene.triggerPokemonFormChange(newPokemon, SpeciesFormChangeActiveTrigger, true);
|
this.scene.triggerPokemonFormChange(newPokemon, SpeciesFormChangeActiveTrigger, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,5 +3,6 @@
|
||||||
"power": "Stärke",
|
"power": "Stärke",
|
||||||
"accuracy": "Genauigkeit",
|
"accuracy": "Genauigkeit",
|
||||||
"abilityFlyInText": "{{passive}}{{abilityName}} von {{pokemonName}} wirkt!",
|
"abilityFlyInText": "{{passive}}{{abilityName}} von {{pokemonName}} wirkt!",
|
||||||
"passive": "Passive Fähigkeit "
|
"passive": "Passive Fähigkeit ",
|
||||||
|
"teraHover": "Tera-Typ {{type}}"
|
||||||
}
|
}
|
|
@ -66,5 +66,6 @@
|
||||||
"revivalBlessing": "{{pokemonName}} ist wieder fit und kampfbereit!",
|
"revivalBlessing": "{{pokemonName}} ist wieder fit und kampfbereit!",
|
||||||
"swapArenaTags": "{{pokemonName}} hat die Effekte, die auf den beiden Seiten des Kampffeldes wirken, miteinander getauscht!",
|
"swapArenaTags": "{{pokemonName}} hat die Effekte, die auf den beiden Seiten des Kampffeldes wirken, miteinander getauscht!",
|
||||||
"exposedMove": "{{pokemonName}} erkennt {{targetPokemonName}}!",
|
"exposedMove": "{{pokemonName}} erkennt {{targetPokemonName}}!",
|
||||||
"safeguard": "{{targetName}} wird durch Bodyguard geschützt!"
|
"safeguard": "{{targetName}} wird durch Bodyguard geschützt!",
|
||||||
|
"afterYou": "{{targetName}} lässt sich auf Galanterie ein!"
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,10 @@
|
||||||
"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!",
|
||||||
|
"canOnlyUseMove": "{{pokemonName}} can only use {{moveName}}!",
|
||||||
|
"moveCannotBeSelected": "{{moveName}} cannot be selected!",
|
||||||
"disableInterruptedMove": "{{pokemonNameWithAffix}}'s {{moveName}}\nis disabled!",
|
"disableInterruptedMove": "{{pokemonNameWithAffix}}'s {{moveName}}\nis disabled!",
|
||||||
|
"throatChopInterruptedMove": "The effects of Throat Chop prevent\n{{pokemonName}} from using certain moves!",
|
||||||
"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!",
|
||||||
|
|
|
@ -69,5 +69,6 @@
|
||||||
"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!",
|
"disabledOnAdd": "{{pokemonNameWithAffix}}'s {{moveName}}\nwas disabled!",
|
||||||
"disabledLapse": "{{pokemonNameWithAffix}}'s {{moveName}}\nis no longer disabled."
|
"disabledLapse": "{{pokemonNameWithAffix}}'s {{moveName}}\nis no longer disabled.",
|
||||||
|
"tarShotOnAdd": "{{pokemonNameWithAffix}} became weaker to fire!"
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,5 +3,6 @@
|
||||||
"power": "Power",
|
"power": "Power",
|
||||||
"accuracy": "Accuracy",
|
"accuracy": "Accuracy",
|
||||||
"abilityFlyInText": " {{pokemonName}}'s {{passive}}{{abilityName}}",
|
"abilityFlyInText": " {{pokemonName}}'s {{passive}}{{abilityName}}",
|
||||||
"passive": "Passive "
|
"passive": "Passive ",
|
||||||
|
"teraHover": "{{type}} Terastallized"
|
||||||
}
|
}
|
|
@ -7,6 +7,7 @@
|
||||||
"switchedStat": "{{pokemonName}} switched {{stat}} with its target!",
|
"switchedStat": "{{pokemonName}} switched {{stat}} with its target!",
|
||||||
"sharedGuard": "{{pokemonName}} shared its guard with the target!",
|
"sharedGuard": "{{pokemonName}} shared its guard with the target!",
|
||||||
"sharedPower": "{{pokemonName}} shared its power with the target!",
|
"sharedPower": "{{pokemonName}} shared its power with the target!",
|
||||||
|
"shiftedStats": "{{pokemonName}} switched its {{statToSwitch}} and {{statToSwitchWith}}!",
|
||||||
"goingAllOutForAttack": "{{pokemonName}} is going all out for this attack!",
|
"goingAllOutForAttack": "{{pokemonName}} is going all out for this attack!",
|
||||||
"regainedHealth": "{{pokemonName}} regained\nhealth!",
|
"regainedHealth": "{{pokemonName}} regained\nhealth!",
|
||||||
"keptGoingAndCrashed": "{{pokemonName}} kept going\nand crashed!",
|
"keptGoingAndCrashed": "{{pokemonName}} kept going\nand crashed!",
|
||||||
|
@ -66,5 +67,6 @@
|
||||||
"revivalBlessing": "{{pokemonName}} was revived!",
|
"revivalBlessing": "{{pokemonName}} was revived!",
|
||||||
"swapArenaTags": "{{pokemonName}} swapped the battle effects affecting each side of the field!",
|
"swapArenaTags": "{{pokemonName}} swapped the battle effects affecting each side of the field!",
|
||||||
"exposedMove": "{{pokemonName}} identified\n{{targetPokemonName}}!",
|
"exposedMove": "{{pokemonName}} identified\n{{targetPokemonName}}!",
|
||||||
"safeguard": "{{targetName}} is protected by Safeguard!"
|
"safeguard": "{{targetName}} is protected by Safeguard!",
|
||||||
|
"afterYou": "{{pokemonName}} took the kind offer!"
|
||||||
}
|
}
|
|
@ -2,11 +2,11 @@
|
||||||
"blockRecoilDamage": "{{pokemonName}}は {{abilityName}}で 反動ダメージを 受けない!",
|
"blockRecoilDamage": "{{pokemonName}}は {{abilityName}}で 反動ダメージを 受けない!",
|
||||||
"badDreams": "{{pokemonName}}は ナイトメアに うなされている!",
|
"badDreams": "{{pokemonName}}は ナイトメアに うなされている!",
|
||||||
"costar": "{{pokemonName}}は {{allyName}}の\n能力変化を コピーした!",
|
"costar": "{{pokemonName}}は {{allyName}}の\n能力変化を コピーした!",
|
||||||
"iceFaceAvoidedDamage": "{{pokemonName}}は\n{{abilityName}}で ダメージを 受けない!",
|
"iceFaceAvoidedDamage": "{{pokemonNameWithAffix}}は\n{{abilityName}}で ダメージを 受けない!",
|
||||||
"perishBody": "{{pokemonName}}の {{abilityName}}で\nおたがいは 3ターン後に ほろびいてしまう!",
|
"perishBody": "{{pokemonName}}の {{abilityName}}で\nおたがいは 3ターン後に ほろびいてしまう!",
|
||||||
"poisonHeal": "{{pokemonName}}は {{abilityName}}で 回復した!",
|
"poisonHeal": "{{pokemonName}}は {{abilityName}}で 回復した!",
|
||||||
"trace": "{{pokemonName}}は 相手の {{targetName}}の\n{{abilityName}}を トレースした!",
|
"trace": "{{pokemonName}}は 相手の {{targetName}}の\n{{abilityName}}を トレースした!",
|
||||||
"windPowerCharged": "{{pokemonName}}は\n{{moveName}}を 受けて じゅうでんした!",
|
"windPowerCharged": "{{pokemonNameWithAffix}}は\n{{moveName}}を 受けて じゅうでんした!",
|
||||||
"quickDraw": "{{pokemonName}}は クイックドロウで\n行動が はやくなった!",
|
"quickDraw": "{{pokemonName}}は クイックドロウで\n行動が はやくなった!",
|
||||||
"disguiseAvoidedDamage": "{{pokemonNameWithAffix}}の\nばけのかわが はがれた!",
|
"disguiseAvoidedDamage": "{{pokemonNameWithAffix}}の\nばけのかわが はがれた!",
|
||||||
"blockItemTheft": "{{pokemonNameWithAffix}}の {{abilityName}}で\n道具を うばわれない!",
|
"blockItemTheft": "{{pokemonNameWithAffix}}の {{abilityName}}で\n道具を うばわれない!",
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -39,5 +39,6 @@
|
||||||
"matBlock": "たたみがえし",
|
"matBlock": "たたみがえし",
|
||||||
"craftyShield": "トリックガード",
|
"craftyShield": "トリックガード",
|
||||||
"tailwind": "おいかぜ",
|
"tailwind": "おいかぜ",
|
||||||
"happyHour": "ハッピータイム"
|
"happyHour": "ハッピータイム",
|
||||||
|
"safeguard": "しんぴなまもり"
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,5 +47,11 @@
|
||||||
"tailwindOnRemovePlayer": "味方の 追い風が 止んだ!",
|
"tailwindOnRemovePlayer": "味方の 追い風が 止んだ!",
|
||||||
"tailwindOnRemoveEnemy": "相手の 追い風が 止んだ!",
|
"tailwindOnRemoveEnemy": "相手の 追い風が 止んだ!",
|
||||||
"happyHourOnAdd": "みんなが ハッピーな気分に\n包まれた!",
|
"happyHourOnAdd": "みんなが ハッピーな気分に\n包まれた!",
|
||||||
"happyHourOnRemove": "みんなの 気分が 元に戻った"
|
"happyHourOnRemove": "みんなの 気分が 元に戻った",
|
||||||
|
"safeguardOnAdd": "場の全体は 神秘のベールに 包まれた!",
|
||||||
|
"safeguardOnAddPlayer": "味方は 神秘のベールに 包まれた!",
|
||||||
|
"safeguardOnAddEnemy": "相手は 神秘のベールに 包まれた!",
|
||||||
|
"safeguardOnRemove": "場の全体を 包んでいた\n神秘のベールが なくなった!",
|
||||||
|
"safeguardOnRemovePlayer": "味方を 包んでいた\n神秘のベールが なくなった!",
|
||||||
|
"safeguardOnRemoveEnemy": "相手を 包んでいた\n神秘のベールが なくなった!"
|
||||||
}
|
}
|
|
@ -4,7 +4,7 @@
|
||||||
"trainerAppearedDouble": "{{trainerName}}が\n勝負を しかけてきた!",
|
"trainerAppearedDouble": "{{trainerName}}が\n勝負を しかけてきた!",
|
||||||
"trainerSendOut": "{{trainerName}}は\n{{pokemonName}}を 繰り出した!",
|
"trainerSendOut": "{{trainerName}}は\n{{pokemonName}}を 繰り出した!",
|
||||||
"singleWildAppeared": "あっ! 野生の {{pokemonName}}が 飛び出してきた!",
|
"singleWildAppeared": "あっ! 野生の {{pokemonName}}が 飛び出してきた!",
|
||||||
"multiWildAppeared": "あっ! 野生の {{pokemonName1}}と\n{{pokemonName2}}が 飛び出してきた!",
|
"multiWildAppeared": "あっ! 野生の {{pokemonName1}}と\n{{pokemonName2}}が 飛び出してきた!",
|
||||||
"playerComeBack": "{{pokemonName}}! 戻れ!",
|
"playerComeBack": "{{pokemonName}}! 戻れ!",
|
||||||
"trainerComeBack": "{{trainerName}}は\n{{pokemonName}}を 引っ込めた!",
|
"trainerComeBack": "{{trainerName}}は\n{{pokemonName}}を 引っ込めた!",
|
||||||
"playerGo": "ゆけっ! {{pokemonName}}!",
|
"playerGo": "ゆけっ! {{pokemonName}}!",
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
"noPokeballStrong": "相手の ポケモンが 強すぎて 捕まえられない!\nまずは 弱めよう!",
|
"noPokeballStrong": "相手の ポケモンが 強すぎて 捕まえられない!\nまずは 弱めよう!",
|
||||||
"noEscapeForce": "見えない 力の せいで\n逃げることが できない!",
|
"noEscapeForce": "見えない 力の せいで\n逃げることが できない!",
|
||||||
"noEscapeTrainer": "ダメだ! 勝負の最中に\n相手に 背中を 見せられない!",
|
"noEscapeTrainer": "ダメだ! 勝負の最中に\n相手に 背中を 見せられない!",
|
||||||
"noEscapePokemon": "{{pokemonName}}の {{moveName}}で {{escapeVerb}}!",
|
"noEscapePokemon": "{{pokemonName}}の {{moveName}}で\n{{escapeVerb}}!",
|
||||||
"runAwaySuccess": " うまく 逃げ切れた!",
|
"runAwaySuccess": " うまく 逃げ切れた!",
|
||||||
"runAwayCannotEscape": "逃げることが できない!",
|
"runAwayCannotEscape": "逃げることが できない!",
|
||||||
"escapeVerbSwitch": "入れ替えることが できない",
|
"escapeVerbSwitch": "入れ替えることが できない",
|
||||||
|
@ -62,6 +62,7 @@
|
||||||
"skipItemQuestion": "本当に アイテムを 取らずに 進みますか?",
|
"skipItemQuestion": "本当に アイテムを 取らずに 進みますか?",
|
||||||
"itemStackFull": "{{fullItemName}}の スタックが いっぱいです。\n代わりに {{itemName}}を 取得します。",
|
"itemStackFull": "{{fullItemName}}の スタックが いっぱいです。\n代わりに {{itemName}}を 取得します。",
|
||||||
"eggHatching": "おや?",
|
"eggHatching": "おや?",
|
||||||
|
"eggSkipPrompt": "タマゴは ふかします!\nタマゴまとめに 飛ばしますか?",
|
||||||
"ivScannerUseQuestion": "{{pokemonName}}を\n個体値スキャナーで 操作しますか?",
|
"ivScannerUseQuestion": "{{pokemonName}}を\n個体値スキャナーで 操作しますか?",
|
||||||
"wildPokemonWithAffix": "野生の {{pokemonName}}",
|
"wildPokemonWithAffix": "野生の {{pokemonName}}",
|
||||||
"foePokemonWithAffix": "相手の {{pokemonName}}",
|
"foePokemonWithAffix": "相手の {{pokemonName}}",
|
||||||
|
|
|
@ -1,46 +1,46 @@
|
||||||
{
|
{
|
||||||
"SITRUS": {
|
"SITRUS": {
|
||||||
"name": "オボンのみ",
|
"name": "オボンのみ",
|
||||||
"effect": "持たせると HPが 50%以下になるとき HPを 25% 回復する"
|
"effect": "持たせると HPが 50%以下に なるとき HPを 25% 回復する"
|
||||||
},
|
},
|
||||||
"LUM": {
|
"LUM": {
|
||||||
"name": "ラムのみ",
|
"name": "ラムのみ",
|
||||||
"effect": "持たせると 状態異常や 混乱になるとき 回復する\n"
|
"effect": "持たせると 状態異常や 混乱に なるとき 回復する"
|
||||||
},
|
},
|
||||||
"ENIGMA": {
|
"ENIGMA": {
|
||||||
"name": "ナゾのみ",
|
"name": "ナゾのみ",
|
||||||
"effect": "持たせると 効果バツグンの 技を 受けたとき HPを 25%回復する"
|
"effect": "持たせると 効果バツグンの 技を 受けたとき HPを 25%回復する"
|
||||||
},
|
},
|
||||||
"LIECHI": {
|
"LIECHI": {
|
||||||
"name": "チイラのみ",
|
"name": "チイラのみ",
|
||||||
"effect": "持たせると HPが 25%以下に なるとき 攻撃が あがる"
|
"effect": "持たせると HPが 25%以下に なるとき 攻撃が あがる"
|
||||||
},
|
},
|
||||||
"GANLON": {
|
"GANLON": {
|
||||||
"name": "リュガのみ",
|
"name": "リュガのみ",
|
||||||
"effect": "持たせると HPが 25%以下に なるとき 防御が あがる\n"
|
"effect": "持たせると HPが 25%以下に なるとき 防御が あがる"
|
||||||
},
|
},
|
||||||
"PETAYA": {
|
"PETAYA": {
|
||||||
"name": "ヤタピのみ",
|
"name": "ヤタピのみ",
|
||||||
"effect": "持たせると HPが 25%以下に なるとき 特攻が あがる\n"
|
"effect": "持たせると HPが 25%以下に なるとき 特攻が あがる"
|
||||||
},
|
},
|
||||||
"APICOT": {
|
"APICOT": {
|
||||||
"name": "ズアのみ",
|
"name": "ズアのみ",
|
||||||
"effect": "持たせると HPが 25%以下に なるとき 特防が あがる\n"
|
"effect": "持たせると HPが 25%以下に なるとき 特防が あがる"
|
||||||
},
|
},
|
||||||
"SALAC": {
|
"SALAC": {
|
||||||
"name": "カムラのみ",
|
"name": "カムラのみ",
|
||||||
"effect": "持たせると HPが 25%以下に なるとき 素早さが あがる"
|
"effect": "持たせると HPが 25%以下に なるとき 素早さが あがる"
|
||||||
},
|
},
|
||||||
"LANSAT": {
|
"LANSAT": {
|
||||||
"name": "サンのみ",
|
"name": "サンのみ",
|
||||||
"effect": "持たせると HPが 25%以下に なるとき 攻撃が 急所に 当たりやすくなる"
|
"effect": "持たせると HPが 25%以下に なるとき 攻撃が 急所に 当たりやすくなる"
|
||||||
},
|
},
|
||||||
"STARF": {
|
"STARF": {
|
||||||
"name": "スターのみ",
|
"name": "スターのみ",
|
||||||
"effect": "持たせると HPが 25%以下に なるとき どれか 1つの 能力が ぐーんと あがる"
|
"effect": "持たせると HPが 25%以下に なるとき どれか 1つの 能力が ぐーんと あがる"
|
||||||
},
|
},
|
||||||
"LEPPA": {
|
"LEPPA": {
|
||||||
"name": "ヒメリのみ",
|
"name": "ヒメリのみ",
|
||||||
"effect": "持たせると PPが 0になる 技のPPを 10回復する"
|
"effect": "持たせると PPが0になる 技の PPを 10回復する"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,6 @@
|
||||||
"pp": "PP",
|
"pp": "PP",
|
||||||
"power": "威力",
|
"power": "威力",
|
||||||
"accuracy": "命中",
|
"accuracy": "命中",
|
||||||
"abilityFlyInText": " {{pokemonName}}の\n{{passive}}:{{abilityName}}",
|
"abilityFlyInText": " {{pokemonName}}の\n{{passive}} {{abilityName}}",
|
||||||
"passive": "パッシブ "
|
"passive": "パッシブ "
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
"unmatchingPassword": "入力したパスワードが 一致しません",
|
"unmatchingPassword": "入力したパスワードが 一致しません",
|
||||||
"passwordNotMatchingConfirmPassword": "パスワードは パスワード確認と 一致する 必要があります",
|
"passwordNotMatchingConfirmPassword": "パスワードは パスワード確認と 一致する 必要があります",
|
||||||
"confirmPassword": "パスワード確認",
|
"confirmPassword": "パスワード確認",
|
||||||
"registrationAgeWarning": "登録では 13歳以上 であることを 確認します。",
|
"registrationAgeWarning": "登録では 13歳以上 であることを 確認します。",
|
||||||
"backToLogin": "ログインへ",
|
"backToLogin": "ログインへ",
|
||||||
"failedToLoadSaveData": "セーブデータの 読み込みは 不可能でした。ページを 再読み込み してください。\n長い間に続く 場合は 管理者に 連絡してください。",
|
"failedToLoadSaveData": "セーブデータの 読み込みは 不可能でした。ページを 再読み込み してください。\n長い間に続く 場合は 管理者に 連絡してください。",
|
||||||
"sessionSuccess": "セッションが 正常に 読み込まれました。",
|
"sessionSuccess": "セッションが 正常に 読み込まれました。",
|
||||||
|
@ -46,10 +46,10 @@
|
||||||
"yes": "はい",
|
"yes": "はい",
|
||||||
"no": "いいえ",
|
"no": "いいえ",
|
||||||
"disclaimer": "免責",
|
"disclaimer": "免責",
|
||||||
"disclaimerDescription": "このゲームは 未完成作品です。\nセーブデータの 損失を含める ゲーム性に関する 問題が 起きる可能性が あります。\nなお、ゲームは 予告なく変更される 可能性もあり、さらに更新され、完成されるとも 限りません。",
|
"disclaimerDescription": "このゲームは 未完成作品です。\nセーブデータの 損失を含める ゲーム性に関する 問題が 起きる可能性が あります。\nなお、ゲームは 予告なく変更される 可能性もあり、\nさらに更新され、完成されるとも 限りません。",
|
||||||
"choosePokemon": "ポケモンを選ぶ",
|
"choosePokemon": "ポケモンを選ぶ",
|
||||||
"renamePokemon": "ニックネームを変える",
|
"renamePokemon": "ニックネームを変える",
|
||||||
"rename": "変える",
|
"rename": "名前を変える",
|
||||||
"nickname": "ニックネーム",
|
"nickname": "ニックネーム",
|
||||||
"errorServerDown": "おや!\nサーバーとの 接続中に 問題が 発生しました。\nゲームは 自動的に 再接続されます から\nウィンドウは 開いたままに しておいても よろしいです。",
|
"errorServerDown": "おや!\nサーバーとの 接続中に 問題が 発生しました。\nゲームは 自動的に 再接続されます から\nウィンドウは 開いたままに しておいても よろしいです。",
|
||||||
"noSaves": "何の セーブファイルも ありません!",
|
"noSaves": "何の セーブファイルも ありません!",
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -4,5 +4,44 @@
|
||||||
"CANCEL": "やめる",
|
"CANCEL": "やめる",
|
||||||
"RELEASE": "逃がす",
|
"RELEASE": "逃がす",
|
||||||
"APPLY": "使う",
|
"APPLY": "使う",
|
||||||
"TEACH": "教える"
|
"TEACH": "教える",
|
||||||
|
"SPLICE": "吸収合体",
|
||||||
|
"UNSPLICE": "合体を分離",
|
||||||
|
"ACTIVATE": "有効にする",
|
||||||
|
"DEACTIVATE": "無効にする",
|
||||||
|
"TRANSFER": "アイテムを移動",
|
||||||
|
"ALL": "全部",
|
||||||
|
"PASS_BATON": "バトンタッチ",
|
||||||
|
"UNPAUSE_EVOLUTION": "進化を有効にする",
|
||||||
|
"REVIVE": "復活する",
|
||||||
|
"RENAME": "名前を変える",
|
||||||
|
"choosePokemon": "ポケモンを 選んで ください。",
|
||||||
|
"doWhatWithThisPokemon": "このポケモンを どうする?",
|
||||||
|
"noEnergy": "{{pokemonName}}は 戦うための\n元気が 残っていません!",
|
||||||
|
"hasEnergy": "{{pokemonName}}は まだまだ 元気だ!",
|
||||||
|
"cantBeUsed": "{{pokemonName}}は このチャレンジで\n使えられません!",
|
||||||
|
"tooManyItems": "{{pokemonName}}は このアイテムが\nこれ以上 持ちきれない!",
|
||||||
|
"anyEffect": "使っても 効果がないよ",
|
||||||
|
"unpausedEvolutions": "{{pokemonName}}は また 進化できる。",
|
||||||
|
"unspliceConfirmation": "本当に {{pokemonName}}を {{fusionName}}から\n分離しますか? {{fusionName}}は なくなる。",
|
||||||
|
"wasReverted": "{{fusionName}}は {{pokemonName}}に 回帰した。",
|
||||||
|
"releaseConfirmation": "本当に {{pokemonName}}を 逃がしますか?",
|
||||||
|
"releaseInBattle": "戦闘中の ポケモンを\n逃がすことは できません!",
|
||||||
|
"selectAMove": "技を 選んでください。",
|
||||||
|
"changeQuantity": "移動する アイテムを 選んでください。\n< と > で 数量が 変えられる。",
|
||||||
|
"selectAnotherPokemonToSplice": "もう一つの ポケモンを 選んで 合体する。",
|
||||||
|
"cancel": "キャンセル",
|
||||||
|
"able": "可能",
|
||||||
|
"notAble": "不可能",
|
||||||
|
"learned": "覚えている",
|
||||||
|
"goodbye": "グッバイ {{pokemonName}}!",
|
||||||
|
"byebye": "ばいばい {{pokemonName}}!",
|
||||||
|
"farewell": "さようなら {{pokemonName}}!",
|
||||||
|
"soLong": "じゃあね {{pokemonName}}!",
|
||||||
|
"thisIsWhereWePart": "これでお別れだね {{pokemonName}}!",
|
||||||
|
"illMissYou": "恋しく思うよ {{pokemonName}}!",
|
||||||
|
"illNeverForgetYou": "一生忘れない {{pokemonName}}!",
|
||||||
|
"untilWeMeetAgain": "また出会える日まで、{{pokemonName}}!",
|
||||||
|
"sayonara": "さらば {{pokemonName}}!",
|
||||||
|
"smellYaLater": "そんじゃ あばよ {{pokemonName}}!"
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
"normal": "普通",
|
"normal": "普通",
|
||||||
"fast": "早い",
|
"fast": "早い",
|
||||||
"faster": "とても早い",
|
"faster": "とても早い",
|
||||||
"skip": "スキップ",
|
"skip": "飛ばす",
|
||||||
"levelUpNotifications": "レベルアップ時のみ",
|
"levelUpNotifications": "レベルアップ時のみ",
|
||||||
"on": "オン",
|
"on": "オン",
|
||||||
"off": "オフ",
|
"off": "オフ",
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
"manageNature": "性格を変える",
|
"manageNature": "性格を変える",
|
||||||
"addToFavorites": "お気に入りにする",
|
"addToFavorites": "お気に入りにする",
|
||||||
"removeFromFavorites": "お気に入りから除く",
|
"removeFromFavorites": "お気に入りから除く",
|
||||||
"useCandies": "飴を使う",
|
"useCandies": "アメを使う",
|
||||||
"selectNature": "性格を選んでください。",
|
"selectNature": "性格を選んでください。",
|
||||||
"selectMoveSwapOut": "入れ替えたい技を選んでください。",
|
"selectMoveSwapOut": "入れ替えたい技を選んでください。",
|
||||||
"selectMoveSwapWith": "他の技と交換してください。",
|
"selectMoveSwapWith": "他の技と交換してください。",
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
{
|
{
|
||||||
"intro": "PokéRogueへようこそ!ログライク要素が\n加わったバトル中心のポケモンファンゲームです。\n$このゲームは収益を上げず、Pokémonおよび使用される\n著作権資産に対する所有権を主張しません。\n$ゲームはまだ作業中ですが、完全にプレイすることができます。\nバグ報告はディスコードコミュニティをご利用ください。\n$ゲームが遅い場合は、ブラウザ設定で「ハードウェア\nアクセラレーション」がオンになっていることを確認してください",
|
"intro": "PokéRogueへ ようこそ! ローグライク要素が\n加わった バトル中心の ポケモンファンゲームです。\n$このゲームは 収益を上げず、Pokémonおよび 使用される\n著作権資産に 対する所有権を 主張しません。\n$ゲームは まだ開発中ですが、完全に プレイすることが できます。\nバグ報告は ディスコードコミュニティを ご利用ください。\n$ゲームが 遅い場合は、ブラウザ設定で「ハードウェア\nアクセラレーション」が オンになっている ことを 確認してください。",
|
||||||
"accessMenu": "メニューにアクセスするには、入力待ちの間にMキーまたはEscを押してください。\nメニューには設定やさまざまな機能が含まれています。",
|
"accessMenu": "メニューを開くには 入力待ちの間に Mキー/Escを 押してください。\nメニューには 設定や 様々な機能が 含まれています。",
|
||||||
"menu": "このメニューから設定にアクセスできます。\n$設定ではゲームスピード、ウィンドウスタイル、\nおよびその他のオプションを変更できます。\n$ここにはさまざまな他の機能もありますので、\nぜひ確認してみてください!",
|
"menu": "このメニューから 設定が 開けます。\n$設定では、ゲームの速さや ウィンドウタイプなどの オプションを 変更できます。\n$ここには 様々な機能が ありますので、\nぜひ 確認してみてください!",
|
||||||
"starterSelect": "この画面でZキーやSpaceを押してポケモンを選択できます。\n選んだポケモンは自分の最初のパーティーになります。\n$最大6匹のパーティーで始めることができますが\nポケモンによってポイントがあり、合計10を超えてはなりません。\n$捕まえたりふかさせたりすることで\n選択できる性別、特性、フォルムなどの幅を広げることができます。\n$個体値も徐々に累積して高くなるので、\n同じポケモンをたくさん捕まえてみてください!",
|
"starterSelect": "この画面では Zキー/空白キーを押して ポケモンが 選択できます。\n選んだポケモンは 最初の手持ちに なります。\n$各ポケモンは ポイントが ある。最大6つを 選べますが\nポケモンのポイントが 合計10を超えては いけません。\n$ポケモンを 捕まえたり タマゴからふかしたり することで\n選択できる 性別、特性、フォルムなどの 幅を広げられます。\n$個体値も 徐々に 累積して 高くなるので、\n同じポケモンを たくさん 捕まえて みてください!",
|
||||||
"pokerus": "毎日ランダムでスターターの\n3種類に紫色の枠が表示されます。\n$登録されたスターターの中にあれば、\nパーティに追加してつよさを確認してみましょう!",
|
"pokerus": "毎日、無作為に スターターの\n3種類には 紫色の枠が 表示されます。\n$登録された スターターの 中に いれば、\n手持ちに加えて 強さを 確認してみましょう!",
|
||||||
"statChange": "ポケモンは交代しない限り、\n次のバトルでも能力変化が維持されます。\n$その代わりに、トレーナーバトルや新しいバイオームに\n入る直前に自動的にリセットされます。\n$CキーまたはShiftキーを押し続けると、\n現在のポケモンの能力変化を確認できます。\n$Vキーを押すと、\n相手が使用した技も確認できます。\n$ただし、今のバトルで相手ポケモンがすでに\n使った技のみが表示されます。",
|
"statChange": "ポケモンを 入れ替えない限り、\n次のバトルでも 能力変化は なくなりません。\n$その代わりに、トレーナーバトルや 新しいバイオームに\n入る直前に 自動的に 能力変化は 元に戻ります。\n$Cキー/Shiftキーを 押し続けると、\n場にいるポケモンの 能力変化を 確認できます。\n$Vキーを押すと、\n相手が出した技も 確認できます。\n$ただし、現在のバトルでの 相手ポケモンが\nすでに使った 技のみが 表示されます。",
|
||||||
"selectItem": "バトルが終わるたびに、\nランダムなアイテム3つの中から1つを選んで獲得します。\n$種類は消耗品、ポケモンの持ち物、\n永続的なパッシブアイテムなど様々です。\n$ほとんどの消耗しない道具は\n効果が累積されます。\n$進化用など一部のアイテムは\n使用できる場合にのみ登場します。\n$持ち物を渡す機能を使用して\nポケモン同士で道具を持たせることもできます。\n$持ち物があれば、アイテム選択画面の\n右下に渡す機能が表示されます。\n$お金で消耗品を購入することもでき、\nウェーブが進むにつれて購入可能な種類が増えます。\n$アイテムを選択すると次のウェーブに進むため、\nまず消耗品の購入を行ってください。",
|
"selectItem": "バトルが 終わるたびには、「ショップ」という\n画面で 3つのご褒美から 1つが選べます。\n$種類は 消耗品、ポケモンの持ち物や道具、\n永続的な パッシブアイテムなど 様々です。\n$ほとんどの 消耗しない 道具は\n効果が 累積されます。\n$例えば 進化アイテムなどの ご褒美は\n使用できる 場合にのみ 登場します。\n$持ち物や道具が\n手持ちポケモン間に 移動できる\n$持ち物や道具が あれば、ショップ画面の\n右下に「アイテム移行」が 表示されます。\n$ショップ画面で お金で 消耗品を 買えます。\nラウンドが 進むにつれて 買えるアイテムが 増えます。\n$ご褒美を 選択すると 次のラウンドに\n進むから、まず 消耗品を 買ってください。",
|
||||||
"eggGacha": "この画面でポケモンのたまごクーポンを\nガチャができます。\n$卵は戦闘を繰り返すうちにふかします。\n珍しいほどもっと長くかかります。\n$ふかさせたポケモンはパーティーに追加されず、\nスターティングに登録されます。\n$卵からふかしたポケモンは一般的に\n野生で捕まえたポケモンよりも高い個体値を持ちます。\n$一部のポケモンは卵からしか手に入りません。\n$各ガチャマシンがそれぞれ異なるボーナスを持っているため、\n好きな方を使ってみてください!,"
|
"eggGacha": "この画面では、「タマゴクーポン」で\nポケモンのタマゴを 取得できます。\n$タマゴは ラウンドが進めるうちに ふかします。\nタマゴのふかは レア度によって 時間が かかります。\n$ふかしたポケモンは 手持ちに 加えられず、\nスターターに 登録されます。\n$ふかしたポケモンは 一般的に\n野生ポケモンよりも 高い個体値があります。\n$あるポケモンは タマゴからしか 手に入りません。\n$各ガチャマシンは 個性的なボーナスが あるますから、\n好きな方から 引いてみてください!,"
|
||||||
}
|
}
|
|
@ -12,6 +12,7 @@
|
||||||
"blockItemTheft": "{{abilityName}} de {{pokemonNameWithAffix}}\nprevine o roubo de itens!",
|
"blockItemTheft": "{{abilityName}} de {{pokemonNameWithAffix}}\nprevine o roubo de itens!",
|
||||||
"typeImmunityHeal": "{{abilityName}} de {{pokemonNameWithAffix}}\nrestaurou um pouco de PS!",
|
"typeImmunityHeal": "{{abilityName}} de {{pokemonNameWithAffix}}\nrestaurou um pouco de PS!",
|
||||||
"nonSuperEffectiveImmunity": "{{pokemonNameWithAffix}} evitou dano\ncom {{abilityName}}!",
|
"nonSuperEffectiveImmunity": "{{pokemonNameWithAffix}} evitou dano\ncom {{abilityName}}!",
|
||||||
|
"fullHpResistType": "{{pokemonNameWithAffix}} fez seu casco brilhar!\nEstá distorcendo o confronte de tipos!",
|
||||||
"moveImmunity": "Isso não afeta {{pokemonNameWithAffix}}!",
|
"moveImmunity": "Isso não afeta {{pokemonNameWithAffix}}!",
|
||||||
"reverseDrain": "{{pokemonNameWithAffix}} absorveu a gosma líquida!",
|
"reverseDrain": "{{pokemonNameWithAffix}} absorveu a gosma líquida!",
|
||||||
"postDefendTypeChange": "{{abilityName}} de {{pokemonNameWithAffix}}\ntransformou-o no tipo {{typeName}}!",
|
"postDefendTypeChange": "{{abilityName}} de {{pokemonNameWithAffix}}\ntransformou-o no tipo {{typeName}}!",
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
"moveNotImplemented": "{{moveName}} ainda não foi implementado e não pode ser usado.",
|
"moveNotImplemented": "{{moveName}} ainda não foi implementado e não pode ser usado.",
|
||||||
"moveNoPP": "Não há mais PP\npara esse movimento!",
|
"moveNoPP": "Não há mais PP\npara esse movimento!",
|
||||||
"moveDisabled": "Não se pode usar {{moveName}} porque foi desabilitado!",
|
"moveDisabled": "Não se pode usar {{moveName}} porque foi desabilitado!",
|
||||||
|
"disableInterruptedMove": "{{moveName}} de {{pokemonNameWithAffix}}\nestá desabilitado!",
|
||||||
"noPokeballForce": "Uma força misteriosa\nte impede de usar Poké Bolas.",
|
"noPokeballForce": "Uma força misteriosa\nte impede de usar Poké Bolas.",
|
||||||
"noPokeballTrainer": "Não se pode capturar\nPokémon dos outros!",
|
"noPokeballTrainer": "Não se pode capturar\nPokémon dos outros!",
|
||||||
"noPokeballMulti": "Não se pode lançar Poké Bolas\nquando há mais de um Pokémon!",
|
"noPokeballMulti": "Não se pode lançar Poké Bolas\nquando há mais de um Pokémon!",
|
||||||
|
@ -61,6 +62,7 @@
|
||||||
"skipItemQuestion": "Tem certeza de que não quer escolher um item?",
|
"skipItemQuestion": "Tem certeza de que não quer escolher um item?",
|
||||||
"itemStackFull": "O estoque de {{fullItemName}} está cheio.\nVocê receberá {{itemName}} no lugar.",
|
"itemStackFull": "O estoque de {{fullItemName}} está cheio.\nVocê receberá {{itemName}} no lugar.",
|
||||||
"eggHatching": "Opa?",
|
"eggHatching": "Opa?",
|
||||||
|
"eggSkipPrompt": "Pular para súmario de ovos?",
|
||||||
"ivScannerUseQuestion": "Quer usar o Scanner de IVs em {{pokemonName}}?",
|
"ivScannerUseQuestion": "Quer usar o Scanner de IVs em {{pokemonName}}?",
|
||||||
"wildPokemonWithAffix": "{{pokemonName}} selvagem",
|
"wildPokemonWithAffix": "{{pokemonName}} selvagem",
|
||||||
"foePokemonWithAffix": "{{pokemonName}} adversário",
|
"foePokemonWithAffix": "{{pokemonName}} adversário",
|
||||||
|
@ -89,7 +91,7 @@
|
||||||
"statSeverelyFell_other": "{{stats}} de {{pokemonNameWithAffix}} diminuíram severamente!",
|
"statSeverelyFell_other": "{{stats}} de {{pokemonNameWithAffix}} diminuíram severamente!",
|
||||||
"statWontGoAnyLower_one": "{{stats}} de {{pokemonNameWithAffix}} não vai mais diminuir!",
|
"statWontGoAnyLower_one": "{{stats}} de {{pokemonNameWithAffix}} não vai mais diminuir!",
|
||||||
"statWontGoAnyLower_other": "{{stats}} de {{pokemonNameWithAffix}} não vão mais diminuir!",
|
"statWontGoAnyLower_other": "{{stats}} de {{pokemonNameWithAffix}} não vão mais diminuir!",
|
||||||
"transformedIntoType": "{{pokemonName}} transformed\ninto the {{type}} type!",
|
"transformedIntoType": "{{pokemonName}} se transformou\nno tipo {{type}}!",
|
||||||
"ppReduced": "O PP do movimento {{moveName}} de\n{{targetName}} foi reduzido em {{reduction}}!",
|
"ppReduced": "O PP do movimento {{moveName}} de\n{{targetName}} foi reduzido em {{reduction}}!",
|
||||||
"retryBattle": "Você gostaria de tentar novamente desde o início da batalha?",
|
"retryBattle": "Você gostaria de tentar novamente desde o início da batalha?",
|
||||||
"unlockedSomething": "{{unlockedThing}}\nfoi desbloqueado.",
|
"unlockedSomething": "{{unlockedThing}}\nfoi desbloqueado.",
|
||||||
|
|
|
@ -67,5 +67,7 @@
|
||||||
"saltCuredLapse": "{{pokemonNameWithAffix}} foi ferido pelo {{moveName}}!",
|
"saltCuredLapse": "{{pokemonNameWithAffix}} foi ferido pelo {{moveName}}!",
|
||||||
"cursedOnAdd": "{{pokemonNameWithAffix}} cortou seus PS pela metade e amaldiçoou {{pokemonName}}!",
|
"cursedOnAdd": "{{pokemonNameWithAffix}} cortou seus PS pela metade e amaldiçoou {{pokemonName}}!",
|
||||||
"cursedLapse": "{{pokemonNameWithAffix}} foi ferido pelo Curse!",
|
"cursedLapse": "{{pokemonNameWithAffix}} foi ferido pelo Curse!",
|
||||||
"stockpilingOnAdd": "{{pokemonNameWithAffix}} estocou {{stockpiledCount}}!"
|
"stockpilingOnAdd": "{{pokemonNameWithAffix}} estocou {{stockpiledCount}}!",
|
||||||
|
"disabledOnAdd": "{{moveName}} de {{pokemonNameWithAffix}}\nfoi desabilitado!",
|
||||||
|
"disabledLapse": "{{moveName}} de {{pokemonNameWithAffix}}\nnão está mais desabilitado."
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"title": "Desafios",
|
"title": "Desafios",
|
||||||
"illegalEvolution": "{{pokemon}} não pode ser escolhido\nnesse desafio!",
|
"illegalEvolution": "{{pokemon}} não pode ser escolhido\nnesse desafio!",
|
||||||
|
"noneSelected": "Nada Selecionado",
|
||||||
"singleGeneration": {
|
"singleGeneration": {
|
||||||
"name": "Geração Única",
|
"name": "Geração Única",
|
||||||
"desc": "Você só pode user Pokémon da {{gen}} geração.",
|
"desc": "Você só pode user Pokémon da {{gen}} geração.",
|
||||||
|
|
|
@ -98,7 +98,7 @@ class DefaultOverrides {
|
||||||
readonly PASSIVE_ABILITY_OVERRIDE: Abilities = Abilities.NONE;
|
readonly PASSIVE_ABILITY_OVERRIDE: Abilities = Abilities.NONE;
|
||||||
readonly STATUS_OVERRIDE: StatusEffect = StatusEffect.NONE;
|
readonly STATUS_OVERRIDE: StatusEffect = StatusEffect.NONE;
|
||||||
readonly GENDER_OVERRIDE: Gender | null = null;
|
readonly GENDER_OVERRIDE: Gender | null = null;
|
||||||
readonly MOVESET_OVERRIDE: Array<Moves> = [];
|
readonly MOVESET_OVERRIDE: Moves | Array<Moves> = [];
|
||||||
readonly SHINY_OVERRIDE: boolean = false;
|
readonly SHINY_OVERRIDE: boolean = false;
|
||||||
readonly VARIANT_OVERRIDE: Variant = 0;
|
readonly VARIANT_OVERRIDE: Variant = 0;
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ class DefaultOverrides {
|
||||||
readonly OPP_PASSIVE_ABILITY_OVERRIDE: Abilities = Abilities.NONE;
|
readonly OPP_PASSIVE_ABILITY_OVERRIDE: Abilities = Abilities.NONE;
|
||||||
readonly OPP_STATUS_OVERRIDE: StatusEffect = StatusEffect.NONE;
|
readonly OPP_STATUS_OVERRIDE: StatusEffect = StatusEffect.NONE;
|
||||||
readonly OPP_GENDER_OVERRIDE: Gender | null = null;
|
readonly OPP_GENDER_OVERRIDE: Gender | null = null;
|
||||||
readonly OPP_MOVESET_OVERRIDE: Array<Moves> = [];
|
readonly OPP_MOVESET_OVERRIDE: Moves | Array<Moves> = [];
|
||||||
readonly OPP_SHINY_OVERRIDE: boolean = false;
|
readonly OPP_SHINY_OVERRIDE: boolean = false;
|
||||||
readonly OPP_VARIANT_OVERRIDE: Variant = 0;
|
readonly OPP_VARIANT_OVERRIDE: Variant = 0;
|
||||||
readonly OPP_IVS_OVERRIDE: number | number[] = [];
|
readonly OPP_IVS_OVERRIDE: number | number[] = [];
|
||||||
|
|
|
@ -221,8 +221,8 @@ export class AttemptCapturePhase extends PokemonPhase {
|
||||||
this.scene.clearEnemyHeldItemModifiers();
|
this.scene.clearEnemyHeldItemModifiers();
|
||||||
this.scene.field.remove(pokemon, true);
|
this.scene.field.remove(pokemon, true);
|
||||||
};
|
};
|
||||||
const addToParty = () => {
|
const addToParty = (slotIndex?: number) => {
|
||||||
const newPokemon = pokemon.addToParty(this.pokeballType);
|
const newPokemon = pokemon.addToParty(this.pokeballType, slotIndex);
|
||||||
const modifiers = this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier, false);
|
const modifiers = this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier, false);
|
||||||
if (this.scene.getParty().filter(p => p.isShiny()).length === 6) {
|
if (this.scene.getParty().filter(p => p.isShiny()).length === 6) {
|
||||||
this.scene.validateAchv(achvs.SHINY_PARTY);
|
this.scene.validateAchv(achvs.SHINY_PARTY);
|
||||||
|
@ -253,7 +253,7 @@ export class AttemptCapturePhase extends PokemonPhase {
|
||||||
this.scene.ui.setMode(Mode.PARTY, PartyUiMode.RELEASE, this.fieldIndex, (slotIndex: integer, _option: PartyOption) => {
|
this.scene.ui.setMode(Mode.PARTY, PartyUiMode.RELEASE, this.fieldIndex, (slotIndex: integer, _option: PartyOption) => {
|
||||||
this.scene.ui.setMode(Mode.MESSAGE).then(() => {
|
this.scene.ui.setMode(Mode.MESSAGE).then(() => {
|
||||||
if (slotIndex < 6) {
|
if (slotIndex < 6) {
|
||||||
addToParty();
|
addToParty(slotIndex);
|
||||||
} else {
|
} else {
|
||||||
promptRelease();
|
promptRelease();
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,8 @@ export class FaintPhase extends PokemonPhase {
|
||||||
if (pokemon.turnData?.attacksReceived?.length) {
|
if (pokemon.turnData?.attacksReceived?.length) {
|
||||||
const lastAttack = pokemon.turnData.attacksReceived[0];
|
const lastAttack = pokemon.turnData.attacksReceived[0];
|
||||||
applyPostFaintAbAttrs(PostFaintAbAttr, pokemon, this.scene.getPokemonById(lastAttack.sourceId)!, new PokemonMove(lastAttack.move).getMove(), lastAttack.result); // TODO: is this bang correct?
|
applyPostFaintAbAttrs(PostFaintAbAttr, pokemon, this.scene.getPokemonById(lastAttack.sourceId)!, new PokemonMove(lastAttack.move).getMove(), lastAttack.result); // TODO: is this bang correct?
|
||||||
|
} else { //If killed by indirect damage, apply post-faint abilities without providing a last move
|
||||||
|
applyPostFaintAbAttrs(PostFaintAbAttr, pokemon);
|
||||||
}
|
}
|
||||||
|
|
||||||
const alivePlayField = this.scene.getField(true);
|
const alivePlayField = this.scene.getField(true);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import BattleScene from "#app/battle-scene";
|
import BattleScene from "#app/battle-scene";
|
||||||
import { initMoveAnim, loadMoveAnimAssets } from "#app/data/battle-anims";
|
import { initMoveAnim, loadMoveAnimAssets } from "#app/data/battle-anims";
|
||||||
import { allMoves } from "#app/data/move";
|
import Move, { allMoves } from "#app/data/move";
|
||||||
import { SpeciesFormChangeMoveLearnedTrigger } from "#app/data/pokemon-forms";
|
import { SpeciesFormChangeMoveLearnedTrigger } from "#app/data/pokemon-forms";
|
||||||
import { Moves } from "#app/enums/moves";
|
import { Moves } from "#app/enums/moves";
|
||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
|
@ -9,14 +9,15 @@ import { SummaryUiMode } from "#app/ui/summary-ui-handler";
|
||||||
import { Mode } from "#app/ui/ui";
|
import { Mode } from "#app/ui/ui";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { PlayerPartyMemberPokemonPhase } from "./player-party-member-pokemon-phase";
|
import { PlayerPartyMemberPokemonPhase } from "./player-party-member-pokemon-phase";
|
||||||
|
import Pokemon from "#app/field/pokemon";
|
||||||
|
|
||||||
export class LearnMovePhase extends PlayerPartyMemberPokemonPhase {
|
export class LearnMovePhase extends PlayerPartyMemberPokemonPhase {
|
||||||
private moveId: Moves;
|
private moveId: Moves;
|
||||||
|
private messageMode: Mode;
|
||||||
private fromTM: boolean;
|
private fromTM: boolean;
|
||||||
|
|
||||||
constructor(scene: BattleScene, partyMemberIndex: integer, moveId: Moves, fromTM?: boolean) {
|
constructor(scene: BattleScene, partyMemberIndex: integer, moveId: Moves, fromTM?: boolean) {
|
||||||
super(scene, partyMemberIndex);
|
super(scene, partyMemberIndex);
|
||||||
|
|
||||||
this.moveId = moveId;
|
this.moveId = moveId;
|
||||||
this.fromTM = fromTM ?? false;
|
this.fromTM = fromTM ?? false;
|
||||||
}
|
}
|
||||||
|
@ -26,87 +27,128 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase {
|
||||||
|
|
||||||
const pokemon = this.getPokemon();
|
const pokemon = this.getPokemon();
|
||||||
const move = allMoves[this.moveId];
|
const move = allMoves[this.moveId];
|
||||||
|
const currentMoveset = pokemon.getMoveset();
|
||||||
|
|
||||||
const existingMoveIndex = pokemon.getMoveset().findIndex(m => m?.moveId === move.id);
|
// The game first checks if the Pokemon already has the move and ends the phase if it does.
|
||||||
|
const hasMoveAlready = currentMoveset.some(m => m?.moveId === move.id) && this.moveId !== Moves.SKETCH;
|
||||||
if (existingMoveIndex > -1) {
|
if (hasMoveAlready) {
|
||||||
return this.end();
|
return this.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
const emptyMoveIndex = pokemon.getMoveset().length < 4
|
this.messageMode = this.scene.ui.getHandler() instanceof EvolutionSceneHandler ? Mode.EVOLUTION_SCENE : Mode.MESSAGE;
|
||||||
? pokemon.getMoveset().length
|
this.scene.ui.setMode(this.messageMode);
|
||||||
: pokemon.getMoveset().findIndex(m => m === null);
|
// If the Pokemon has less than 4 moves, the new move is added to the largest empty moveset index
|
||||||
|
// If it has 4 moves, the phase then checks if the player wants to replace the move itself.
|
||||||
const messageMode = this.scene.ui.getHandler() instanceof EvolutionSceneHandler
|
if (currentMoveset.length < 4) {
|
||||||
? Mode.EVOLUTION_SCENE
|
this.learnMove(currentMoveset.length, move, pokemon);
|
||||||
: Mode.MESSAGE;
|
|
||||||
|
|
||||||
if (emptyMoveIndex > -1) {
|
|
||||||
pokemon.setMove(emptyMoveIndex, this.moveId);
|
|
||||||
if (this.fromTM) {
|
|
||||||
pokemon.usedTMs.push(this.moveId);
|
|
||||||
}
|
|
||||||
initMoveAnim(this.scene, this.moveId).then(() => {
|
|
||||||
loadMoveAnimAssets(this.scene, [this.moveId], true)
|
|
||||||
.then(() => {
|
|
||||||
this.scene.ui.setMode(messageMode).then(() => {
|
|
||||||
// Sound loaded into game as is
|
|
||||||
this.scene.playSound("level_up_fanfare");
|
|
||||||
this.scene.ui.showText(i18next.t("battle:learnMove", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name }), null, () => {
|
|
||||||
this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeMoveLearnedTrigger, true);
|
|
||||||
this.end();
|
|
||||||
}, messageMode === Mode.EVOLUTION_SCENE ? 1000 : null, true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
this.scene.ui.setMode(messageMode).then(() => {
|
this.replaceMoveCheck(move, pokemon);
|
||||||
this.scene.ui.showText(i18next.t("battle:learnMovePrompt", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name }), null, () => {
|
}
|
||||||
this.scene.ui.showText(i18next.t("battle:learnMoveLimitReached", { pokemonName: getPokemonNameWithAffix(pokemon) }), null, () => {
|
}
|
||||||
this.scene.ui.showText(i18next.t("battle:learnMoveReplaceQuestion", { moveName: move.name }), null, () => {
|
|
||||||
const noHandler = () => {
|
/**
|
||||||
this.scene.ui.setMode(messageMode).then(() => {
|
* This displays a chain of messages (listed below) and asks if the user wishes to forget a move.
|
||||||
this.scene.ui.showText(i18next.t("battle:learnMoveStopTeaching", { moveName: move.name }), null, () => {
|
*
|
||||||
this.scene.ui.setModeWithoutClear(Mode.CONFIRM, () => {
|
* > [Pokemon] wants to learn the move [MoveName]
|
||||||
this.scene.ui.setMode(messageMode);
|
* > However, [Pokemon] already knows four moves.
|
||||||
this.scene.ui.showText(i18next.t("battle:learnMoveNotLearned", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name }), null, () => this.end(), null, true);
|
* > Should a move be forgotten and replaced with [MoveName]? --> `Mode.CONFIRM` -> Yes: Go to `this.forgetMoveProcess()`, No: Go to `this.rejectMoveAndEnd()`
|
||||||
}, () => {
|
* @param move The Move to be learned
|
||||||
this.scene.ui.setMode(messageMode);
|
* @param Pokemon The Pokemon learning the move
|
||||||
this.scene.unshiftPhase(new LearnMovePhase(this.scene, this.partyMemberIndex, this.moveId));
|
*/
|
||||||
this.end();
|
async replaceMoveCheck(move: Move, pokemon: Pokemon) {
|
||||||
});
|
const learnMovePrompt = i18next.t("battle:learnMovePrompt", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name });
|
||||||
});
|
const moveLimitReached = i18next.t("battle:learnMoveLimitReached", { pokemonName: getPokemonNameWithAffix(pokemon) });
|
||||||
});
|
const shouldReplaceQ = i18next.t("battle:learnMoveReplaceQuestion", { moveName: move.name });
|
||||||
};
|
const preQText = [learnMovePrompt, moveLimitReached].join("$");
|
||||||
this.scene.ui.setModeWithoutClear(Mode.CONFIRM, () => {
|
await this.scene.ui.showTextPromise(preQText);
|
||||||
this.scene.ui.setMode(messageMode);
|
await this.scene.ui.showTextPromise(shouldReplaceQ, undefined, false);
|
||||||
this.scene.ui.showText(i18next.t("battle:learnMoveForgetQuestion"), null, () => {
|
await this.scene.ui.setModeWithoutClear(Mode.CONFIRM,
|
||||||
this.scene.ui.setModeWithoutClear(Mode.SUMMARY, this.getPokemon(), SummaryUiMode.LEARN_MOVE, move, (moveIndex: integer) => {
|
() => this.forgetMoveProcess(move, pokemon), // Yes
|
||||||
|
() => { // No
|
||||||
|
this.scene.ui.setMode(this.messageMode);
|
||||||
|
this.rejectMoveAndEnd(move, pokemon);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This facilitates the process in which an old move is chosen to be forgotten.
|
||||||
|
*
|
||||||
|
* > Which move should be forgotten?
|
||||||
|
*
|
||||||
|
* The game then goes `Mode.SUMMARY` to select a move to be forgotten.
|
||||||
|
* If a player does not select a move or chooses the new move (`moveIndex === 4`), the game goes to `this.rejectMoveAndEnd()`.
|
||||||
|
* If an old move is selected, the function then passes the `moveIndex` to `this.learnMove()`
|
||||||
|
* @param move The Move to be learned
|
||||||
|
* @param Pokemon The Pokemon learning the move
|
||||||
|
*/
|
||||||
|
async forgetMoveProcess(move: Move, pokemon: Pokemon) {
|
||||||
|
this.scene.ui.setMode(this.messageMode);
|
||||||
|
await this.scene.ui.showTextPromise(i18next.t("battle:learnMoveForgetQuestion"), undefined, true);
|
||||||
|
await this.scene.ui.setModeWithoutClear(Mode.SUMMARY, pokemon, SummaryUiMode.LEARN_MOVE, move, (moveIndex: integer) => {
|
||||||
if (moveIndex === 4) {
|
if (moveIndex === 4) {
|
||||||
noHandler();
|
this.scene.ui.setMode(this.messageMode).then(() => this.rejectMoveAndEnd(move, pokemon));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.scene.ui.setMode(messageMode).then(() => {
|
const forgetSuccessText = i18next.t("battle:learnMoveForgetSuccess", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: pokemon.moveset[moveIndex]!.getName() });
|
||||||
this.scene.ui.showText(i18next.t("battle:countdownPoof"), null, () => {
|
const fullText = [i18next.t("battle:countdownPoof"), forgetSuccessText, i18next.t("battle:learnMoveAnd")].join("$");
|
||||||
this.scene.ui.showText(i18next.t("battle:learnMoveForgetSuccess", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: pokemon.moveset[moveIndex]!.getName() }), null, () => { // TODO: is the bang correct?
|
this.scene.ui.setMode(this.messageMode).then(() => this.learnMove(moveIndex, move, pokemon, fullText));
|
||||||
this.scene.ui.showText(i18next.t("battle:learnMoveAnd"), null, () => {
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This asks the player if they wish to end the current move learning process.
|
||||||
|
*
|
||||||
|
* > Stop trying to teach [MoveName]? --> `Mode.CONFIRM` --> Yes: > [Pokemon] did not learn the move [MoveName], No: `this.replaceMoveCheck()`
|
||||||
|
*
|
||||||
|
* If the player wishes to not teach the Pokemon the move, it displays a message and ends the phase.
|
||||||
|
* If the player reconsiders, it repeats the process for a Pokemon with a full moveset once again.
|
||||||
|
* @param move The Move to be learned
|
||||||
|
* @param Pokemon The Pokemon learning the move
|
||||||
|
*/
|
||||||
|
async rejectMoveAndEnd(move: Move, pokemon: Pokemon) {
|
||||||
|
await this.scene.ui.showTextPromise(i18next.t("battle:learnMoveStopTeaching", { moveName: move.name }), undefined, false);
|
||||||
|
this.scene.ui.setModeWithoutClear(Mode.CONFIRM,
|
||||||
|
() => {
|
||||||
|
this.scene.ui.setMode(this.messageMode);
|
||||||
|
this.scene.ui.showTextPromise(i18next.t("battle:learnMoveNotLearned", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name }), undefined, true).then(() => this.end());
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
this.scene.ui.setMode(this.messageMode);
|
||||||
|
this.replaceMoveCheck(move, pokemon);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This teaches the Pokemon the new move and ends the phase.
|
||||||
|
* When a Pokemon forgets a move and learns a new one, its 'Learn Move' message is significantly longer.
|
||||||
|
*
|
||||||
|
* Pokemon with a `moveset.length < 4`
|
||||||
|
* > [Pokemon] learned [MoveName]
|
||||||
|
*
|
||||||
|
* Pokemon with a `moveset.length > 4`
|
||||||
|
* > 1... 2... and 3... and Poof!
|
||||||
|
* > [Pokemon] forgot how to use [MoveName]
|
||||||
|
* > And...
|
||||||
|
* > [Pokemon] learned [MoveName]!
|
||||||
|
* @param move The Move to be learned
|
||||||
|
* @param Pokemon The Pokemon learning the move
|
||||||
|
*/
|
||||||
|
async learnMove(index: number, move: Move, pokemon: Pokemon, textMessage?: string) {
|
||||||
if (this.fromTM) {
|
if (this.fromTM) {
|
||||||
pokemon.usedTMs.push(this.moveId);
|
pokemon.usedTMs.push(this.moveId);
|
||||||
}
|
}
|
||||||
pokemon.setMove(moveIndex, Moves.NONE);
|
pokemon.setMove(index, this.moveId);
|
||||||
this.scene.unshiftPhase(new LearnMovePhase(this.scene, this.partyMemberIndex, this.moveId));
|
initMoveAnim(this.scene, this.moveId).then(() => {
|
||||||
|
loadMoveAnimAssets(this.scene, [this.moveId], true);
|
||||||
|
this.scene.playSound("level_up_fanfare"); // Sound loaded into game as is
|
||||||
|
});
|
||||||
|
this.scene.ui.setMode(this.messageMode);
|
||||||
|
const learnMoveText = i18next.t("battle:learnMove", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name });
|
||||||
|
textMessage = textMessage ? textMessage+"$"+learnMoveText : learnMoveText;
|
||||||
|
await this.scene.ui.showTextPromise(textMessage, this.messageMode === Mode.EVOLUTION_SCENE ? 1000 : undefined, true);
|
||||||
|
this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeMoveLearnedTrigger, true);
|
||||||
this.end();
|
this.end();
|
||||||
}, null, true);
|
|
||||||
}, null, true);
|
|
||||||
}, null, true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}, null, true);
|
|
||||||
}, noHandler);
|
|
||||||
});
|
|
||||||
}, null, true);
|
|
||||||
}, null, true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ export class QuietFormChangePhase extends BattlePhase {
|
||||||
pokemonFormTintSprite.setVisible(false);
|
pokemonFormTintSprite.setVisible(false);
|
||||||
pokemonFormTintSprite.setTintFill(0xFFFFFF);
|
pokemonFormTintSprite.setTintFill(0xFFFFFF);
|
||||||
|
|
||||||
this.scene.playSound("PRSFX- Transform");
|
this.scene.playSound("battle_anims/PRSFX- Transform");
|
||||||
|
|
||||||
this.scene.tweens.add({
|
this.scene.tweens.add({
|
||||||
targets: pokemonTintSprite,
|
targets: pokemonTintSprite,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import BattleScene from "#app/battle-scene";
|
import BattleScene from "#app/battle-scene";
|
||||||
import { applyPreWeatherEffectAbAttrs, SuppressWeatherEffectAbAttr, PreWeatherDamageAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPostWeatherLapseAbAttrs, PostWeatherLapseAbAttr } from "#app/data/ability.js";
|
import { applyPreWeatherEffectAbAttrs, SuppressWeatherEffectAbAttr, PreWeatherDamageAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPostWeatherLapseAbAttrs, PostWeatherLapseAbAttr } from "#app/data/ability";
|
||||||
import { CommonAnim } from "#app/data/battle-anims";
|
import { CommonAnim } from "#app/data/battle-anims";
|
||||||
import { Weather, getWeatherDamageMessage, getWeatherLapseMessage } from "#app/data/weather";
|
import { Weather, getWeatherDamageMessage, getWeatherLapseMessage } from "#app/data/weather";
|
||||||
import { BattlerTagType } from "#app/enums/battler-tag-type";
|
import { BattlerTagType } from "#app/enums/battler-tag-type";
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { allSpecies } from "#app/data/pokemon-species.js";
|
import { allSpecies } from "#app/data/pokemon-species";
|
||||||
import { AbilityAttr, defaultStarterSpecies, DexAttr, SessionSaveData, SystemSaveData } from "./game-data";
|
import { AbilityAttr, defaultStarterSpecies, DexAttr, SessionSaveData, SystemSaveData } from "./game-data";
|
||||||
import { SettingKeys } from "./settings/settings";
|
import { SettingKeys } from "./settings/settings";
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ 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 GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
@ -27,7 +26,7 @@ describe("Abilities - Aura Break", () => {
|
||||||
game = new GameManager(phaserGame);
|
game = new GameManager(phaserGame);
|
||||||
game.override.battleType("single");
|
game.override.battleType("single");
|
||||||
game.override.moveset([Moves.MOONBLAST, Moves.DARK_PULSE, Moves.MOONBLAST, Moves.DARK_PULSE]);
|
game.override.moveset([Moves.MOONBLAST, Moves.DARK_PULSE, Moves.MOONBLAST, Moves.DARK_PULSE]);
|
||||||
game.override.enemyMoveset(SPLASH_ONLY);
|
game.override.enemyMoveset(Moves.SPLASH);
|
||||||
game.override.enemyAbility(Abilities.AURA_BREAK);
|
game.override.enemyAbility(Abilities.AURA_BREAK);
|
||||||
game.override.enemySpecies(Species.SHUCKLE);
|
game.override.enemySpecies(Species.SHUCKLE);
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { TurnEndPhase } from "#app/phases/turn-end-phase";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
@ -31,7 +30,7 @@ describe("Abilities - Battery", () => {
|
||||||
game.override.enemySpecies(Species.SHUCKLE);
|
game.override.enemySpecies(Species.SHUCKLE);
|
||||||
game.override.enemyAbility(Abilities.BALL_FETCH);
|
game.override.enemyAbility(Abilities.BALL_FETCH);
|
||||||
game.override.moveset([Moves.TACKLE, Moves.BREAKING_SWIPE, Moves.SPLASH, Moves.DAZZLING_GLEAM]);
|
game.override.moveset([Moves.TACKLE, Moves.BREAKING_SWIPE, Moves.SPLASH, Moves.DAZZLING_GLEAM]);
|
||||||
game.override.enemyMoveset(SPLASH_ONLY);
|
game.override.enemyMoveset(Moves.SPLASH);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("raises the power of allies' special moves by 30%", async () => {
|
it("raises the power of allies' special moves by 30%", async () => {
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import { Stat } from "#enums/stat";
|
import { Stat } from "#enums/stat";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
@ -31,7 +30,7 @@ describe("Abilities - Beast Boost", () => {
|
||||||
.ability(Abilities.BEAST_BOOST)
|
.ability(Abilities.BEAST_BOOST)
|
||||||
.startingLevel(2000)
|
.startingLevel(2000)
|
||||||
.moveset([ Moves.FLAMETHROWER ])
|
.moveset([ Moves.FLAMETHROWER ])
|
||||||
.enemyMoveset(SPLASH_ONLY);
|
.enemyMoveset(Moves.SPLASH);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should prefer highest stat to boost its corresponding stat stage by 1 when winning a battle", async() => {
|
it("should prefer highest stat to boost its corresponding stat stage by 1 when winning a battle", async() => {
|
||||||
|
@ -51,7 +50,7 @@ describe("Abilities - Beast Boost", () => {
|
||||||
}, 20000);
|
}, 20000);
|
||||||
|
|
||||||
it("should use in-battle overriden stats when determining the stat stage to raise by 1", async() => {
|
it("should use in-battle overriden stats when determining the stat stage to raise by 1", async() => {
|
||||||
game.override.enemyMoveset(new Array(4).fill(Moves.GUARD_SPLIT));
|
game.override.enemyMoveset([Moves.GUARD_SPLIT]);
|
||||||
|
|
||||||
await game.classicMode.startBattle([Species.SLOWBRO]);
|
await game.classicMode.startBattle([Species.SLOWBRO]);
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { Stat } from "#enums/stat";
|
import { Moves } from "#app/enums/moves";
|
||||||
import GameManager from "#test/utils/gameManager";
|
|
||||||
import { Abilities } from "#enums/abilities";
|
import { Abilities } from "#enums/abilities";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
|
import { Stat } from "#enums/stat";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
import { SPLASH_ONLY } from "../utils/testUtils";
|
|
||||||
|
|
||||||
describe("Abilities - Contrary", () => {
|
describe("Abilities - Contrary", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
|
@ -27,7 +27,7 @@ describe("Abilities - Contrary", () => {
|
||||||
.enemySpecies(Species.BULBASAUR)
|
.enemySpecies(Species.BULBASAUR)
|
||||||
.enemyAbility(Abilities.CONTRARY)
|
.enemyAbility(Abilities.CONTRARY)
|
||||||
.ability(Abilities.INTIMIDATE)
|
.ability(Abilities.INTIMIDATE)
|
||||||
.enemyMoveset(SPLASH_ONLY);
|
.enemyMoveset(Moves.SPLASH);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should invert stat changes when applied", async() => {
|
it("should invert stat changes when applied", async() => {
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { Species } from "#app/enums/species";
|
||||||
import { CommandPhase } from "#app/phases/command-phase";
|
import { CommandPhase } from "#app/phases/command-phase";
|
||||||
import { MessagePhase } from "#app/phases/message-phase";
|
import { MessagePhase } from "#app/phases/message-phase";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
||||||
|
|
||||||
|
@ -30,7 +29,7 @@ describe("Abilities - COSTAR", () => {
|
||||||
game.override.battleType("double");
|
game.override.battleType("double");
|
||||||
game.override.ability(Abilities.COSTAR);
|
game.override.ability(Abilities.COSTAR);
|
||||||
game.override.moveset([Moves.SPLASH, Moves.NASTY_PLOT]);
|
game.override.moveset([Moves.SPLASH, Moves.NASTY_PLOT]);
|
||||||
game.override.enemyMoveset(SPLASH_ONLY);
|
game.override.enemyMoveset(Moves.SPLASH);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ describe("Abilities - Dancer", () => {
|
||||||
.moveset([Moves.SWORDS_DANCE, Moves.SPLASH])
|
.moveset([Moves.SWORDS_DANCE, Moves.SPLASH])
|
||||||
.enemySpecies(Species.MAGIKARP)
|
.enemySpecies(Species.MAGIKARP)
|
||||||
.enemyAbility(Abilities.DANCER)
|
.enemyAbility(Abilities.DANCER)
|
||||||
.enemyMoveset(Array(4).fill(Moves.VICTORY_DANCE));
|
.enemyMoveset([Moves.VICTORY_DANCE]);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reference Link: https://bulbapedia.bulbagarden.net/wiki/Dancer_(Ability)
|
// Reference Link: https://bulbapedia.bulbagarden.net/wiki/Dancer_(Ability)
|
||||||
|
|
|
@ -6,7 +6,6 @@ import { StatusEffect } from "#app/data/status-effect";
|
||||||
import { Stat } from "#enums/stat";
|
import { Stat } from "#enums/stat";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
import { SPLASH_ONLY } from "../utils/testUtils";
|
|
||||||
|
|
||||||
const TIMEOUT = 20 * 1000;
|
const TIMEOUT = 20 * 1000;
|
||||||
|
|
||||||
|
@ -31,7 +30,7 @@ describe("Abilities - Disguise", () => {
|
||||||
game.override
|
game.override
|
||||||
.battleType("single")
|
.battleType("single")
|
||||||
.enemySpecies(Species.MIMIKYU)
|
.enemySpecies(Species.MIMIKYU)
|
||||||
.enemyMoveset(SPLASH_ONLY)
|
.enemyMoveset(Moves.SPLASH)
|
||||||
.starterSpecies(Species.REGIELEKI)
|
.starterSpecies(Species.REGIELEKI)
|
||||||
.moveset([Moves.SHADOW_SNEAK, Moves.VACUUM_WAVE, Moves.TOXIC_THREAD, Moves.SPLASH]);
|
.moveset([Moves.SHADOW_SNEAK, Moves.VACUUM_WAVE, Moves.TOXIC_THREAD, Moves.SPLASH]);
|
||||||
}, TIMEOUT);
|
}, TIMEOUT);
|
||||||
|
@ -108,7 +107,7 @@ describe("Abilities - Disguise", () => {
|
||||||
}, TIMEOUT);
|
}, TIMEOUT);
|
||||||
|
|
||||||
it("persists form change when switched out", async () => {
|
it("persists form change when switched out", async () => {
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.SHADOW_SNEAK));
|
game.override.enemyMoveset([Moves.SHADOW_SNEAK]);
|
||||||
game.override.starterSpecies(0);
|
game.override.starterSpecies(0);
|
||||||
|
|
||||||
await game.classicMode.startBattle([ Species.MIMIKYU, Species.FURRET ]);
|
await game.classicMode.startBattle([ Species.MIMIKYU, Species.FURRET ]);
|
||||||
|
@ -194,7 +193,7 @@ describe("Abilities - Disguise", () => {
|
||||||
}, TIMEOUT);
|
}, TIMEOUT);
|
||||||
|
|
||||||
it("doesn't faint twice when fainting due to Disguise break damage, nor prevent faint from Disguise break damage if using Endure", async () => {
|
it("doesn't faint twice when fainting due to Disguise break damage, nor prevent faint from Disguise break damage if using Endure", async () => {
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.ENDURE));
|
game.override.enemyMoveset([Moves.ENDURE]);
|
||||||
await game.classicMode.startBattle();
|
await game.classicMode.startBattle();
|
||||||
|
|
||||||
const mimikyu = game.scene.getEnemyPokemon()!;
|
const mimikyu = game.scene.getEnemyPokemon()!;
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
import { Species } from "#app/enums/species";
|
import { Species } from "#app/enums/species";
|
||||||
import { TurnEndPhase } from "#app/phases/turn-end-phase";
|
|
||||||
import { Abilities } from "#enums/abilities";
|
import { Abilities } from "#enums/abilities";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
@ -23,63 +21,56 @@ describe("Abilities - Dry Skin", () => {
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
game = new GameManager(phaserGame);
|
game = new GameManager(phaserGame);
|
||||||
game.override.battleType("single");
|
game.override
|
||||||
game.override.disableCrits();
|
.battleType("single")
|
||||||
game.override.enemyAbility(Abilities.DRY_SKIN);
|
.disableCrits()
|
||||||
game.override.enemyMoveset(SPLASH_ONLY);
|
.enemyAbility(Abilities.DRY_SKIN)
|
||||||
game.override.enemySpecies(Species.CHARMANDER);
|
.enemyMoveset(Moves.SPLASH)
|
||||||
game.override.ability(Abilities.UNNERVE);
|
.enemySpecies(Species.CHARMANDER)
|
||||||
game.override.starterSpecies(Species.CHANDELURE);
|
.ability(Abilities.BALL_FETCH)
|
||||||
|
.moveset([Moves.SUNNY_DAY, Moves.RAIN_DANCE, Moves.SPLASH, Moves.WATER_GUN])
|
||||||
|
.starterSpecies(Species.CHANDELURE);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("during sunlight, lose 1/8 of maximum health at the end of each turn", async () => {
|
it("during sunlight, lose 1/8 of maximum health at the end of each turn", async () => {
|
||||||
game.override.moveset([Moves.SUNNY_DAY, Moves.SPLASH]);
|
await game.classicMode.startBattle();
|
||||||
|
|
||||||
await game.startBattle();
|
|
||||||
|
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
expect(enemy).not.toBe(undefined);
|
|
||||||
|
|
||||||
// first turn
|
// first turn
|
||||||
let previousEnemyHp = enemy.hp;
|
|
||||||
game.move.select(Moves.SUNNY_DAY);
|
game.move.select(Moves.SUNNY_DAY);
|
||||||
await game.phaseInterceptor.to(TurnEndPhase);
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
expect(enemy.hp).toBeLessThan(previousEnemyHp);
|
expect(enemy.hp).toBeLessThan(enemy.getMaxHp());
|
||||||
|
|
||||||
// second turn
|
// second turn
|
||||||
previousEnemyHp = enemy.hp;
|
enemy.hp = enemy.getMaxHp();
|
||||||
game.move.select(Moves.SPLASH);
|
game.move.select(Moves.SPLASH);
|
||||||
await game.phaseInterceptor.to(TurnEndPhase);
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
expect(enemy.hp).toBeLessThan(previousEnemyHp);
|
expect(enemy.hp).toBeLessThan(enemy.getMaxHp());
|
||||||
});
|
});
|
||||||
|
|
||||||
it("during rain, gain 1/8 of maximum health at the end of each turn", async () => {
|
it("during rain, gain 1/8 of maximum health at the end of each turn", async () => {
|
||||||
game.override.moveset([Moves.RAIN_DANCE, Moves.SPLASH]);
|
await game.classicMode.startBattle();
|
||||||
|
|
||||||
await game.startBattle();
|
|
||||||
|
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
expect(enemy).not.toBe(undefined);
|
|
||||||
|
|
||||||
enemy.hp = 1;
|
enemy.hp = 1;
|
||||||
|
|
||||||
// first turn
|
// first turn
|
||||||
let previousEnemyHp = enemy.hp;
|
|
||||||
game.move.select(Moves.RAIN_DANCE);
|
game.move.select(Moves.RAIN_DANCE);
|
||||||
await game.phaseInterceptor.to(TurnEndPhase);
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
expect(enemy.hp).toBeGreaterThan(previousEnemyHp);
|
expect(enemy.hp).toBeGreaterThan(1);
|
||||||
|
|
||||||
// second turn
|
// second turn
|
||||||
previousEnemyHp = enemy.hp;
|
enemy.hp = 1;
|
||||||
game.move.select(Moves.SPLASH);
|
game.move.select(Moves.SPLASH);
|
||||||
await game.phaseInterceptor.to(TurnEndPhase);
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
expect(enemy.hp).toBeGreaterThan(previousEnemyHp);
|
expect(enemy.hp).toBeGreaterThan(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("opposing fire attacks do 25% more damage", async () => {
|
it("opposing fire attacks do 25% more damage", async () => {
|
||||||
game.override.moveset([Moves.FLAMETHROWER]);
|
game.override.moveset([Moves.FLAMETHROWER]);
|
||||||
|
await game.classicMode.startBattle();
|
||||||
await game.startBattle();
|
|
||||||
|
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
const initialHP = 1000;
|
const initialHP = 1000;
|
||||||
|
@ -87,72 +78,65 @@ describe("Abilities - Dry Skin", () => {
|
||||||
|
|
||||||
// first turn
|
// first turn
|
||||||
game.move.select(Moves.FLAMETHROWER);
|
game.move.select(Moves.FLAMETHROWER);
|
||||||
await game.phaseInterceptor.to(TurnEndPhase);
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
const fireDamageTakenWithDrySkin = initialHP - enemy.hp;
|
const fireDamageTakenWithDrySkin = initialHP - enemy.hp;
|
||||||
|
|
||||||
expect(enemy.hp > 0);
|
|
||||||
enemy.hp = initialHP;
|
enemy.hp = initialHP;
|
||||||
game.override.enemyAbility(Abilities.NONE);
|
game.override.enemyAbility(Abilities.NONE);
|
||||||
|
|
||||||
// second turn
|
// second turn
|
||||||
game.move.select(Moves.FLAMETHROWER);
|
game.move.select(Moves.FLAMETHROWER);
|
||||||
await game.phaseInterceptor.to(TurnEndPhase);
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
const fireDamageTakenWithoutDrySkin = initialHP - enemy.hp;
|
const fireDamageTakenWithoutDrySkin = initialHP - enemy.hp;
|
||||||
|
|
||||||
expect(fireDamageTakenWithDrySkin).toBeGreaterThan(fireDamageTakenWithoutDrySkin);
|
expect(fireDamageTakenWithDrySkin).toBeGreaterThan(fireDamageTakenWithoutDrySkin);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("opposing water attacks heal 1/4 of maximum health and deal no damage", async () => {
|
it("opposing water attacks heal 1/4 of maximum health and deal no damage", async () => {
|
||||||
game.override.moveset([Moves.WATER_GUN]);
|
await game.classicMode.startBattle();
|
||||||
|
|
||||||
await game.startBattle();
|
|
||||||
|
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
expect(enemy).not.toBe(undefined);
|
|
||||||
|
|
||||||
enemy.hp = 1;
|
enemy.hp = 1;
|
||||||
|
|
||||||
game.move.select(Moves.WATER_GUN);
|
game.move.select(Moves.WATER_GUN);
|
||||||
await game.phaseInterceptor.to(TurnEndPhase);
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
expect(enemy.hp).toBeGreaterThan(1);
|
expect(enemy.hp).toBeGreaterThan(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("opposing water attacks do not heal if they were protected from", async () => {
|
it("opposing water attacks do not heal if they were protected from", async () => {
|
||||||
game.override.moveset([Moves.WATER_GUN]);
|
game.override.enemyMoveset([Moves.PROTECT]);
|
||||||
|
|
||||||
await game.startBattle();
|
await game.classicMode.startBattle();
|
||||||
|
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
expect(enemy).not.toBe(undefined);
|
|
||||||
|
|
||||||
enemy.hp = 1;
|
enemy.hp = 1;
|
||||||
game.override.enemyMoveset([Moves.PROTECT, Moves.PROTECT, Moves.PROTECT, Moves.PROTECT]);
|
|
||||||
|
|
||||||
game.move.select(Moves.WATER_GUN);
|
game.move.select(Moves.WATER_GUN);
|
||||||
await game.phaseInterceptor.to(TurnEndPhase);
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
expect(enemy.hp).toBe(1);
|
expect(enemy.hp).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("multi-strike water attacks only heal once", async () => {
|
it("multi-strike water attacks only heal once", async () => {
|
||||||
game.override.moveset([Moves.WATER_GUN, Moves.WATER_SHURIKEN]);
|
game.override.moveset([Moves.WATER_GUN, Moves.WATER_SHURIKEN]);
|
||||||
|
|
||||||
await game.startBattle();
|
await game.classicMode.startBattle();
|
||||||
|
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
expect(enemy).not.toBe(undefined);
|
|
||||||
|
|
||||||
enemy.hp = 1;
|
enemy.hp = 1;
|
||||||
|
|
||||||
// first turn
|
// first turn
|
||||||
game.move.select(Moves.WATER_SHURIKEN);
|
game.move.select(Moves.WATER_SHURIKEN);
|
||||||
await game.phaseInterceptor.to(TurnEndPhase);
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
const healthGainedFromWaterShuriken = enemy.hp - 1;
|
const healthGainedFromWaterShuriken = enemy.hp - 1;
|
||||||
|
|
||||||
enemy.hp = 1;
|
enemy.hp = 1;
|
||||||
|
|
||||||
// second turn
|
// second turn
|
||||||
game.move.select(Moves.WATER_GUN);
|
game.move.select(Moves.WATER_GUN);
|
||||||
await game.phaseInterceptor.to(TurnEndPhase);
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
const healthGainedFromWaterGun = enemy.hp - 1;
|
const healthGainedFromWaterGun = enemy.hp - 1;
|
||||||
|
|
||||||
expect(healthGainedFromWaterShuriken).toBe(healthGainedFromWaterGun);
|
expect(healthGainedFromWaterShuriken).toBe(healthGainedFromWaterGun);
|
||||||
|
|
|
@ -7,7 +7,6 @@ import { TurnEndPhase } from "#app/phases/turn-end-phase";
|
||||||
import { Abilities } from "#enums/abilities";
|
import { Abilities } from "#enums/abilities";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
@ -38,7 +37,7 @@ describe("Abilities - Flash Fire", () => {
|
||||||
|
|
||||||
|
|
||||||
it("immune to Fire-type moves", async () => {
|
it("immune to Fire-type moves", async () => {
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.EMBER)).moveset(SPLASH_ONLY);
|
game.override.enemyMoveset([Moves.EMBER]).moveset(Moves.SPLASH);
|
||||||
await game.startBattle([Species.BLISSEY]);
|
await game.startBattle([Species.BLISSEY]);
|
||||||
|
|
||||||
const blissey = game.scene.getPlayerPokemon()!;
|
const blissey = game.scene.getPlayerPokemon()!;
|
||||||
|
@ -49,7 +48,7 @@ describe("Abilities - Flash Fire", () => {
|
||||||
}, 20000);
|
}, 20000);
|
||||||
|
|
||||||
it("not activate if the Pokémon is protected from the Fire-type move", async () => {
|
it("not activate if the Pokémon is protected from the Fire-type move", async () => {
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.EMBER)).moveset([Moves.PROTECT]);
|
game.override.enemyMoveset([Moves.EMBER]).moveset([Moves.PROTECT]);
|
||||||
await game.startBattle([Species.BLISSEY]);
|
await game.startBattle([Species.BLISSEY]);
|
||||||
|
|
||||||
const blissey = game.scene.getPlayerPokemon()!;
|
const blissey = game.scene.getPlayerPokemon()!;
|
||||||
|
@ -60,7 +59,7 @@ describe("Abilities - Flash Fire", () => {
|
||||||
}, 20000);
|
}, 20000);
|
||||||
|
|
||||||
it("activated by Will-O-Wisp", async () => {
|
it("activated by Will-O-Wisp", async () => {
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.WILL_O_WISP)).moveset(SPLASH_ONLY);
|
game.override.enemyMoveset([Moves.WILL_O_WISP]).moveset(Moves.SPLASH);
|
||||||
await game.startBattle([Species.BLISSEY]);
|
await game.startBattle([Species.BLISSEY]);
|
||||||
|
|
||||||
const blissey = game.scene.getPlayerPokemon()!;
|
const blissey = game.scene.getPlayerPokemon()!;
|
||||||
|
@ -75,7 +74,7 @@ describe("Abilities - Flash Fire", () => {
|
||||||
}, 20000);
|
}, 20000);
|
||||||
|
|
||||||
it("activated after being frozen", async () => {
|
it("activated after being frozen", async () => {
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.EMBER)).moveset(SPLASH_ONLY);
|
game.override.enemyMoveset([Moves.EMBER]).moveset(Moves.SPLASH);
|
||||||
game.override.statusEffect(StatusEffect.FREEZE);
|
game.override.statusEffect(StatusEffect.FREEZE);
|
||||||
await game.startBattle([Species.BLISSEY]);
|
await game.startBattle([Species.BLISSEY]);
|
||||||
|
|
||||||
|
@ -88,7 +87,7 @@ describe("Abilities - Flash Fire", () => {
|
||||||
}, 20000);
|
}, 20000);
|
||||||
|
|
||||||
it("not passing with baton pass", async () => {
|
it("not passing with baton pass", async () => {
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.EMBER)).moveset([Moves.BATON_PASS]);
|
game.override.enemyMoveset([Moves.EMBER]).moveset([Moves.BATON_PASS]);
|
||||||
await game.startBattle([Species.BLISSEY, Species.CHANSEY]);
|
await game.startBattle([Species.BLISSEY, Species.CHANSEY]);
|
||||||
|
|
||||||
// ensure use baton pass after enemy moved
|
// ensure use baton pass after enemy moved
|
||||||
|
@ -104,7 +103,7 @@ describe("Abilities - Flash Fire", () => {
|
||||||
}, 20000);
|
}, 20000);
|
||||||
|
|
||||||
it("boosts Fire-type move when the ability is activated", async () => {
|
it("boosts Fire-type move when the ability is activated", async () => {
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.FIRE_PLEDGE)).moveset([Moves.EMBER, Moves.SPLASH]);
|
game.override.enemyMoveset([Moves.FIRE_PLEDGE]).moveset([Moves.EMBER, Moves.SPLASH]);
|
||||||
game.override.enemyAbility(Abilities.FLASH_FIRE).ability(Abilities.NONE);
|
game.override.enemyAbility(Abilities.FLASH_FIRE).ability(Abilities.NONE);
|
||||||
await game.startBattle([Species.BLISSEY]);
|
await game.startBattle([Species.BLISSEY]);
|
||||||
const blissey = game.scene.getPlayerPokemon()!;
|
const blissey = game.scene.getPlayerPokemon()!;
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { WeatherType } from "#app/enums/weather-type";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
@ -44,7 +43,7 @@ describe("Abilities - Flower Gift", () => {
|
||||||
game.override
|
game.override
|
||||||
.moveset([Moves.SPLASH, Moves.RAIN_DANCE, Moves.SUNNY_DAY, Moves.SKILL_SWAP])
|
.moveset([Moves.SPLASH, Moves.RAIN_DANCE, Moves.SUNNY_DAY, Moves.SKILL_SWAP])
|
||||||
.enemySpecies(Species.MAGIKARP)
|
.enemySpecies(Species.MAGIKARP)
|
||||||
.enemyMoveset(SPLASH_ONLY)
|
.enemyMoveset(Moves.SPLASH)
|
||||||
.enemyAbility(Abilities.BALL_FETCH);
|
.enemyAbility(Abilities.BALL_FETCH);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -92,7 +91,7 @@ describe("Abilities - Flower Gift", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("reverts to Overcast Form when the Pokémon loses Flower Gift, changes form under Harsh Sunlight/Sunny when it regains it", async () => {
|
it("reverts to Overcast Form when the Pokémon loses Flower Gift, changes form under Harsh Sunlight/Sunny when it regains it", async () => {
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.SKILL_SWAP)).weather(WeatherType.HARSH_SUN);
|
game.override.enemyMoveset([Moves.SKILL_SWAP]).weather(WeatherType.HARSH_SUN);
|
||||||
|
|
||||||
await game.classicMode.startBattle([Species.CHERRIM]);
|
await game.classicMode.startBattle([Species.CHERRIM]);
|
||||||
|
|
||||||
|
@ -111,7 +110,7 @@ describe("Abilities - Flower Gift", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("reverts to Overcast Form when the Flower Gift is suppressed, changes form under Harsh Sunlight/Sunny when it regains it", async () => {
|
it("reverts to Overcast Form when the Flower Gift is suppressed, changes form under Harsh Sunlight/Sunny when it regains it", async () => {
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.GASTRO_ACID)).weather(WeatherType.HARSH_SUN);
|
game.override.enemyMoveset([Moves.GASTRO_ACID]).weather(WeatherType.HARSH_SUN);
|
||||||
|
|
||||||
await game.classicMode.startBattle([Species.CHERRIM, Species.MAGIKARP]);
|
await game.classicMode.startBattle([Species.CHERRIM, Species.MAGIKARP]);
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@ import { TurnEndPhase } from "#app/phases/turn-end-phase";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
@ -67,7 +66,7 @@ describe("Abilities - Forecast", () => {
|
||||||
game.override
|
game.override
|
||||||
.moveset([Moves.SPLASH, Moves.RAIN_DANCE, Moves.SUNNY_DAY, Moves.TACKLE])
|
.moveset([Moves.SPLASH, Moves.RAIN_DANCE, Moves.SUNNY_DAY, Moves.TACKLE])
|
||||||
.enemySpecies(Species.MAGIKARP)
|
.enemySpecies(Species.MAGIKARP)
|
||||||
.enemyMoveset(SPLASH_ONLY)
|
.enemyMoveset(Moves.SPLASH)
|
||||||
.enemyAbility(Abilities.BALL_FETCH);
|
.enemyAbility(Abilities.BALL_FETCH);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -229,7 +228,7 @@ describe("Abilities - Forecast", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("reverts to Normal Form when Forecast is suppressed, changes form to match the weather when it regains it", async () => {
|
it("reverts to Normal Form when Forecast is suppressed, changes form to match the weather when it regains it", async () => {
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.GASTRO_ACID)).weather(WeatherType.RAIN);
|
game.override.enemyMoveset([Moves.GASTRO_ACID]).weather(WeatherType.RAIN);
|
||||||
await game.startBattle([Species.CASTFORM, Species.PIKACHU]);
|
await game.startBattle([Species.CASTFORM, Species.PIKACHU]);
|
||||||
const castform = game.scene.getPlayerPokemon()!;
|
const castform = game.scene.getPlayerPokemon()!;
|
||||||
|
|
||||||
|
@ -260,7 +259,7 @@ describe("Abilities - Forecast", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not change Castform's form until after Stealth Rock deals damage", async () => {
|
it("does not change Castform's form until after Stealth Rock deals damage", async () => {
|
||||||
game.override.weather(WeatherType.RAIN).enemyMoveset(Array(4).fill(Moves.STEALTH_ROCK));
|
game.override.weather(WeatherType.RAIN).enemyMoveset([Moves.STEALTH_ROCK]);
|
||||||
await game.startBattle([Species.PIKACHU, Species.CASTFORM]);
|
await game.startBattle([Species.PIKACHU, Species.CASTFORM]);
|
||||||
|
|
||||||
// First turn - set up stealth rock
|
// First turn - set up stealth rock
|
||||||
|
|
|
@ -6,7 +6,6 @@ import { Moves } from "#app/enums/moves";
|
||||||
import { Species } from "#app/enums/species";
|
import { Species } from "#app/enums/species";
|
||||||
import { HitResult } from "#app/field/pokemon";
|
import { HitResult } from "#app/field/pokemon";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
@ -36,7 +35,7 @@ describe("Abilities - Galvanize", () => {
|
||||||
.moveset([Moves.TACKLE, Moves.REVELATION_DANCE, Moves.FURY_SWIPES])
|
.moveset([Moves.TACKLE, Moves.REVELATION_DANCE, Moves.FURY_SWIPES])
|
||||||
.enemySpecies(Species.DUSCLOPS)
|
.enemySpecies(Species.DUSCLOPS)
|
||||||
.enemyAbility(Abilities.BALL_FETCH)
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
.enemyMoveset(SPLASH_ONLY)
|
.enemyMoveset(Moves.SPLASH)
|
||||||
.enemyLevel(100);
|
.enemyLevel(100);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
import { BattlerIndex } from "#app/battle";
|
||||||
|
import { Moves } from "#app/enums/moves";
|
||||||
|
import { Species } from "#app/enums/species";
|
||||||
|
import { Stat } from "#app/enums/stat";
|
||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
describe("Abilities - Gorilla Tactics", () => {
|
||||||
|
let phaserGame: Phaser.Game;
|
||||||
|
let game: GameManager;
|
||||||
|
const TIMEOUT = 20 * 1000;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
phaserGame = new Phaser.Game({
|
||||||
|
type: Phaser.HEADLESS,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
game.phaseInterceptor.restoreOg();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
game = new GameManager(phaserGame);
|
||||||
|
game.override
|
||||||
|
.battleType("single")
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
|
.enemyMoveset([Moves.SPLASH, Moves.DISABLE])
|
||||||
|
.enemySpecies(Species.MAGIKARP)
|
||||||
|
.enemyLevel(30)
|
||||||
|
.moveset([Moves.SPLASH, Moves.TACKLE, Moves.GROWL])
|
||||||
|
.ability(Abilities.GORILLA_TACTICS);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("boosts the Pokémon's Attack by 50%, but limits the Pokémon to using only one move", async () => {
|
||||||
|
await game.classicMode.startBattle([Species.GALAR_DARMANITAN]);
|
||||||
|
|
||||||
|
const darmanitan = game.scene.getPlayerPokemon()!;
|
||||||
|
const initialAtkStat = darmanitan.getStat(Stat.ATK);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.forceEnemyMove(Moves.SPLASH);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
|
expect(darmanitan.getStat(Stat.ATK, false)).toBeCloseTo(initialAtkStat * 1.5);
|
||||||
|
// Other moves should be restricted
|
||||||
|
expect(darmanitan.isMoveRestricted(Moves.TACKLE)).toBe(true);
|
||||||
|
expect(darmanitan.isMoveRestricted(Moves.SPLASH)).toBe(false);
|
||||||
|
}, TIMEOUT);
|
||||||
|
|
||||||
|
it("should struggle if the only usable move is disabled", async () => {
|
||||||
|
await game.classicMode.startBattle([Species.GALAR_DARMANITAN]);
|
||||||
|
|
||||||
|
const darmanitan = game.scene.getPlayerPokemon()!;
|
||||||
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
|
// First turn, lock move to Growl
|
||||||
|
game.move.select(Moves.GROWL);
|
||||||
|
await game.forceEnemyMove(Moves.SPLASH);
|
||||||
|
|
||||||
|
// Second turn, Growl is interrupted by Disable
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
game.move.select(Moves.GROWL);
|
||||||
|
await game.forceEnemyMove(Moves.DISABLE);
|
||||||
|
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
expect(enemy.getStatStage(Stat.ATK)).toBe(-1); // Only the effect of the first Growl should be applied
|
||||||
|
|
||||||
|
// Third turn, Struggle is used
|
||||||
|
await game.toNextTurn();
|
||||||
|
|
||||||
|
game.move.select(Moves.TACKLE);
|
||||||
|
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to("MoveEndPhase");
|
||||||
|
expect(darmanitan.hp).toBeLessThan(darmanitan.getMaxHp());
|
||||||
|
}, TIMEOUT);
|
||||||
|
});
|
|
@ -11,7 +11,6 @@ import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
import { SPLASH_ONLY } from "../utils/testUtils";
|
|
||||||
import { Stat } from "#enums/stat";
|
import { Stat } from "#enums/stat";
|
||||||
|
|
||||||
describe("Abilities - Gulp Missile", () => {
|
describe("Abilities - Gulp Missile", () => {
|
||||||
|
@ -49,7 +48,7 @@ describe("Abilities - Gulp Missile", () => {
|
||||||
.moveset([Moves.SURF, Moves.DIVE, Moves.SPLASH])
|
.moveset([Moves.SURF, Moves.DIVE, Moves.SPLASH])
|
||||||
.enemySpecies(Species.SNORLAX)
|
.enemySpecies(Species.SNORLAX)
|
||||||
.enemyAbility(Abilities.BALL_FETCH)
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
.enemyMoveset(SPLASH_ONLY)
|
.enemyMoveset(Moves.SPLASH)
|
||||||
.enemyLevel(5);
|
.enemyLevel(5);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -108,7 +107,7 @@ describe("Abilities - Gulp Missile", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("deals 1/4 of the attacker's maximum HP when hit by a damaging attack", async () => {
|
it("deals 1/4 of the attacker's maximum HP when hit by a damaging attack", async () => {
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.TACKLE));
|
game.override.enemyMoveset([Moves.TACKLE]);
|
||||||
await game.startBattle([Species.CRAMORANT]);
|
await game.startBattle([Species.CRAMORANT]);
|
||||||
|
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
|
@ -121,7 +120,7 @@ describe("Abilities - Gulp Missile", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not have any effect when hit by non-damaging attack", async () => {
|
it("does not have any effect when hit by non-damaging attack", async () => {
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.TAIL_WHIP));
|
game.override.enemyMoveset([Moves.TAIL_WHIP]);
|
||||||
await game.startBattle([Species.CRAMORANT]);
|
await game.startBattle([Species.CRAMORANT]);
|
||||||
|
|
||||||
const cramorant = game.scene.getPlayerPokemon()!;
|
const cramorant = game.scene.getPlayerPokemon()!;
|
||||||
|
@ -140,7 +139,7 @@ describe("Abilities - Gulp Missile", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("lowers attacker's DEF stat stage by 1 when hit in Gulping form", async () => {
|
it("lowers attacker's DEF stat stage by 1 when hit in Gulping form", async () => {
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.TACKLE));
|
game.override.enemyMoveset([Moves.TACKLE]);
|
||||||
await game.startBattle([Species.CRAMORANT]);
|
await game.startBattle([Species.CRAMORANT]);
|
||||||
|
|
||||||
const cramorant = game.scene.getPlayerPokemon()!;
|
const cramorant = game.scene.getPlayerPokemon()!;
|
||||||
|
@ -164,7 +163,7 @@ describe("Abilities - Gulp Missile", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("paralyzes the enemy when hit in Gorging form", async () => {
|
it("paralyzes the enemy when hit in Gorging form", async () => {
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.TACKLE));
|
game.override.enemyMoveset([Moves.TACKLE]);
|
||||||
await game.startBattle([Species.CRAMORANT]);
|
await game.startBattle([Species.CRAMORANT]);
|
||||||
|
|
||||||
const cramorant = game.scene.getPlayerPokemon()!;
|
const cramorant = game.scene.getPlayerPokemon()!;
|
||||||
|
@ -188,7 +187,7 @@ describe("Abilities - Gulp Missile", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not activate the ability when underwater", async () => {
|
it("does not activate the ability when underwater", async () => {
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.SURF));
|
game.override.enemyMoveset([Moves.SURF]);
|
||||||
await game.startBattle([Species.CRAMORANT]);
|
await game.startBattle([Species.CRAMORANT]);
|
||||||
|
|
||||||
const cramorant = game.scene.getPlayerPokemon()!;
|
const cramorant = game.scene.getPlayerPokemon()!;
|
||||||
|
@ -201,7 +200,7 @@ describe("Abilities - Gulp Missile", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("prevents effect damage but inflicts secondary effect on attacker with Magic Guard", async () => {
|
it("prevents effect damage but inflicts secondary effect on attacker with Magic Guard", async () => {
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.TACKLE)).enemyAbility(Abilities.MAGIC_GUARD);
|
game.override.enemyMoveset([Moves.TACKLE]).enemyAbility(Abilities.MAGIC_GUARD);
|
||||||
await game.startBattle([Species.CRAMORANT]);
|
await game.startBattle([Species.CRAMORANT]);
|
||||||
|
|
||||||
const cramorant = game.scene.getPlayerPokemon()!;
|
const cramorant = game.scene.getPlayerPokemon()!;
|
||||||
|
@ -225,7 +224,7 @@ describe("Abilities - Gulp Missile", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("cannot be suppressed", async () => {
|
it("cannot be suppressed", async () => {
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.GASTRO_ACID));
|
game.override.enemyMoveset([Moves.GASTRO_ACID]);
|
||||||
await game.startBattle([Species.CRAMORANT]);
|
await game.startBattle([Species.CRAMORANT]);
|
||||||
|
|
||||||
const cramorant = game.scene.getPlayerPokemon()!;
|
const cramorant = game.scene.getPlayerPokemon()!;
|
||||||
|
@ -245,7 +244,7 @@ describe("Abilities - Gulp Missile", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("cannot be swapped with another ability", async () => {
|
it("cannot be swapped with another ability", async () => {
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.SKILL_SWAP));
|
game.override.enemyMoveset([Moves.SKILL_SWAP]);
|
||||||
await game.startBattle([Species.CRAMORANT]);
|
await game.startBattle([Species.CRAMORANT]);
|
||||||
|
|
||||||
const cramorant = game.scene.getPlayerPokemon()!;
|
const cramorant = game.scene.getPlayerPokemon()!;
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { toDmgValue } from "#app/utils";
|
||||||
import { Abilities } from "#enums/abilities";
|
import { Abilities } from "#enums/abilities";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
@ -30,7 +29,7 @@ describe("Abilities - Heatproof", () => {
|
||||||
.disableCrits()
|
.disableCrits()
|
||||||
.enemySpecies(Species.CHARMANDER)
|
.enemySpecies(Species.CHARMANDER)
|
||||||
.enemyAbility(Abilities.HEATPROOF)
|
.enemyAbility(Abilities.HEATPROOF)
|
||||||
.enemyMoveset(SPLASH_ONLY)
|
.enemyMoveset(Moves.SPLASH)
|
||||||
.enemyLevel(100)
|
.enemyLevel(100)
|
||||||
.starterSpecies(Species.CHANDELURE)
|
.starterSpecies(Species.CHANDELURE)
|
||||||
.ability(Abilities.BALL_FETCH)
|
.ability(Abilities.BALL_FETCH)
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { Stat } from "#app/enums/stat";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
@ -29,7 +28,7 @@ describe("Abilities - Hustle", () => {
|
||||||
.moveset([ Moves.TACKLE, Moves.GIGA_DRAIN, Moves.FISSURE ])
|
.moveset([ Moves.TACKLE, Moves.GIGA_DRAIN, Moves.FISSURE ])
|
||||||
.disableCrits()
|
.disableCrits()
|
||||||
.battleType("single")
|
.battleType("single")
|
||||||
.enemyMoveset(SPLASH_ONLY)
|
.enemyMoveset(Moves.SPLASH)
|
||||||
.enemySpecies(Species.SHUCKLE)
|
.enemySpecies(Species.SHUCKLE)
|
||||||
.enemyAbility(Abilities.BALL_FETCH);
|
.enemyAbility(Abilities.BALL_FETCH);
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,7 +3,6 @@ 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 GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
@ -29,7 +28,7 @@ describe("Abilities - Hyper Cutter", () => {
|
||||||
.ability(Abilities.BALL_FETCH)
|
.ability(Abilities.BALL_FETCH)
|
||||||
.enemySpecies(Species.SHUCKLE)
|
.enemySpecies(Species.SHUCKLE)
|
||||||
.enemyAbility(Abilities.HYPER_CUTTER)
|
.enemyAbility(Abilities.HYPER_CUTTER)
|
||||||
.enemyMoveset(SPLASH_ONLY);
|
.enemyMoveset(Moves.SPLASH);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reference Link: https://bulbapedia.bulbagarden.net/wiki/Hyper_Cutter_(Ability)
|
// Reference Link: https://bulbapedia.bulbagarden.net/wiki/Hyper_Cutter_(Ability)
|
||||||
|
|
|
@ -6,7 +6,6 @@ import { TurnEndPhase } from "#app/phases/turn-end-phase";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Stat, BATTLE_STATS, EFFECTIVE_STATS } from "#enums/stat";
|
import { Stat, BATTLE_STATS, EFFECTIVE_STATS } from "#enums/stat";
|
||||||
import { Abilities } from "#enums/abilities";
|
import { Abilities } from "#enums/abilities";
|
||||||
import { SPLASH_ONLY } from "../utils/testUtils";
|
|
||||||
|
|
||||||
// TODO: Add more tests once Imposter is fully implemented
|
// TODO: Add more tests once Imposter is fully implemented
|
||||||
describe("Abilities - Imposter", () => {
|
describe("Abilities - Imposter", () => {
|
||||||
|
@ -31,9 +30,9 @@ describe("Abilities - Imposter", () => {
|
||||||
.enemyLevel(200)
|
.enemyLevel(200)
|
||||||
.enemyAbility(Abilities.BEAST_BOOST)
|
.enemyAbility(Abilities.BEAST_BOOST)
|
||||||
.enemyPassiveAbility(Abilities.BALL_FETCH)
|
.enemyPassiveAbility(Abilities.BALL_FETCH)
|
||||||
.enemyMoveset(SPLASH_ONLY)
|
.enemyMoveset(Moves.SPLASH)
|
||||||
.ability(Abilities.IMPOSTER)
|
.ability(Abilities.IMPOSTER)
|
||||||
.moveset(SPLASH_ONLY);
|
.moveset(Moves.SPLASH);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should copy species, ability, gender, all stats except HP, all stat stages, moveset, and types of target", async () => {
|
it("should copy species, ability, gender, all stats except HP, all stat stages, moveset, and types of target", async () => {
|
||||||
|
@ -77,7 +76,7 @@ describe("Abilities - Imposter", () => {
|
||||||
}, 20000);
|
}, 20000);
|
||||||
|
|
||||||
it("should copy in-battle overridden stats", async () => {
|
it("should copy in-battle overridden stats", async () => {
|
||||||
game.override.enemyMoveset(new Array(4).fill(Moves.POWER_SPLIT));
|
game.override.enemyMoveset([Moves.POWER_SPLIT]);
|
||||||
|
|
||||||
await game.startBattle([
|
await game.startBattle([
|
||||||
Species.DITTO
|
Species.DITTO
|
||||||
|
|
|
@ -7,7 +7,6 @@ import { getMovePosition } from "#test/utils/gameManagerUtils";
|
||||||
import { Abilities } from "#enums/abilities";
|
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 { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
|
|
||||||
describe("Abilities - Intimidate", () => {
|
describe("Abilities - Intimidate", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
|
@ -31,7 +30,7 @@ describe("Abilities - Intimidate", () => {
|
||||||
.enemyPassiveAbility(Abilities.HYDRATION)
|
.enemyPassiveAbility(Abilities.HYDRATION)
|
||||||
.ability(Abilities.INTIMIDATE)
|
.ability(Abilities.INTIMIDATE)
|
||||||
.startingWave(3)
|
.startingWave(3)
|
||||||
.enemyMoveset(SPLASH_ONLY);
|
.enemyMoveset(Moves.SPLASH);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should lower ATK stat stage by 1 of enemy Pokemon on entry and player switch", async () => {
|
it("should lower ATK stat stage by 1 of enemy Pokemon on entry and player switch", async () => {
|
||||||
|
@ -108,7 +107,7 @@ describe("Abilities - Intimidate", () => {
|
||||||
|
|
||||||
it("should lower ATK stat stage by 1 for every switch", async () => {
|
it("should lower ATK stat stage by 1 for every switch", async () => {
|
||||||
game.override.moveset([Moves.SPLASH])
|
game.override.moveset([Moves.SPLASH])
|
||||||
.enemyMoveset(new Array(4).fill(Moves.VOLT_SWITCH))
|
.enemyMoveset([Moves.VOLT_SWITCH])
|
||||||
.startingWave(5);
|
.startingWave(5);
|
||||||
await game.classicMode.startBattle([ Species.MIGHTYENA, Species.POOCHYENA ]);
|
await game.classicMode.startBattle([ Species.MIGHTYENA, Species.POOCHYENA ]);
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ import { Biome } from "#enums/biome";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
||||||
|
|
||||||
|
@ -183,7 +182,7 @@ describe("Abilities - Libero", () => {
|
||||||
"ability applies correctly even if the pokemon's move misses",
|
"ability applies correctly even if the pokemon's move misses",
|
||||||
async () => {
|
async () => {
|
||||||
game.override.moveset([Moves.TACKLE]);
|
game.override.moveset([Moves.TACKLE]);
|
||||||
game.override.enemyMoveset(SPLASH_ONLY);
|
game.override.enemyMoveset(Moves.SPLASH);
|
||||||
|
|
||||||
await game.startBattle([Species.MAGIKARP]);
|
await game.startBattle([Species.MAGIKARP]);
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ 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 GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
@ -39,7 +38,7 @@ describe("Abilities - Magic Guard", () => {
|
||||||
/** Enemy Pokemon overrides */
|
/** Enemy Pokemon overrides */
|
||||||
game.override.enemySpecies(Species.SNORLAX);
|
game.override.enemySpecies(Species.SNORLAX);
|
||||||
game.override.enemyAbility(Abilities.INSOMNIA);
|
game.override.enemyAbility(Abilities.INSOMNIA);
|
||||||
game.override.enemyMoveset(SPLASH_ONLY);
|
game.override.enemyMoveset(Moves.SPLASH);
|
||||||
game.override.enemyLevel(100);
|
game.override.enemyLevel(100);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ 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 GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
@ -29,8 +28,8 @@ describe("Abilities - Moody", () => {
|
||||||
.enemySpecies(Species.RATTATA)
|
.enemySpecies(Species.RATTATA)
|
||||||
.enemyAbility(Abilities.BALL_FETCH)
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
.ability(Abilities.MOODY)
|
.ability(Abilities.MOODY)
|
||||||
.enemyMoveset(SPLASH_ONLY)
|
.enemyMoveset(Moves.SPLASH)
|
||||||
.moveset(SPLASH_ONLY);
|
.moveset(Moves.SPLASH);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should increase one stat stage by 2 and decrease a different stat stage by 1",
|
it("should increase one stat stage by 2 and decrease a different stat stage by 1",
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
import { SPLASH_ONLY } from "../utils/testUtils";
|
|
||||||
import { BattlerIndex } from "#app/battle";
|
import { BattlerIndex } from "#app/battle";
|
||||||
import { EnemyCommandPhase } from "#app/phases/enemy-command-phase";
|
import { EnemyCommandPhase } from "#app/phases/enemy-command-phase";
|
||||||
import { VictoryPhase } from "#app/phases/victory-phase";
|
import { VictoryPhase } from "#app/phases/victory-phase";
|
||||||
|
@ -34,7 +33,7 @@ describe("Abilities - Moxie", () => {
|
||||||
game.override.ability(Abilities.MOXIE);
|
game.override.ability(Abilities.MOXIE);
|
||||||
game.override.startingLevel(2000);
|
game.override.startingLevel(2000);
|
||||||
game.override.moveset([ moveToUse ]);
|
game.override.moveset([ moveToUse ]);
|
||||||
game.override.enemyMoveset(SPLASH_ONLY);
|
game.override.enemyMoveset(Moves.SPLASH);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should raise ATK stat stage by 1 when winning a battle", async() => {
|
it("should raise ATK stat stage by 1 when winning a battle", async() => {
|
||||||
|
|
|
@ -7,7 +7,6 @@ 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 GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
@ -34,7 +33,7 @@ describe("Abilities - Parental Bond", () => {
|
||||||
game.override.ability(Abilities.PARENTAL_BOND);
|
game.override.ability(Abilities.PARENTAL_BOND);
|
||||||
game.override.enemySpecies(Species.SNORLAX);
|
game.override.enemySpecies(Species.SNORLAX);
|
||||||
game.override.enemyAbility(Abilities.FUR_COAT);
|
game.override.enemyAbility(Abilities.FUR_COAT);
|
||||||
game.override.enemyMoveset(SPLASH_ONLY);
|
game.override.enemyMoveset(Moves.SPLASH);
|
||||||
game.override.startingLevel(100);
|
game.override.startingLevel(100);
|
||||||
game.override.enemyLevel(100);
|
game.override.enemyLevel(100);
|
||||||
});
|
});
|
||||||
|
@ -175,7 +174,7 @@ describe("Abilities - Parental Bond", () => {
|
||||||
"should not apply multiplier to counter moves",
|
"should not apply multiplier to counter moves",
|
||||||
async () => {
|
async () => {
|
||||||
game.override.moveset([Moves.COUNTER]);
|
game.override.moveset([Moves.COUNTER]);
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.TACKLE));
|
game.override.enemyMoveset([Moves.TACKLE]);
|
||||||
|
|
||||||
await game.classicMode.startBattle([Species.SHUCKLE]);
|
await game.classicMode.startBattle([Species.SHUCKLE]);
|
||||||
|
|
||||||
|
@ -465,7 +464,7 @@ describe("Abilities - Parental Bond", () => {
|
||||||
"should not cause user to hit into King's Shield more than once",
|
"should not cause user to hit into King's Shield more than once",
|
||||||
async () => {
|
async () => {
|
||||||
game.override.moveset([Moves.TACKLE]);
|
game.override.moveset([Moves.TACKLE]);
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.KINGS_SHIELD));
|
game.override.enemyMoveset([Moves.KINGS_SHIELD]);
|
||||||
|
|
||||||
await game.classicMode.startBattle([Species.MAGIKARP]);
|
await game.classicMode.startBattle([Species.MAGIKARP]);
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ import { Species } from "#enums/species";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
import { SPLASH_ONLY } from "../utils/testUtils";
|
|
||||||
|
|
||||||
describe("Abilities - Pastel Veil", () => {
|
describe("Abilities - Pastel Veil", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
|
@ -31,7 +30,7 @@ describe("Abilities - Pastel Veil", () => {
|
||||||
.moveset([Moves.TOXIC_THREAD, Moves.SPLASH])
|
.moveset([Moves.TOXIC_THREAD, Moves.SPLASH])
|
||||||
.enemyAbility(Abilities.BALL_FETCH)
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
.enemySpecies(Species.SUNKERN)
|
.enemySpecies(Species.SUNKERN)
|
||||||
.enemyMoveset(SPLASH_ONLY);
|
.enemyMoveset(Moves.SPLASH);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("prevents the user and its allies from being afflicted by poison", async () => {
|
it("prevents the user and its allies from being afflicted by poison", async () => {
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { TurnEndPhase } from "#app/phases/turn-end-phase";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
@ -29,7 +28,7 @@ describe("Abilities - Power Spot", () => {
|
||||||
game = new GameManager(phaserGame);
|
game = new GameManager(phaserGame);
|
||||||
game.override.battleType("double");
|
game.override.battleType("double");
|
||||||
game.override.moveset([Moves.TACKLE, Moves.BREAKING_SWIPE, Moves.SPLASH, Moves.DAZZLING_GLEAM]);
|
game.override.moveset([Moves.TACKLE, Moves.BREAKING_SWIPE, Moves.SPLASH, Moves.DAZZLING_GLEAM]);
|
||||||
game.override.enemyMoveset(SPLASH_ONLY);
|
game.override.enemyMoveset(Moves.SPLASH);
|
||||||
game.override.enemySpecies(Species.SHUCKLE);
|
game.override.enemySpecies(Species.SHUCKLE);
|
||||||
game.override.enemyAbility(Abilities.BALL_FETCH);
|
game.override.enemyAbility(Abilities.BALL_FETCH);
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,7 +9,6 @@ import { Biome } from "#enums/biome";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
||||||
|
|
||||||
|
@ -183,7 +182,7 @@ describe("Abilities - Protean", () => {
|
||||||
"ability applies correctly even if the pokemon's move misses",
|
"ability applies correctly even if the pokemon's move misses",
|
||||||
async () => {
|
async () => {
|
||||||
game.override.moveset([Moves.TACKLE]);
|
game.override.moveset([Moves.TACKLE]);
|
||||||
game.override.enemyMoveset(SPLASH_ONLY);
|
game.override.enemyMoveset(Moves.SPLASH);
|
||||||
|
|
||||||
await game.startBattle([Species.MAGIKARP]);
|
await game.startBattle([Species.MAGIKARP]);
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ describe("Abilities - Quick Draw", () => {
|
||||||
game.override.enemyLevel(100);
|
game.override.enemyLevel(100);
|
||||||
game.override.enemySpecies(Species.MAGIKARP);
|
game.override.enemySpecies(Species.MAGIKARP);
|
||||||
game.override.enemyAbility(Abilities.BALL_FETCH);
|
game.override.enemyAbility(Abilities.BALL_FETCH);
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.TACKLE));
|
game.override.enemyMoveset([Moves.TACKLE]);
|
||||||
|
|
||||||
vi.spyOn(allAbilities[Abilities.QUICK_DRAW].getAttrs(BypassSpeedChanceAbAttr)[0], "chance", "get").mockReturnValue(100);
|
vi.spyOn(allAbilities[Abilities.QUICK_DRAW].getAttrs(BypassSpeedChanceAbAttr)[0], "chance", "get").mockReturnValue(100);
|
||||||
});
|
});
|
||||||
|
@ -76,7 +76,7 @@ describe("Abilities - Quick Draw", () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
test("does not increase priority", async () => {
|
test("does not increase priority", async () => {
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.EXTREME_SPEED));
|
game.override.enemyMoveset([Moves.EXTREME_SPEED]);
|
||||||
|
|
||||||
await game.startBattle();
|
await game.startBattle();
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ describe("Abilities - Sand Spit", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should trigger when hit with damaging move", async () => {
|
it("should trigger when hit with damaging move", async () => {
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.TACKLE));
|
game.override.enemyMoveset([Moves.TACKLE]);
|
||||||
await game.startBattle();
|
await game.startBattle();
|
||||||
|
|
||||||
game.move.select(Moves.SPLASH);
|
game.move.select(Moves.SPLASH);
|
||||||
|
@ -45,7 +45,7 @@ describe("Abilities - Sand Spit", () => {
|
||||||
}, 20000);
|
}, 20000);
|
||||||
|
|
||||||
it("should not trigger when targetted with status moves", async () => {
|
it("should not trigger when targetted with status moves", async () => {
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.GROWL));
|
game.override.enemyMoveset([Moves.GROWL]);
|
||||||
await game.startBattle();
|
await game.startBattle();
|
||||||
|
|
||||||
game.move.select(Moves.COIL);
|
game.move.select(Moves.COIL);
|
||||||
|
|
|
@ -9,7 +9,6 @@ import { Species } from "#enums/species";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
import { SPLASH_ONLY } from "../utils/testUtils";
|
|
||||||
|
|
||||||
// See also: TypeImmunityAbAttr
|
// See also: TypeImmunityAbAttr
|
||||||
describe("Abilities - Sap Sipper", () => {
|
describe("Abilities - Sap Sipper", () => {
|
||||||
|
@ -37,7 +36,7 @@ describe("Abilities - Sap Sipper", () => {
|
||||||
const enemyAbility = Abilities.SAP_SIPPER;
|
const enemyAbility = Abilities.SAP_SIPPER;
|
||||||
|
|
||||||
game.override.moveset([ moveToUse ]);
|
game.override.moveset([ moveToUse ]);
|
||||||
game.override.enemyMoveset(SPLASH_ONLY);
|
game.override.enemyMoveset(Moves.SPLASH);
|
||||||
game.override.enemySpecies(Species.DUSKULL);
|
game.override.enemySpecies(Species.DUSKULL);
|
||||||
game.override.enemyAbility(enemyAbility);
|
game.override.enemyAbility(enemyAbility);
|
||||||
|
|
||||||
|
@ -59,7 +58,7 @@ describe("Abilities - Sap Sipper", () => {
|
||||||
const enemyAbility = Abilities.SAP_SIPPER;
|
const enemyAbility = Abilities.SAP_SIPPER;
|
||||||
|
|
||||||
game.override.moveset([ moveToUse ]);
|
game.override.moveset([ moveToUse ]);
|
||||||
game.override.enemyMoveset(SPLASH_ONLY);
|
game.override.enemyMoveset(Moves.SPLASH);
|
||||||
game.override.enemySpecies(Species.RATTATA);
|
game.override.enemySpecies(Species.RATTATA);
|
||||||
game.override.enemyAbility(enemyAbility);
|
game.override.enemyAbility(enemyAbility);
|
||||||
|
|
||||||
|
@ -80,7 +79,7 @@ describe("Abilities - Sap Sipper", () => {
|
||||||
const enemyAbility = Abilities.SAP_SIPPER;
|
const enemyAbility = Abilities.SAP_SIPPER;
|
||||||
|
|
||||||
game.override.moveset([ moveToUse ]);
|
game.override.moveset([ moveToUse ]);
|
||||||
game.override.enemyMoveset(SPLASH_ONLY);
|
game.override.enemyMoveset(Moves.SPLASH);
|
||||||
game.override.enemySpecies(Species.RATTATA);
|
game.override.enemySpecies(Species.RATTATA);
|
||||||
game.override.enemyAbility(enemyAbility);
|
game.override.enemyAbility(enemyAbility);
|
||||||
|
|
||||||
|
@ -100,7 +99,7 @@ describe("Abilities - Sap Sipper", () => {
|
||||||
const enemyAbility = Abilities.SAP_SIPPER;
|
const enemyAbility = Abilities.SAP_SIPPER;
|
||||||
|
|
||||||
game.override.moveset([ moveToUse ]);
|
game.override.moveset([ moveToUse ]);
|
||||||
game.override.enemyMoveset(SPLASH_ONLY);
|
game.override.enemyMoveset(Moves.SPLASH);
|
||||||
game.override.enemySpecies(Species.RATTATA);
|
game.override.enemySpecies(Species.RATTATA);
|
||||||
game.override.enemyAbility(enemyAbility);
|
game.override.enemyAbility(enemyAbility);
|
||||||
|
|
||||||
|
@ -123,7 +122,7 @@ describe("Abilities - Sap Sipper", () => {
|
||||||
|
|
||||||
game.override.moveset([ moveToUse ]);
|
game.override.moveset([ moveToUse ]);
|
||||||
game.override.ability(ability);
|
game.override.ability(ability);
|
||||||
game.override.enemyMoveset(SPLASH_ONLY);
|
game.override.enemyMoveset(Moves.SPLASH);
|
||||||
game.override.enemySpecies(Species.RATTATA);
|
game.override.enemySpecies(Species.RATTATA);
|
||||||
game.override.enemyAbility(Abilities.NONE);
|
game.override.enemyAbility(Abilities.NONE);
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { Stat } from "#enums/stat";
|
import { Moves } from "#app/enums/moves";
|
||||||
import GameManager from "#test/utils/gameManager";
|
|
||||||
import { Abilities } from "#enums/abilities";
|
import { Abilities } from "#enums/abilities";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
|
import { Stat } from "#enums/stat";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
import { SPLASH_ONLY } from "../utils/testUtils";
|
|
||||||
|
|
||||||
describe("Abilities - Simple", () => {
|
describe("Abilities - Simple", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
|
@ -27,7 +27,7 @@ describe("Abilities - Simple", () => {
|
||||||
.enemySpecies(Species.BULBASAUR)
|
.enemySpecies(Species.BULBASAUR)
|
||||||
.enemyAbility(Abilities.SIMPLE)
|
.enemyAbility(Abilities.SIMPLE)
|
||||||
.ability(Abilities.INTIMIDATE)
|
.ability(Abilities.INTIMIDATE)
|
||||||
.enemyMoveset(SPLASH_ONLY);
|
.enemyMoveset(Moves.SPLASH);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should double stat changes when applied", async() => {
|
it("should double stat changes when applied", async() => {
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { Abilities } from "#app/enums/abilities";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
@ -31,7 +30,7 @@ describe("Abilities - Steely Spirit", () => {
|
||||||
game.override.enemySpecies(Species.SHUCKLE);
|
game.override.enemySpecies(Species.SHUCKLE);
|
||||||
game.override.enemyAbility(Abilities.BALL_FETCH);
|
game.override.enemyAbility(Abilities.BALL_FETCH);
|
||||||
game.override.moveset([Moves.IRON_HEAD, Moves.SPLASH]);
|
game.override.moveset([Moves.IRON_HEAD, Moves.SPLASH]);
|
||||||
game.override.enemyMoveset(SPLASH_ONLY);
|
game.override.enemyMoveset(Moves.SPLASH);
|
||||||
vi.spyOn(allMoves[moveToCheck], "calculateBattlePower");
|
vi.spyOn(allMoves[moveToCheck], "calculateBattlePower");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ import { TurnEndPhase } from "#app/phases/turn-end-phase";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
@ -45,7 +44,7 @@ describe("Abilities - Sweet Veil", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("causes Rest to fail when used by the user or its allies", async () => {
|
it("causes Rest to fail when used by the user or its allies", async () => {
|
||||||
game.override.enemyMoveset(SPLASH_ONLY);
|
game.override.enemyMoveset(Moves.SPLASH);
|
||||||
await game.startBattle([Species.SWIRLIX, Species.MAGIKARP]);
|
await game.startBattle([Species.SWIRLIX, Species.MAGIKARP]);
|
||||||
|
|
||||||
game.move.select(Moves.SPLASH);
|
game.move.select(Moves.SPLASH);
|
||||||
|
@ -72,7 +71,7 @@ describe("Abilities - Sweet Veil", () => {
|
||||||
game.override.enemySpecies(Species.PIKACHU);
|
game.override.enemySpecies(Species.PIKACHU);
|
||||||
game.override.enemyLevel(5);
|
game.override.enemyLevel(5);
|
||||||
game.override.startingLevel(5);
|
game.override.startingLevel(5);
|
||||||
game.override.enemyMoveset(SPLASH_ONLY);
|
game.override.enemyMoveset(Moves.SPLASH);
|
||||||
|
|
||||||
await game.startBattle([Species.SHUCKLE, Species.SHUCKLE, Species.SWIRLIX]);
|
await game.startBattle([Species.SHUCKLE, Species.SHUCKLE, Species.SWIRLIX]);
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ describe("Abilities - Tera Shell", () => {
|
||||||
.moveset([Moves.SPLASH])
|
.moveset([Moves.SPLASH])
|
||||||
.enemySpecies(Species.SNORLAX)
|
.enemySpecies(Species.SNORLAX)
|
||||||
.enemyAbility(Abilities.INSOMNIA)
|
.enemyAbility(Abilities.INSOMNIA)
|
||||||
.enemyMoveset(Array(4).fill(Moves.MACH_PUNCH))
|
.enemyMoveset([Moves.MACH_PUNCH])
|
||||||
.startingLevel(100)
|
.startingLevel(100)
|
||||||
.enemyLevel(100);
|
.enemyLevel(100);
|
||||||
});
|
});
|
||||||
|
@ -60,7 +60,7 @@ describe("Abilities - Tera Shell", () => {
|
||||||
it(
|
it(
|
||||||
"should not override type immunities",
|
"should not override type immunities",
|
||||||
async () => {
|
async () => {
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.SHADOW_SNEAK));
|
game.override.enemyMoveset([Moves.SHADOW_SNEAK]);
|
||||||
|
|
||||||
await game.classicMode.startBattle([Species.SNORLAX]);
|
await game.classicMode.startBattle([Species.SNORLAX]);
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ describe("Abilities - Tera Shell", () => {
|
||||||
it(
|
it(
|
||||||
"should not override type multipliers less than 0.5x",
|
"should not override type multipliers less than 0.5x",
|
||||||
async () => {
|
async () => {
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.QUICK_ATTACK));
|
game.override.enemyMoveset([Moves.QUICK_ATTACK]);
|
||||||
|
|
||||||
await game.classicMode.startBattle([Species.AGGRON]);
|
await game.classicMode.startBattle([Species.AGGRON]);
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ describe("Abilities - Tera Shell", () => {
|
||||||
it(
|
it(
|
||||||
"should not affect the effectiveness of fixed-damage moves",
|
"should not affect the effectiveness of fixed-damage moves",
|
||||||
async () => {
|
async () => {
|
||||||
game.override.enemyMoveset(Array(4).fill(Moves.DRAGON_RAGE));
|
game.override.enemyMoveset([Moves.DRAGON_RAGE]);
|
||||||
|
|
||||||
await game.classicMode.startBattle([Species.CHARIZARD]);
|
await game.classicMode.startBattle([Species.CHARIZARD]);
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ 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 GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
@ -28,7 +27,7 @@ describe("Abilities - Wind Power", () => {
|
||||||
game.override.enemySpecies(Species.SHIFTRY);
|
game.override.enemySpecies(Species.SHIFTRY);
|
||||||
game.override.enemyAbility(Abilities.WIND_POWER);
|
game.override.enemyAbility(Abilities.WIND_POWER);
|
||||||
game.override.moveset([Moves.TAILWIND, Moves.SPLASH, Moves.PETAL_BLIZZARD, Moves.SANDSTORM]);
|
game.override.moveset([Moves.TAILWIND, Moves.SPLASH, Moves.PETAL_BLIZZARD, Moves.SANDSTORM]);
|
||||||
game.override.enemyMoveset(SPLASH_ONLY);
|
game.override.enemyMoveset(Moves.SPLASH);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("it becomes charged when hit by wind moves", async () => {
|
it("it becomes charged when hit by wind moves", async () => {
|
||||||
|
|
|
@ -3,7 +3,6 @@ import GameManager from "#test/utils/gameManager";
|
||||||
import { Abilities } from "#enums/abilities";
|
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 { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
@ -28,7 +27,7 @@ describe("Abilities - Wind Rider", () => {
|
||||||
.enemySpecies(Species.SHIFTRY)
|
.enemySpecies(Species.SHIFTRY)
|
||||||
.enemyAbility(Abilities.WIND_RIDER)
|
.enemyAbility(Abilities.WIND_RIDER)
|
||||||
.moveset([Moves.TAILWIND, Moves.SPLASH, Moves.PETAL_BLIZZARD, Moves.SANDSTORM])
|
.moveset([Moves.TAILWIND, Moves.SPLASH, Moves.PETAL_BLIZZARD, Moves.SANDSTORM])
|
||||||
.enemyMoveset(SPLASH_ONLY);
|
.enemyMoveset(Moves.SPLASH);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("takes no damage from wind moves and its ATK stat stage is raised by 1 when hit by one", async () => {
|
it("takes no damage from wind moves and its ATK stat stage is raised by 1 when hit by one", async () => {
|
||||||
|
|
|
@ -5,7 +5,6 @@ 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 GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
@ -30,7 +29,7 @@ describe("Abilities - Wonder Skin", () => {
|
||||||
game.override.ability(Abilities.BALL_FETCH);
|
game.override.ability(Abilities.BALL_FETCH);
|
||||||
game.override.enemySpecies(Species.SHUCKLE);
|
game.override.enemySpecies(Species.SHUCKLE);
|
||||||
game.override.enemyAbility(Abilities.WONDER_SKIN);
|
game.override.enemyAbility(Abilities.WONDER_SKIN);
|
||||||
game.override.enemyMoveset(SPLASH_ONLY);
|
game.override.enemyMoveset(Moves.SPLASH);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("lowers accuracy of status moves to 50%", async () => {
|
it("lowers accuracy of status moves to 50%", async () => {
|
||||||
|
|
|
@ -6,7 +6,6 @@ import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
import { SPLASH_ONLY } from "../utils/testUtils";
|
|
||||||
|
|
||||||
const TIMEOUT = 20 * 1000;
|
const TIMEOUT = 20 * 1000;
|
||||||
|
|
||||||
|
@ -30,8 +29,8 @@ describe("Abilities - ZERO TO HERO", () => {
|
||||||
game = new GameManager(phaserGame);
|
game = new GameManager(phaserGame);
|
||||||
game.override
|
game.override
|
||||||
.battleType("single")
|
.battleType("single")
|
||||||
.moveset(SPLASH_ONLY)
|
.moveset(Moves.SPLASH)
|
||||||
.enemyMoveset(SPLASH_ONLY)
|
.enemyMoveset(Moves.SPLASH)
|
||||||
.enemyAbility(Abilities.BALL_FETCH);
|
.enemyAbility(Abilities.BALL_FETCH);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ import { Species } from "#enums/species";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
import { SPLASH_ONLY } from "../utils/testUtils";
|
|
||||||
|
|
||||||
describe("Arena - Gravity", () => {
|
describe("Arena - Gravity", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
|
@ -32,7 +31,7 @@ describe("Arena - Gravity", () => {
|
||||||
.ability(Abilities.UNNERVE)
|
.ability(Abilities.UNNERVE)
|
||||||
.enemyAbility(Abilities.BALL_FETCH)
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
.enemySpecies(Species.SHUCKLE)
|
.enemySpecies(Species.SHUCKLE)
|
||||||
.enemyMoveset(SPLASH_ONLY);
|
.enemyMoveset(Moves.SPLASH);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reference: https://bulbapedia.bulbagarden.net/wiki/Gravity_(move)
|
// Reference: https://bulbapedia.bulbagarden.net/wiki/Gravity_(move)
|
||||||
|
|
|
@ -31,7 +31,7 @@ describe("Weather - Fog", () => {
|
||||||
game.override.ability(Abilities.BALL_FETCH);
|
game.override.ability(Abilities.BALL_FETCH);
|
||||||
game.override.enemyAbility(Abilities.BALL_FETCH);
|
game.override.enemyAbility(Abilities.BALL_FETCH);
|
||||||
game.override.enemySpecies(Species.MAGIKARP);
|
game.override.enemySpecies(Species.MAGIKARP);
|
||||||
game.override.enemyMoveset(new Array(4).fill(Moves.SPLASH));
|
game.override.enemyMoveset([Moves.SPLASH]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("move accuracy is multiplied by 90%", async () => {
|
it("move accuracy is multiplied by 90%", async () => {
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { Species } from "#enums/species";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
import { SPLASH_ONLY } from "../utils/testUtils";
|
|
||||||
import { BattlerIndex } from "#app/battle";
|
import { BattlerIndex } from "#app/battle";
|
||||||
|
|
||||||
describe("Weather - Hail", () => {
|
describe("Weather - Hail", () => {
|
||||||
|
@ -26,8 +25,8 @@ describe("Weather - Hail", () => {
|
||||||
game.override
|
game.override
|
||||||
.weather(WeatherType.HAIL)
|
.weather(WeatherType.HAIL)
|
||||||
.battleType("single")
|
.battleType("single")
|
||||||
.moveset(SPLASH_ONLY)
|
.moveset(Moves.SPLASH)
|
||||||
.enemyMoveset(SPLASH_ONLY)
|
.enemyMoveset(Moves.SPLASH)
|
||||||
.enemySpecies(Species.MAGIKARP);
|
.enemySpecies(Species.MAGIKARP);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { Species } from "#enums/species";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
import { SPLASH_ONLY } from "../utils/testUtils";
|
|
||||||
|
|
||||||
describe("Weather - Sandstorm", () => {
|
describe("Weather - Sandstorm", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
|
@ -25,8 +24,8 @@ describe("Weather - Sandstorm", () => {
|
||||||
game.override
|
game.override
|
||||||
.weather(WeatherType.SANDSTORM)
|
.weather(WeatherType.SANDSTORM)
|
||||||
.battleType("single")
|
.battleType("single")
|
||||||
.moveset(SPLASH_ONLY)
|
.moveset(Moves.SPLASH)
|
||||||
.enemyMoveset(SPLASH_ONLY)
|
.enemyMoveset(Moves.SPLASH)
|
||||||
.enemySpecies(Species.MAGIKARP);
|
.enemySpecies(Species.MAGIKARP);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { allMoves } from "#app/data/move";
|
import { allMoves } from "#app/data/move";
|
||||||
|
import { StatusEffect } from "#app/enums/status-effect";
|
||||||
import { TurnStartPhase } from "#app/phases/turn-start-phase";
|
import { TurnStartPhase } from "#app/phases/turn-start-phase";
|
||||||
import { Abilities } from "#enums/abilities";
|
import { Abilities } from "#enums/abilities";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
|
@ -33,7 +34,7 @@ describe("Weather - Strong Winds", () => {
|
||||||
it("electric type move is not very effective on Rayquaza", async () => {
|
it("electric type move is not very effective on Rayquaza", async () => {
|
||||||
game.override.enemySpecies(Species.RAYQUAZA);
|
game.override.enemySpecies(Species.RAYQUAZA);
|
||||||
|
|
||||||
await game.startBattle([Species.PIKACHU]);
|
await game.classicMode.startBattle([Species.PIKACHU]);
|
||||||
const pikachu = game.scene.getPlayerPokemon()!;
|
const pikachu = game.scene.getPlayerPokemon()!;
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ describe("Weather - Strong Winds", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("electric type move is neutral for flying type pokemon", async () => {
|
it("electric type move is neutral for flying type pokemon", async () => {
|
||||||
await game.startBattle([Species.PIKACHU]);
|
await game.classicMode.startBattle([Species.PIKACHU]);
|
||||||
const pikachu = game.scene.getPlayerPokemon()!;
|
const pikachu = game.scene.getPlayerPokemon()!;
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
|
@ -55,7 +56,7 @@ describe("Weather - Strong Winds", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("ice type move is neutral for flying type pokemon", async () => {
|
it("ice type move is neutral for flying type pokemon", async () => {
|
||||||
await game.startBattle([Species.PIKACHU]);
|
await game.classicMode.startBattle([Species.PIKACHU]);
|
||||||
const pikachu = game.scene.getPlayerPokemon()!;
|
const pikachu = game.scene.getPlayerPokemon()!;
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
|
@ -66,7 +67,7 @@ describe("Weather - Strong Winds", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("rock type move is neutral for flying type pokemon", async () => {
|
it("rock type move is neutral for flying type pokemon", async () => {
|
||||||
await game.startBattle([Species.PIKACHU]);
|
await game.classicMode.startBattle([Species.PIKACHU]);
|
||||||
const pikachu = game.scene.getPlayerPokemon()!;
|
const pikachu = game.scene.getPlayerPokemon()!;
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
|
@ -75,4 +76,18 @@ describe("Weather - Strong Winds", () => {
|
||||||
await game.phaseInterceptor.to(TurnStartPhase);
|
await game.phaseInterceptor.to(TurnStartPhase);
|
||||||
expect(enemy.getAttackTypeEffectiveness(allMoves[Moves.ROCK_SLIDE].type, pikachu)).toBe(1);
|
expect(enemy.getAttackTypeEffectiveness(allMoves[Moves.ROCK_SLIDE].type, pikachu)).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("weather goes away when last trainer pokemon dies to indirect damage", async () => {
|
||||||
|
game.override.enemyStatusEffect(StatusEffect.POISON);
|
||||||
|
|
||||||
|
await game.classicMode.startBattle([Species.MAGIKARP]);
|
||||||
|
|
||||||
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
|
enemy.hp = 1;
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
|
expect(game.scene.arena.weather?.weatherType).toBeUndefined();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -25,7 +25,6 @@ import { PlayerGender } from "#enums/player-gender";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
import { SPLASH_ONLY } from "../utils/testUtils";
|
|
||||||
|
|
||||||
describe("Test Battle Phase", () => {
|
describe("Test Battle Phase", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
|
@ -319,7 +318,7 @@ describe("Test Battle Phase", () => {
|
||||||
.startingWave(1)
|
.startingWave(1)
|
||||||
.startingLevel(100)
|
.startingLevel(100)
|
||||||
.moveset([moveToUse])
|
.moveset([moveToUse])
|
||||||
.enemyMoveset(SPLASH_ONLY)
|
.enemyMoveset(Moves.SPLASH)
|
||||||
.startingHeldItems([{ name: "TEMP_STAT_STAGE_BOOSTER", type: Stat.ACC }]);
|
.startingHeldItems([{ name: "TEMP_STAT_STAGE_BOOSTER", type: Stat.ACC }]);
|
||||||
|
|
||||||
await game.startBattle();
|
await game.startBattle();
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { ArenaTagType } from "#enums/arena-tag-type";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
@ -31,7 +30,7 @@ describe("Round Down and Minimun 1 test in Damage Calculation", () => {
|
||||||
|
|
||||||
it("When the user fails to use Jump Kick with Wonder Guard ability, the damage should be 1.", async () => {
|
it("When the user fails to use Jump Kick with Wonder Guard ability, the damage should be 1.", async () => {
|
||||||
game.override.enemySpecies(Species.GASTLY);
|
game.override.enemySpecies(Species.GASTLY);
|
||||||
game.override.enemyMoveset(SPLASH_ONLY);
|
game.override.enemyMoveset(Moves.SPLASH);
|
||||||
game.override.starterSpecies(Species.SHEDINJA);
|
game.override.starterSpecies(Species.SHEDINJA);
|
||||||
game.override.moveset([Moves.JUMP_KICK]);
|
game.override.moveset([Moves.JUMP_KICK]);
|
||||||
game.override.ability(Abilities.WONDER_GUARD);
|
game.override.ability(Abilities.WONDER_GUARD);
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { TurnInitPhase } from "#app/phases/turn-init-phase";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
@ -29,7 +28,7 @@ describe("Double Battles", () => {
|
||||||
// double-battle player's pokemon both fainted in same round, then revive one, and next double battle summons two player's pokemon successfully.
|
// double-battle player's pokemon both fainted in same round, then revive one, and next double battle summons two player's pokemon successfully.
|
||||||
// (There were bugs that either only summon one when can summon two, player stuck in switchPhase etc)
|
// (There were bugs that either only summon one when can summon two, player stuck in switchPhase etc)
|
||||||
it("3v2 edge case: player summons 2 pokemon on the next battle after being fainted and revived", async () => {
|
it("3v2 edge case: player summons 2 pokemon on the next battle after being fainted and revived", async () => {
|
||||||
game.override.battleType("double").enemyMoveset(SPLASH_ONLY).moveset(SPLASH_ONLY);
|
game.override.battleType("double").enemyMoveset(Moves.SPLASH).moveset(Moves.SPLASH);
|
||||||
await game.startBattle([
|
await game.startBattle([
|
||||||
Species.BULBASAUR,
|
Species.BULBASAUR,
|
||||||
Species.CHARIZARD,
|
Species.CHARIZARD,
|
||||||
|
|
|
@ -8,7 +8,6 @@ import { Species } from "#enums/species";
|
||||||
import { StatusEffect } from "#enums/status-effect";
|
import { StatusEffect } from "#enums/status-effect";
|
||||||
import GameManager from "#test/utils/gameManager";
|
import GameManager from "#test/utils/gameManager";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
const TIMEOUT = 20 * 1000;
|
const TIMEOUT = 20 * 1000;
|
||||||
|
@ -38,7 +37,7 @@ describe("Inverse Battle", () => {
|
||||||
.ability(Abilities.BALL_FETCH)
|
.ability(Abilities.BALL_FETCH)
|
||||||
.enemySpecies(Species.MAGIKARP)
|
.enemySpecies(Species.MAGIKARP)
|
||||||
.enemyAbility(Abilities.BALL_FETCH)
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
.enemyMoveset(SPLASH_ONLY);
|
.enemyMoveset(Moves.SPLASH);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Immune types are 2x effective - Thunderbolt against Ground Type", async () => {
|
it("Immune types are 2x effective - Thunderbolt against Ground Type", async () => {
|
||||||
|
|
|
@ -2,7 +2,6 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
import GameManager from "./utils/gameManager";
|
import GameManager from "./utils/gameManager";
|
||||||
import { Species } from "#app/enums/species";
|
import { Species } from "#app/enums/species";
|
||||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||||
import { SPLASH_ONLY } from "./utils/testUtils";
|
|
||||||
import { Abilities } from "#app/enums/abilities";
|
import { Abilities } from "#app/enums/abilities";
|
||||||
import { Moves } from "#app/enums/moves";
|
import { Moves } from "#app/enums/moves";
|
||||||
import { EFFECTIVE_STATS } from "#app/enums/stat";
|
import { EFFECTIVE_STATS } from "#app/enums/stat";
|
||||||
|
@ -33,7 +32,7 @@ describe("Boss Pokemon / Shields", () => {
|
||||||
.disableTrainerWaves()
|
.disableTrainerWaves()
|
||||||
.disableCrits()
|
.disableCrits()
|
||||||
.enemySpecies(Species.RATTATA)
|
.enemySpecies(Species.RATTATA)
|
||||||
.enemyMoveset(SPLASH_ONLY)
|
.enemyMoveset(Moves.SPLASH)
|
||||||
.enemyHeldItems([])
|
.enemyHeldItems([])
|
||||||
.startingLevel(1000)
|
.startingLevel(1000)
|
||||||
.moveset([Moves.FALSE_SWIPE, Moves.SUPER_FANG, Moves.SPLASH])
|
.moveset([Moves.FALSE_SWIPE, Moves.SUPER_FANG, Moves.SPLASH])
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
import { Egg } from "#app/data/egg";
|
||||||
|
import { EggSourceType } from "#app/enums/egg-source-types";
|
||||||
|
import { EggTier } from "#app/enums/egg-type";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
describe("Manaphy Eggs", () => {
|
||||||
|
let phaserGame: Phaser.Game;
|
||||||
|
let game: GameManager;
|
||||||
|
const EGG_HATCH_COUNT: integer = 48;
|
||||||
|
let rngSweepProgress: number = 0;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
phaserGame = new Phaser.Game({
|
||||||
|
type: Phaser.HEADLESS,
|
||||||
|
});
|
||||||
|
game = new GameManager(phaserGame);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
game.phaseInterceptor.restoreOg();
|
||||||
|
vi.restoreAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await game.importData("src/test/utils/saves/everything.prsv");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In our tests, we will perform an "RNG sweep" by letting rngSweepProgress
|
||||||
|
* increase uniformly from 0 to 1 in order to get a uniform sample of the
|
||||||
|
* possible RNG outcomes. This will let us quickly and consistently find
|
||||||
|
* the probability of each RNG outcome.
|
||||||
|
*/
|
||||||
|
vi.spyOn(Phaser.Math.RND, "realInRange").mockImplementation((min: number, max: number) => {
|
||||||
|
return rngSweepProgress * (max - min) + min;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should have correct Manaphy rates and Rare Egg Move rates, from the egg gacha", () => {
|
||||||
|
const scene = game.scene;
|
||||||
|
|
||||||
|
let manaphyCount = 0;
|
||||||
|
let phioneCount = 0;
|
||||||
|
let rareEggMoveCount = 0;
|
||||||
|
for (let i = 0; i < EGG_HATCH_COUNT; i++) {
|
||||||
|
rngSweepProgress = (2 * i + 1) / (2 * EGG_HATCH_COUNT);
|
||||||
|
|
||||||
|
const newEgg = new Egg({ scene, tier: EggTier.COMMON, sourceType: EggSourceType.GACHA_SHINY, id: 204 });
|
||||||
|
const newHatch = newEgg.generatePlayerPokemon(scene);
|
||||||
|
if (newHatch.species.speciesId === Species.MANAPHY) {
|
||||||
|
manaphyCount++;
|
||||||
|
} else if (newHatch.species.speciesId === Species.PHIONE) {
|
||||||
|
phioneCount++;
|
||||||
|
}
|
||||||
|
if (newEgg.eggMoveIndex === 3) {
|
||||||
|
rareEggMoveCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(manaphyCount + phioneCount).toBe(EGG_HATCH_COUNT);
|
||||||
|
expect(manaphyCount).toBe(1/8 * EGG_HATCH_COUNT);
|
||||||
|
expect(rareEggMoveCount).toBe(1/12 * EGG_HATCH_COUNT);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should have correct Manaphy rates and Rare Egg Move rates, from Phione species eggs", () => {
|
||||||
|
const scene = game.scene;
|
||||||
|
|
||||||
|
let manaphyCount = 0;
|
||||||
|
let phioneCount = 0;
|
||||||
|
let rareEggMoveCount = 0;
|
||||||
|
for (let i = 0; i < EGG_HATCH_COUNT; i++) {
|
||||||
|
rngSweepProgress = (2 * i + 1) / (2 * EGG_HATCH_COUNT);
|
||||||
|
|
||||||
|
const newEgg = new Egg({ scene, species: Species.PHIONE, sourceType: EggSourceType.SAME_SPECIES_EGG });
|
||||||
|
const newHatch = newEgg.generatePlayerPokemon(scene);
|
||||||
|
if (newHatch.species.speciesId === Species.MANAPHY) {
|
||||||
|
manaphyCount++;
|
||||||
|
} else if (newHatch.species.speciesId === Species.PHIONE) {
|
||||||
|
phioneCount++;
|
||||||
|
}
|
||||||
|
if (newEgg.eggMoveIndex === 3) {
|
||||||
|
rareEggMoveCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(manaphyCount + phioneCount).toBe(EGG_HATCH_COUNT);
|
||||||
|
expect(manaphyCount).toBe(1/8 * EGG_HATCH_COUNT);
|
||||||
|
expect(rareEggMoveCount).toBe(1/6 * EGG_HATCH_COUNT);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should have correct Manaphy rates and Rare Egg Move rates, from Manaphy species eggs", () => {
|
||||||
|
const scene = game.scene;
|
||||||
|
|
||||||
|
let manaphyCount = 0;
|
||||||
|
let phioneCount = 0;
|
||||||
|
let rareEggMoveCount = 0;
|
||||||
|
for (let i = 0; i < EGG_HATCH_COUNT; i++) {
|
||||||
|
rngSweepProgress = (2 * i + 1) / (2 * EGG_HATCH_COUNT);
|
||||||
|
|
||||||
|
const newEgg = new Egg({ scene, species: Species.MANAPHY, sourceType: EggSourceType.SAME_SPECIES_EGG });
|
||||||
|
const newHatch = newEgg.generatePlayerPokemon(scene);
|
||||||
|
if (newHatch.species.speciesId === Species.MANAPHY) {
|
||||||
|
manaphyCount++;
|
||||||
|
} else if (newHatch.species.speciesId === Species.PHIONE) {
|
||||||
|
phioneCount++;
|
||||||
|
}
|
||||||
|
if (newEgg.eggMoveIndex === 3) {
|
||||||
|
rareEggMoveCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(phioneCount).toBe(0);
|
||||||
|
expect(manaphyCount).toBe(EGG_HATCH_COUNT);
|
||||||
|
expect(rareEggMoveCount).toBe(1/6 * EGG_HATCH_COUNT);
|
||||||
|
});
|
||||||
|
});
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue