mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-06-30 21:42:20 +02:00
Merge branch 'held-item-refactor' of https://github.com/Wlowscha/pokerogue into held-item-refactor
This commit is contained in:
commit
0533d6c35a
2
.github/pull_request_template.md
vendored
2
.github/pull_request_template.md
vendored
@ -65,7 +65,7 @@ Do the reviewers need to do something special in order to test your changes?
|
|||||||
- [ ] The PR is self-contained and cannot be split into smaller PRs?
|
- [ ] The PR is self-contained and cannot be split into smaller PRs?
|
||||||
- [ ] Have I provided a clear explanation of the changes?
|
- [ ] Have I provided a clear explanation of the changes?
|
||||||
- [ ] Have I tested the changes manually?
|
- [ ] Have I tested the changes manually?
|
||||||
- [ ] Are all unit tests still passing? (`npm run test`)
|
- [ ] Are all unit tests still passing? (`npm run test:silent`)
|
||||||
- [ ] Have I created new automated tests (`npm run create-test`) or updated existing tests related to the PR's changes?
|
- [ ] Have I created new automated tests (`npm run create-test`) or updated existing tests related to the PR's changes?
|
||||||
- [ ] Have I provided screenshots/videos of the changes (if applicable)?
|
- [ ] Have I provided screenshots/videos of the changes (if applicable)?
|
||||||
- [ ] Have I made sure that any UI change works for both UI themes (default and legacy)?
|
- [ ] Have I made sure that any UI change works for both UI themes (default and legacy)?
|
||||||
|
20
biome.jsonc
20
biome.jsonc
@ -38,6 +38,9 @@
|
|||||||
"src/data/balance/tms.ts"
|
"src/data/balance/tms.ts"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// While it'd be nice to enable consistent sorting, enabling this causes issues due to circular import resolution order
|
||||||
|
// TODO: Remove if we ever get down to 0 circular imports
|
||||||
"organizeImports": { "enabled": false },
|
"organizeImports": { "enabled": false },
|
||||||
"linter": {
|
"linter": {
|
||||||
"ignore": [
|
"ignore": [
|
||||||
@ -55,13 +58,13 @@
|
|||||||
},
|
},
|
||||||
"style": {
|
"style": {
|
||||||
"noVar": "error",
|
"noVar": "error",
|
||||||
"useEnumInitializers": "off",
|
"useEnumInitializers": "off", // large enums like Moves/Species would make this cumbersome
|
||||||
"useBlockStatements": "error",
|
"useBlockStatements": "error",
|
||||||
"useConst": "error",
|
"useConst": "error",
|
||||||
"useImportType": "error",
|
"useImportType": "error",
|
||||||
"noNonNullAssertion": "off", // TODO: Turn this on ASAP and fix all non-null assertions
|
"noNonNullAssertion": "off", // TODO: Turn this on ASAP and fix all non-null assertions in non-test files
|
||||||
"noParameterAssign": "off",
|
"noParameterAssign": "off",
|
||||||
"useExponentiationOperator": "off",
|
"useExponentiationOperator": "off", // Too typo-prone and easy to mixup with standard multiplication (* vs **)
|
||||||
"useDefaultParameterLast": "off", // TODO: Fix spots in the codebase where this flag would be triggered, and then enable
|
"useDefaultParameterLast": "off", // TODO: Fix spots in the codebase where this flag would be triggered, and then enable
|
||||||
"useSingleVarDeclarator": "off",
|
"useSingleVarDeclarator": "off",
|
||||||
"useNodejsImportProtocol": "off",
|
"useNodejsImportProtocol": "off",
|
||||||
@ -70,17 +73,20 @@
|
|||||||
},
|
},
|
||||||
"suspicious": {
|
"suspicious": {
|
||||||
"noDoubleEquals": "error",
|
"noDoubleEquals": "error",
|
||||||
|
// While this would be a nice rule to enable, the current structure of the codebase makes this infeasible
|
||||||
|
// due to being used for move/ability `args` params and save data-related code.
|
||||||
|
// This can likely be enabled for all non-utils files once these are eventually reworked, but until then we leave it off.
|
||||||
"noExplicitAny": "off",
|
"noExplicitAny": "off",
|
||||||
"noAssignInExpressions": "off",
|
"noAssignInExpressions": "off",
|
||||||
"noPrototypeBuiltins": "off",
|
"noPrototypeBuiltins": "off",
|
||||||
"noFallthroughSwitchClause": "off",
|
"noFallthroughSwitchClause": "error", // Prevents accidental automatic fallthroughs in switch cases (use disable comment if needed)
|
||||||
"noImplicitAnyLet": "info", // TODO: Refactor and make this an error
|
"noImplicitAnyLet": "warn", // TODO: Refactor and make this an error
|
||||||
"noRedeclare": "off", // TODO: Refactor and make this an error
|
"noRedeclare": "info", // TODO: Refactor and make this an error
|
||||||
"noGlobalIsNan": "off",
|
"noGlobalIsNan": "off",
|
||||||
"noAsyncPromiseExecutor": "warn" // TODO: Refactor and make this an error
|
"noAsyncPromiseExecutor": "warn" // TODO: Refactor and make this an error
|
||||||
},
|
},
|
||||||
"complexity": {
|
"complexity": {
|
||||||
"noExcessiveCognitiveComplexity": "warn",
|
"noExcessiveCognitiveComplexity": "warn", // TODO: Refactor and make this an error
|
||||||
"useLiteralKeys": "off",
|
"useLiteralKeys": "off",
|
||||||
"noForEach": "off", // Foreach vs for of is not that simple.
|
"noForEach": "off", // Foreach vs for of is not that simple.
|
||||||
"noUselessSwitchCase": "off", // Explicit > Implicit
|
"noUselessSwitchCase": "off", // Explicit > Implicit
|
||||||
|
@ -1,40 +1,34 @@
|
|||||||
# ESLint
|
# Biome
|
||||||
|
|
||||||
## Key Features
|
## Key Features
|
||||||
|
|
||||||
1. **Automation**:
|
1. **Automation**:
|
||||||
- A pre-commit hook has been added to automatically run ESLint on the added or modified files, ensuring code quality before commits.
|
- A pre-commit hook has been added to automatically run Biome on the added or modified files, ensuring code quality before commits.
|
||||||
|
|
||||||
2. **Manual Usage**:
|
2. **Manual Usage**:
|
||||||
- If you prefer not to use the pre-commit hook, you can manually run ESLint to automatically fix issues using the command:
|
- If you prefer not to use the pre-commit hook, you can manually run biome to automatically fix issues using the command:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npx eslint --fix . or npm run eslint
|
npx @biomejs/biome --write
|
||||||
```
|
```
|
||||||
|
|
||||||
- Running this command will lint all files in the repository.
|
- Running this command will lint all files in the repository.
|
||||||
|
|
||||||
3. **GitHub Action**:
|
3. **GitHub Action**:
|
||||||
- A GitHub Action has been added to automatically run ESLint on every push and pull request, ensuring code quality in the CI/CD pipeline.
|
- A GitHub Action has been added to automatically run Biome on every push and pull request, ensuring code quality in the CI/CD pipeline.
|
||||||
|
|
||||||
## Summary of ESLint Rules
|
If you are getting linting errors from biome and want to see which files they are coming from, you can find that out by running biome in a way that is configured to only show the errors for that specific rule: ``npx @biomejs/biome lint --only=category/ruleName``
|
||||||
|
|
||||||
1. **General Rules**:
|
## Summary of Biome Rules
|
||||||
- **Equality**: Use `===` and `!==` instead of `==` and `!=` (`eqeqeq`).
|
|
||||||
- **Indentation**: Enforce 2-space indentation (`indent`).
|
|
||||||
- **Quotes**: Use doublequotes for strings (`quotes`).
|
|
||||||
- **Variable Declarations**:
|
|
||||||
- Disallow `var`; use `let` or `const` (`no-var`).
|
|
||||||
- Prefer `const` for variables that are never reassigned (`prefer-const`).
|
|
||||||
- **Unused Variables**: Allow unused function parameters but enforce error for other unused variables (`@typescript-eslint/no-unused-vars`).
|
|
||||||
- **End of Line**: Ensure at least one newline at the end of files (`eol-last`).
|
|
||||||
- **Curly Braces**: Enforce the use of curly braces for all control statements (`curly`).
|
|
||||||
- **Brace Style**: Use one true brace style (`1tbs`) for TypeScript-specific syntax (`@typescript-eslint/brace-style`).
|
|
||||||
|
|
||||||
2. **TypeScript-Specific Rules**:
|
We use the [recommended ruleset](https://biomejs.dev/linter/rules/) for Biome, with some customizations to better suit our project's needs.
|
||||||
- **Semicolons**:
|
|
||||||
- Enforce semicolons for TypeScript-specific syntax (`@typescript-eslint/semi`).
|
|
||||||
- Disallow unnecessary semicolons (`@typescript-eslint/no-extra-semi`).
|
|
||||||
|
|
||||||
## Benefits
|
For a complete list of rules and their configurations, refer to the `biome.jsonc` file in the project root.
|
||||||
|
|
||||||
- **Consistency**: Ensures consistent coding style across the project.
|
Some things to consider:
|
||||||
- **Code Quality**: Helps catch potential errors and improve overall code quality.
|
|
||||||
- **Readability**: Makes the codebase easier to read and maintain.
|
- We have disabled rules that prioritize style over performance, such as `useTemplate`
|
||||||
|
- Some rules are currently marked as warnings (`warn`) to allow for gradual refactoring without blocking development. Do not write new code that triggers these warnings.
|
||||||
|
- The linter is configured to ignore specific files and folders, such as large or complex files that are pending refactors, to improve performance and focus on actionable areas.
|
||||||
|
|
||||||
|
Formatting is also handled by Biome. You should not have to worry about manually formatting your code.
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import tseslint from "@typescript-eslint/eslint-plugin";
|
/** @ts-check */
|
||||||
|
import tseslint from "typescript-eslint";
|
||||||
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 importX from "eslint-plugin-import-x";
|
import importX from "eslint-plugin-import-x";
|
||||||
|
|
||||||
export default [
|
export default tseslint.config(
|
||||||
{
|
{
|
||||||
name: "eslint-config",
|
name: "eslint-config",
|
||||||
files: ["src/**/*.{ts,tsx,js,jsx}", "test/**/*.{ts,tsx,js,jsx}"],
|
files: ["src/**/*.{ts,tsx,js,jsx}", "test/**/*.{ts,tsx,js,jsx}"],
|
||||||
@ -14,12 +15,11 @@ export default [
|
|||||||
plugins: {
|
plugins: {
|
||||||
"import-x": importX,
|
"import-x": importX,
|
||||||
"@stylistic/ts": stylisticTs,
|
"@stylistic/ts": stylisticTs,
|
||||||
"@typescript-eslint": tseslint,
|
"@typescript-eslint": tseslint.plugin,
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
"prefer-const": "error", // Enforces the use of `const` for variables that are never reassigned
|
|
||||||
"no-undef": "off", // Disables the rule that disallows the use of undeclared variables (TypeScript handles this)
|
"no-undef": "off", // Disables the rule that disallows the use of undeclared variables (TypeScript handles this)
|
||||||
"no-extra-semi": ["error"], // Disallows unnecessary semicolons for TypeScript-specific syntax
|
"no-extra-semi": "error", // Disallows unnecessary semicolons for TypeScript-specific syntax
|
||||||
"import-x/extensions": ["error", "never", { json: "always" }], // Enforces no extension for imports unless json
|
"import-x/extensions": ["error", "never", { json: "always" }], // Enforces no extension for imports unless json
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -33,11 +33,11 @@ export default [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: {
|
plugins: {
|
||||||
"@typescript-eslint": tseslint,
|
"@typescript-eslint": tseslint.plugin,
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
"@typescript-eslint/no-floating-promises": "error", // Require Promise-like statements to be handled appropriately. - https://typescript-eslint.io/rules/no-floating-promises/
|
"@typescript-eslint/no-floating-promises": "error", // Require Promise-like statements to be handled appropriately. - https://typescript-eslint.io/rules/no-floating-promises/
|
||||||
"@typescript-eslint/no-misused-promises": "error", // Disallow Promises in places not designed to handle them. - https://typescript-eslint.io/rules/no-misused-promises/
|
"@typescript-eslint/no-misused-promises": "error", // Disallow Promises in places not designed to handle them. - https://typescript-eslint.io/rules/no-misused-promises/
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
);
|
||||||
|
18
package-lock.json
generated
18
package-lock.json
generated
@ -18,8 +18,8 @@
|
|||||||
"i18next-korean-postposition-processor": "^1.0.0",
|
"i18next-korean-postposition-processor": "^1.0.0",
|
||||||
"json-stable-stringify": "^1.2.0",
|
"json-stable-stringify": "^1.2.0",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"phaser": "^3.70.0",
|
"phaser": "^3.88.2",
|
||||||
"phaser3-rex-plugins": "^1.80.14"
|
"phaser3-rex-plugins": "^1.80.15"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "1.9.4",
|
"@biomejs/biome": "1.9.4",
|
||||||
@ -48,7 +48,7 @@
|
|||||||
"vitest-canvas-mock": "^0.3.3"
|
"vitest-canvas-mock": "^0.3.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20.0.0"
|
"node": ">=22.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@ampproject/remapping": {
|
"node_modules/@ampproject/remapping": {
|
||||||
@ -6227,18 +6227,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/phaser": {
|
"node_modules/phaser": {
|
||||||
"version": "3.80.1",
|
"version": "3.88.2",
|
||||||
"resolved": "https://registry.npmjs.org/phaser/-/phaser-3.80.1.tgz",
|
"resolved": "https://registry.npmjs.org/phaser/-/phaser-3.88.2.tgz",
|
||||||
"integrity": "sha512-VQGAWoDOkEpAWYkI+PUADv5Ql+SM0xpLuAMBJHz9tBcOLqjJ2wd8bUhxJgOqclQlLTg97NmMd9MhS75w16x1Cw==",
|
"integrity": "sha512-UBgd2sAFuRJbF2xKaQ5jpMWB8oETncChLnymLGHcrnT53vaqiGrQWbUKUDBawKLm24sghjKo4Bf+/xfv8espZQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"eventemitter3": "^5.0.1"
|
"eventemitter3": "^5.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/phaser3-rex-plugins": {
|
"node_modules/phaser3-rex-plugins": {
|
||||||
"version": "1.80.14",
|
"version": "1.80.15",
|
||||||
"resolved": "https://registry.npmjs.org/phaser3-rex-plugins/-/phaser3-rex-plugins-1.80.14.tgz",
|
"resolved": "https://registry.npmjs.org/phaser3-rex-plugins/-/phaser3-rex-plugins-1.80.15.tgz",
|
||||||
"integrity": "sha512-eHi3VgryO9umNu6D1yQU5IS6tH4TyC2Y6RgJ495nNp37X2fdYnmYpBfgFg+YaumvtaoOvCkUVyi/YqWNPf2X2A==",
|
"integrity": "sha512-Ur973N1W5st6XEYBcJko8eTcEbdDHMM+m7VqvT3j/EJeJwYyJ3bVb33JJDsFgefk3A2iAz2itP/UY7CzxJOJVA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dagre": "^0.8.5",
|
"dagre": "^0.8.5",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "pokemon-rogue-battle",
|
"name": "pokemon-rogue-battle",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.8.4",
|
"version": "1.8.5",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "vite",
|
"start": "vite",
|
||||||
@ -9,7 +9,7 @@
|
|||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"build:beta": "vite build --mode beta",
|
"build:beta": "vite build --mode beta",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"test": "vitest run",
|
"test": "vitest run --no-isolate",
|
||||||
"test:cov": "vitest run --coverage --no-isolate",
|
"test:cov": "vitest run --coverage --no-isolate",
|
||||||
"test:watch": "vitest watch --coverage --no-isolate",
|
"test:watch": "vitest watch --coverage --no-isolate",
|
||||||
"test:silent": "vitest run --silent --no-isolate",
|
"test:silent": "vitest run --silent --no-isolate",
|
||||||
@ -63,8 +63,8 @@
|
|||||||
"i18next-korean-postposition-processor": "^1.0.0",
|
"i18next-korean-postposition-processor": "^1.0.0",
|
||||||
"json-stable-stringify": "^1.2.0",
|
"json-stable-stringify": "^1.2.0",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"phaser": "^3.70.0",
|
"phaser": "^3.88.2",
|
||||||
"phaser3-rex-plugins": "^1.80.14"
|
"phaser3-rex-plugins": "^1.80.15"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22.0.0"
|
"node": ">=22.0.0"
|
||||||
|
@ -516,8 +516,36 @@
|
|||||||
"trimmed": true,
|
"trimmed": true,
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 28, "h": 11 },
|
"spriteSourceSize": { "x": 0, "y": 0, "w": 28, "h": 11 },
|
||||||
"sourceSize": { "w": 28, "h": 11 }
|
"sourceSize": { "w": 28, "h": 11 }
|
||||||
|
},
|
||||||
|
"BACK_SLASH.png": {
|
||||||
|
"frame": { "x": 147, "y": 66, "w": 12, "h": 11 },
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": true,
|
||||||
|
"spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
|
||||||
|
"sourceSize": { "w": 12, "h": 11 }
|
||||||
|
},
|
||||||
|
"FORWARD_SLASH.png": {
|
||||||
|
"frame": { "x": 144, "y": 55, "w": 12, "h": 11 },
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": true,
|
||||||
|
"spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
|
||||||
|
"sourceSize": { "w": 12, "h": 11 }
|
||||||
|
},
|
||||||
|
"COMMA.png": {
|
||||||
|
"frame": { "x": 144, "y": 44, "w": 12, "h": 11 },
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": true,
|
||||||
|
"spriteSourceSize": { "x": 0, "y": 0, "w": 12, "h": 11 },
|
||||||
|
"sourceSize": { "w": 12, "h": 11 }
|
||||||
|
},
|
||||||
|
"PERIOD.png": {
|
||||||
|
"frame": { "x": 143, "y": 22, "w": 11, "h": 11 },
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": true,
|
||||||
|
"spriteSourceSize": { "x": 0, "y": 0, "w": 11, "h": 11 },
|
||||||
|
"sourceSize": { "w": 11, "h": 11 }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"meta": {
|
"meta": {
|
||||||
"app": "https://www.aseprite.org/",
|
"app": "https://www.aseprite.org/",
|
||||||
"version": "1.3.7-dev",
|
"version": "1.3.7-dev",
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.6 KiB |
@ -1 +1 @@
|
|||||||
Subproject commit e98f0eb9c2022bc78b53f0444424c636498e725a
|
Subproject commit 833dc40ec7409031fcea147ccbc45ec9c0ba0213
|
@ -1,7 +1,7 @@
|
|||||||
import { pokerogueApi } from "#app/plugins/api/pokerogue-api";
|
import { pokerogueApi } from "#app/plugins/api/pokerogue-api";
|
||||||
import type { UserInfo } from "#app/@types/UserInfo";
|
import type { UserInfo } from "#app/@types/UserInfo";
|
||||||
import { bypassLogin } from "#app/battle-scene";
|
import { bypassLogin } from "./global-vars/bypass-login";
|
||||||
import { randomString } from "#app/utils";
|
import { randomString } from "#app/utils/common";
|
||||||
|
|
||||||
export let loggedInUser: UserInfo | null = null;
|
export let loggedInUser: UserInfo | null = null;
|
||||||
// This is a random string that is used to identify the client session - unique per session (tab or window) so that the game will only save on the one that the server is expecting
|
// This is a random string that is used to identify the client session - unique per session (tab or window) so that the game will only save on the one that the server is expecting
|
||||||
|
@ -18,7 +18,7 @@ import {
|
|||||||
isNullOrUndefined,
|
isNullOrUndefined,
|
||||||
BooleanHolder,
|
BooleanHolder,
|
||||||
type Constructor,
|
type Constructor,
|
||||||
} from "#app/utils";
|
} from "#app/utils/common";
|
||||||
import type { Modifier, ModifierPredicate, TurnHeldItemTransferModifier } from "./modifier/modifier";
|
import type { Modifier, ModifierPredicate, TurnHeldItemTransferModifier } from "./modifier/modifier";
|
||||||
import {
|
import {
|
||||||
ConsumableModifier,
|
ConsumableModifier,
|
||||||
@ -77,7 +77,8 @@ import {
|
|||||||
} from "#app/data/abilities/ability";
|
} from "#app/data/abilities/ability";
|
||||||
import { allAbilities } from "./data/data-lists";
|
import { allAbilities } from "./data/data-lists";
|
||||||
import type { FixedBattleConfig } from "#app/battle";
|
import type { FixedBattleConfig } from "#app/battle";
|
||||||
import Battle, { BattleType } from "#app/battle";
|
import Battle from "#app/battle";
|
||||||
|
import { BattleType } from "#enums/battle-type";
|
||||||
import type { GameMode } from "#app/game-mode";
|
import type { GameMode } from "#app/game-mode";
|
||||||
import { GameModes, getGameMode } from "#app/game-mode";
|
import { GameModes, getGameMode } from "#app/game-mode";
|
||||||
import FieldSpritePipeline from "#app/pipelines/field-sprite";
|
import FieldSpritePipeline from "#app/pipelines/field-sprite";
|
||||||
@ -150,7 +151,6 @@ import { NextEncounterPhase } from "#app/phases/next-encounter-phase";
|
|||||||
import { PokemonAnimPhase } from "#app/phases/pokemon-anim-phase";
|
import { PokemonAnimPhase } from "#app/phases/pokemon-anim-phase";
|
||||||
import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase";
|
import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase";
|
||||||
import { ReturnPhase } from "#app/phases/return-phase";
|
import { ReturnPhase } from "#app/phases/return-phase";
|
||||||
import { SelectBiomePhase } from "#app/phases/select-biome-phase";
|
|
||||||
import { ShowTrainerPhase } from "#app/phases/show-trainer-phase";
|
import { ShowTrainerPhase } from "#app/phases/show-trainer-phase";
|
||||||
import { SummonPhase } from "#app/phases/summon-phase";
|
import { SummonPhase } from "#app/phases/summon-phase";
|
||||||
import { SwitchPhase } from "#app/phases/switch-phase";
|
import { SwitchPhase } from "#app/phases/switch-phase";
|
||||||
@ -184,8 +184,8 @@ import { HideAbilityPhase } from "#app/phases/hide-ability-phase";
|
|||||||
import { expSpriteKeys } from "./sprites/sprite-keys";
|
import { expSpriteKeys } from "./sprites/sprite-keys";
|
||||||
import { hasExpSprite } from "./sprites/sprite-utils";
|
import { hasExpSprite } from "./sprites/sprite-utils";
|
||||||
import { timedEventManager } from "./global-event-manager";
|
import { timedEventManager } from "./global-event-manager";
|
||||||
|
import { starterColors } from "./global-vars/starter-colors";
|
||||||
export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1";
|
import { startingWave } from "./starting-wave";
|
||||||
|
|
||||||
const DEBUG_RNG = false;
|
const DEBUG_RNG = false;
|
||||||
|
|
||||||
@ -193,13 +193,6 @@ const OPP_IVS_OVERRIDE_VALIDATED: number[] = (
|
|||||||
Array.isArray(Overrides.OPP_IVS_OVERRIDE) ? Overrides.OPP_IVS_OVERRIDE : new Array(6).fill(Overrides.OPP_IVS_OVERRIDE)
|
Array.isArray(Overrides.OPP_IVS_OVERRIDE) ? Overrides.OPP_IVS_OVERRIDE : new Array(6).fill(Overrides.OPP_IVS_OVERRIDE)
|
||||||
).map(iv => (Number.isNaN(iv) || iv === null || iv > 31 ? -1 : iv));
|
).map(iv => (Number.isNaN(iv) || iv === null || iv > 31 ? -1 : iv));
|
||||||
|
|
||||||
export const startingWave = Overrides.STARTING_WAVE_OVERRIDE || 1;
|
|
||||||
|
|
||||||
export let starterColors: StarterColors;
|
|
||||||
interface StarterColors {
|
|
||||||
[key: string]: [string, string];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PokeballCounts {
|
export interface PokeballCounts {
|
||||||
[pb: string]: number;
|
[pb: string]: number;
|
||||||
}
|
}
|
||||||
@ -809,11 +802,11 @@ export default class BattleScene extends SceneBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async initStarterColors(): Promise<void> {
|
async initStarterColors(): Promise<void> {
|
||||||
if (starterColors) {
|
if (Object.keys(starterColors).length > 0) {
|
||||||
|
// already initialized
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const sc = await this.cachedFetch("./starter-colors.json").then(res => res.json());
|
const sc = await this.cachedFetch("./starter-colors.json").then(res => res.json());
|
||||||
starterColors = {};
|
|
||||||
for (const key of Object.keys(sc)) {
|
for (const key of Object.keys(sc)) {
|
||||||
starterColors[key] = sc[key];
|
starterColors[key] = sc[key];
|
||||||
}
|
}
|
||||||
@ -1304,6 +1297,16 @@ export default class BattleScene extends SceneBase {
|
|||||||
return Math.max(doubleChance.value, 1);
|
return Math.max(doubleChance.value, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isNewBiome(currentBattle = this.currentBattle) {
|
||||||
|
const isWaveIndexMultipleOfTen = !(currentBattle.waveIndex % 10);
|
||||||
|
const isEndlessOrDaily = this.gameMode.hasShortBiomes || this.gameMode.isDaily;
|
||||||
|
const isEndlessFifthWave = this.gameMode.hasShortBiomes && currentBattle.waveIndex % 5 === 0;
|
||||||
|
const isWaveIndexMultipleOfFiftyMinusOne = currentBattle.waveIndex % 50 === 49;
|
||||||
|
const isNewBiome =
|
||||||
|
isWaveIndexMultipleOfTen || isEndlessFifthWave || (isEndlessOrDaily && isWaveIndexMultipleOfFiftyMinusOne);
|
||||||
|
return isNewBiome;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: ...this never actually returns `null`, right?
|
// TODO: ...this never actually returns `null`, right?
|
||||||
newBattle(
|
newBattle(
|
||||||
waveIndex?: number,
|
waveIndex?: number,
|
||||||
@ -1338,22 +1341,27 @@ export default class BattleScene extends SceneBase {
|
|||||||
} else {
|
} else {
|
||||||
if (
|
if (
|
||||||
!this.gameMode.hasTrainers ||
|
!this.gameMode.hasTrainers ||
|
||||||
|
Overrides.BATTLE_TYPE_OVERRIDE === BattleType.WILD ||
|
||||||
(Overrides.DISABLE_STANDARD_TRAINERS_OVERRIDE && isNullOrUndefined(trainerData))
|
(Overrides.DISABLE_STANDARD_TRAINERS_OVERRIDE && isNullOrUndefined(trainerData))
|
||||||
) {
|
) {
|
||||||
newBattleType = BattleType.WILD;
|
newBattleType = BattleType.WILD;
|
||||||
} else if (battleType === undefined) {
|
|
||||||
newBattleType = this.gameMode.isWaveTrainer(newWaveIndex, this.arena) ? BattleType.TRAINER : BattleType.WILD;
|
|
||||||
} else {
|
} else {
|
||||||
newBattleType = battleType;
|
newBattleType =
|
||||||
|
Overrides.BATTLE_TYPE_OVERRIDE ??
|
||||||
|
battleType ??
|
||||||
|
(this.gameMode.isWaveTrainer(newWaveIndex, this.arena) ? BattleType.TRAINER : BattleType.WILD);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newBattleType === BattleType.TRAINER) {
|
if (newBattleType === BattleType.TRAINER) {
|
||||||
const trainerType = this.arena.randomTrainerType(newWaveIndex);
|
const trainerType =
|
||||||
|
Overrides.RANDOM_TRAINER_OVERRIDE?.trainerType ?? this.arena.randomTrainerType(newWaveIndex);
|
||||||
let doubleTrainer = false;
|
let doubleTrainer = false;
|
||||||
if (trainerConfigs[trainerType].doubleOnly) {
|
if (trainerConfigs[trainerType].doubleOnly) {
|
||||||
doubleTrainer = true;
|
doubleTrainer = true;
|
||||||
} else if (trainerConfigs[trainerType].hasDouble) {
|
} else if (trainerConfigs[trainerType].hasDouble) {
|
||||||
doubleTrainer = !randSeedInt(this.getDoubleBattleChance(newWaveIndex, playerField));
|
doubleTrainer =
|
||||||
|
Overrides.RANDOM_TRAINER_OVERRIDE?.alwaysDouble ||
|
||||||
|
!randSeedInt(this.getDoubleBattleChance(newWaveIndex, playerField));
|
||||||
// Add a check that special trainers can't be double except for tate and liza - they should use the normal double chance
|
// Add a check that special trainers can't be double except for tate and liza - they should use the normal double chance
|
||||||
if (
|
if (
|
||||||
trainerConfigs[trainerType].trainerTypeDouble &&
|
trainerConfigs[trainerType].trainerTypeDouble &&
|
||||||
@ -1373,7 +1381,10 @@ export default class BattleScene extends SceneBase {
|
|||||||
|
|
||||||
// Check for mystery encounter
|
// Check for mystery encounter
|
||||||
// Can only occur in place of a standard (non-boss) wild battle, waves 10-180
|
// Can only occur in place of a standard (non-boss) wild battle, waves 10-180
|
||||||
if (this.isWaveMysteryEncounter(newBattleType, newWaveIndex) || newBattleType === BattleType.MYSTERY_ENCOUNTER) {
|
if (
|
||||||
|
!Overrides.BATTLE_TYPE_OVERRIDE &&
|
||||||
|
(this.isWaveMysteryEncounter(newBattleType, newWaveIndex) || newBattleType === BattleType.MYSTERY_ENCOUNTER)
|
||||||
|
) {
|
||||||
newBattleType = BattleType.MYSTERY_ENCOUNTER;
|
newBattleType = BattleType.MYSTERY_ENCOUNTER;
|
||||||
// Reset to base spawn weight
|
// Reset to base spawn weight
|
||||||
this.mysteryEncounterSaveData.encounterSpawnChance = BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT;
|
this.mysteryEncounterSaveData.encounterSpawnChance = BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT;
|
||||||
@ -1395,10 +1406,10 @@ export default class BattleScene extends SceneBase {
|
|||||||
newDouble = false;
|
newDouble = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isNullOrUndefined(Overrides.BATTLE_TYPE_OVERRIDE)) {
|
if (!isNullOrUndefined(Overrides.BATTLE_STYLE_OVERRIDE)) {
|
||||||
let doubleOverrideForWave: "single" | "double" | null = null;
|
let doubleOverrideForWave: "single" | "double" | null = null;
|
||||||
|
|
||||||
switch (Overrides.BATTLE_TYPE_OVERRIDE) {
|
switch (Overrides.BATTLE_STYLE_OVERRIDE) {
|
||||||
case "double":
|
case "double":
|
||||||
doubleOverrideForWave = "double";
|
doubleOverrideForWave = "double";
|
||||||
break;
|
break;
|
||||||
@ -1418,7 +1429,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Override battles into single only if not fighting with trainers.
|
* Override battles into single only if not fighting with trainers.
|
||||||
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/1948 | GitHub Issue #1948}
|
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/1948 GitHub Issue #1948}
|
||||||
*/
|
*/
|
||||||
if (newBattleType !== BattleType.TRAINER && doubleOverrideForWave === "single") {
|
if (newBattleType !== BattleType.TRAINER && doubleOverrideForWave === "single") {
|
||||||
newDouble = false;
|
newDouble = false;
|
||||||
@ -1459,12 +1470,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!waveIndex && lastBattle) {
|
if (!waveIndex && lastBattle) {
|
||||||
const isWaveIndexMultipleOfTen = !(lastBattle.waveIndex % 10);
|
const isNewBiome = this.isNewBiome(lastBattle);
|
||||||
const isEndlessOrDaily = this.gameMode.hasShortBiomes || this.gameMode.isDaily;
|
|
||||||
const isEndlessFifthWave = this.gameMode.hasShortBiomes && lastBattle.waveIndex % 5 === 0;
|
|
||||||
const isWaveIndexMultipleOfFiftyMinusOne = lastBattle.waveIndex % 50 === 49;
|
|
||||||
const isNewBiome =
|
|
||||||
isWaveIndexMultipleOfTen || isEndlessFifthWave || (isEndlessOrDaily && isWaveIndexMultipleOfFiftyMinusOne);
|
|
||||||
const resetArenaState =
|
const resetArenaState =
|
||||||
isNewBiome ||
|
isNewBiome ||
|
||||||
[BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(this.currentBattle.battleType) ||
|
[BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(this.currentBattle.battleType) ||
|
||||||
@ -1513,7 +1519,6 @@ export default class BattleScene extends SceneBase {
|
|||||||
if (!this.gameMode.hasRandomBiomes && !isNewBiome) {
|
if (!this.gameMode.hasRandomBiomes && !isNewBiome) {
|
||||||
this.pushPhase(new NextEncounterPhase());
|
this.pushPhase(new NextEncounterPhase());
|
||||||
} else {
|
} else {
|
||||||
this.pushPhase(new SelectBiomePhase());
|
|
||||||
this.pushPhase(new NewBiomeEncounterPhase());
|
this.pushPhase(new NewBiomeEncounterPhase());
|
||||||
|
|
||||||
const newMaxExpLevel = this.getMaxExpLevel();
|
const newMaxExpLevel = this.getMaxExpLevel();
|
||||||
|
@ -8,7 +8,7 @@ import {
|
|||||||
shiftCharCodes,
|
shiftCharCodes,
|
||||||
randSeedItem,
|
randSeedItem,
|
||||||
randInt,
|
randInt,
|
||||||
} from "#app/utils";
|
} from "#app/utils/common";
|
||||||
import Trainer, { TrainerVariant } from "./field/trainer";
|
import Trainer, { TrainerVariant } from "./field/trainer";
|
||||||
import type { GameMode } from "./game-mode";
|
import type { GameMode } from "./game-mode";
|
||||||
import { MoneyMultiplierModifier, PokemonHeldItemModifier } from "./modifier/modifier";
|
import { MoneyMultiplierModifier, PokemonHeldItemModifier } from "./modifier/modifier";
|
||||||
@ -30,36 +30,8 @@ import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
|||||||
import type { CustomModifierSettings } from "#app/modifier/modifier-type";
|
import type { CustomModifierSettings } from "#app/modifier/modifier-type";
|
||||||
import { ModifierTier } from "#app/modifier/modifier-tier";
|
import { ModifierTier } from "#app/modifier/modifier-tier";
|
||||||
import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
|
import { BattleType } from "#enums/battle-type";
|
||||||
export enum ClassicFixedBossWaves {
|
import { ClassicFixedBossWaves } from "#enums/fixed-boss-waves";
|
||||||
TOWN_YOUNGSTER = 5,
|
|
||||||
RIVAL_1 = 8,
|
|
||||||
RIVAL_2 = 25,
|
|
||||||
EVIL_GRUNT_1 = 35,
|
|
||||||
RIVAL_3 = 55,
|
|
||||||
EVIL_GRUNT_2 = 62,
|
|
||||||
EVIL_GRUNT_3 = 64,
|
|
||||||
EVIL_ADMIN_1 = 66,
|
|
||||||
RIVAL_4 = 95,
|
|
||||||
EVIL_GRUNT_4 = 112,
|
|
||||||
EVIL_ADMIN_2 = 114,
|
|
||||||
EVIL_BOSS_1 = 115,
|
|
||||||
RIVAL_5 = 145,
|
|
||||||
EVIL_BOSS_2 = 165,
|
|
||||||
ELITE_FOUR_1 = 182,
|
|
||||||
ELITE_FOUR_2 = 184,
|
|
||||||
ELITE_FOUR_3 = 186,
|
|
||||||
ELITE_FOUR_4 = 188,
|
|
||||||
CHAMPION = 190,
|
|
||||||
RIVAL_6 = 195,
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum BattleType {
|
|
||||||
WILD,
|
|
||||||
TRAINER,
|
|
||||||
CLEAR,
|
|
||||||
MYSTERY_ENCOUNTER,
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum BattlerIndex {
|
export enum BattlerIndex {
|
||||||
ATTACKER = -1,
|
ATTACKER = -1,
|
||||||
|
@ -31,6 +31,7 @@ const cfg_keyboard_qwerty = {
|
|||||||
KEY_X: Phaser.Input.Keyboard.KeyCodes.X,
|
KEY_X: Phaser.Input.Keyboard.KeyCodes.X,
|
||||||
KEY_Y: Phaser.Input.Keyboard.KeyCodes.Y,
|
KEY_Y: Phaser.Input.Keyboard.KeyCodes.Y,
|
||||||
KEY_Z: Phaser.Input.Keyboard.KeyCodes.Z,
|
KEY_Z: Phaser.Input.Keyboard.KeyCodes.Z,
|
||||||
|
|
||||||
KEY_0: Phaser.Input.Keyboard.KeyCodes.ZERO,
|
KEY_0: Phaser.Input.Keyboard.KeyCodes.ZERO,
|
||||||
KEY_1: Phaser.Input.Keyboard.KeyCodes.ONE,
|
KEY_1: Phaser.Input.Keyboard.KeyCodes.ONE,
|
||||||
KEY_2: Phaser.Input.Keyboard.KeyCodes.TWO,
|
KEY_2: Phaser.Input.Keyboard.KeyCodes.TWO,
|
||||||
@ -41,11 +42,7 @@ const cfg_keyboard_qwerty = {
|
|||||||
KEY_7: Phaser.Input.Keyboard.KeyCodes.SEVEN,
|
KEY_7: Phaser.Input.Keyboard.KeyCodes.SEVEN,
|
||||||
KEY_8: Phaser.Input.Keyboard.KeyCodes.EIGHT,
|
KEY_8: Phaser.Input.Keyboard.KeyCodes.EIGHT,
|
||||||
KEY_9: Phaser.Input.Keyboard.KeyCodes.NINE,
|
KEY_9: Phaser.Input.Keyboard.KeyCodes.NINE,
|
||||||
KEY_CTRL: Phaser.Input.Keyboard.KeyCodes.CTRL,
|
|
||||||
KEY_DEL: Phaser.Input.Keyboard.KeyCodes.DELETE,
|
|
||||||
KEY_END: Phaser.Input.Keyboard.KeyCodes.END,
|
|
||||||
KEY_ENTER: Phaser.Input.Keyboard.KeyCodes.ENTER,
|
|
||||||
KEY_ESC: Phaser.Input.Keyboard.KeyCodes.ESC,
|
|
||||||
KEY_F1: Phaser.Input.Keyboard.KeyCodes.F1,
|
KEY_F1: Phaser.Input.Keyboard.KeyCodes.F1,
|
||||||
KEY_F2: Phaser.Input.Keyboard.KeyCodes.F2,
|
KEY_F2: Phaser.Input.Keyboard.KeyCodes.F2,
|
||||||
KEY_F3: Phaser.Input.Keyboard.KeyCodes.F3,
|
KEY_F3: Phaser.Input.Keyboard.KeyCodes.F3,
|
||||||
@ -58,24 +55,41 @@ const cfg_keyboard_qwerty = {
|
|||||||
KEY_F10: Phaser.Input.Keyboard.KeyCodes.F10,
|
KEY_F10: Phaser.Input.Keyboard.KeyCodes.F10,
|
||||||
KEY_F11: Phaser.Input.Keyboard.KeyCodes.F11,
|
KEY_F11: Phaser.Input.Keyboard.KeyCodes.F11,
|
||||||
KEY_F12: Phaser.Input.Keyboard.KeyCodes.F12,
|
KEY_F12: Phaser.Input.Keyboard.KeyCodes.F12,
|
||||||
KEY_HOME: Phaser.Input.Keyboard.KeyCodes.HOME,
|
|
||||||
KEY_INSERT: Phaser.Input.Keyboard.KeyCodes.INSERT,
|
|
||||||
KEY_PAGE_DOWN: Phaser.Input.Keyboard.KeyCodes.PAGE_DOWN,
|
KEY_PAGE_DOWN: Phaser.Input.Keyboard.KeyCodes.PAGE_DOWN,
|
||||||
KEY_PAGE_UP: Phaser.Input.Keyboard.KeyCodes.PAGE_UP,
|
KEY_PAGE_UP: Phaser.Input.Keyboard.KeyCodes.PAGE_UP,
|
||||||
|
|
||||||
|
KEY_CTRL: Phaser.Input.Keyboard.KeyCodes.CTRL,
|
||||||
|
KEY_DEL: Phaser.Input.Keyboard.KeyCodes.DELETE,
|
||||||
|
KEY_END: Phaser.Input.Keyboard.KeyCodes.END,
|
||||||
|
KEY_ENTER: Phaser.Input.Keyboard.KeyCodes.ENTER,
|
||||||
|
KEY_ESC: Phaser.Input.Keyboard.KeyCodes.ESC,
|
||||||
|
KEY_HOME: Phaser.Input.Keyboard.KeyCodes.HOME,
|
||||||
|
KEY_INSERT: Phaser.Input.Keyboard.KeyCodes.INSERT,
|
||||||
|
|
||||||
KEY_PLUS: Phaser.Input.Keyboard.KeyCodes.NUMPAD_ADD, // Assuming numpad plus
|
KEY_PLUS: Phaser.Input.Keyboard.KeyCodes.NUMPAD_ADD, // Assuming numpad plus
|
||||||
KEY_MINUS: Phaser.Input.Keyboard.KeyCodes.NUMPAD_SUBTRACT, // Assuming numpad minus
|
KEY_MINUS: Phaser.Input.Keyboard.KeyCodes.NUMPAD_SUBTRACT, // Assuming numpad minus
|
||||||
KEY_QUOTATION: Phaser.Input.Keyboard.KeyCodes.QUOTES,
|
KEY_QUOTATION: Phaser.Input.Keyboard.KeyCodes.QUOTES,
|
||||||
KEY_SHIFT: Phaser.Input.Keyboard.KeyCodes.SHIFT,
|
KEY_SHIFT: Phaser.Input.Keyboard.KeyCodes.SHIFT,
|
||||||
|
|
||||||
KEY_SPACE: Phaser.Input.Keyboard.KeyCodes.SPACE,
|
KEY_SPACE: Phaser.Input.Keyboard.KeyCodes.SPACE,
|
||||||
KEY_TAB: Phaser.Input.Keyboard.KeyCodes.TAB,
|
KEY_TAB: Phaser.Input.Keyboard.KeyCodes.TAB,
|
||||||
KEY_TILDE: Phaser.Input.Keyboard.KeyCodes.BACKTICK,
|
KEY_TILDE: Phaser.Input.Keyboard.KeyCodes.BACKTICK,
|
||||||
|
|
||||||
KEY_ARROW_UP: Phaser.Input.Keyboard.KeyCodes.UP,
|
KEY_ARROW_UP: Phaser.Input.Keyboard.KeyCodes.UP,
|
||||||
KEY_ARROW_DOWN: Phaser.Input.Keyboard.KeyCodes.DOWN,
|
KEY_ARROW_DOWN: Phaser.Input.Keyboard.KeyCodes.DOWN,
|
||||||
KEY_ARROW_LEFT: Phaser.Input.Keyboard.KeyCodes.LEFT,
|
KEY_ARROW_LEFT: Phaser.Input.Keyboard.KeyCodes.LEFT,
|
||||||
KEY_ARROW_RIGHT: Phaser.Input.Keyboard.KeyCodes.RIGHT,
|
KEY_ARROW_RIGHT: Phaser.Input.Keyboard.KeyCodes.RIGHT,
|
||||||
|
|
||||||
KEY_LEFT_BRACKET: Phaser.Input.Keyboard.KeyCodes.OPEN_BRACKET,
|
KEY_LEFT_BRACKET: Phaser.Input.Keyboard.KeyCodes.OPEN_BRACKET,
|
||||||
KEY_RIGHT_BRACKET: Phaser.Input.Keyboard.KeyCodes.CLOSED_BRACKET,
|
KEY_RIGHT_BRACKET: Phaser.Input.Keyboard.KeyCodes.CLOSED_BRACKET,
|
||||||
|
|
||||||
KEY_SEMICOLON: Phaser.Input.Keyboard.KeyCodes.SEMICOLON,
|
KEY_SEMICOLON: Phaser.Input.Keyboard.KeyCodes.SEMICOLON,
|
||||||
|
KEY_COMMA: Phaser.Input.Keyboard.KeyCodes.COMMA,
|
||||||
|
KEY_PERIOD: Phaser.Input.Keyboard.KeyCodes.PERIOD,
|
||||||
|
KEY_BACK_SLASH: Phaser.Input.Keyboard.KeyCodes.BACK_SLASH,
|
||||||
|
KEY_FORWARD_SLASH: Phaser.Input.Keyboard.KeyCodes.FORWARD_SLASH,
|
||||||
|
|
||||||
KEY_BACKSPACE: Phaser.Input.Keyboard.KeyCodes.BACKSPACE,
|
KEY_BACKSPACE: Phaser.Input.Keyboard.KeyCodes.BACKSPACE,
|
||||||
KEY_ALT: Phaser.Input.Keyboard.KeyCodes.ALT,
|
KEY_ALT: Phaser.Input.Keyboard.KeyCodes.ALT,
|
||||||
},
|
},
|
||||||
@ -160,6 +174,10 @@ const cfg_keyboard_qwerty = {
|
|||||||
KEY_RIGHT_BRACKET: "RIGHT_BRACKET.png",
|
KEY_RIGHT_BRACKET: "RIGHT_BRACKET.png",
|
||||||
|
|
||||||
KEY_SEMICOLON: "SEMICOLON.png",
|
KEY_SEMICOLON: "SEMICOLON.png",
|
||||||
|
KEY_COMMA: "COMMA.png",
|
||||||
|
KEY_PERIOD: "PERIOD.png",
|
||||||
|
KEY_BACK_SLASH: "BACK_SLASH.png",
|
||||||
|
KEY_FORWARD_SLASH: "FORWARD_SLASH.png",
|
||||||
|
|
||||||
KEY_BACKSPACE: "BACK.png",
|
KEY_BACKSPACE: "BACK.png",
|
||||||
KEY_ALT: "ALT.png",
|
KEY_ALT: "ALT.png",
|
||||||
|
@ -9,3 +9,8 @@ export const SESSION_ID_COOKIE_NAME: string = "pokerogue_sessionId";
|
|||||||
|
|
||||||
/** Max value for an integer attribute in {@linkcode SystemSaveData} */
|
/** Max value for an integer attribute in {@linkcode SystemSaveData} */
|
||||||
export const MAX_INT_ATTR_VALUE = 0x80000000;
|
export const MAX_INT_ATTR_VALUE = 0x80000000;
|
||||||
|
|
||||||
|
/** The min and max waves for mystery encounters to spawn in classic mode */
|
||||||
|
export const CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES: [number, number] = [10, 180] as const;
|
||||||
|
/** The min and max waves for mystery encounters to spawn in challenge mode */
|
||||||
|
export const CHALLENGE_MODE_MYSTERY_ENCOUNTER_WAVES: [number, number] = [10, 180] as const;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import type { AbAttrCondition } from "#app/@types/ability-types";
|
import type { AbAttrCondition } from "#app/@types/ability-types";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import type * as Utils from "#app/utils";
|
import type { BooleanHolder } from "#app/utils/common";
|
||||||
|
|
||||||
export abstract class AbAttr {
|
export abstract class AbAttr {
|
||||||
public showAbility: boolean;
|
public showAbility: boolean;
|
||||||
@ -22,7 +22,7 @@ export abstract class AbAttr {
|
|||||||
_pokemon: Pokemon,
|
_pokemon: Pokemon,
|
||||||
_passive: boolean,
|
_passive: boolean,
|
||||||
_simulated: boolean,
|
_simulated: boolean,
|
||||||
_cancelled: Utils.BooleanHolder | null,
|
_cancelled: BooleanHolder | null,
|
||||||
_args: any[],
|
_args: any[],
|
||||||
): void {}
|
): void {}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import type { AbAttrCondition } from "#app/@types/ability-types";
|
|||||||
import type { AbAttr } from "#app/data/abilities/ab-attrs/ab-attr";
|
import type { AbAttr } from "#app/data/abilities/ab-attrs/ab-attr";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import type { Localizable } from "#app/interfaces/locales";
|
import type { Localizable } from "#app/interfaces/locales";
|
||||||
import type { Constructor } from "#app/utils";
|
import type { Constructor } from "#app/utils/common";
|
||||||
|
|
||||||
export class Ability implements Localizable {
|
export class Ability implements Localizable {
|
||||||
public id: Abilities;
|
public id: Abilities;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { HitResult, MoveResult, PlayerPokemon } from "#app/field/pokemon";
|
import { HitResult, MoveResult, PlayerPokemon } from "#app/field/pokemon";
|
||||||
import { BooleanHolder, NumberHolder, toDmgValue, isNullOrUndefined, randSeedItem, randSeedInt, type Constructor } from "#app/utils";
|
import { BooleanHolder, NumberHolder, toDmgValue, isNullOrUndefined, randSeedItem, randSeedInt, type Constructor } from "#app/utils/common";
|
||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import { BattlerTagLapseType, GroundedTag } from "#app/data/battler-tags";
|
import { BattlerTagLapseType, GroundedTag } from "#app/data/battler-tags";
|
||||||
import { getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffectHealText } from "#app/data/status-effect";
|
import { getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffectHealText } from "#app/data/status-effect";
|
||||||
@ -30,7 +30,7 @@ import i18next from "i18next";
|
|||||||
import { Command } from "#app/ui/command-ui-handler";
|
import { Command } from "#app/ui/command-ui-handler";
|
||||||
import { BerryModifierType } from "#app/modifier/modifier-type";
|
import { BerryModifierType } from "#app/modifier/modifier-type";
|
||||||
import { getPokeballName } from "#app/data/pokeball";
|
import { getPokeballName } from "#app/data/pokeball";
|
||||||
import { BattleType } from "#app/battle";
|
import { BattleType } from "#enums/battle-type";
|
||||||
import { MovePhase } from "#app/phases/move-phase";
|
import { MovePhase } from "#app/phases/move-phase";
|
||||||
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
|
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
|
||||||
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
||||||
@ -44,6 +44,7 @@ import { PokemonTransformPhase } from "#app/phases/pokemon-transform-phase";
|
|||||||
import { allAbilities } from "#app/data/data-lists";
|
import { allAbilities } from "#app/data/data-lists";
|
||||||
import { AbAttr } from "#app/data/abilities/ab-attrs/ab-attr";
|
import { AbAttr } from "#app/data/abilities/ab-attrs/ab-attr";
|
||||||
import { Ability } from "#app/data/abilities/ability-class";
|
import { Ability } from "#app/data/abilities/ability-class";
|
||||||
|
import { TrainerVariant } from "#app/field/trainer";
|
||||||
|
|
||||||
// Enum imports
|
// Enum imports
|
||||||
import { Stat, type BattleStat , BATTLE_STATS, EFFECTIVE_STATS, getStatKey, type EffectiveStat } from "#enums/stat";
|
import { Stat, type BattleStat , BATTLE_STATS, EFFECTIVE_STATS, getStatKey, type EffectiveStat } from "#enums/stat";
|
||||||
@ -61,6 +62,7 @@ import { MoveFlags } from "#enums/MoveFlags";
|
|||||||
import { MoveTarget } from "#enums/MoveTarget";
|
import { MoveTarget } from "#enums/MoveTarget";
|
||||||
import { MoveCategory } from "#enums/MoveCategory";
|
import { MoveCategory } from "#enums/MoveCategory";
|
||||||
|
|
||||||
|
|
||||||
// Type imports
|
// Type imports
|
||||||
import type { EnemyPokemon, PokemonMove } from "#app/field/pokemon";
|
import type { EnemyPokemon, PokemonMove } from "#app/field/pokemon";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
@ -70,6 +72,7 @@ import type { AbAttrCondition, PokemonDefendCondition, PokemonStatStageChangeCon
|
|||||||
import type { BattlerIndex } from "#app/battle";
|
import type { BattlerIndex } from "#app/battle";
|
||||||
import type Move from "#app/data/moves/move";
|
import type Move from "#app/data/moves/move";
|
||||||
import type { ArenaTrapTag, SuppressAbilitiesTag } from "#app/data/arena-tag";
|
import type { ArenaTrapTag, SuppressAbilitiesTag } from "#app/data/arena-tag";
|
||||||
|
import { SelectBiomePhase } from "#app/phases/select-biome-phase";
|
||||||
|
|
||||||
export class BlockRecoilDamageAttr extends AbAttr {
|
export class BlockRecoilDamageAttr extends AbAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -651,8 +654,8 @@ export class MoveImmunityStatStageChangeAbAttr extends MoveImmunityAbAttr {
|
|||||||
*/
|
*/
|
||||||
export class ReverseDrainAbAttr extends PostDefendAbAttr {
|
export class ReverseDrainAbAttr extends PostDefendAbAttr {
|
||||||
|
|
||||||
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
|
override canApplyPostDefend(_pokemon: Pokemon, _passive: boolean, _simulated: boolean, _attacker: Pokemon, move: Move, _hitResult: HitResult | null, args: any[]): boolean {
|
||||||
return move.hasAttr(HitHealAttr) && !move.hitsSubstitute(attacker, pokemon);
|
return move.hasAttr(HitHealAttr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -691,7 +694,7 @@ export class PostDefendStatStageChangeAbAttr extends PostDefendAbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
|
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
|
||||||
return this.condition(pokemon, attacker, move) && !move.hitsSubstitute(attacker, pokemon);
|
return this.condition(pokemon, attacker, move);
|
||||||
}
|
}
|
||||||
|
|
||||||
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
|
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
|
||||||
@ -732,7 +735,7 @@ export class PostDefendHpGatedStatStageChangeAbAttr extends PostDefendAbAttr {
|
|||||||
const hpGateFlat: number = Math.ceil(pokemon.getMaxHp() * this.hpGate);
|
const hpGateFlat: number = Math.ceil(pokemon.getMaxHp() * this.hpGate);
|
||||||
const lastAttackReceived = pokemon.turnData.attacksReceived[pokemon.turnData.attacksReceived.length - 1];
|
const lastAttackReceived = pokemon.turnData.attacksReceived[pokemon.turnData.attacksReceived.length - 1];
|
||||||
const damageReceived = lastAttackReceived?.damage || 0;
|
const damageReceived = lastAttackReceived?.damage || 0;
|
||||||
return this.condition(pokemon, attacker, move) && (pokemon.hp <= hpGateFlat && (pokemon.hp + damageReceived) > hpGateFlat) && !move.hitsSubstitute(attacker, pokemon);
|
return this.condition(pokemon, attacker, move) && (pokemon.hp <= hpGateFlat && (pokemon.hp + damageReceived) > hpGateFlat);
|
||||||
}
|
}
|
||||||
|
|
||||||
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
|
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
|
||||||
@ -755,7 +758,7 @@ export class PostDefendApplyArenaTrapTagAbAttr extends PostDefendAbAttr {
|
|||||||
|
|
||||||
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
|
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
|
||||||
const tag = globalScene.arena.getTag(this.tagType) as ArenaTrapTag;
|
const tag = globalScene.arena.getTag(this.tagType) as ArenaTrapTag;
|
||||||
return (this.condition(pokemon, attacker, move) && !move.hitsSubstitute(attacker, pokemon))
|
return (this.condition(pokemon, attacker, move))
|
||||||
&& (!globalScene.arena.getTag(this.tagType) || tag.layers < tag.maxLayers);
|
&& (!globalScene.arena.getTag(this.tagType) || tag.layers < tag.maxLayers);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -777,7 +780,7 @@ export class PostDefendApplyBattlerTagAbAttr extends PostDefendAbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
|
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
|
||||||
return this.condition(pokemon, attacker, move) && !move.hitsSubstitute(attacker, pokemon);
|
return this.condition(pokemon, attacker, move);
|
||||||
}
|
}
|
||||||
|
|
||||||
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
|
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
|
||||||
@ -794,7 +797,7 @@ export class PostDefendTypeChangeAbAttr extends PostDefendAbAttr {
|
|||||||
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
|
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
|
||||||
this.type = attacker.getMoveType(move);
|
this.type = attacker.getMoveType(move);
|
||||||
const pokemonTypes = pokemon.getTypes(true);
|
const pokemonTypes = pokemon.getTypes(true);
|
||||||
return hitResult < HitResult.NO_EFFECT && !move.hitsSubstitute(attacker, pokemon) && (simulated || pokemonTypes.length !== 1 || pokemonTypes[0] !== this.type);
|
return hitResult < HitResult.NO_EFFECT && (simulated || pokemonTypes.length !== 1 || pokemonTypes[0] !== this.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, _args: any[]): void {
|
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, _args: any[]): void {
|
||||||
@ -821,7 +824,7 @@ export class PostDefendTerrainChangeAbAttr extends PostDefendAbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
|
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
|
||||||
return hitResult < HitResult.NO_EFFECT && !move.hitsSubstitute(attacker, pokemon) && globalScene.arena.canSetTerrain(this.terrainType);
|
return hitResult < HitResult.NO_EFFECT && globalScene.arena.canSetTerrain(this.terrainType);
|
||||||
}
|
}
|
||||||
|
|
||||||
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, _args: any[]): void {
|
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, _args: any[]): void {
|
||||||
@ -845,7 +848,7 @@ export class PostDefendContactApplyStatusEffectAbAttr extends PostDefendAbAttr {
|
|||||||
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
|
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
|
||||||
const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)];
|
const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)];
|
||||||
return move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}) && !attacker.status
|
return move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}) && !attacker.status
|
||||||
&& (this.chance === -1 || pokemon.randSeedInt(100) < this.chance) && !move.hitsSubstitute(attacker, pokemon)
|
&& (this.chance === -1 || pokemon.randSeedInt(100) < this.chance)
|
||||||
&& attacker.canSetStatus(effect, true, false, pokemon);
|
&& attacker.canSetStatus(effect, true, false, pokemon);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -885,7 +888,7 @@ export class PostDefendContactApplyTagChanceAbAttr extends PostDefendAbAttr {
|
|||||||
|
|
||||||
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
|
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
|
||||||
return move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}) && pokemon.randSeedInt(100) < this.chance
|
return move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}) && pokemon.randSeedInt(100) < this.chance
|
||||||
&& !move.hitsSubstitute(attacker, pokemon) && attacker.canAddTag(this.tagType);
|
&& attacker.canAddTag(this.tagType);
|
||||||
}
|
}
|
||||||
|
|
||||||
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
|
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
|
||||||
@ -906,10 +909,6 @@ export class PostDefendCritStatStageChangeAbAttr extends PostDefendAbAttr {
|
|||||||
this.stages = stages;
|
this.stages = stages;
|
||||||
}
|
}
|
||||||
|
|
||||||
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
|
|
||||||
return !move.hitsSubstitute(attacker, pokemon);
|
|
||||||
}
|
|
||||||
|
|
||||||
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
|
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
|
||||||
if (!simulated) {
|
if (!simulated) {
|
||||||
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ this.stat ], this.stages));
|
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ this.stat ], this.stages));
|
||||||
@ -932,7 +931,7 @@ export class PostDefendContactDamageAbAttr extends PostDefendAbAttr {
|
|||||||
|
|
||||||
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
|
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
|
||||||
return !simulated && move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon})
|
return !simulated && move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon})
|
||||||
&& !attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr) && !move.hitsSubstitute(attacker, pokemon);
|
&& !attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr);
|
||||||
}
|
}
|
||||||
|
|
||||||
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
|
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
|
||||||
@ -991,7 +990,7 @@ export class PostDefendWeatherChangeAbAttr extends PostDefendAbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
|
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
|
||||||
return (!(this.condition && !this.condition(pokemon, attacker, move) || move.hitsSubstitute(attacker, pokemon))
|
return (!(this.condition && !this.condition(pokemon, attacker, move))
|
||||||
&& !globalScene.arena.weather?.isImmutable() && globalScene.arena.canSetWeather(this.weatherType));
|
&& !globalScene.arena.weather?.isImmutable() && globalScene.arena.canSetWeather(this.weatherType));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1009,7 +1008,7 @@ export class PostDefendAbilitySwapAbAttr extends PostDefendAbAttr {
|
|||||||
|
|
||||||
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
|
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
|
||||||
return move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon})
|
return move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon})
|
||||||
&& attacker.getAbility().isSwappable && !move.hitsSubstitute(attacker, pokemon);
|
&& attacker.getAbility().isSwappable;
|
||||||
}
|
}
|
||||||
|
|
||||||
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, args: any[]): void {
|
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, args: any[]): void {
|
||||||
@ -1035,10 +1034,10 @@ export class PostDefendAbilityGiveAbAttr extends PostDefendAbAttr {
|
|||||||
|
|
||||||
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
|
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
|
||||||
return move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}) && attacker.getAbility().isSuppressable
|
return move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}) && attacker.getAbility().isSuppressable
|
||||||
&& !attacker.getAbility().hasAttr(PostDefendAbilityGiveAbAttr) && !move.hitsSubstitute(attacker, pokemon);
|
&& !attacker.getAbility().hasAttr(PostDefendAbilityGiveAbAttr);
|
||||||
}
|
}
|
||||||
|
|
||||||
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
|
override applyPostDefend(_pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
|
||||||
if (!simulated) {
|
if (!simulated) {
|
||||||
attacker.setTempAbility(allAbilities[this.ability]);
|
attacker.setTempAbility(allAbilities[this.ability]);
|
||||||
}
|
}
|
||||||
@ -1064,7 +1063,7 @@ export class PostDefendMoveDisableAbAttr extends PostDefendAbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
|
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
|
||||||
return attacker.getTag(BattlerTagType.DISABLED) === null && !move.hitsSubstitute(attacker, pokemon)
|
return attacker.getTag(BattlerTagType.DISABLED) === null
|
||||||
&& move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}) && (this.chance === -1 || pokemon.randSeedInt(100) < this.chance);
|
&& move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}) && (this.chance === -1 || pokemon.randSeedInt(100) < this.chance);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1768,7 +1767,6 @@ export class PostAttackApplyStatusEffectAbAttr extends PostAttackAbAttr {
|
|||||||
override canApplyPostAttack(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
|
override canApplyPostAttack(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
|
||||||
if (
|
if (
|
||||||
super.canApplyPostAttack(pokemon, passive, simulated, attacker, move, hitResult, args)
|
super.canApplyPostAttack(pokemon, passive, simulated, attacker, move, hitResult, args)
|
||||||
&& !(pokemon !== attacker && move.hitsSubstitute(attacker, pokemon))
|
|
||||||
&& (simulated || !attacker.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && pokemon !== attacker
|
&& (simulated || !attacker.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && pokemon !== attacker
|
||||||
&& (!this.contactRequired || move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon})) && pokemon.randSeedInt(100) < this.chance && !pokemon.status)
|
&& (!this.contactRequired || move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon})) && pokemon.randSeedInt(100) < this.chance && !pokemon.status)
|
||||||
) {
|
) {
|
||||||
@ -1835,8 +1833,7 @@ export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr {
|
|||||||
if (
|
if (
|
||||||
!simulated &&
|
!simulated &&
|
||||||
hitResult < HitResult.NO_EFFECT &&
|
hitResult < HitResult.NO_EFFECT &&
|
||||||
(!this.condition || this.condition(pokemon, attacker, move)) &&
|
(!this.condition || this.condition(pokemon, attacker, move))
|
||||||
!move.hitsSubstitute(attacker, pokemon)
|
|
||||||
) {
|
) {
|
||||||
const heldItems = this.getTargetHeldItems(attacker).filter((i) => i.isTransferable);
|
const heldItems = this.getTargetHeldItems(attacker).filter((i) => i.isTransferable);
|
||||||
if (heldItems.length) {
|
if (heldItems.length) {
|
||||||
@ -2217,18 +2214,6 @@ export class PostSummonMessageAbAttr extends PostSummonAbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes illusions when a Pokemon is summoned.
|
|
||||||
*/
|
|
||||||
export class PostSummonRemoveIllusionAbAttr extends PostSummonAbAttr {
|
|
||||||
applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean {
|
|
||||||
for (const pokemon of globalScene.getField(true)) {
|
|
||||||
pokemon.breakIllusion();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class PostSummonUnnamedMessageAbAttr extends PostSummonAbAttr {
|
export class PostSummonUnnamedMessageAbAttr extends PostSummonAbAttr {
|
||||||
//Attr doesn't force pokemon name on the message
|
//Attr doesn't force pokemon name on the message
|
||||||
private message: string;
|
private message: string;
|
||||||
@ -3187,6 +3172,7 @@ export class PreSetStatusAbAttr extends AbAttr {
|
|||||||
*/
|
*/
|
||||||
export class PreSetStatusEffectImmunityAbAttr extends PreSetStatusAbAttr {
|
export class PreSetStatusEffectImmunityAbAttr extends PreSetStatusAbAttr {
|
||||||
protected immuneEffects: StatusEffect[];
|
protected immuneEffects: StatusEffect[];
|
||||||
|
private lastEffect: StatusEffect;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param immuneEffects - The status effects to which the Pokémon is immune.
|
* @param immuneEffects - The status effects to which the Pokémon is immune.
|
||||||
@ -3212,6 +3198,7 @@ export class PreSetStatusEffectImmunityAbAttr extends PreSetStatusAbAttr {
|
|||||||
*/
|
*/
|
||||||
override applyPreSetStatus(pokemon: Pokemon, passive: boolean, simulated: boolean, effect: StatusEffect, cancelled: BooleanHolder, args: any[]): void {
|
override applyPreSetStatus(pokemon: Pokemon, passive: boolean, simulated: boolean, effect: StatusEffect, cancelled: BooleanHolder, args: any[]): void {
|
||||||
cancelled.value = true;
|
cancelled.value = true;
|
||||||
|
this.lastEffect = effect;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string {
|
getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string {
|
||||||
@ -3219,7 +3206,7 @@ export class PreSetStatusEffectImmunityAbAttr extends PreSetStatusAbAttr {
|
|||||||
i18next.t("abilityTriggers:statusEffectImmunityWithName", {
|
i18next.t("abilityTriggers:statusEffectImmunityWithName", {
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
abilityName,
|
abilityName,
|
||||||
statusEffectName: getStatusEffectDescriptor(args[0] as StatusEffect)
|
statusEffectName: getStatusEffectDescriptor(this.lastEffect)
|
||||||
}) :
|
}) :
|
||||||
i18next.t("abilityTriggers:statusEffectImmunity", {
|
i18next.t("abilityTriggers:statusEffectImmunity", {
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
@ -5073,6 +5060,8 @@ export class PostSummonStatStageChangeOnArenaAbAttr extends PostSummonStatStageC
|
|||||||
/**
|
/**
|
||||||
* Takes no damage from the first hit of a damaging move.
|
* Takes no damage from the first hit of a damaging move.
|
||||||
* This is used in the Disguise and Ice Face abilities.
|
* This is used in the Disguise and Ice Face abilities.
|
||||||
|
*
|
||||||
|
* Does not apply to a user's substitute
|
||||||
* @extends ReceivedMoveDamageMultiplierAbAttr
|
* @extends ReceivedMoveDamageMultiplierAbAttr
|
||||||
*/
|
*/
|
||||||
export class FormBlockDamageAbAttr extends ReceivedMoveDamageMultiplierAbAttr {
|
export class FormBlockDamageAbAttr extends ReceivedMoveDamageMultiplierAbAttr {
|
||||||
@ -5175,7 +5164,14 @@ export class IllusionPreSummonAbAttr extends PreSummonAbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class IllusionBreakAbAttr extends PostDefendAbAttr {
|
export class IllusionBreakAbAttr extends AbAttr {
|
||||||
|
override apply(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _cancelled: BooleanHolder | null, _args: any[]): void {
|
||||||
|
pokemon.breakIllusion();
|
||||||
|
pokemon.summonData.illusionBroken = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PostDefendIllusionBreakAbAttr extends PostDefendAbAttr {
|
||||||
/**
|
/**
|
||||||
* Destroy the illusion upon taking damage
|
* Destroy the illusion upon taking damage
|
||||||
*
|
*
|
||||||
@ -5490,6 +5486,11 @@ class ForceSwitchOutHelper {
|
|||||||
|
|
||||||
if (switchOutTarget.hp) {
|
if (switchOutTarget.hp) {
|
||||||
globalScene.pushPhase(new BattleEndPhase(false));
|
globalScene.pushPhase(new BattleEndPhase(false));
|
||||||
|
|
||||||
|
if (globalScene.gameMode.hasRandomBiomes || globalScene.isNewBiome()) {
|
||||||
|
globalScene.pushPhase(new SelectBiomePhase());
|
||||||
|
}
|
||||||
|
|
||||||
globalScene.pushPhase(new NewBattlePhase());
|
globalScene.pushPhase(new NewBattlePhase());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5526,8 +5527,8 @@ class ForceSwitchOutHelper {
|
|||||||
|
|
||||||
const party = player ? globalScene.getPlayerParty() : globalScene.getEnemyParty();
|
const party = player ? globalScene.getPlayerParty() : globalScene.getEnemyParty();
|
||||||
return (!player && globalScene.currentBattle.battleType === BattleType.WILD)
|
return (!player && globalScene.currentBattle.battleType === BattleType.WILD)
|
||||||
|| party.filter(p => p.isAllowedInBattle()
|
|| party.filter(p => p.isAllowedInBattle() && !p.isOnField()
|
||||||
&& (player || (p as EnemyPokemon).trainerSlot === (switchOutTarget as EnemyPokemon).trainerSlot)).length > globalScene.currentBattle.getBattlerCount();
|
&& (player || (p as EnemyPokemon).trainerSlot === (switchOutTarget as EnemyPokemon).trainerSlot)).length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -6267,7 +6268,7 @@ export function applyOnGainAbAttrs(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears primal weather/neutralizing gas during the turn if {@linkcode pokemon}'s ability corresponds to one
|
* Applies ability attributes which activate when the ability is lost or suppressed (i.e. primal weather)
|
||||||
*/
|
*/
|
||||||
export function applyOnLoseAbAttrs(pokemon: Pokemon, passive = false, simulated = false, ...args: any[]): void {
|
export function applyOnLoseAbAttrs(pokemon: Pokemon, passive = false, simulated = false, ...args: any[]): void {
|
||||||
applySingleAbAttrs<PreLeaveFieldAbAttr>(
|
applySingleAbAttrs<PreLeaveFieldAbAttr>(
|
||||||
@ -6279,6 +6280,17 @@ export function applyOnLoseAbAttrs(pokemon: Pokemon, passive = false, simulated
|
|||||||
args,
|
args,
|
||||||
true,
|
true,
|
||||||
simulated);
|
simulated);
|
||||||
|
|
||||||
|
applySingleAbAttrs<IllusionBreakAbAttr>(
|
||||||
|
pokemon,
|
||||||
|
passive,
|
||||||
|
IllusionBreakAbAttr,
|
||||||
|
(attr, passive) => attr.apply(pokemon, passive, simulated, null, args),
|
||||||
|
(attr, passive) => attr.canApply(pokemon, passive, simulated, args),
|
||||||
|
args,
|
||||||
|
true,
|
||||||
|
simulated
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -6778,11 +6790,12 @@ export function initAbilities() {
|
|||||||
return isNullOrUndefined(movePhase);
|
return isNullOrUndefined(movePhase);
|
||||||
}, 1.3),
|
}, 1.3),
|
||||||
new Ability(Abilities.ILLUSION, 5)
|
new Ability(Abilities.ILLUSION, 5)
|
||||||
//The pokemon generate an illusion if it's available
|
// The Pokemon generate an illusion if it's available
|
||||||
.attr(IllusionPreSummonAbAttr, false)
|
.attr(IllusionPreSummonAbAttr, false)
|
||||||
//The pokemon loses his illusion when he is damaged by a move
|
.attr(IllusionBreakAbAttr)
|
||||||
.attr(IllusionBreakAbAttr, true)
|
// The Pokemon loses its illusion when damaged by a move
|
||||||
//Illusion is available again after a battle
|
.attr(PostDefendIllusionBreakAbAttr, true)
|
||||||
|
// Illusion is available again after a battle
|
||||||
.conditionalAttr((pokemon) => pokemon.isAllowedInBattle(), IllusionPostBattleAbAttr, false)
|
.conditionalAttr((pokemon) => pokemon.isAllowedInBattle(), IllusionPostBattleAbAttr, false)
|
||||||
.uncopiable()
|
.uncopiable()
|
||||||
.bypassFaint(),
|
.bypassFaint(),
|
||||||
@ -7196,8 +7209,6 @@ export function initAbilities() {
|
|||||||
.attr(PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr)
|
.attr(PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr)
|
||||||
.uncopiable()
|
.uncopiable()
|
||||||
.attr(NoTransformAbilityAbAttr)
|
.attr(NoTransformAbilityAbAttr)
|
||||||
.attr(PostSummonMessageAbAttr, (pokemon: Pokemon) => i18next.t("abilityTriggers:postSummonNeutralizingGas", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }))
|
|
||||||
.attr(PostSummonRemoveIllusionAbAttr)
|
|
||||||
.bypassFaint(),
|
.bypassFaint(),
|
||||||
new Ability(Abilities.PASTEL_VEIL, 8)
|
new Ability(Abilities.PASTEL_VEIL, 8)
|
||||||
.attr(PostSummonUserFieldRemoveStatusEffectAbAttr, StatusEffect.POISON, StatusEffect.TOXIC)
|
.attr(PostSummonUserFieldRemoveStatusEffectAbAttr, StatusEffect.POISON, StatusEffect.TOXIC)
|
||||||
@ -7218,7 +7229,7 @@ export function initAbilities() {
|
|||||||
new Ability(Abilities.CURIOUS_MEDICINE, 8)
|
new Ability(Abilities.CURIOUS_MEDICINE, 8)
|
||||||
.attr(PostSummonClearAllyStatStagesAbAttr),
|
.attr(PostSummonClearAllyStatStagesAbAttr),
|
||||||
new Ability(Abilities.TRANSISTOR, 8)
|
new Ability(Abilities.TRANSISTOR, 8)
|
||||||
.attr(MoveTypePowerBoostAbAttr, PokemonType.ELECTRIC),
|
.attr(MoveTypePowerBoostAbAttr, PokemonType.ELECTRIC, 1.3),
|
||||||
new Ability(Abilities.DRAGONS_MAW, 8)
|
new Ability(Abilities.DRAGONS_MAW, 8)
|
||||||
.attr(MoveTypePowerBoostAbAttr, PokemonType.DRAGON),
|
.attr(MoveTypePowerBoostAbAttr, PokemonType.DRAGON),
|
||||||
new Ability(Abilities.CHILLING_NEIGH, 8)
|
new Ability(Abilities.CHILLING_NEIGH, 8)
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import type { Arena } from "#app/field/arena";
|
import type { Arena } from "#app/field/arena";
|
||||||
import { PokemonType } from "#enums/pokemon-type";
|
import { PokemonType } from "#enums/pokemon-type";
|
||||||
import { BooleanHolder, NumberHolder, toDmgValue } from "#app/utils";
|
import { BooleanHolder, NumberHolder, toDmgValue } from "#app/utils/common";
|
||||||
import { allMoves } from "#app/data/moves/move";
|
import { allMoves } from "#app/data/moves/move";
|
||||||
import { MoveTarget } from "#enums/MoveTarget";
|
import { MoveTarget } from "#enums/MoveTarget";
|
||||||
import { MoveCategory } from "#enums/MoveCategory";
|
import { MoveCategory } from "#enums/MoveCategory";
|
||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import { HitResult, PokemonMove } from "#app/field/pokemon";
|
import { HitResult } from "#app/field/pokemon";
|
||||||
import { StatusEffect } from "#enums/status-effect";
|
import { StatusEffect } from "#enums/status-effect";
|
||||||
import type { BattlerIndex } from "#app/battle";
|
import type { BattlerIndex } from "#app/battle";
|
||||||
import {
|
import {
|
||||||
@ -335,7 +335,7 @@ export class ConditionalProtectTag extends ArenaTag {
|
|||||||
* @param arena the {@linkcode Arena} containing this tag
|
* @param arena the {@linkcode Arena} containing this tag
|
||||||
* @param simulated `true` if the tag is applied quietly; `false` otherwise.
|
* @param simulated `true` if the tag is applied quietly; `false` otherwise.
|
||||||
* @param isProtected a {@linkcode BooleanHolder} used to flag if the move is protected against
|
* @param isProtected a {@linkcode BooleanHolder} used to flag if the move is protected against
|
||||||
* @param attacker the attacking {@linkcode Pokemon}
|
* @param _attacker the attacking {@linkcode Pokemon}
|
||||||
* @param defender the defending {@linkcode Pokemon}
|
* @param defender the defending {@linkcode Pokemon}
|
||||||
* @param moveId the {@linkcode Moves | identifier} for the move being used
|
* @param moveId the {@linkcode Moves | identifier} for the move being used
|
||||||
* @param ignoresProtectBypass a {@linkcode BooleanHolder} used to flag if a protection effect supercedes effects that ignore protection
|
* @param ignoresProtectBypass a {@linkcode BooleanHolder} used to flag if a protection effect supercedes effects that ignore protection
|
||||||
@ -345,7 +345,7 @@ export class ConditionalProtectTag extends ArenaTag {
|
|||||||
arena: Arena,
|
arena: Arena,
|
||||||
simulated: boolean,
|
simulated: boolean,
|
||||||
isProtected: BooleanHolder,
|
isProtected: BooleanHolder,
|
||||||
attacker: Pokemon,
|
_attacker: Pokemon,
|
||||||
defender: Pokemon,
|
defender: Pokemon,
|
||||||
moveId: Moves,
|
moveId: Moves,
|
||||||
ignoresProtectBypass: BooleanHolder,
|
ignoresProtectBypass: BooleanHolder,
|
||||||
@ -354,8 +354,6 @@ export class ConditionalProtectTag extends ArenaTag {
|
|||||||
if (!isProtected.value) {
|
if (!isProtected.value) {
|
||||||
isProtected.value = true;
|
isProtected.value = true;
|
||||||
if (!simulated) {
|
if (!simulated) {
|
||||||
attacker.stopMultiHit(defender);
|
|
||||||
|
|
||||||
new CommonBattleAnim(CommonAnim.PROTECT, defender).play();
|
new CommonBattleAnim(CommonAnim.PROTECT, defender).play();
|
||||||
globalScene.queueMessage(
|
globalScene.queueMessage(
|
||||||
i18next.t("arenaTag:conditionalProtectApply", {
|
i18next.t("arenaTag:conditionalProtectApply", {
|
||||||
@ -899,7 +897,7 @@ export class DelayedAttackTag extends ArenaTag {
|
|||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
globalScene.unshiftPhase(
|
globalScene.unshiftPhase(
|
||||||
new MoveEffectPhase(this.sourceId!, [this.targetIndex], new PokemonMove(this.sourceMove!, 0, 0, true)),
|
new MoveEffectPhase(this.sourceId!, [this.targetIndex], allMoves[this.sourceMove!], false, true),
|
||||||
); // TODO: are those bangs correct?
|
); // TODO: are those bangs correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { PokemonType } from "#enums/pokemon-type";
|
import { PokemonType } from "#enums/pokemon-type";
|
||||||
import { randSeedInt, getEnumValues } from "#app/utils";
|
import { randSeedInt, getEnumValues } from "#app/utils/common";
|
||||||
import type { SpeciesFormEvolution } from "#app/data/balance/pokemon-evolutions";
|
import type { SpeciesFormEvolution } from "#app/data/balance/pokemon-evolutions";
|
||||||
import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
|
import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { allMoves } from "#app/data/moves/move";
|
import { allMoves } from "#app/data/moves/move";
|
||||||
import { getEnumKeys, getEnumValues } from "#app/utils";
|
import { getEnumKeys, getEnumValues } from "#app/utils/common";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import { Gender } from "#app/data/gender";
|
|||||||
import { PokeballType } from "#enums/pokeball";
|
import { PokeballType } from "#enums/pokeball";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import { PokemonType } from "#enums/pokemon-type";
|
import { PokemonType } from "#enums/pokemon-type";
|
||||||
import { randSeedInt } from "#app/utils";
|
import { randSeedInt } from "#app/utils/common";
|
||||||
import { WeatherType } from "#enums/weather-type";
|
import { WeatherType } from "#enums/weather-type";
|
||||||
import { Nature } from "#enums/nature";
|
import { Nature } from "#enums/nature";
|
||||||
import { Biome } from "#enums/biome";
|
import { Biome } from "#enums/biome";
|
||||||
@ -14,6 +14,7 @@ import { DamageMoneyRewardModifier, ExtraModifierModifier, MoneyMultiplierModifi
|
|||||||
import { SpeciesFormKey } from "#enums/species-form-key";
|
import { SpeciesFormKey } from "#enums/species-form-key";
|
||||||
import { speciesStarterCosts } from "./starters";
|
import { speciesStarterCosts } from "./starters";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
import { initI18n } from "#app/plugins/i18n";
|
||||||
|
|
||||||
|
|
||||||
export enum SpeciesWildEvolutionDelay {
|
export enum SpeciesWildEvolutionDelay {
|
||||||
@ -95,6 +96,9 @@ export class SpeciesFormEvolution {
|
|||||||
public description = "";
|
public description = "";
|
||||||
|
|
||||||
constructor(speciesId: Species, preFormKey: string | null, evoFormKey: string | null, level: number, item: EvolutionItem | null, condition: SpeciesEvolutionCondition | null, wildDelay?: SpeciesWildEvolutionDelay) {
|
constructor(speciesId: Species, preFormKey: string | null, evoFormKey: string | null, level: number, item: EvolutionItem | null, condition: SpeciesEvolutionCondition | null, wildDelay?: SpeciesWildEvolutionDelay) {
|
||||||
|
if (!i18next.isInitialized) {
|
||||||
|
initI18n();
|
||||||
|
}
|
||||||
this.speciesId = speciesId;
|
this.speciesId = speciesId;
|
||||||
this.preFormKey = preFormKey;
|
this.preFormKey = preFormKey;
|
||||||
this.evoFormKey = evoFormKey;
|
this.evoFormKey = evoFormKey;
|
||||||
|
@ -19383,6 +19383,44 @@ export const pokemonFormLevelMoves: PokemonSpeciesFormLevelMoves = {
|
|||||||
[ 100, Moves.SEED_FLARE ],
|
[ 100, Moves.SEED_FLARE ],
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
[Species.BASCULIN]: {
|
||||||
|
1: [
|
||||||
|
[ 1, Moves.TAIL_WHIP ],
|
||||||
|
[ 1, Moves.WATER_GUN ],
|
||||||
|
[ 4, Moves.TACKLE ],
|
||||||
|
[ 8, Moves.FLAIL ],
|
||||||
|
[ 12, Moves.AQUA_JET ],
|
||||||
|
[ 16, Moves.BITE ],
|
||||||
|
[ 20, Moves.SCARY_FACE ],
|
||||||
|
[ 24, Moves.HEADBUTT ],
|
||||||
|
[ 28, Moves.SOAK ],
|
||||||
|
[ 32, Moves.CRUNCH ],
|
||||||
|
[ 36, Moves.TAKE_DOWN ],
|
||||||
|
[ 40, Moves.FINAL_GAMBIT ],
|
||||||
|
[ 44, Moves.WAVE_CRASH ],
|
||||||
|
[ 48, Moves.THRASH ],
|
||||||
|
[ 52, Moves.DOUBLE_EDGE ],
|
||||||
|
[ 56, Moves.HEAD_SMASH ],
|
||||||
|
],
|
||||||
|
2: [
|
||||||
|
[ 1, Moves.TAIL_WHIP ],
|
||||||
|
[ 1, Moves.WATER_GUN ],
|
||||||
|
[ 4, Moves.TACKLE ],
|
||||||
|
[ 8, Moves.FLAIL ],
|
||||||
|
[ 12, Moves.AQUA_JET ],
|
||||||
|
[ 16, Moves.BITE ],
|
||||||
|
[ 20, Moves.SCARY_FACE ],
|
||||||
|
[ 24, Moves.HEADBUTT ],
|
||||||
|
[ 28, Moves.SOAK ],
|
||||||
|
[ 32, Moves.CRUNCH ],
|
||||||
|
[ 36, Moves.TAKE_DOWN ],
|
||||||
|
[ 40, Moves.UPROAR ],
|
||||||
|
[ 44, Moves.WAVE_CRASH ],
|
||||||
|
[ 48, Moves.THRASH ],
|
||||||
|
[ 52, Moves.DOUBLE_EDGE ],
|
||||||
|
[ 56, Moves.HEAD_SMASH ],
|
||||||
|
]
|
||||||
|
},
|
||||||
[Species.KYUREM]: {
|
[Species.KYUREM]: {
|
||||||
1: [
|
1: [
|
||||||
[ 1, Moves.DRAGON_BREATH ],
|
[ 1, Moves.DRAGON_BREATH ],
|
||||||
|
@ -4,159 +4,103 @@ export type SignatureSpecies = {
|
|||||||
[key in string]: (Species | Species[])[];
|
[key in string]: (Species | Species[])[];
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* The signature species for each Gym Leader, Elite Four member, and Champion.
|
* The signature species for each Gym Leader, Elite Four member, and Champion.
|
||||||
* The key is the trainer type, and the value is an array of Species or Species arrays.
|
* The key is the trainer type, and the value is an array of Species or Species arrays.
|
||||||
* This is in a separate const so it can be accessed from other places and not just the trainerConfigs
|
* This is in a separate const so it can be accessed from other places and not just the trainerConfigs
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* The `Proxy` object allows us to define a handler that will intercept
|
||||||
|
* the property access and return an empty array if the property does not exist in the object.
|
||||||
|
*
|
||||||
|
* This means that accessing `signatureSpecies` will not throw an error if the property does not exist,
|
||||||
|
* but instead default to an empty array.
|
||||||
*/
|
*/
|
||||||
export const signatureSpecies: SignatureSpecies = {
|
export const signatureSpecies: SignatureSpecies = new Proxy({
|
||||||
// Gym Leaders- Kanto
|
// Gym Leaders- Kanto
|
||||||
BROCK: [Species.GEODUDE, Species.ONIX],
|
BROCK: [Species.ONIX, Species.GEODUDE, [Species.OMANYTE, Species.KABUTO], Species.AERODACTYL],
|
||||||
MISTY: [Species.STARYU, Species.PSYDUCK],
|
MISTY: [Species.STARYU, Species.PSYDUCK, Species.WOOPER, Species.LAPRAS],
|
||||||
LT_SURGE: [Species.VOLTORB, Species.PIKACHU, Species.ELECTABUZZ],
|
LT_SURGE: [Species.PICHU, Species.VOLTORB, Species.ELEKID, Species.JOLTEON],
|
||||||
ERIKA: [Species.ODDISH, Species.BELLSPROUT, Species.TANGELA, Species.HOPPIP],
|
ERIKA: [Species.ODDISH, Species.BELLSPROUT, Species.TANGELA, Species.HOPPIP],
|
||||||
JANINE: [Species.VENONAT, Species.SPINARAK, Species.ZUBAT],
|
JANINE: [Species.VENONAT, Species.SPINARAK, Species.ZUBAT, Species.KOFFING],
|
||||||
SABRINA: [Species.ABRA, Species.MR_MIME, Species.ESPEON],
|
SABRINA: [Species.ABRA, Species.MR_MIME, Species.SMOOCHUM, Species.ESPEON],
|
||||||
BLAINE: [Species.GROWLITHE, Species.PONYTA, Species.MAGMAR],
|
BLAINE: [Species.GROWLITHE, Species.PONYTA, Species.MAGBY, Species.VULPIX],
|
||||||
GIOVANNI: [Species.SANDILE, Species.MURKROW, Species.NIDORAN_M, Species.NIDORAN_F],
|
GIOVANNI: [Species.RHYHORN, Species.MEOWTH, [Species.NIDORAN_F, Species.NIDORAN_M], Species.DIGLETT], // Tera Ground Meowth
|
||||||
// Gym Leaders- Johto
|
// Gym Leaders- Johto
|
||||||
FALKNER: [Species.PIDGEY, Species.HOOTHOOT, Species.DODUO],
|
FALKNER: [Species.PIDGEY, Species.HOOTHOOT, Species.NATU, Species.MURKROW],
|
||||||
BUGSY: [Species.SCYTHER, Species.HERACROSS, Species.SHUCKLE, Species.PINSIR],
|
BUGSY: [Species.SCYTHER, Species.SHUCKLE, Species.YANMA, [Species.PINSIR, Species.HERACROSS]],
|
||||||
WHITNEY: [Species.JIGGLYPUFF, Species.MILTANK, Species.AIPOM, Species.GIRAFARIG],
|
WHITNEY: [Species.MILTANK, Species.AIPOM, Species.IGGLYBUFF, [Species.GIRAFARIG, Species.STANTLER]],
|
||||||
MORTY: [Species.GASTLY, Species.MISDREAVUS, Species.SABLEYE],
|
MORTY: [Species.GASTLY, Species.MISDREAVUS, Species.DUSKULL, Species.SABLEYE],
|
||||||
CHUCK: [Species.POLIWRATH, Species.MANKEY],
|
CHUCK: [Species.POLIWRATH, Species.MANKEY, Species.TYROGUE, Species.MACHOP],
|
||||||
JASMINE: [Species.MAGNEMITE, Species.STEELIX],
|
JASMINE: [Species.STEELIX, Species.MAGNEMITE, Species.PINECO, Species.SKARMORY],
|
||||||
PRYCE: [Species.SEEL, Species.SWINUB],
|
PRYCE: [Species.SWINUB, Species.SEEL, Species.SHELLDER, Species.SNEASEL],
|
||||||
CLAIR: [Species.DRATINI, Species.HORSEA, Species.GYARADOS],
|
CLAIR: [Species.HORSEA, Species.DRATINI, Species.MAGIKARP, Species.DRUDDIGON], // Tera Dragon Magikarp
|
||||||
// Gym Leaders- Hoenn
|
// Gym Leaders- Hoenn
|
||||||
ROXANNE: [Species.GEODUDE, Species.NOSEPASS],
|
ROXANNE: [Species.NOSEPASS, Species.GEODUDE, [Species.LILEEP, Species.ANORITH], Species.ARON],
|
||||||
BRAWLY: [Species.MACHOP, Species.MAKUHITA],
|
BRAWLY: [Species.MAKUHITA, Species.MACHOP, Species.MEDITITE, Species.SHROOMISH],
|
||||||
WATTSON: [Species.MAGNEMITE, Species.VOLTORB, Species.ELECTRIKE],
|
WATTSON: [Species.ELECTRIKE, Species.VOLTORB, Species.MAGNEMITE, [Species.PLUSLE, Species.MINUN]],
|
||||||
FLANNERY: [Species.SLUGMA, Species.TORKOAL, Species.NUMEL],
|
FLANNERY: [Species.TORKOAL, Species.SLUGMA, Species.NUMEL, Species.HOUNDOUR],
|
||||||
NORMAN: [Species.SLAKOTH, Species.SPINDA, Species.ZIGZAGOON, Species.KECLEON],
|
NORMAN: [Species.SLAKOTH, Species.KECLEON, Species.WHISMUR, Species.ZANGOOSE],
|
||||||
WINONA: [Species.SWABLU, Species.WINGULL, Species.TROPIUS, Species.SKARMORY],
|
WINONA: [Species.SWABLU, Species.WINGULL, Species.TROPIUS, Species.SKARMORY],
|
||||||
TATE: [Species.SOLROCK, Species.NATU, Species.CHIMECHO, Species.GALLADE],
|
TATE: [Species.SOLROCK, Species.NATU, Species.CHINGLING, Species.GALLADE],
|
||||||
LIZA: [Species.LUNATONE, Species.SPOINK, Species.BALTOY, Species.GARDEVOIR],
|
LIZA: [Species.LUNATONE, Species.BALTOY, Species.SPOINK, Species.GARDEVOIR],
|
||||||
JUAN: [Species.HORSEA, Species.BARBOACH, Species.SPHEAL, Species.RELICANTH],
|
JUAN: [Species.HORSEA, Species.SPHEAL, Species.BARBOACH, Species.CORPHISH],
|
||||||
// Gym Leaders- Sinnoh
|
// Gym Leaders- Sinnoh
|
||||||
ROARK: [Species.CRANIDOS, Species.LARVITAR, Species.GEODUDE],
|
ROARK: [Species.CRANIDOS, Species.GEODUDE, Species.NOSEPASS, Species.LARVITAR],
|
||||||
GARDENIA: [Species.ROSELIA, Species.TANGELA, Species.TURTWIG],
|
GARDENIA: [Species.BUDEW, Species.CHERUBI, Species.TURTWIG, Species.LEAFEON],
|
||||||
MAYLENE: [Species.LUCARIO, Species.MEDITITE, Species.CHIMCHAR],
|
MAYLENE: [Species.RIOLU, Species.MEDITITE, Species.CHIMCHAR, Species.CROAGUNK],
|
||||||
CRASHER_WAKE: [Species.BUIZEL, Species.WOOPER, Species.PIPLUP, Species.MAGIKARP],
|
CRASHER_WAKE: [Species.BUIZEL, Species.WOOPER, Species.PIPLUP, Species.MAGIKARP],
|
||||||
FANTINA: [Species.MISDREAVUS, Species.DRIFLOON, Species.SPIRITOMB],
|
FANTINA: [Species.MISDREAVUS, Species.DRIFLOON, Species.DUSKULL, Species.SPIRITOMB],
|
||||||
BYRON: [Species.SHIELDON, Species.BRONZOR, Species.AGGRON],
|
BYRON: [Species.SHIELDON, Species.BRONZOR, Species.ARON, Species.SKARMORY],
|
||||||
CANDICE: [Species.SNEASEL, Species.SNOVER, Species.SNORUNT],
|
CANDICE: [Species.FROSLASS, Species.SNOVER, Species.SNEASEL, Species.GLACEON],
|
||||||
VOLKNER: [Species.SHINX, Species.CHINCHOU, Species.ROTOM],
|
VOLKNER: [Species.ELEKID, Species.SHINX, Species.CHINCHOU, Species.ROTOM],
|
||||||
// Gym Leaders- Unova
|
// Gym Leaders- Unova
|
||||||
CILAN: [Species.PANSAGE, Species.FOONGUS, Species.PETILIL],
|
CILAN: [Species.PANSAGE, Species.SNIVY, Species.MARACTUS, Species.FERROSEED],
|
||||||
CHILI: [Species.PANSEAR, Species.DARUMAKA, Species.NUMEL],
|
CHILI: [Species.PANSEAR, Species.TEPIG, Species.HEATMOR, Species.DARUMAKA],
|
||||||
CRESS: [Species.PANPOUR, Species.TYMPOLE, Species.SLOWPOKE],
|
CRESS: [Species.PANPOUR, Species.OSHAWOTT, Species.BASCULIN, Species.TYMPOLE],
|
||||||
CHEREN: [Species.LILLIPUP, Species.MINCCINO, Species.PIDOVE],
|
CHEREN: [Species.LILLIPUP, Species.MINCCINO, Species.PIDOVE, Species.BOUFFALANT],
|
||||||
LENORA: [Species.PATRAT, Species.DEERLING, Species.AUDINO],
|
LENORA: [Species.PATRAT, Species.DEERLING, Species.AUDINO, Species.BRAVIARY],
|
||||||
ROXIE: [Species.VENIPEDE, Species.TRUBBISH, Species.SKORUPI],
|
ROXIE: [Species.VENIPEDE, Species.KOFFING, Species.TRUBBISH, Species.TOXEL],
|
||||||
BURGH: [Species.SEWADDLE, Species.SHELMET, Species.KARRABLAST],
|
BURGH: [Species.SEWADDLE, Species.DWEBBLE, [Species.KARRABLAST, Species.SHELMET], Species.DURANT],
|
||||||
ELESA: [Species.EMOLGA, Species.BLITZLE, Species.JOLTIK],
|
ELESA: [Species.BLITZLE, Species.EMOLGA, Species.JOLTIK, Species.TYNAMO],
|
||||||
CLAY: [Species.DRILBUR, Species.SANDILE, Species.GOLETT],
|
CLAY: [Species.DRILBUR, Species.SANDILE, Species.TYMPOLE, Species.GOLETT],
|
||||||
SKYLA: [Species.DUCKLETT, Species.WOOBAT, Species.RUFFLET],
|
SKYLA: [Species.DUCKLETT, Species.WOOBAT, [Species.RUFFLET, Species.VULLABY], Species.ARCHEN],
|
||||||
BRYCEN: [Species.CRYOGONAL, Species.VANILLITE, Species.CUBCHOO],
|
BRYCEN: [Species.CRYOGONAL, Species.VANILLITE, Species.CUBCHOO, Species.GALAR_DARUMAKA],
|
||||||
DRAYDEN: [Species.DRUDDIGON, Species.AXEW, Species.DEINO],
|
DRAYDEN: [Species.AXEW, Species.DRUDDIGON, Species.TRAPINCH, Species.DEINO],
|
||||||
MARLON: [Species.WAILMER, Species.FRILLISH, Species.TIRTOUGA],
|
MARLON: [Species.FRILLISH, Species.TIRTOUGA, Species.WAILMER, Species.MANTYKE],
|
||||||
// Gym Leaders- Kalos
|
// Gym Leaders- Kalos
|
||||||
VIOLA: [Species.SURSKIT, Species.SCATTERBUG],
|
VIOLA: [Species.SCATTERBUG, Species.SURSKIT, Species.CUTIEFLY, Species.BLIPBUG],
|
||||||
GRANT: [Species.AMAURA, Species.TYRUNT],
|
GRANT: [Species.TYRUNT, Species.AMAURA, Species.BINACLE, Species.DWEBBLE],
|
||||||
KORRINA: [Species.HAWLUCHA, Species.LUCARIO, Species.MIENFOO],
|
KORRINA: [Species.RIOLU, Species.MIENFOO, Species.HAWLUCHA, Species.PANCHAM],
|
||||||
RAMOS: [Species.SKIDDO, Species.HOPPIP, Species.BELLSPROUT],
|
RAMOS: [Species.SKIDDO, Species.HOPPIP, Species.BELLSPROUT, [Species.PHANTUMP, Species.PUMPKABOO]],
|
||||||
CLEMONT: [Species.HELIOPTILE, Species.MAGNEMITE, Species.EMOLGA],
|
CLEMONT: [Species.HELIOPTILE, Species.MAGNEMITE, Species.DEDENNE, Species.ROTOM],
|
||||||
VALERIE: [Species.SYLVEON, Species.MAWILE, Species.MR_MIME],
|
VALERIE: [Species.SYLVEON, Species.MAWILE, Species.MR_MIME, [Species.SPRITZEE, Species.SWIRLIX]],
|
||||||
OLYMPIA: [Species.ESPURR, Species.SIGILYPH, Species.SLOWKING],
|
OLYMPIA: [Species.ESPURR, Species.SIGILYPH, Species.INKAY, Species.SLOWKING],
|
||||||
WULFRIC: [Species.BERGMITE, Species.SNOVER, Species.CRYOGONAL],
|
WULFRIC: [Species.BERGMITE, Species.SNOVER, Species.CRYOGONAL, Species.SWINUB],
|
||||||
// Gym Leaders- Galar
|
// Gym Leaders- Galar
|
||||||
MILO: [Species.GOSSIFLEUR, Species.APPLIN, Species.BOUNSWEET],
|
MILO: [Species.GOSSIFLEUR, Species.SEEDOT, Species.APPLIN, Species.LOTAD],
|
||||||
NESSA: [Species.CHEWTLE, Species.ARROKUDA, Species.WIMPOD],
|
NESSA: [Species.CHEWTLE, Species.WIMPOD, Species.ARROKUDA, Species.MAREANIE],
|
||||||
KABU: [Species.SIZZLIPEDE, Species.VULPIX, Species.TORKOAL],
|
KABU: [Species.SIZZLIPEDE, Species.VULPIX, Species.GROWLITHE, Species.TORKOAL],
|
||||||
BEA: [Species.GALAR_FARFETCHD, Species.MACHOP, Species.CLOBBOPUS],
|
BEA: [Species.MACHOP, Species.GALAR_FARFETCHD, Species.CLOBBOPUS, Species.FALINKS],
|
||||||
ALLISTER: [Species.GALAR_YAMASK, Species.GALAR_CORSOLA, Species.GASTLY],
|
ALLISTER: [Species.GASTLY, Species.GALAR_YAMASK, Species.GALAR_CORSOLA, Species.SINISTEA],
|
||||||
OPAL: [Species.MILCERY, Species.TOGETIC, Species.GALAR_WEEZING],
|
OPAL: [Species.MILCERY, Species.GALAR_WEEZING, Species.TOGEPI, Species.MAWILE],
|
||||||
BEDE: [Species.HATENNA, Species.GALAR_PONYTA, Species.GARDEVOIR],
|
BEDE: [Species.HATENNA, Species.GALAR_PONYTA, Species.GARDEVOIR, Species.SYLVEON],
|
||||||
GORDIE: [Species.ROLYCOLY, Species.STONJOURNER, Species.BINACLE],
|
GORDIE: [Species.ROLYCOLY, [Species.SHUCKLE, Species.BINACLE], Species.STONJOURNER, Species.LARVITAR],
|
||||||
MELONY: [Species.SNOM, Species.GALAR_DARUMAKA, Species.GALAR_MR_MIME],
|
MELONY: [Species.LAPRAS, Species.SNOM, Species.EISCUE, [Species.GALAR_MR_MIME, Species.GALAR_DARUMAKA]],
|
||||||
PIERS: [Species.GALAR_ZIGZAGOON, Species.SCRAGGY, Species.INKAY],
|
PIERS: [Species.GALAR_ZIGZAGOON, Species.SCRAGGY, Species.TOXEL, Species.INKAY], // Tera Dark Toxel
|
||||||
MARNIE: [Species.IMPIDIMP, Species.PURRLOIN, Species.MORPEKO],
|
MARNIE: [Species.IMPIDIMP, Species.MORPEKO, Species.PURRLOIN, Species.CROAGUNK], // Tera Dark Croagunk
|
||||||
RAIHAN: [Species.DURALUDON, Species.TURTONATOR, Species.GOOMY],
|
RAIHAN: [Species.DURALUDON, Species.TRAPINCH, Species.GOOMY, Species.TURTONATOR],
|
||||||
// Gym Leaders- Paldea; First slot is Tera
|
// Gym Leaders- Paldea; First slot is Tera
|
||||||
KATY: [Species.TEDDIURSA, Species.NYMBLE, Species.TAROUNTULA], // Tera Bug Teddiursa
|
KATY: [Species.TEDDIURSA, Species.NYMBLE, Species.TAROUNTULA, Species.RELLOR], // Tera Bug Teddiursa
|
||||||
BRASSIUS: [Species.SUDOWOODO, Species.BRAMBLIN, Species.SMOLIV], // Tera Grass Sudowoodo
|
BRASSIUS: [Species.BONSLY, Species.SMOLIV, Species.BRAMBLIN, Species.SUNKERN], // Tera Grass Bonsly
|
||||||
IONO: [Species.MISDREAVUS, Species.TADBULB, Species.WATTREL], // Tera Ghost Misdreavus
|
IONO: [Species.MISDREAVUS, Species.TADBULB, Species.WATTREL, Species.MAGNEMITE], // Tera Ghost Misdreavus
|
||||||
KOFU: [Species.CRABRAWLER, Species.VELUZA, Species.WIGLETT, Species.WINGULL], // Tera Water Crabrawler
|
KOFU: [Species.CRABRAWLER, Species.VELUZA, Species.WIGLETT, Species.WINGULL], // Tera Water Crabrawler
|
||||||
LARRY: [Species.STARLY, Species.DUNSPARCE, Species.LECHONK, Species.KOMALA], // Tera Normal Starly
|
LARRY: [Species.STARLY, Species.DUNSPARCE, Species.LECHONK, Species.KOMALA], // Tera Normal Starly
|
||||||
RYME: [Species.TOXEL, Species.GREAVARD, Species.SHUPPET, Species.MIMIKYU], // Tera Ghost Toxel
|
RYME: [Species.TOXEL, Species.GREAVARD, Species.SHUPPET, Species.MIMIKYU], // Tera Ghost Toxel
|
||||||
TULIP: [Species.FLABEBE, Species.FLITTLE, Species.RALTS, Species.GIRAFARIG], // Tera Psychic Flabebe
|
TULIP: [Species.FLABEBE, Species.FLITTLE, Species.RALTS, Species.GIRAFARIG], // Tera Psychic Flabebe
|
||||||
GRUSHA: [Species.SWABLU, Species.CETODDLE, Species.CUBCHOO, Species.ALOLA_VULPIX], // Tera Ice Swablu
|
GRUSHA: [Species.SWABLU, Species.CETODDLE, Species.SNOM, Species.CUBCHOO], // Tera Ice Swablu
|
||||||
|
}, {
|
||||||
// Elite Four- Kanto
|
get(target, prop: string) {
|
||||||
LORELEI: [
|
return target[prop as keyof SignatureSpecies] ?? [];
|
||||||
Species.JYNX,
|
}
|
||||||
[Species.SLOWBRO, Species.GALAR_SLOWBRO],
|
});
|
||||||
Species.LAPRAS,
|
|
||||||
[Species.CLOYSTER, Species.ALOLA_SANDSLASH],
|
|
||||||
],
|
|
||||||
BRUNO: [Species.MACHAMP, Species.HITMONCHAN, Species.HITMONLEE, [Species.GOLEM, Species.ALOLA_GOLEM]],
|
|
||||||
AGATHA: [Species.GENGAR, [Species.ARBOK, Species.WEEZING], Species.CROBAT, Species.ALOLA_MAROWAK],
|
|
||||||
LANCE: [Species.DRAGONITE, Species.GYARADOS, Species.AERODACTYL, Species.ALOLA_EXEGGUTOR],
|
|
||||||
// Elite Four- Johto (Bruno included)
|
|
||||||
WILL: [Species.XATU, Species.JYNX, [Species.SLOWBRO, Species.SLOWKING], Species.EXEGGUTOR],
|
|
||||||
KOGA: [[Species.MUK, Species.WEEZING], [Species.VENOMOTH, Species.ARIADOS], Species.CROBAT, Species.TENTACRUEL],
|
|
||||||
KAREN: [Species.UMBREON, Species.HONCHKROW, Species.HOUNDOOM, Species.WEAVILE],
|
|
||||||
// Elite Four- Hoenn
|
|
||||||
SIDNEY: [
|
|
||||||
[Species.SHIFTRY, Species.CACTURNE],
|
|
||||||
[Species.SHARPEDO, Species.CRAWDAUNT],
|
|
||||||
Species.ABSOL,
|
|
||||||
Species.MIGHTYENA,
|
|
||||||
],
|
|
||||||
PHOEBE: [Species.SABLEYE, Species.DUSKNOIR, Species.BANETTE, [Species.DRIFBLIM, Species.MISMAGIUS]],
|
|
||||||
GLACIA: [Species.GLALIE, Species.WALREIN, Species.FROSLASS, Species.ABOMASNOW],
|
|
||||||
DRAKE: [Species.ALTARIA, Species.SALAMENCE, Species.FLYGON, Species.KINGDRA],
|
|
||||||
// Elite Four- Sinnoh
|
|
||||||
AARON: [[Species.SCIZOR, Species.KLEAVOR], Species.HERACROSS, [Species.VESPIQUEN, Species.YANMEGA], Species.DRAPION],
|
|
||||||
BERTHA: [Species.WHISCASH, Species.HIPPOWDON, Species.GLISCOR, Species.RHYPERIOR],
|
|
||||||
FLINT: [
|
|
||||||
[Species.RAPIDASH, Species.FLAREON],
|
|
||||||
Species.MAGMORTAR,
|
|
||||||
[Species.STEELIX, Species.LOPUNNY],
|
|
||||||
Species.INFERNAPE,
|
|
||||||
], // Tera Fire Steelix or Lopunny
|
|
||||||
LUCIAN: [Species.MR_MIME, Species.GALLADE, Species.BRONZONG, [Species.ALAKAZAM, Species.ESPEON]],
|
|
||||||
// Elite Four- Unova
|
|
||||||
SHAUNTAL: [Species.COFAGRIGUS, Species.CHANDELURE, Species.GOLURK, Species.JELLICENT],
|
|
||||||
MARSHAL: [Species.CONKELDURR, Species.MIENSHAO, Species.THROH, Species.SAWK],
|
|
||||||
GRIMSLEY: [Species.LIEPARD, Species.KINGAMBIT, Species.SCRAFTY, Species.KROOKODILE],
|
|
||||||
CAITLIN: [Species.MUSHARNA, Species.GOTHITELLE, Species.SIGILYPH, Species.REUNICLUS],
|
|
||||||
// Elite Four- Kalos
|
|
||||||
MALVA: [Species.PYROAR, Species.TORKOAL, Species.CHANDELURE, Species.TALONFLAME],
|
|
||||||
SIEBOLD: [Species.CLAWITZER, Species.GYARADOS, Species.BARBARACLE, Species.STARMIE],
|
|
||||||
WIKSTROM: [Species.KLEFKI, Species.PROBOPASS, Species.SCIZOR, Species.AEGISLASH],
|
|
||||||
DRASNA: [Species.DRAGALGE, Species.DRUDDIGON, Species.ALTARIA, Species.NOIVERN],
|
|
||||||
// Elite Four- Alola
|
|
||||||
HALA: [Species.HARIYAMA, Species.BEWEAR, Species.CRABOMINABLE, [Species.POLIWRATH, Species.ANNIHILAPE]],
|
|
||||||
MOLAYNE: [Species.KLEFKI, Species.MAGNEZONE, Species.METAGROSS, Species.ALOLA_DUGTRIO],
|
|
||||||
OLIVIA: [Species.RELICANTH, Species.CARBINK, Species.ALOLA_GOLEM, Species.LYCANROC],
|
|
||||||
ACEROLA: [[Species.BANETTE, Species.DRIFBLIM], Species.MIMIKYU, Species.DHELMISE, Species.PALOSSAND],
|
|
||||||
KAHILI: [[Species.BRAVIARY, Species.MANDIBUZZ], Species.HAWLUCHA, Species.ORICORIO, Species.TOUCANNON],
|
|
||||||
// Elite Four- Galar
|
|
||||||
MARNIE_ELITE: [Species.MORPEKO, Species.LIEPARD, [Species.TOXICROAK, Species.SCRAFTY], Species.GRIMMSNARL],
|
|
||||||
NESSA_ELITE: [Species.GOLISOPOD, [Species.QUAGSIRE, Species.PELIPPER], Species.TOXAPEX, Species.DREDNAW],
|
|
||||||
BEA_ELITE: [Species.HAWLUCHA, [Species.GRAPPLOCT, Species.SIRFETCHD], Species.FALINKS, Species.MACHAMP],
|
|
||||||
ALLISTER_ELITE: [Species.DUSKNOIR, [Species.POLTEAGEIST, Species.RUNERIGUS], Species.CURSOLA, Species.GENGAR],
|
|
||||||
RAIHAN_ELITE: [Species.GOODRA, [Species.TORKOAL, Species.TURTONATOR], Species.FLYGON, Species.ARCHALUDON],
|
|
||||||
// Elite Four- Paldea
|
|
||||||
RIKA: [Species.CLODSIRE, [Species.DUGTRIO, Species.DONPHAN], Species.CAMERUPT, Species.WHISCASH], // Tera Ground Clodsire
|
|
||||||
POPPY: [Species.TINKATON, Species.BRONZONG, Species.CORVIKNIGHT, Species.COPPERAJAH], // Tera Steel Tinkaton
|
|
||||||
LARRY_ELITE: [Species.FLAMIGO, Species.STARAPTOR, [Species.ALTARIA, Species.TROPIUS], Species.ORICORIO], // Tera Flying Flamigo; random Oricorio
|
|
||||||
HASSEL: [Species.BAXCALIBUR, [Species.FLAPPLE, Species.APPLETUN], Species.DRAGALGE, Species.NOIVERN], // Tera Dragon Baxcalibur
|
|
||||||
// Elite Four- BBL
|
|
||||||
CRISPIN: [Species.BLAZIKEN, Species.MAGMORTAR, [Species.CAMERUPT, Species.TALONFLAME], Species.ROTOM], // Tera Fire Blaziken; Heat Rotom
|
|
||||||
AMARYS: [Species.METAGROSS, Species.SCIZOR, Species.EMPOLEON, Species.SKARMORY], // Tera Steel Metagross
|
|
||||||
LACEY: [Species.EXCADRILL, Species.PRIMARINA, [Species.WHIMSICOTT, Species.ALCREMIE], Species.GRANBULL], // Tera Fairy Excadrill
|
|
||||||
DRAYTON: [Species.ARCHALUDON, Species.DRAGONITE, Species.HAXORUS, Species.SCEPTILE], // Tera Dragon Archaludon
|
|
||||||
};
|
|
||||||
|
@ -5724,7 +5724,6 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.SCOLIPEDE,
|
Species.SCOLIPEDE,
|
||||||
Species.WHIMSICOTT,
|
Species.WHIMSICOTT,
|
||||||
Species.LILLIGANT,
|
Species.LILLIGANT,
|
||||||
Species.BASCULIN,
|
|
||||||
Species.KROOKODILE,
|
Species.KROOKODILE,
|
||||||
Species.DARMANITAN,
|
Species.DARMANITAN,
|
||||||
Species.CRUSTLE,
|
Species.CRUSTLE,
|
||||||
@ -6023,6 +6022,11 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.HISUI_DECIDUEYE,
|
Species.HISUI_DECIDUEYE,
|
||||||
Species.PALDEA_TAUROS,
|
Species.PALDEA_TAUROS,
|
||||||
Species.BLOODMOON_URSALUNA,
|
Species.BLOODMOON_URSALUNA,
|
||||||
|
[
|
||||||
|
Species.BASCULIN,
|
||||||
|
"blue-striped",
|
||||||
|
"red-striped",
|
||||||
|
]
|
||||||
],
|
],
|
||||||
[Moves.LOW_KICK]: [
|
[Moves.LOW_KICK]: [
|
||||||
Species.SANDSHREW,
|
Species.SANDSHREW,
|
||||||
@ -19335,7 +19339,6 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.CONKELDURR,
|
Species.CONKELDURR,
|
||||||
Species.THROH,
|
Species.THROH,
|
||||||
Species.SAWK,
|
Species.SAWK,
|
||||||
Species.BASCULIN,
|
|
||||||
Species.DARMANITAN,
|
Species.DARMANITAN,
|
||||||
Species.SCRAFTY,
|
Species.SCRAFTY,
|
||||||
Species.ESCAVALIER,
|
Species.ESCAVALIER,
|
||||||
@ -19449,6 +19452,11 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.HISUI_BRAVIARY,
|
Species.HISUI_BRAVIARY,
|
||||||
Species.HISUI_DECIDUEYE,
|
Species.HISUI_DECIDUEYE,
|
||||||
Species.PALDEA_TAUROS,
|
Species.PALDEA_TAUROS,
|
||||||
|
[
|
||||||
|
Species.BASCULIN,
|
||||||
|
"blue-striped",
|
||||||
|
"red-striped",
|
||||||
|
],
|
||||||
],
|
],
|
||||||
[Moves.SPITE]: [
|
[Moves.SPITE]: [
|
||||||
Species.EKANS,
|
Species.EKANS,
|
||||||
@ -51341,7 +51349,6 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.SCOLIPEDE,
|
Species.SCOLIPEDE,
|
||||||
Species.WHIMSICOTT,
|
Species.WHIMSICOTT,
|
||||||
Species.LILLIGANT,
|
Species.LILLIGANT,
|
||||||
Species.BASCULIN,
|
|
||||||
Species.KROOKODILE,
|
Species.KROOKODILE,
|
||||||
Species.DARMANITAN,
|
Species.DARMANITAN,
|
||||||
Species.CRUSTLE,
|
Species.CRUSTLE,
|
||||||
@ -51655,6 +51662,11 @@ export const tmSpecies: TmSpecies = {
|
|||||||
Species.HISUI_DECIDUEYE,
|
Species.HISUI_DECIDUEYE,
|
||||||
Species.PALDEA_TAUROS,
|
Species.PALDEA_TAUROS,
|
||||||
Species.BLOODMOON_URSALUNA,
|
Species.BLOODMOON_URSALUNA,
|
||||||
|
[
|
||||||
|
Species.BASCULIN,
|
||||||
|
"blue-striped",
|
||||||
|
"red-striped",
|
||||||
|
],
|
||||||
],
|
],
|
||||||
[Moves.NASTY_PLOT]: [
|
[Moves.NASTY_PLOT]: [
|
||||||
Species.PIKACHU,
|
Species.PIKACHU,
|
||||||
|
@ -2,11 +2,11 @@ import { globalScene } from "#app/global-scene";
|
|||||||
import { AttackMove, BeakBlastHeaderAttr, DelayedAttackAttr, SelfStatusMove, allMoves } from "./moves/move";
|
import { AttackMove, BeakBlastHeaderAttr, DelayedAttackAttr, SelfStatusMove, allMoves } from "./moves/move";
|
||||||
import { MoveFlags } from "#enums/MoveFlags";
|
import { MoveFlags } from "#enums/MoveFlags";
|
||||||
import type Pokemon from "../field/pokemon";
|
import type Pokemon from "../field/pokemon";
|
||||||
import { type nil, getFrameMs, getEnumKeys, getEnumValues, animationFileName } from "../utils";
|
import { type nil, getFrameMs, getEnumKeys, getEnumValues, animationFileName } from "../utils/common";
|
||||||
import type { BattlerIndex } from "../battle";
|
import type { BattlerIndex } from "../battle";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { SubstituteTag } from "./battler-tags";
|
import { SubstituteTag } from "./battler-tags";
|
||||||
import { isNullOrUndefined } from "../utils";
|
import { isNullOrUndefined } from "../utils/common";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { EncounterAnim } from "#enums/encounter-anims";
|
import { EncounterAnim } from "#enums/encounter-anims";
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
|
|||||||
import type { StatStageChangeCallback } from "#app/phases/stat-stage-change-phase";
|
import type { StatStageChangeCallback } from "#app/phases/stat-stage-change-phase";
|
||||||
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
||||||
import i18next from "#app/plugins/i18n";
|
import i18next from "#app/plugins/i18n";
|
||||||
import { BooleanHolder, getFrameMs, NumberHolder, toDmgValue } from "#app/utils";
|
import { BooleanHolder, getFrameMs, NumberHolder, toDmgValue } from "#app/utils/common";
|
||||||
import { Abilities } from "#enums/abilities";
|
import { Abilities } from "#enums/abilities";
|
||||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
@ -42,7 +42,7 @@ import { Species } from "#enums/species";
|
|||||||
import { EFFECTIVE_STATS, getStatKey, Stat, type BattleStat, type EffectiveStat } from "#enums/stat";
|
import { EFFECTIVE_STATS, getStatKey, Stat, type BattleStat, type EffectiveStat } from "#enums/stat";
|
||||||
import { StatusEffect } from "#enums/status-effect";
|
import { StatusEffect } from "#enums/status-effect";
|
||||||
import { WeatherType } from "#enums/weather-type";
|
import { WeatherType } from "#enums/weather-type";
|
||||||
import { isNullOrUndefined } from "#app/utils";
|
import { isNullOrUndefined } from "#app/utils/common";
|
||||||
|
|
||||||
export enum BattlerTagLapseType {
|
export enum BattlerTagLapseType {
|
||||||
FAINT,
|
FAINT,
|
||||||
@ -2637,7 +2637,7 @@ export class GulpMissileTag extends BattlerTag {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (moveEffectPhase.move.getMove().hitsSubstitute(attacker, pokemon)) {
|
if (moveEffectPhase.move.hitsSubstitute(attacker, pokemon)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2993,7 +2993,7 @@ export class SubstituteTag extends BattlerTag {
|
|||||||
if (!attacker) {
|
if (!attacker) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const move = moveEffectPhase.move.getMove();
|
const move = moveEffectPhase.move;
|
||||||
const firstHit = attacker.turnData.hitCount === attacker.turnData.hitsLeft;
|
const firstHit = attacker.turnData.hitCount === attacker.turnData.hitsLeft;
|
||||||
|
|
||||||
if (firstHit && move.hitsSubstitute(attacker, pokemon)) {
|
if (firstHit && move.hitsSubstitute(attacker, pokemon)) {
|
||||||
@ -3681,7 +3681,7 @@ function getMoveEffectPhaseData(_pokemon: Pokemon): { phase: MoveEffectPhase; at
|
|||||||
return {
|
return {
|
||||||
phase: phase,
|
phase: phase,
|
||||||
attacker: phase.getPokemon(),
|
attacker: phase.getPokemon(),
|
||||||
move: phase.move.getMove(),
|
move: phase.move,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -2,7 +2,7 @@ import { getPokemonNameWithAffix } from "../messages";
|
|||||||
import type Pokemon from "../field/pokemon";
|
import type Pokemon from "../field/pokemon";
|
||||||
import { HitResult } from "../field/pokemon";
|
import { HitResult } from "../field/pokemon";
|
||||||
import { getStatusEffectHealText } from "./status-effect";
|
import { getStatusEffectHealText } from "./status-effect";
|
||||||
import { NumberHolder, toDmgValue, randSeedInt } from "#app/utils";
|
import { NumberHolder, toDmgValue, randSeedInt } from "#app/utils/common";
|
||||||
import {
|
import {
|
||||||
DoubleBerryEffectAbAttr,
|
DoubleBerryEffectAbAttr,
|
||||||
PostItemLostAbAttr,
|
PostItemLostAbAttr,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { BooleanHolder, type NumberHolder, randSeedItem, deepCopy } from "#app/utils";
|
import { BooleanHolder, type NumberHolder, randSeedItem, deepCopy } from "#app/utils/common";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import type { DexAttrProps, GameData } from "#app/system/game-data";
|
import type { DexAttrProps, GameData } from "#app/system/game-data";
|
||||||
import { defaultStarterSpecies } from "#app/system/game-data";
|
import { defaultStarterSpecies } from "#app/system/game-data";
|
||||||
@ -8,7 +8,9 @@ import { speciesStarterCosts } from "#app/data/balance/starters";
|
|||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import { PokemonMove } from "#app/field/pokemon";
|
import { PokemonMove } from "#app/field/pokemon";
|
||||||
import type { FixedBattleConfig } from "#app/battle";
|
import type { FixedBattleConfig } from "#app/battle";
|
||||||
import { ClassicFixedBossWaves, BattleType, getRandomTrainerFunc } from "#app/battle";
|
import { getRandomTrainerFunc } from "#app/battle";
|
||||||
|
import { ClassicFixedBossWaves } from "#enums/fixed-boss-waves";
|
||||||
|
import { BattleType } from "#enums/battle-type";
|
||||||
import Trainer, { TrainerVariant } from "#app/field/trainer";
|
import Trainer, { TrainerVariant } from "#app/field/trainer";
|
||||||
import { PokemonType } from "#enums/pokemon-type";
|
import { PokemonType } from "#enums/pokemon-type";
|
||||||
import { Challenges } from "#enums/challenges";
|
import { Challenges } from "#enums/challenges";
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import type { Abilities } from "#enums/abilities";
|
import type { Abilities } from "#enums/abilities";
|
||||||
import type { PokemonType } from "#enums/pokemon-type";
|
import type { PokemonType } from "#enums/pokemon-type";
|
||||||
import { isNullOrUndefined } from "#app/utils";
|
import { isNullOrUndefined } from "#app/utils/common";
|
||||||
import type { Nature } from "#enums/nature";
|
import type { Nature } from "#enums/nature";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,7 +3,7 @@ import type { Species } from "#enums/species";
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import { PlayerPokemon } from "#app/field/pokemon";
|
import { PlayerPokemon } from "#app/field/pokemon";
|
||||||
import type { Starter } from "#app/ui/starter-select-ui-handler";
|
import type { Starter } from "#app/ui/starter-select-ui-handler";
|
||||||
import { randSeedGauss, randSeedInt, randSeedItem, getEnumValues } from "#app/utils";
|
import { randSeedGauss, randSeedInt, randSeedItem, getEnumValues } from "#app/utils/common";
|
||||||
import type { PokemonSpeciesForm } from "#app/data/pokemon-species";
|
import type { PokemonSpeciesForm } from "#app/data/pokemon-species";
|
||||||
import PokemonSpecies, { getPokemonSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species";
|
import PokemonSpecies, { getPokemonSpecies, getPokemonSpeciesForm } from "#app/data/pokemon-species";
|
||||||
import { speciesStarterCosts } from "#app/data/balance/starters";
|
import { speciesStarterCosts } from "#app/data/balance/starters";
|
||||||
|
@ -4,7 +4,7 @@ import type PokemonSpecies from "#app/data/pokemon-species";
|
|||||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||||
import { speciesStarterCosts } from "#app/data/balance/starters";
|
import { speciesStarterCosts } from "#app/data/balance/starters";
|
||||||
import { VariantTier } from "#enums/variant-tier";
|
import { VariantTier } from "#enums/variant-tier";
|
||||||
import { randInt, randomString, randSeedInt, getIvsFromId } from "#app/utils";
|
import { randInt, randomString, randSeedInt, getIvsFromId } from "#app/utils/common";
|
||||||
import Overrides from "#app/overrides";
|
import Overrides from "#app/overrides";
|
||||||
import { pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions";
|
import { pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions";
|
||||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||||
|
20
src/data/moves/move-utils.ts
Normal file
20
src/data/moves/move-utils.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { MoveTarget } from "#enums/MoveTarget";
|
||||||
|
import type Move from "./move";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether the move targets the field
|
||||||
|
*
|
||||||
|
* Examples include
|
||||||
|
* - Hazard moves like spikes
|
||||||
|
* - Weather moves like rain dance
|
||||||
|
* - User side moves like reflect and safeguard
|
||||||
|
*/
|
||||||
|
export function isFieldTargeted(move: Move): boolean {
|
||||||
|
switch (move.moveTarget) {
|
||||||
|
case MoveTarget.BOTH_SIDES:
|
||||||
|
case MoveTarget.USER_SIDE:
|
||||||
|
case MoveTarget.ENEMY_SIDE:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
@ -29,7 +29,7 @@ import {
|
|||||||
} from "../status-effect";
|
} from "../status-effect";
|
||||||
import { getTypeDamageMultiplier } from "../type";
|
import { getTypeDamageMultiplier } from "../type";
|
||||||
import { PokemonType } from "#enums/pokemon-type";
|
import { PokemonType } from "#enums/pokemon-type";
|
||||||
import { BooleanHolder, NumberHolder, isNullOrUndefined, toDmgValue, randSeedItem, randSeedInt, getEnumValues, toReadableString, type Constructor } from "#app/utils";
|
import { BooleanHolder, NumberHolder, isNullOrUndefined, toDmgValue, randSeedItem, randSeedInt, getEnumValues, toReadableString, type Constructor } from "#app/utils/common";
|
||||||
import { WeatherType } from "#enums/weather-type";
|
import { WeatherType } from "#enums/weather-type";
|
||||||
import type { ArenaTrapTag } from "../arena-tag";
|
import type { ArenaTrapTag } from "../arena-tag";
|
||||||
import { ArenaTagSide, WeakenMoveTypeTag } from "../arena-tag";
|
import { ArenaTagSide, WeakenMoveTypeTag } from "../arena-tag";
|
||||||
@ -60,6 +60,7 @@ import {
|
|||||||
MoveTypeChangeAbAttr,
|
MoveTypeChangeAbAttr,
|
||||||
PostDamageForceSwitchAbAttr,
|
PostDamageForceSwitchAbAttr,
|
||||||
PostItemLostAbAttr,
|
PostItemLostAbAttr,
|
||||||
|
ReflectStatusMoveAbAttr,
|
||||||
ReverseDrainAbAttr,
|
ReverseDrainAbAttr,
|
||||||
UserFieldMoveTypePowerBoostAbAttr,
|
UserFieldMoveTypePowerBoostAbAttr,
|
||||||
VariableMovePowerAbAttr,
|
VariableMovePowerAbAttr,
|
||||||
@ -75,7 +76,7 @@ import {
|
|||||||
PreserveBerryModifier,
|
PreserveBerryModifier,
|
||||||
} from "../../modifier/modifier";
|
} from "../../modifier/modifier";
|
||||||
import type { BattlerIndex } from "../../battle";
|
import type { BattlerIndex } from "../../battle";
|
||||||
import { BattleType } from "../../battle";
|
import { BattleType } from "#enums/battle-type";
|
||||||
import { TerrainType } from "../terrain";
|
import { TerrainType } from "../terrain";
|
||||||
import { ModifierPoolType } from "#app/modifier/modifier-type";
|
import { ModifierPoolType } from "#app/modifier/modifier-type";
|
||||||
import { Command } from "../../ui/command-ui-handler";
|
import { Command } from "../../ui/command-ui-handler";
|
||||||
@ -122,6 +123,8 @@ import { MoveEffectTrigger } from "#enums/MoveEffectTrigger";
|
|||||||
import { MultiHitType } from "#enums/MultiHitType";
|
import { MultiHitType } from "#enums/MultiHitType";
|
||||||
import { invalidAssistMoves, invalidCopycatMoves, invalidMetronomeMoves, invalidMirrorMoveMoves, invalidSleepTalkMoves } from "./invalid-moves";
|
import { invalidAssistMoves, invalidCopycatMoves, invalidMetronomeMoves, invalidMirrorMoveMoves, invalidSleepTalkMoves } from "./invalid-moves";
|
||||||
import { applyAttackTypeBoosterHeldItem } from "#app/modifier/held-items";
|
import { applyAttackTypeBoosterHeldItem } from "#app/modifier/held-items";
|
||||||
|
import { TrainerVariant } from "#app/field/trainer";
|
||||||
|
import { SelectBiomePhase } from "#app/phases/select-biome-phase";
|
||||||
|
|
||||||
type MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => boolean;
|
type MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => boolean;
|
||||||
type UserMoveConditionFunc = (user: Pokemon, move: Move) => boolean;
|
type UserMoveConditionFunc = (user: Pokemon, move: Move) => boolean;
|
||||||
@ -650,7 +653,7 @@ export default class Move implements Localizable {
|
|||||||
break;
|
break;
|
||||||
case MoveFlags.IGNORE_ABILITIES:
|
case MoveFlags.IGNORE_ABILITIES:
|
||||||
if (user.hasAbilityWithAttr(MoveAbilityBypassAbAttr)) {
|
if (user.hasAbilityWithAttr(MoveAbilityBypassAbAttr)) {
|
||||||
const abilityEffectsIgnored = new BooleanHolder(false);
|
const abilityEffectsIgnored = new BooleanHolder(false);
|
||||||
applyAbAttrs(MoveAbilityBypassAbAttr, user, abilityEffectsIgnored, false, this);
|
applyAbAttrs(MoveAbilityBypassAbAttr, user, abilityEffectsIgnored, false, this);
|
||||||
if (abilityEffectsIgnored.value) {
|
if (abilityEffectsIgnored.value) {
|
||||||
return true;
|
return true;
|
||||||
@ -665,6 +668,17 @@ export default class Move implements Localizable {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case MoveFlags.REFLECTABLE:
|
||||||
|
// If the target is not semi-invulnerable and either has magic coat active or an unignored magic bounce ability
|
||||||
|
if (
|
||||||
|
target?.getTag(SemiInvulnerableTag) ||
|
||||||
|
!(target?.getTag(BattlerTagType.MAGIC_COAT) ||
|
||||||
|
(!this.doesFlagEffectApply({ flag: MoveFlags.IGNORE_ABILITIES, user, target }) &&
|
||||||
|
target?.hasAbilityWithAttr(ReflectStatusMoveAbAttr)))
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return !!(this.flags & flag);
|
return !!(this.flags & flag);
|
||||||
@ -1716,7 +1730,7 @@ export class SacrificialAttr extends MoveEffectAttr {
|
|||||||
**/
|
**/
|
||||||
export class SacrificialAttrOnHit extends MoveEffectAttr {
|
export class SacrificialAttrOnHit extends MoveEffectAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(true, { trigger: MoveEffectTrigger.HIT });
|
super(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1955,6 +1969,14 @@ export class PartyStatusCureAttr extends MoveEffectAttr {
|
|||||||
* @extends MoveEffectAttr
|
* @extends MoveEffectAttr
|
||||||
*/
|
*/
|
||||||
export class FlameBurstAttr extends MoveEffectAttr {
|
export class FlameBurstAttr extends MoveEffectAttr {
|
||||||
|
constructor() {
|
||||||
|
/**
|
||||||
|
* This is self-targeted to bypass immunity to target-facing secondary
|
||||||
|
* effects when the target has an active Substitute doll.
|
||||||
|
* TODO: Find a more intuitive way to implement Substitute bypassing.
|
||||||
|
*/
|
||||||
|
super(true);
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* @param user - n/a
|
* @param user - n/a
|
||||||
* @param target - The target Pokémon.
|
* @param target - The target Pokémon.
|
||||||
@ -2177,7 +2199,7 @@ export class HitHealAttr extends MoveEffectAttr {
|
|||||||
private healStat: EffectiveStat | null;
|
private healStat: EffectiveStat | null;
|
||||||
|
|
||||||
constructor(healRatio?: number | null, healStat?: EffectiveStat) {
|
constructor(healRatio?: number | null, healStat?: EffectiveStat) {
|
||||||
super(true, { trigger: MoveEffectTrigger.HIT });
|
super(true);
|
||||||
|
|
||||||
this.healRatio = healRatio ?? 0.5;
|
this.healRatio = healRatio ?? 0.5;
|
||||||
this.healStat = healStat ?? null;
|
this.healStat = healStat ?? null;
|
||||||
@ -2426,7 +2448,7 @@ export class StatusEffectAttr extends MoveEffectAttr {
|
|||||||
public overrideStatus: boolean = false;
|
public overrideStatus: boolean = false;
|
||||||
|
|
||||||
constructor(effect: StatusEffect, selfTarget?: boolean, turnsRemaining?: number, overrideStatus: boolean = false) {
|
constructor(effect: StatusEffect, selfTarget?: boolean, turnsRemaining?: number, overrideStatus: boolean = false) {
|
||||||
super(selfTarget, { trigger: MoveEffectTrigger.HIT });
|
super(selfTarget);
|
||||||
|
|
||||||
this.effect = effect;
|
this.effect = effect;
|
||||||
this.turnsRemaining = turnsRemaining;
|
this.turnsRemaining = turnsRemaining;
|
||||||
@ -2434,26 +2456,15 @@ export class StatusEffectAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
if (!this.selfTarget && move.hitsSubstitute(user, target)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const moveChance = this.getMoveChance(user, target, move, this.selfTarget, true);
|
const moveChance = this.getMoveChance(user, target, move, this.selfTarget, true);
|
||||||
const statusCheck = moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance;
|
const statusCheck = moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance;
|
||||||
if (statusCheck) {
|
if (statusCheck) {
|
||||||
const pokemon = this.selfTarget ? user : target;
|
const pokemon = this.selfTarget ? user : target;
|
||||||
if (pokemon.status && !this.overrideStatus) {
|
if (user !== target && move.category === MoveCategory.STATUS && !target.canSetStatus(this.effect, false, false, user, true)) {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user !== target && target.isSafeguarded(user)) {
|
|
||||||
if (move.category === MoveCategory.STATUS) {
|
|
||||||
globalScene.queueMessage(i18next.t("moveTriggers:safeguard", { targetName: getPokemonNameWithAffix(target) }));
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (((!pokemon.status || this.overrideStatus) || (pokemon.status.effect === this.effect && moveChance < 0))
|
if (((!pokemon.status || this.overrideStatus) || (pokemon.status.effect === this.effect && moveChance < 0))
|
||||||
&& pokemon.trySetStatus(this.effect, true, user, this.turnsRemaining, null, this.overrideStatus)) {
|
&& pokemon.trySetStatus(this.effect, true, user, this.turnsRemaining, null, this.overrideStatus, false)) {
|
||||||
applyPostAttackAbAttrs(ConfusionOnStatusEffectAbAttr, user, target, move, null, false, this.effect);
|
applyPostAttackAbAttrs(ConfusionOnStatusEffectAbAttr, user, target, move, null, false, this.effect);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2495,7 +2506,7 @@ export class MultiStatusEffectAttr extends StatusEffectAttr {
|
|||||||
|
|
||||||
export class PsychoShiftEffectAttr extends MoveEffectAttr {
|
export class PsychoShiftEffectAttr extends MoveEffectAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(false, { trigger: MoveEffectTrigger.HIT });
|
super(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2534,15 +2545,11 @@ export class StealHeldItemChanceAttr extends MoveEffectAttr {
|
|||||||
private chance: number;
|
private chance: number;
|
||||||
|
|
||||||
constructor(chance: number) {
|
constructor(chance: number) {
|
||||||
super(false, { trigger: MoveEffectTrigger.HIT });
|
super(false);
|
||||||
this.chance = chance;
|
this.chance = chance;
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
if (move.hitsSubstitute(user, target)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const rand = Phaser.Math.RND.realInRange(0, 1);
|
const rand = Phaser.Math.RND.realInRange(0, 1);
|
||||||
if (rand >= this.chance) {
|
if (rand >= this.chance) {
|
||||||
return false;
|
return false;
|
||||||
@ -2590,7 +2597,7 @@ export class RemoveHeldItemAttr extends MoveEffectAttr {
|
|||||||
private berriesOnly: boolean;
|
private berriesOnly: boolean;
|
||||||
|
|
||||||
constructor(berriesOnly: boolean) {
|
constructor(berriesOnly: boolean) {
|
||||||
super(false, { trigger: MoveEffectTrigger.HIT });
|
super(false);
|
||||||
this.berriesOnly = berriesOnly;
|
this.berriesOnly = berriesOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2600,17 +2607,13 @@ export class RemoveHeldItemAttr extends MoveEffectAttr {
|
|||||||
* @param target Target {@linkcode Pokemon} that the moves applies to
|
* @param target Target {@linkcode Pokemon} that the moves applies to
|
||||||
* @param move {@linkcode Move} that is used
|
* @param move {@linkcode Move} that is used
|
||||||
* @param args N/A
|
* @param args N/A
|
||||||
* @returns {boolean} True if an item was removed
|
* @returns True if an item was removed
|
||||||
*/
|
*/
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
if (!this.berriesOnly && target.isPlayer()) { // "Wild Pokemon cannot knock off Player Pokemon's held items" (See Bulbapedia)
|
if (!this.berriesOnly && target.isPlayer()) { // "Wild Pokemon cannot knock off Player Pokemon's held items" (See Bulbapedia)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (move.hitsSubstitute(user, target)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cancelled = new BooleanHolder(false);
|
const cancelled = new BooleanHolder(false);
|
||||||
applyAbAttrs(BlockItemTheftAbAttr, target, cancelled); // Check for abilities that block item theft
|
applyAbAttrs(BlockItemTheftAbAttr, target, cancelled); // Check for abilities that block item theft
|
||||||
|
|
||||||
@ -2664,8 +2667,8 @@ export class RemoveHeldItemAttr extends MoveEffectAttr {
|
|||||||
*/
|
*/
|
||||||
export class EatBerryAttr extends MoveEffectAttr {
|
export class EatBerryAttr extends MoveEffectAttr {
|
||||||
protected chosenBerry: BerryModifier | undefined;
|
protected chosenBerry: BerryModifier | undefined;
|
||||||
constructor() {
|
constructor(selfTarget: boolean) {
|
||||||
super(true, { trigger: MoveEffectTrigger.HIT });
|
super(selfTarget);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Causes the target to eat a berry.
|
* Causes the target to eat a berry.
|
||||||
@ -2680,17 +2683,20 @@ export class EatBerryAttr extends MoveEffectAttr {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const heldBerries = this.getTargetHeldBerries(target);
|
const pokemon = this.selfTarget ? user : target;
|
||||||
|
|
||||||
|
const heldBerries = this.getTargetHeldBerries(pokemon);
|
||||||
if (heldBerries.length <= 0) {
|
if (heldBerries.length <= 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this.chosenBerry = heldBerries[user.randSeedInt(heldBerries.length)];
|
this.chosenBerry = heldBerries[user.randSeedInt(heldBerries.length)];
|
||||||
const preserve = new BooleanHolder(false);
|
const preserve = new BooleanHolder(false);
|
||||||
globalScene.applyModifiers(PreserveBerryModifier, target.isPlayer(), target, preserve); // check for berry pouch preservation
|
// check for berry pouch preservation
|
||||||
|
globalScene.applyModifiers(PreserveBerryModifier, pokemon.isPlayer(), pokemon, preserve);
|
||||||
if (!preserve.value) {
|
if (!preserve.value) {
|
||||||
this.reduceBerryModifier(target);
|
this.reduceBerryModifier(pokemon);
|
||||||
}
|
}
|
||||||
this.eatBerry(target);
|
this.eatBerry(pokemon);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2718,20 +2724,17 @@ export class EatBerryAttr extends MoveEffectAttr {
|
|||||||
*/
|
*/
|
||||||
export class StealEatBerryAttr extends EatBerryAttr {
|
export class StealEatBerryAttr extends EatBerryAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super(false);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* User steals a random berry from the target and then eats it.
|
* User steals a random berry from the target and then eats it.
|
||||||
* @param {Pokemon} user Pokemon that used the move and will eat the stolen berry
|
* @param user - Pokemon that used the move and will eat the stolen berry
|
||||||
* @param {Pokemon} target Pokemon that will have its berry stolen
|
* @param target - Pokemon that will have its berry stolen
|
||||||
* @param {Move} move Move being used
|
* @param move - Move being used
|
||||||
* @param {any[]} args Unused
|
* @param args Unused
|
||||||
* @returns {boolean} true if the function succeeds
|
* @returns true if the function succeeds
|
||||||
*/
|
*/
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
if (move.hitsSubstitute(user, target)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const cancelled = new BooleanHolder(false);
|
const cancelled = new BooleanHolder(false);
|
||||||
applyAbAttrs(BlockItemTheftAbAttr, target, cancelled); // check for abilities that block item theft
|
applyAbAttrs(BlockItemTheftAbAttr, target, cancelled); // check for abilities that block item theft
|
||||||
if (cancelled.value === true) {
|
if (cancelled.value === true) {
|
||||||
@ -2782,10 +2785,6 @@ export class HealStatusEffectAttr extends MoveEffectAttr {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.selfTarget && move.hitsSubstitute(user, target)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special edge case for shield dust blocking Sparkling Aria curing burn
|
// Special edge case for shield dust blocking Sparkling Aria curing burn
|
||||||
const moveTargets = getMoveTargets(user, move.id);
|
const moveTargets = getMoveTargets(user, move.id);
|
||||||
if (target.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && move.id === Moves.SPARKLING_ARIA && moveTargets.targets.length === 1) {
|
if (target.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && move.id === Moves.SPARKLING_ARIA && moveTargets.targets.length === 1) {
|
||||||
@ -3163,14 +3162,6 @@ export class StatStageChangeAttr extends MoveEffectAttr {
|
|||||||
return this.options?.showMessage ?? true;
|
return this.options?.showMessage ?? true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates when the stat change should trigger
|
|
||||||
* @default MoveEffectTrigger.HIT
|
|
||||||
*/
|
|
||||||
public override get trigger () {
|
|
||||||
return this.options?.trigger ?? MoveEffectTrigger.HIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to change stats of the user or target (depending on value of selfTarget) if conditions are met
|
* Attempts to change stats of the user or target (depending on value of selfTarget) if conditions are met
|
||||||
* @param user {@linkcode Pokemon} the user of the move
|
* @param user {@linkcode Pokemon} the user of the move
|
||||||
@ -3184,10 +3175,6 @@ export class StatStageChangeAttr extends MoveEffectAttr {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.selfTarget && move.hitsSubstitute(user, target)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const moveChance = this.getMoveChance(user, target, move, this.selfTarget, true);
|
const moveChance = this.getMoveChance(user, target, move, this.selfTarget, true);
|
||||||
if (moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance) {
|
if (moveChance < 0 || moveChance === 100 || user.randSeedInt(100) < moveChance) {
|
||||||
const stages = this.getLevels(user);
|
const stages = this.getLevels(user);
|
||||||
@ -3471,7 +3458,7 @@ export class CutHpStatStageBoostAttr extends StatStageChangeAttr {
|
|||||||
*/
|
*/
|
||||||
export class OrderUpStatBoostAttr extends MoveEffectAttr {
|
export class OrderUpStatBoostAttr extends MoveEffectAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(true, { trigger: MoveEffectTrigger.HIT });
|
super(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
override apply(user: Pokemon, target: Pokemon, move: Move, args?: any[]): boolean {
|
override apply(user: Pokemon, target: Pokemon, move: Move, args?: any[]): boolean {
|
||||||
@ -3548,17 +3535,15 @@ export class ResetStatsAttr extends MoveEffectAttr {
|
|||||||
this.targetAllPokemon = targetAllPokemon;
|
this.targetAllPokemon = targetAllPokemon;
|
||||||
}
|
}
|
||||||
|
|
||||||
override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
override apply(_user: Pokemon, target: Pokemon, _move: Move, _args: any[]): boolean {
|
||||||
if (this.targetAllPokemon) {
|
if (this.targetAllPokemon) {
|
||||||
// Target all pokemon on the field when Freezy Frost or Haze are used
|
// Target all pokemon on the field when Freezy Frost or Haze are used
|
||||||
const activePokemon = globalScene.getField(true);
|
const activePokemon = globalScene.getField(true);
|
||||||
activePokemon.forEach((p) => this.resetStats(p));
|
activePokemon.forEach((p) => this.resetStats(p));
|
||||||
globalScene.queueMessage(i18next.t("moveTriggers:statEliminated"));
|
globalScene.queueMessage(i18next.t("moveTriggers:statEliminated"));
|
||||||
} else { // Affects only the single target when Clear Smog is used
|
} else { // Affects only the single target when Clear Smog is used
|
||||||
if (!move.hitsSubstitute(user, target)) {
|
this.resetStats(target);
|
||||||
this.resetStats(target);
|
globalScene.queueMessage(i18next.t("moveTriggers:resetStats", { pokemonName: getPokemonNameWithAffix(target) }));
|
||||||
globalScene.queueMessage(i18next.t("moveTriggers:resetStats", { pokemonName: getPokemonNameWithAffix(target) }));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -4217,7 +4202,8 @@ export class PresentPowerAttr extends VariablePowerAttr {
|
|||||||
(args[0] as NumberHolder).value = 120;
|
(args[0] as NumberHolder).value = 120;
|
||||||
} else if (80 < powerSeed && powerSeed <= 100) {
|
} else if (80 < powerSeed && powerSeed <= 100) {
|
||||||
// If this move is multi-hit, disable all other hits
|
// If this move is multi-hit, disable all other hits
|
||||||
user.stopMultiHit();
|
user.turnData.hitCount = 1;
|
||||||
|
user.turnData.hitsLeft = 1;
|
||||||
globalScene.unshiftPhase(new PokemonHealPhase(target.getBattlerIndex(),
|
globalScene.unshiftPhase(new PokemonHealPhase(target.getBattlerIndex(),
|
||||||
toDmgValue(target.getMaxHp() / 4), i18next.t("moveTriggers:regainedHealth", { pokemonName: getPokemonNameWithAffix(target) }), true));
|
toDmgValue(target.getMaxHp() / 4), i18next.t("moveTriggers:regainedHealth", { pokemonName: getPokemonNameWithAffix(target) }), true));
|
||||||
}
|
}
|
||||||
@ -4811,8 +4797,8 @@ export class ShellSideArmCategoryAttr extends VariableMoveCategoryAttr {
|
|||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
const category = (args[0] as NumberHolder);
|
const category = (args[0] as NumberHolder);
|
||||||
|
|
||||||
const predictedPhysDmg = target.getBaseDamage(user, move, MoveCategory.PHYSICAL, true, true, true, true);
|
const predictedPhysDmg = target.getBaseDamage({source: user, move, moveCategory: MoveCategory.PHYSICAL, ignoreAbility: true, ignoreSourceAbility: true, ignoreAllyAbility: true, ignoreSourceAllyAbility: true, simulated: true});
|
||||||
const predictedSpecDmg = target.getBaseDamage(user, move, MoveCategory.SPECIAL, true, true, true, true);
|
const predictedSpecDmg = target.getBaseDamage({source: user, move, moveCategory: MoveCategory.SPECIAL, ignoreAbility: true, ignoreSourceAbility: true, ignoreAllyAbility: true, ignoreSourceAllyAbility: true, simulated: true});
|
||||||
|
|
||||||
if (predictedPhysDmg > predictedSpecDmg) {
|
if (predictedPhysDmg > predictedSpecDmg) {
|
||||||
category.value = MoveCategory.PHYSICAL;
|
category.value = MoveCategory.PHYSICAL;
|
||||||
@ -5371,7 +5357,7 @@ export class BypassRedirectAttr extends MoveAttr {
|
|||||||
|
|
||||||
export class FrenzyAttr extends MoveEffectAttr {
|
export class FrenzyAttr extends MoveEffectAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(true, { trigger: MoveEffectTrigger.HIT, lastHitOnly: true });
|
super(true, { lastHitOnly: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
canApply(user: Pokemon, target: Pokemon, move: Move, args: any[]) {
|
canApply(user: Pokemon, target: Pokemon, move: Move, args: any[]) {
|
||||||
@ -5443,22 +5429,20 @@ export class AddBattlerTagAttr extends MoveEffectAttr {
|
|||||||
protected cancelOnFail: boolean;
|
protected cancelOnFail: boolean;
|
||||||
private failOnOverlap: boolean;
|
private failOnOverlap: boolean;
|
||||||
|
|
||||||
constructor(tagType: BattlerTagType, selfTarget: boolean = false, failOnOverlap: boolean = false, turnCountMin: number = 0, turnCountMax?: number, lastHitOnly: boolean = false, cancelOnFail: boolean = false) {
|
constructor(tagType: BattlerTagType, selfTarget: boolean = false, failOnOverlap: boolean = false, turnCountMin: number = 0, turnCountMax?: number, lastHitOnly: boolean = false) {
|
||||||
super(selfTarget, { lastHitOnly: lastHitOnly });
|
super(selfTarget, { lastHitOnly: lastHitOnly });
|
||||||
|
|
||||||
this.tagType = tagType;
|
this.tagType = tagType;
|
||||||
this.turnCountMin = turnCountMin;
|
this.turnCountMin = turnCountMin;
|
||||||
this.turnCountMax = turnCountMax !== undefined ? turnCountMax : turnCountMin;
|
this.turnCountMax = turnCountMax !== undefined ? turnCountMax : turnCountMin;
|
||||||
this.failOnOverlap = !!failOnOverlap;
|
this.failOnOverlap = !!failOnOverlap;
|
||||||
this.cancelOnFail = cancelOnFail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
canApply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
canApply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
if (!super.canApply(user, target, move, args) || (this.cancelOnFail === true && user.getLastXMoves(1)[0]?.result === MoveResult.FAIL)) {
|
if (!super.canApply(user, target, move, args)) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
@ -5549,19 +5533,6 @@ export class LeechSeedAttr extends AddBattlerTagAttr {
|
|||||||
constructor() {
|
constructor() {
|
||||||
super(BattlerTagType.SEEDED);
|
super(BattlerTagType.SEEDED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a Seeding effect to the target if the target does not have an active Substitute.
|
|
||||||
* @param user the {@linkcode Pokemon} using the move
|
|
||||||
* @param target the {@linkcode Pokemon} targeted by the move
|
|
||||||
* @param move the {@linkcode Move} invoking this effect
|
|
||||||
* @param args n/a
|
|
||||||
* @returns `true` if the effect successfully applies; `false` otherwise
|
|
||||||
*/
|
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
|
||||||
return !move.hitsSubstitute(user, target)
|
|
||||||
&& super.apply(user, target, move, args);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -5737,13 +5708,6 @@ export class FlinchAttr extends AddBattlerTagAttr {
|
|||||||
constructor() {
|
constructor() {
|
||||||
super(BattlerTagType.FLINCHED, false);
|
super(BattlerTagType.FLINCHED, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
|
||||||
if (!move.hitsSubstitute(user, target)) {
|
|
||||||
return super.apply(user, target, move, args);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ConfuseAttr extends AddBattlerTagAttr {
|
export class ConfuseAttr extends AddBattlerTagAttr {
|
||||||
@ -5759,16 +5723,13 @@ export class ConfuseAttr extends AddBattlerTagAttr {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!move.hitsSubstitute(user, target)) {
|
return super.apply(user, target, move, args);
|
||||||
return super.apply(user, target, move, args);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RechargeAttr extends AddBattlerTagAttr {
|
export class RechargeAttr extends AddBattlerTagAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(BattlerTagType.RECHARGING, true, false, 1, 1, true, true);
|
super(BattlerTagType.RECHARGING, true, false, 1, 1, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6151,7 +6112,7 @@ export class AddPledgeEffectAttr extends AddArenaTagAttr {
|
|||||||
* @see {@linkcode apply}
|
* @see {@linkcode apply}
|
||||||
*/
|
*/
|
||||||
export class RevivalBlessingAttr extends MoveEffectAttr {
|
export class RevivalBlessingAttr extends MoveEffectAttr {
|
||||||
constructor(user?: boolean) {
|
constructor() {
|
||||||
super(true);
|
super(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6296,9 +6257,10 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
|
|||||||
return false;
|
return false;
|
||||||
} else if (globalScene.currentBattle.battleType !== BattleType.WILD) { // Switch out logic for enemy trainers
|
} else if (globalScene.currentBattle.battleType !== BattleType.WILD) { // Switch out logic for enemy trainers
|
||||||
// Find indices of off-field Pokemon that are eligible to be switched into
|
// Find indices of off-field Pokemon that are eligible to be switched into
|
||||||
|
const isPartnerTrainer = globalScene.currentBattle.trainer?.isPartner();
|
||||||
const eligibleNewIndices: number[] = [];
|
const eligibleNewIndices: number[] = [];
|
||||||
globalScene.getEnemyParty().forEach((pokemon, index) => {
|
globalScene.getEnemyParty().forEach((pokemon, index) => {
|
||||||
if (pokemon.isAllowedInBattle() && !pokemon.isOnField()) {
|
if (pokemon.isAllowedInBattle() && !pokemon.isOnField() && (!isPartnerTrainer || pokemon.trainerSlot === (switchOutTarget as EnemyPokemon).trainerSlot)) {
|
||||||
eligibleNewIndices.push(index);
|
eligibleNewIndices.push(index);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -6348,15 +6310,6 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (globalScene.currentBattle.waveIndex % 10 === 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't allow wild mons to flee with U-turn et al.
|
|
||||||
if (this.selfSwitch && !user.isPlayer() && move.category !== MoveCategory.STATUS) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const allyPokemon = switchOutTarget.getAlly();
|
const allyPokemon = switchOutTarget.getAlly();
|
||||||
|
|
||||||
if (switchOutTarget.hp > 0) {
|
if (switchOutTarget.hp > 0) {
|
||||||
@ -6369,13 +6322,17 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!allyPokemon?.isActive(true)) {
|
// clear out enemy held item modifiers of the switch out target
|
||||||
globalScene.clearEnemyHeldItemModifiers();
|
globalScene.clearEnemyHeldItemModifiers(switchOutTarget);
|
||||||
|
|
||||||
if (switchOutTarget.hp) {
|
if (!allyPokemon?.isActive(true) && switchOutTarget.hp) {
|
||||||
globalScene.pushPhase(new BattleEndPhase(false));
|
globalScene.pushPhase(new BattleEndPhase(false));
|
||||||
|
|
||||||
|
if (globalScene.gameMode.hasRandomBiomes || globalScene.isNewBiome()) {
|
||||||
|
globalScene.pushPhase(new SelectBiomePhase());
|
||||||
|
}
|
||||||
|
|
||||||
globalScene.pushPhase(new NewBattlePhase());
|
globalScene.pushPhase(new NewBattlePhase());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6394,16 +6351,13 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
getSwitchOutCondition(): MoveConditionFunc {
|
getSwitchOutCondition(): MoveConditionFunc {
|
||||||
return (user, target, move) => {
|
return (user, target, move) => {
|
||||||
const switchOutTarget = (this.selfSwitch ? user : target);
|
const switchOutTarget = (this.selfSwitch ? user : target);
|
||||||
const player = switchOutTarget instanceof PlayerPokemon;
|
const player = switchOutTarget instanceof PlayerPokemon;
|
||||||
|
|
||||||
if (!this.selfSwitch) {
|
if (!this.selfSwitch) {
|
||||||
if (move.hitsSubstitute(user, target)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dondozo with an allied Tatsugiri in its mouth cannot be forced out
|
// Dondozo with an allied Tatsugiri in its mouth cannot be forced out
|
||||||
const commandedTag = switchOutTarget.getTag(BattlerTagType.COMMANDED);
|
const commandedTag = switchOutTarget.getTag(BattlerTagType.COMMANDED);
|
||||||
if (commandedTag?.getSourcePokemon()?.isActive(true)) {
|
if (commandedTag?.getSourcePokemon()?.isActive(true)) {
|
||||||
@ -6417,23 +6371,23 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
|
|||||||
|
|
||||||
const blockedByAbility = new BooleanHolder(false);
|
const blockedByAbility = new BooleanHolder(false);
|
||||||
applyAbAttrs(ForceSwitchOutImmunityAbAttr, target, blockedByAbility);
|
applyAbAttrs(ForceSwitchOutImmunityAbAttr, target, blockedByAbility);
|
||||||
return !blockedByAbility.value;
|
if (blockedByAbility.value) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!player && globalScene.currentBattle.battleType === BattleType.WILD) {
|
if (!player && globalScene.currentBattle.battleType === BattleType.WILD) {
|
||||||
if (this.isBatonPass()) {
|
// wild pokemon cannot switch out with baton pass.
|
||||||
return false;
|
return !this.isBatonPass()
|
||||||
}
|
&& globalScene.currentBattle.waveIndex % 10 !== 0
|
||||||
// Don't allow wild opponents to flee on the boss stage since it can ruin a run early on
|
// Don't allow wild mons to flee with U-turn et al.
|
||||||
if (globalScene.currentBattle.waveIndex % 10 === 0) {
|
&& !(this.selfSwitch && MoveCategory.STATUS !== move.category);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const party = player ? globalScene.getPlayerParty() : globalScene.getEnemyParty();
|
const party = player ? globalScene.getPlayerParty() : globalScene.getEnemyParty();
|
||||||
return (!player && !globalScene.currentBattle.battleType)
|
return party.filter(p => p.isAllowedInBattle() && !p.isOnField()
|
||||||
|| party.filter(p => p.isAllowedInBattle()
|
&& (player || (p as EnemyPokemon).trainerSlot === (switchOutTarget as EnemyPokemon).trainerSlot)).length > 0;
|
||||||
&& (player || (p as EnemyPokemon).trainerSlot === (switchOutTarget as EnemyPokemon).trainerSlot)).length > globalScene.currentBattle.getBattlerCount();
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6658,7 +6612,7 @@ export class ChangeTypeAttr extends MoveEffectAttr {
|
|||||||
private type: PokemonType;
|
private type: PokemonType;
|
||||||
|
|
||||||
constructor(type: PokemonType) {
|
constructor(type: PokemonType) {
|
||||||
super(false, { trigger: MoveEffectTrigger.HIT });
|
super(false);
|
||||||
|
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
@ -6681,7 +6635,7 @@ export class AddTypeAttr extends MoveEffectAttr {
|
|||||||
private type: PokemonType;
|
private type: PokemonType;
|
||||||
|
|
||||||
constructor(type: PokemonType) {
|
constructor(type: PokemonType) {
|
||||||
super(false, { trigger: MoveEffectTrigger.HIT });
|
super(false);
|
||||||
|
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
@ -7377,7 +7331,7 @@ export class AbilityChangeAttr extends MoveEffectAttr {
|
|||||||
public ability: Abilities;
|
public ability: Abilities;
|
||||||
|
|
||||||
constructor(ability: Abilities, selfTarget?: boolean) {
|
constructor(ability: Abilities, selfTarget?: boolean) {
|
||||||
super(selfTarget, { trigger: MoveEffectTrigger.HIT });
|
super(selfTarget);
|
||||||
|
|
||||||
this.ability = ability;
|
this.ability = ability;
|
||||||
}
|
}
|
||||||
@ -7408,7 +7362,7 @@ export class AbilityCopyAttr extends MoveEffectAttr {
|
|||||||
public copyToPartner: boolean;
|
public copyToPartner: boolean;
|
||||||
|
|
||||||
constructor(copyToPartner: boolean = false) {
|
constructor(copyToPartner: boolean = false) {
|
||||||
super(false, { trigger: MoveEffectTrigger.HIT });
|
super(false);
|
||||||
|
|
||||||
this.copyToPartner = copyToPartner;
|
this.copyToPartner = copyToPartner;
|
||||||
}
|
}
|
||||||
@ -7449,7 +7403,7 @@ export class AbilityGiveAttr extends MoveEffectAttr {
|
|||||||
public copyToPartner: boolean;
|
public copyToPartner: boolean;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(false, { trigger: MoveEffectTrigger.HIT });
|
super(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
@ -7712,23 +7666,9 @@ export class AverageStatsAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DiscourageFrequentUseAttr extends MoveAttr {
|
|
||||||
getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
|
|
||||||
const lastMoves = user.getLastXMoves(4);
|
|
||||||
console.log(lastMoves);
|
|
||||||
for (let m = 0; m < lastMoves.length; m++) {
|
|
||||||
if (lastMoves[m].move === move.id) {
|
|
||||||
return (4 - (m + 1)) * -10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class MoneyAttr extends MoveEffectAttr {
|
export class MoneyAttr extends MoveEffectAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(true, { trigger: MoveEffectTrigger.HIT, firstHitOnly: true });
|
super(true, {firstHitOnly: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move): boolean {
|
||||||
@ -7795,7 +7735,7 @@ export class StatusIfBoostedAttr extends MoveEffectAttr {
|
|||||||
public effect: StatusEffect;
|
public effect: StatusEffect;
|
||||||
|
|
||||||
constructor(effect: StatusEffect) {
|
constructor(effect: StatusEffect) {
|
||||||
super(true, { trigger: MoveEffectTrigger.HIT });
|
super(true);
|
||||||
this.effect = effect;
|
this.effect = effect;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8191,7 +8131,7 @@ export type MoveTargetSet = {
|
|||||||
|
|
||||||
export function getMoveTargets(user: Pokemon, move: Moves, replaceTarget?: MoveTarget): MoveTargetSet {
|
export function getMoveTargets(user: Pokemon, move: Moves, replaceTarget?: MoveTarget): MoveTargetSet {
|
||||||
const variableTarget = new NumberHolder(0);
|
const variableTarget = new NumberHolder(0);
|
||||||
user.getOpponents().forEach(p => applyMoveAttrs(VariableTargetAttr, user, p, allMoves[move], variableTarget));
|
user.getOpponents(false).forEach(p => applyMoveAttrs(VariableTargetAttr, user, p, allMoves[move], variableTarget));
|
||||||
|
|
||||||
let moveTarget: MoveTarget | undefined;
|
let moveTarget: MoveTarget | undefined;
|
||||||
if (allMoves[move].hasAttr(VariableTargetAttr)) {
|
if (allMoves[move].hasAttr(VariableTargetAttr)) {
|
||||||
@ -8203,7 +8143,7 @@ export function getMoveTargets(user: Pokemon, move: Moves, replaceTarget?: MoveT
|
|||||||
} else if (move === undefined) {
|
} else if (move === undefined) {
|
||||||
moveTarget = MoveTarget.NEAR_ENEMY;
|
moveTarget = MoveTarget.NEAR_ENEMY;
|
||||||
}
|
}
|
||||||
const opponents = user.getOpponents();
|
const opponents = user.getOpponents(false);
|
||||||
|
|
||||||
let set: Pokemon[] = [];
|
let set: Pokemon[] = [];
|
||||||
let multiple = false;
|
let multiple = false;
|
||||||
@ -8679,7 +8619,9 @@ export function initMoves() {
|
|||||||
.condition((user, target, move) => !target.summonData?.illusion && !user.summonData?.illusion)
|
.condition((user, target, move) => !target.summonData?.illusion && !user.summonData?.illusion)
|
||||||
// transforming from or into fusion pokemon causes various problems (such as crashes)
|
// transforming from or into fusion pokemon causes various problems (such as crashes)
|
||||||
.condition((user, target, move) => !target.getTag(BattlerTagType.SUBSTITUTE) && !user.fusionSpecies && !target.fusionSpecies)
|
.condition((user, target, move) => !target.getTag(BattlerTagType.SUBSTITUTE) && !user.fusionSpecies && !target.fusionSpecies)
|
||||||
.ignoresProtect(),
|
.ignoresProtect()
|
||||||
|
// Transforming should copy the target's rage fist hit count
|
||||||
|
.edgeCase(),
|
||||||
new AttackMove(Moves.BUBBLE, PokemonType.WATER, MoveCategory.SPECIAL, 40, 100, 30, 10, 0, 1)
|
new AttackMove(Moves.BUBBLE, PokemonType.WATER, MoveCategory.SPECIAL, 40, 100, 30, 10, 0, 1)
|
||||||
.attr(StatStageChangeAttr, [ Stat.SPD ], -1)
|
.attr(StatStageChangeAttr, [ Stat.SPD ], -1)
|
||||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||||
@ -10564,8 +10506,7 @@ export function initMoves() {
|
|||||||
} else {
|
} else {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
.attr(DiscourageFrequentUseAttr),
|
|
||||||
|
|
||||||
new AttackMove(Moves.SNIPE_SHOT, PokemonType.WATER, MoveCategory.SPECIAL, 80, 100, 15, -1, 0, 8)
|
new AttackMove(Moves.SNIPE_SHOT, PokemonType.WATER, MoveCategory.SPECIAL, 80, 100, 15, -1, 0, 8)
|
||||||
.attr(HighCritAttr)
|
.attr(HighCritAttr)
|
||||||
@ -10574,7 +10515,7 @@ export function initMoves() {
|
|||||||
.attr(JawLockAttr)
|
.attr(JawLockAttr)
|
||||||
.bitingMove(),
|
.bitingMove(),
|
||||||
new SelfStatusMove(Moves.STUFF_CHEEKS, PokemonType.NORMAL, -1, 10, -1, 0, 8)
|
new SelfStatusMove(Moves.STUFF_CHEEKS, PokemonType.NORMAL, -1, 10, -1, 0, 8)
|
||||||
.attr(EatBerryAttr)
|
.attr(EatBerryAttr, true)
|
||||||
.attr(StatStageChangeAttr, [ Stat.DEF ], 2, true)
|
.attr(StatStageChangeAttr, [ Stat.DEF ], 2, true)
|
||||||
.condition((user) => {
|
.condition((user) => {
|
||||||
const userBerries = globalScene.findModifiers(m => m instanceof BerryModifier, user.isPlayer());
|
const userBerries = globalScene.findModifiers(m => m instanceof BerryModifier, user.isPlayer());
|
||||||
@ -10598,7 +10539,7 @@ export function initMoves() {
|
|||||||
.makesContact(false)
|
.makesContact(false)
|
||||||
.partial(), // smart targetting is unimplemented
|
.partial(), // smart targetting is unimplemented
|
||||||
new StatusMove(Moves.TEATIME, PokemonType.NORMAL, -1, 10, -1, 0, 8)
|
new StatusMove(Moves.TEATIME, PokemonType.NORMAL, -1, 10, -1, 0, 8)
|
||||||
.attr(EatBerryAttr)
|
.attr(EatBerryAttr, false)
|
||||||
.target(MoveTarget.ALL),
|
.target(MoveTarget.ALL),
|
||||||
new StatusMove(Moves.OCTOLOCK, PokemonType.FIGHTING, 100, 15, -1, 0, 8)
|
new StatusMove(Moves.OCTOLOCK, PokemonType.FIGHTING, 100, 15, -1, 0, 8)
|
||||||
.condition(failIfGhostTypeCondition)
|
.condition(failIfGhostTypeCondition)
|
||||||
@ -11239,6 +11180,8 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.TEMPER_FLARE, PokemonType.FIRE, MoveCategory.PHYSICAL, 75, 100, 10, -1, 0, 9)
|
new AttackMove(Moves.TEMPER_FLARE, PokemonType.FIRE, MoveCategory.PHYSICAL, 75, 100, 10, -1, 0, 9)
|
||||||
.attr(MovePowerMultiplierAttr, (user, target, move) => user.getLastXMoves(2)[1]?.result === MoveResult.MISS || user.getLastXMoves(2)[1]?.result === MoveResult.FAIL ? 2 : 1),
|
.attr(MovePowerMultiplierAttr, (user, target, move) => user.getLastXMoves(2)[1]?.result === MoveResult.MISS || user.getLastXMoves(2)[1]?.result === MoveResult.FAIL ? 2 : 1),
|
||||||
new AttackMove(Moves.SUPERCELL_SLAM, PokemonType.ELECTRIC, MoveCategory.PHYSICAL, 100, 95, 15, -1, 0, 9)
|
new AttackMove(Moves.SUPERCELL_SLAM, PokemonType.ELECTRIC, MoveCategory.PHYSICAL, 100, 95, 15, -1, 0, 9)
|
||||||
|
.attr(AlwaysHitMinimizeAttr)
|
||||||
|
.attr(HitsTagForDoubleDamageAttr, BattlerTagType.MINIMIZED)
|
||||||
.attr(MissEffectAttr, crashDamageFunc)
|
.attr(MissEffectAttr, crashDamageFunc)
|
||||||
.attr(NoEffectAttr, crashDamageFunc)
|
.attr(NoEffectAttr, crashDamageFunc)
|
||||||
.recklessMove(),
|
.recklessMove(),
|
||||||
|
@ -14,7 +14,7 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
|||||||
import { TrainerType } from "#enums/trainer-type";
|
import { TrainerType } from "#enums/trainer-type";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import { getSpriteKeysFromSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
import { getSpriteKeysFromSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||||
import { randSeedInt } from "#app/utils";
|
import { randSeedInt } from "#app/utils/common";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import type { IEggOptions } from "#app/data/egg";
|
import type { IEggOptions } from "#app/data/egg";
|
||||||
import { EggSourceType } from "#enums/egg-source-types";
|
import { EggSourceType } from "#enums/egg-source-types";
|
||||||
@ -22,7 +22,7 @@ import { EggTier } from "#enums/egg-type";
|
|||||||
import { PartyHealPhase } from "#app/phases/party-heal-phase";
|
import { PartyHealPhase } from "#app/phases/party-heal-phase";
|
||||||
import { ModifierTier } from "#app/modifier/modifier-tier";
|
import { ModifierTier } from "#app/modifier/modifier-tier";
|
||||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
|
|
||||||
/** the i18n namespace for the encounter */
|
/** the i18n namespace for the encounter */
|
||||||
const namespace = "mysteryEncounters/aTrainersTest";
|
const namespace = "mysteryEncounters/aTrainersTest";
|
||||||
|
@ -24,7 +24,7 @@ import { BerryModifier, PokemonInstantReviveModifier } from "#app/modifier/modif
|
|||||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
import { randInt } from "#app/utils";
|
import { randInt } from "#app/utils/common";
|
||||||
import { BattlerIndex } from "#app/battle";
|
import { BattlerIndex } from "#app/battle";
|
||||||
import {
|
import {
|
||||||
applyModifierTypeToPlayerPokemon,
|
applyModifierTypeToPlayerPokemon,
|
||||||
@ -37,7 +37,7 @@ import type HeldModifierConfig from "#app/interfaces/held-modifier-config";
|
|||||||
import type { BerryType } from "#enums/berry-type";
|
import type { BerryType } from "#enums/berry-type";
|
||||||
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
||||||
import { Stat } from "#enums/stat";
|
import { Stat } from "#enums/stat";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
|
||||||
/** the i18n namespace for this encounter */
|
/** the i18n namespace for this encounter */
|
||||||
|
@ -23,7 +23,7 @@ import { speciesStarterCosts } from "#app/data/balance/starters";
|
|||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
|
import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
|
||||||
/** the i18n namespace for this encounter */
|
/** the i18n namespace for this encounter */
|
||||||
|
@ -13,7 +13,7 @@ import type { PlayerPokemon } from "#app/field/pokemon";
|
|||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import type { BerryModifierType, ModifierTypeOption } from "#app/modifier/modifier-type";
|
import type { BerryModifierType, ModifierTypeOption } from "#app/modifier/modifier-type";
|
||||||
import { ModifierPoolType, modifierTypes, regenerateModifierPoolThresholds } from "#app/modifier/modifier-type";
|
import { ModifierPoolType, modifierTypes, regenerateModifierPoolThresholds } from "#app/modifier/modifier-type";
|
||||||
import { randSeedInt } from "#app/utils";
|
import { randSeedInt } from "#app/utils/common";
|
||||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
@ -36,7 +36,7 @@ import i18next from "#app/plugins/i18n";
|
|||||||
import { BerryType } from "#enums/berry-type";
|
import { BerryType } from "#enums/berry-type";
|
||||||
import { PERMANENT_STATS, Stat } from "#enums/stat";
|
import { PERMANENT_STATS, Stat } from "#enums/stat";
|
||||||
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
|
|
||||||
/** the i18n namespace for the encounter */
|
/** the i18n namespace for the encounter */
|
||||||
const namespace = "mysteryEncounters/berriesAbound";
|
const namespace = "mysteryEncounters/berriesAbound";
|
||||||
|
@ -16,7 +16,7 @@ import { TrainerSlot } from "#enums/trainer-slot";
|
|||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { PartyMemberStrength } from "#enums/party-member-strength";
|
import { PartyMemberStrength } from "#enums/party-member-strength";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import { isNullOrUndefined, randSeedInt, randSeedShuffle } from "#app/utils";
|
import { isNullOrUndefined, randSeedInt, randSeedShuffle } from "#app/utils/common";
|
||||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||||
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
@ -52,7 +52,7 @@ import i18next from "i18next";
|
|||||||
import MoveInfoOverlay from "#app/ui/move-info-overlay";
|
import MoveInfoOverlay from "#app/ui/move-info-overlay";
|
||||||
import { allMoves } from "#app/data/moves/move";
|
import { allMoves } from "#app/data/moves/move";
|
||||||
import { ModifierTier } from "#app/modifier/modifier-tier";
|
import { ModifierTier } from "#app/modifier/modifier-tier";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import { getSpriteKeysFromSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
import { getSpriteKeysFromSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||||
|
|
||||||
/** the i18n namespace for the encounter */
|
/** the i18n namespace for the encounter */
|
||||||
|
@ -31,9 +31,9 @@ import {
|
|||||||
import { PokemonType } from "#enums/pokemon-type";
|
import { PokemonType } from "#enums/pokemon-type";
|
||||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
import { randSeedInt, randSeedShuffle } from "#app/utils";
|
import { randSeedInt, randSeedShuffle } from "#app/utils/common";
|
||||||
import { showEncounterDialogue, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
import { showEncounterDialogue, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||||
import { Mode } from "#app/ui/ui";
|
import { UiMode } from "#enums/ui-mode";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import type { OptionSelectConfig } from "#app/ui/abstact-option-select-ui-handler";
|
import type { OptionSelectConfig } from "#app/ui/abstact-option-select-ui-handler";
|
||||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||||
@ -46,7 +46,7 @@ import { Moves } from "#enums/moves";
|
|||||||
import { EncounterBattleAnim } from "#app/data/battle-anims";
|
import { EncounterBattleAnim } from "#app/data/battle-anims";
|
||||||
import { MoveCategory } from "#enums/MoveCategory";
|
import { MoveCategory } from "#enums/MoveCategory";
|
||||||
import { CustomPokemonData } from "#app/data/custom-pokemon-data";
|
import { CustomPokemonData } from "#app/data/custom-pokemon-data";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import { EncounterAnim } from "#enums/encounter-anims";
|
import { EncounterAnim } from "#enums/encounter-anims";
|
||||||
import { Challenges } from "#enums/challenges";
|
import { Challenges } from "#enums/challenges";
|
||||||
|
|
||||||
@ -437,7 +437,7 @@ async function handleSwapAbility() {
|
|||||||
await showEncounterDialogue(`${namespace}:option.1.apply_ability_dialogue`, `${namespace}:speaker`);
|
await showEncounterDialogue(`${namespace}:option.1.apply_ability_dialogue`, `${namespace}:speaker`);
|
||||||
await showEncounterText(`${namespace}:option.1.apply_ability_message`);
|
await showEncounterText(`${namespace}:option.1.apply_ability_message`);
|
||||||
|
|
||||||
globalScene.ui.setMode(Mode.MESSAGE).then(() => {
|
globalScene.ui.setMode(UiMode.MESSAGE).then(() => {
|
||||||
displayYesNoOptions(resolve);
|
displayYesNoOptions(resolve);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -467,7 +467,7 @@ function displayYesNoOptions(resolve) {
|
|||||||
maxOptions: 7,
|
maxOptions: 7,
|
||||||
yOffset: 0,
|
yOffset: 0,
|
||||||
};
|
};
|
||||||
globalScene.ui.setModeWithoutClear(Mode.OPTION_SELECT, config, null, true);
|
globalScene.ui.setModeWithoutClear(UiMode.OPTION_SELECT, config, null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onYesAbilitySwap(resolve) {
|
function onYesAbilitySwap(resolve) {
|
||||||
@ -477,11 +477,11 @@ function onYesAbilitySwap(resolve) {
|
|||||||
|
|
||||||
applyAbilityOverrideToPokemon(pokemon, encounter.misc.ability);
|
applyAbilityOverrideToPokemon(pokemon, encounter.misc.ability);
|
||||||
encounter.setDialogueToken("chosenPokemon", pokemon.getNameToRender());
|
encounter.setDialogueToken("chosenPokemon", pokemon.getNameToRender());
|
||||||
globalScene.ui.setMode(Mode.MESSAGE).then(() => resolve(true));
|
globalScene.ui.setMode(UiMode.MESSAGE).then(() => resolve(true));
|
||||||
};
|
};
|
||||||
|
|
||||||
const onPokemonNotSelected = () => {
|
const onPokemonNotSelected = () => {
|
||||||
globalScene.ui.setMode(Mode.MESSAGE).then(() => {
|
globalScene.ui.setMode(UiMode.MESSAGE).then(() => {
|
||||||
displayYesNoOptions(resolve);
|
displayYesNoOptions(resolve);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -24,7 +24,7 @@ import { TrainerSlot } from "#enums/trainer-slot";
|
|||||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import { EnemyPokemon, PokemonMove } from "#app/field/pokemon";
|
import { EnemyPokemon, PokemonMove } from "#app/field/pokemon";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||||
import { LearnMovePhase } from "#app/phases/learn-move-phase";
|
import { LearnMovePhase } from "#app/phases/learn-move-phase";
|
||||||
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { PokemonType } from "#enums/pokemon-type";
|
import type { PokemonType } from "#enums/pokemon-type";
|
||||||
import { isNullOrUndefined, randSeedInt } from "#app/utils";
|
import { isNullOrUndefined, randSeedInt } from "#app/utils/common";
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
@ -19,7 +19,7 @@ import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode
|
|||||||
import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
|
import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
|
||||||
import type { PokemonHeldItemModifier } from "#app/modifier/modifier";
|
import type { PokemonHeldItemModifier } from "#app/modifier/modifier";
|
||||||
import { PokemonFormChangeItemModifier } from "#app/modifier/modifier";
|
import { PokemonFormChangeItemModifier } from "#app/modifier/modifier";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import { Challenges } from "#enums/challenges";
|
import { Challenges } from "#enums/challenges";
|
||||||
|
|
||||||
/** i18n namespace for encounter */
|
/** i18n namespace for encounter */
|
||||||
|
@ -18,7 +18,7 @@ import { applyModifierTypeToPlayerPokemon } from "#app/data/mystery-encounters/u
|
|||||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import type { PokemonHeldItemModifier, PokemonInstantReviveModifier } from "#app/modifier/modifier";
|
import type { PokemonHeldItemModifier, PokemonInstantReviveModifier } from "#app/modifier/modifier";
|
||||||
import {
|
import {
|
||||||
BerryModifier,
|
BerryModifier,
|
||||||
@ -32,7 +32,7 @@ import { modifierTypes } from "#app/modifier/modifier-type";
|
|||||||
import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
|
import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
|
||||||
import i18next from "#app/plugins/i18n";
|
import i18next from "#app/plugins/i18n";
|
||||||
import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
||||||
import { randSeedItem } from "#app/utils";
|
import { randSeedItem } from "#app/utils/common";
|
||||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
|
@ -4,13 +4,13 @@ import {
|
|||||||
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import type { ModifierTypeFunc } from "#app/modifier/modifier-type";
|
import type { ModifierTypeFunc } from "#app/modifier/modifier-type";
|
||||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||||
import { randSeedInt } from "#app/utils";
|
import { randSeedInt } from "#app/utils/common";
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||||
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
|
|
||||||
/** i18n namespace for encounter */
|
/** i18n namespace for encounter */
|
||||||
const namespace = "mysteryEncounters/departmentStoreSale";
|
const namespace = "mysteryEncounters/departmentStoreSale";
|
||||||
|
@ -18,7 +18,7 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
|||||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
import { Stat } from "#enums/stat";
|
import { Stat } from "#enums/stat";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
|
|
||||||
/** i18n namespace for the encounter */
|
/** i18n namespace for the encounter */
|
||||||
const namespace = "mysteryEncounters/fieldTrip";
|
const namespace = "mysteryEncounters/fieldTrip";
|
||||||
|
@ -30,7 +30,7 @@ import { PokemonMove } from "#app/field/pokemon";
|
|||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { EncounterBattleAnim } from "#app/data/battle-anims";
|
import { EncounterBattleAnim } from "#app/data/battle-anims";
|
||||||
import { WeatherType } from "#enums/weather-type";
|
import { WeatherType } from "#enums/weather-type";
|
||||||
import { isNullOrUndefined, randSeedInt } from "#app/utils";
|
import { isNullOrUndefined, randSeedInt } from "#app/utils/common";
|
||||||
import { StatusEffect } from "#enums/status-effect";
|
import { StatusEffect } from "#enums/status-effect";
|
||||||
import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||||
import {
|
import {
|
||||||
@ -41,7 +41,7 @@ import {
|
|||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
import { EncounterAnim } from "#enums/encounter-anims";
|
import { EncounterAnim } from "#enums/encounter-anims";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import { Abilities } from "#enums/abilities";
|
import { Abilities } from "#enums/abilities";
|
||||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
||||||
|
@ -31,9 +31,9 @@ import {
|
|||||||
import PokemonData from "#app/system/pokemon-data";
|
import PokemonData from "#app/system/pokemon-data";
|
||||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||||
import { randSeedInt } from "#app/utils";
|
import { randSeedInt } from "#app/utils/common";
|
||||||
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
|
|
||||||
/** the i18n namespace for the encounter */
|
/** the i18n namespace for the encounter */
|
||||||
const namespace = "mysteryEncounters/fightOrFlight";
|
const namespace = "mysteryEncounters/fightOrFlight";
|
||||||
|
@ -30,7 +30,7 @@ import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms";
|
|||||||
import { PostSummonPhase } from "#app/phases/post-summon-phase";
|
import { PostSummonPhase } from "#app/phases/post-summon-phase";
|
||||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||||
import { Nature } from "#enums/nature";
|
import { Nature } from "#enums/nature";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import { isPokemonValidForEncounterOptionSelection } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
import { isPokemonValidForEncounterOptionSelection } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||||
|
|
||||||
/** the i18n namespace for the encounter */
|
/** the i18n namespace for the encounter */
|
||||||
|
@ -23,7 +23,14 @@ import { allSpecies, getPokemonSpecies } from "#app/data/pokemon-species";
|
|||||||
import { getTypeRgb } from "#app/data/type";
|
import { getTypeRgb } from "#app/data/type";
|
||||||
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
import { NumberHolder, isNullOrUndefined, randInt, randSeedInt, randSeedShuffle, randSeedItem } from "#app/utils";
|
import {
|
||||||
|
NumberHolder,
|
||||||
|
isNullOrUndefined,
|
||||||
|
randInt,
|
||||||
|
randSeedInt,
|
||||||
|
randSeedShuffle,
|
||||||
|
randSeedItem,
|
||||||
|
} from "#app/utils/common";
|
||||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import { EnemyPokemon, PokemonMove } from "#app/field/pokemon";
|
import { EnemyPokemon, PokemonMove } from "#app/field/pokemon";
|
||||||
@ -41,7 +48,7 @@ import { Gender, getGenderSymbol } from "#app/data/gender";
|
|||||||
import { getNatureName } from "#app/data/nature";
|
import { getNatureName } from "#app/data/nature";
|
||||||
import { getPokeballAtlasKey, getPokeballTintColor } from "#app/data/pokeball";
|
import { getPokeballAtlasKey, getPokeballTintColor } from "#app/data/pokeball";
|
||||||
import { getEncounterText, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
import { getEncounterText, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import { addPokemonDataToDexAndValidateAchievements } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
import { addPokemonDataToDexAndValidateAchievements } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||||
import type { PokeballType } from "#enums/pokeball";
|
import type { PokeballType } from "#enums/pokeball";
|
||||||
import { doShinySparkleAnim } from "#app/field/anims";
|
import { doShinySparkleAnim } from "#app/field/anims";
|
||||||
|
@ -10,7 +10,7 @@ import { leaveEncounterWithoutBattle, setEncounterExp } from "../utils/encounter
|
|||||||
import { applyDamageToPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
import { applyDamageToPokemon } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import { PokemonMove } from "#app/field/pokemon";
|
import { PokemonMove } from "#app/field/pokemon";
|
||||||
|
|
||||||
const OPTION_1_REQUIRED_MOVE = Moves.SURF;
|
const OPTION_1_REQUIRED_MOVE = Moves.SURF;
|
||||||
|
@ -12,11 +12,11 @@ import { modifierTypes } from "#app/modifier/modifier-type";
|
|||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { PartyMemberStrength } from "#enums/party-member-strength";
|
import { PartyMemberStrength } from "#enums/party-member-strength";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import { randSeedInt } from "#app/utils";
|
import { randSeedInt } from "#app/utils/common";
|
||||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||||
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
import { MysteryEncounterBuilder } from "#app/data/mystery-encounters/mystery-encounter";
|
||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
|
|
||||||
/** the i18n namespace for the encounter */
|
/** the i18n namespace for the encounter */
|
||||||
const namespace = "mysteryEncounters/mysteriousChallengers";
|
const namespace = "mysteryEncounters/mysteriousChallengers";
|
||||||
|
@ -15,10 +15,10 @@ import {
|
|||||||
koPlayerPokemon,
|
koPlayerPokemon,
|
||||||
} from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
} from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import { ModifierTier } from "#app/modifier/modifier-tier";
|
import { ModifierTier } from "#app/modifier/modifier-tier";
|
||||||
import { GameOverPhase } from "#app/phases/game-over-phase";
|
import { GameOverPhase } from "#app/phases/game-over-phase";
|
||||||
import { randSeedInt } from "#app/utils";
|
import { randSeedInt } from "#app/utils/common";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
|
@ -20,7 +20,7 @@ import { showEncounterDialogue, showEncounterText } from "#app/data/mystery-enco
|
|||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import { isPokemonValidForEncounterOptionSelection } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
import { isPokemonValidForEncounterOptionSelection } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||||
|
|
||||||
/** the i18n namespace for the encounter */
|
/** the i18n namespace for the encounter */
|
||||||
|
@ -15,7 +15,7 @@ import { HiddenAbilityRateBoosterModifier, IvScannerModifier } from "#app/modifi
|
|||||||
import type { EnemyPokemon } from "#app/field/pokemon";
|
import type { EnemyPokemon } from "#app/field/pokemon";
|
||||||
import { PokeballType } from "#enums/pokeball";
|
import { PokeballType } from "#enums/pokeball";
|
||||||
import { PlayerGender } from "#enums/player-gender";
|
import { PlayerGender } from "#enums/player-gender";
|
||||||
import { NumberHolder, randSeedInt } from "#app/utils";
|
import { NumberHolder, randSeedInt } from "#app/utils/common";
|
||||||
import type PokemonSpecies from "#app/data/pokemon-species";
|
import type PokemonSpecies from "#app/data/pokemon-species";
|
||||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||||
import { MoneyRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
import { MoneyRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
||||||
@ -31,7 +31,7 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
|||||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
import { ScanIvsPhase } from "#app/phases/scan-ivs-phase";
|
import { ScanIvsPhase } from "#app/phases/scan-ivs-phase";
|
||||||
import { SummonPhase } from "#app/phases/summon-phase";
|
import { SummonPhase } from "#app/phases/summon-phase";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import { NON_LEGEND_PARADOX_POKEMON } from "#app/data/balance/special-species-groups";
|
import { NON_LEGEND_PARADOX_POKEMON } from "#app/data/balance/special-species-groups";
|
||||||
|
|
||||||
/** the i18n namespace for the encounter */
|
/** the i18n namespace for the encounter */
|
||||||
|
@ -8,7 +8,7 @@ import {
|
|||||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import { modifierTypes } from "#app/modifier/modifier-type";
|
import { modifierTypes } from "#app/modifier/modifier-type";
|
||||||
import { randSeedInt } from "#app/utils";
|
import { randSeedInt } from "#app/utils/common";
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
@ -26,7 +26,7 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
|||||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
import type { Nature } from "#enums/nature";
|
import type { Nature } from "#enums/nature";
|
||||||
import { getNatureName } from "#app/data/nature";
|
import { getNatureName } from "#app/data/nature";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
|
||||||
/** the i18n namespace for this encounter */
|
/** the i18n namespace for this encounter */
|
||||||
|
@ -26,7 +26,7 @@ import { getPokemonSpecies } from "#app/data/pokemon-species";
|
|||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
import { PartyHealPhase } from "#app/phases/party-heal-phase";
|
import { PartyHealPhase } from "#app/phases/party-heal-phase";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import { BerryType } from "#enums/berry-type";
|
import { BerryType } from "#enums/berry-type";
|
||||||
import { CustomPokemonData } from "#app/data/custom-pokemon-data";
|
import { CustomPokemonData } from "#app/data/custom-pokemon-data";
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import {
|
|||||||
transitionMysteryEncounterIntroVisuals,
|
transitionMysteryEncounterIntroVisuals,
|
||||||
updatePlayerMoney,
|
updatePlayerMoney,
|
||||||
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import { randSeedInt } from "#app/utils";
|
import { randSeedInt } from "#app/utils/common";
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||||
@ -29,7 +29,7 @@ import { BattlerTagType } from "#enums/battler-tag-type";
|
|||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
||||||
import { Stat } from "#enums/stat";
|
import { Stat } from "#enums/stat";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import {
|
import {
|
||||||
getEncounterPokemonLevelForWave,
|
getEncounterPokemonLevelForWave,
|
||||||
STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER,
|
STANDARD_ENCOUNTER_BOOSTED_LEVEL_MODIFIER,
|
||||||
|
@ -7,11 +7,11 @@ import {
|
|||||||
import { trainerConfigs } from "#app/data/trainers/trainer-config";
|
import { trainerConfigs } from "#app/data/trainers/trainer-config";
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import { randSeedShuffle } from "#app/utils";
|
import { randSeedShuffle } from "#app/utils/common";
|
||||||
import type MysteryEncounter from "../mystery-encounter";
|
import type MysteryEncounter from "../mystery-encounter";
|
||||||
import { MysteryEncounterBuilder } from "../mystery-encounter";
|
import { MysteryEncounterBuilder } from "../mystery-encounter";
|
||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import { Biome } from "#enums/biome";
|
import { Biome } from "#enums/biome";
|
||||||
import { TrainerType } from "#enums/trainer-type";
|
import { TrainerType } from "#enums/trainer-type";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
@ -3,7 +3,7 @@ import {
|
|||||||
transitionMysteryEncounterIntroVisuals,
|
transitionMysteryEncounterIntroVisuals,
|
||||||
updatePlayerMoney,
|
updatePlayerMoney,
|
||||||
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
} from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import { isNullOrUndefined, randSeedInt } from "#app/utils";
|
import { isNullOrUndefined, NumberHolder, randSeedInt, randSeedItem } from "#app/utils/common";
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||||
@ -26,9 +26,10 @@ import { showEncounterDialogue } from "#app/data/mystery-encounters/utils/encoun
|
|||||||
import PokemonData from "#app/system/pokemon-data";
|
import PokemonData from "#app/system/pokemon-data";
|
||||||
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import { Abilities } from "#enums/abilities";
|
import { Abilities } from "#enums/abilities";
|
||||||
import { NON_LEGEND_PARADOX_POKEMON } from "#app/data/balance/special-species-groups";
|
import { NON_LEGEND_PARADOX_POKEMON, NON_LEGEND_ULTRA_BEASTS } from "#app/data/balance/special-species-groups";
|
||||||
|
import { timedEventManager } from "#app/global-event-manager";
|
||||||
|
|
||||||
/** the i18n namespace for this encounter */
|
/** the i18n namespace for this encounter */
|
||||||
const namespace = "mysteryEncounters/thePokemonSalesman";
|
const namespace = "mysteryEncounters/thePokemonSalesman";
|
||||||
@ -38,6 +39,9 @@ const MAX_POKEMON_PRICE_MULTIPLIER = 4;
|
|||||||
/** Odds of shiny magikarp will be 1/value */
|
/** Odds of shiny magikarp will be 1/value */
|
||||||
const SHINY_MAGIKARP_WEIGHT = 100;
|
const SHINY_MAGIKARP_WEIGHT = 100;
|
||||||
|
|
||||||
|
/** Odds of event sale will be value/100 */
|
||||||
|
const EVENT_THRESHOLD = 50;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pokemon Salesman encounter.
|
* Pokemon Salesman encounter.
|
||||||
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3799 | GitHub Issue #3799}
|
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/3799 | GitHub Issue #3799}
|
||||||
@ -82,15 +86,46 @@ export const ThePokemonSalesmanEncounter: MysteryEncounter = MysteryEncounterBui
|
|||||||
tries++;
|
tries++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const r = randSeedInt(SHINY_MAGIKARP_WEIGHT);
|
||||||
|
|
||||||
|
const validEventEncounters = timedEventManager
|
||||||
|
.getEventEncounters()
|
||||||
|
.filter(
|
||||||
|
s =>
|
||||||
|
!getPokemonSpecies(s.species).legendary &&
|
||||||
|
!getPokemonSpecies(s.species).subLegendary &&
|
||||||
|
!getPokemonSpecies(s.species).mythical &&
|
||||||
|
!NON_LEGEND_PARADOX_POKEMON.includes(s.species) &&
|
||||||
|
!NON_LEGEND_ULTRA_BEASTS.includes(s.species),
|
||||||
|
);
|
||||||
|
|
||||||
let pokemon: PlayerPokemon;
|
let pokemon: PlayerPokemon;
|
||||||
|
/**
|
||||||
|
* Mon is determined as follows:
|
||||||
|
* If you roll the 1% for Shiny Magikarp, you get Magikarp with a random variant
|
||||||
|
* If an event with more than 1 valid event encounter species is active, you have 20% chance to get one of those
|
||||||
|
* If the rolled species has no HA, and there are valid event encounters, you will get one of those
|
||||||
|
* If the rolled species has no HA and there are no valid event encounters, you will get Shiny Magikarp
|
||||||
|
* Mons rolled from the event encounter pool get 2 extra shiny rolls
|
||||||
|
*/
|
||||||
if (
|
if (
|
||||||
randSeedInt(SHINY_MAGIKARP_WEIGHT) === 0 ||
|
r === 0 ||
|
||||||
isNullOrUndefined(species.abilityHidden) ||
|
((isNullOrUndefined(species.abilityHidden) || species.abilityHidden === Abilities.NONE) &&
|
||||||
species.abilityHidden === Abilities.NONE
|
(validEventEncounters.length === 0))
|
||||||
) {
|
) {
|
||||||
// If no HA mon found or you roll 1%, give shiny Magikarp with random variant
|
// If you roll 1%, give shiny Magikarp with random variant
|
||||||
species = getPokemonSpecies(Species.MAGIKARP);
|
species = getPokemonSpecies(Species.MAGIKARP);
|
||||||
pokemon = new PlayerPokemon(species, 5, 2, species.formIndex, undefined, true);
|
pokemon = new PlayerPokemon(species, 5, 2, undefined, undefined, true);
|
||||||
|
} else if (
|
||||||
|
(validEventEncounters.length > 0 && (r <= EVENT_THRESHOLD ||
|
||||||
|
(isNullOrUndefined(species.abilityHidden) || species.abilityHidden === Abilities.NONE)))
|
||||||
|
) {
|
||||||
|
// If you roll 20%, give event encounter with 2 extra shiny rolls and its HA, if it has one
|
||||||
|
const enc = randSeedItem(validEventEncounters);
|
||||||
|
species = getPokemonSpecies(enc.species);
|
||||||
|
pokemon = new PlayerPokemon(species, 5, species.abilityHidden === Abilities.NONE ? undefined : 2, enc.formIndex);
|
||||||
|
pokemon.trySetShinySeed();
|
||||||
|
pokemon.trySetShinySeed();
|
||||||
} else {
|
} else {
|
||||||
pokemon = new PlayerPokemon(species, 5, 2, species.formIndex);
|
pokemon = new PlayerPokemon(species, 5, 2, species.formIndex);
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
|||||||
import { CustomPokemonData } from "#app/data/custom-pokemon-data";
|
import { CustomPokemonData } from "#app/data/custom-pokemon-data";
|
||||||
import { Stat } from "#enums/stat";
|
import { Stat } from "#enums/stat";
|
||||||
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
|
|
||||||
/** the i18n namespace for the encounter */
|
/** the i18n namespace for the encounter */
|
||||||
const namespace = "mysteryEncounters/theStrongStuff";
|
const namespace = "mysteryEncounters/theStrongStuff";
|
||||||
|
@ -32,7 +32,7 @@ import { ShowTrainerPhase } from "#app/phases/show-trainer-phase";
|
|||||||
import { ReturnPhase } from "#app/phases/return-phase";
|
import { ReturnPhase } from "#app/phases/return-phase";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { ModifierTier } from "#app/modifier/modifier-tier";
|
import { ModifierTier } from "#app/modifier/modifier-tier";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
|
|
||||||
/** the i18n namespace for the encounter */
|
/** the i18n namespace for the encounter */
|
||||||
|
@ -15,7 +15,7 @@ import type { PokemonHeldItemModifier } from "#app/modifier/modifier";
|
|||||||
import { AbilityAttr } from "#app/system/game-data";
|
import { AbilityAttr } from "#app/system/game-data";
|
||||||
import PokemonData from "#app/system/pokemon-data";
|
import PokemonData from "#app/system/pokemon-data";
|
||||||
import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
||||||
import { isNullOrUndefined, randSeedShuffle } from "#app/utils";
|
import { isNullOrUndefined, randSeedShuffle } from "#app/utils/common";
|
||||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
@ -28,7 +28,7 @@ import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode
|
|||||||
import type HeldModifierConfig from "#app/interfaces/held-modifier-config";
|
import type HeldModifierConfig from "#app/interfaces/held-modifier-config";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { getStatKey } from "#enums/stat";
|
import { getStatKey } from "#enums/stat";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import { isPokemonValidForEncounterOptionSelection } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
import { isPokemonValidForEncounterOptionSelection } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||||
import type { Nature } from "#enums/nature";
|
import type { Nature } from "#enums/nature";
|
||||||
|
|
||||||
|
@ -26,8 +26,8 @@ import { getPokemonSpecies } from "#app/data/pokemon-species";
|
|||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { BattlerIndex } from "#app/battle";
|
import { BattlerIndex } from "#app/battle";
|
||||||
import { PokemonMove } from "#app/field/pokemon";
|
import { PokemonMove } from "#app/field/pokemon";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
import { randSeedInt } from "#app/utils";
|
import { randSeedInt } from "#app/utils/common";
|
||||||
|
|
||||||
/** the i18n namespace for this encounter */
|
/** the i18n namespace for this encounter */
|
||||||
const namespace = "mysteryEncounters/trashToTreasure";
|
const namespace = "mysteryEncounters/trashToTreasure";
|
||||||
|
@ -27,7 +27,7 @@ import {
|
|||||||
getSpriteKeysFromPokemon,
|
getSpriteKeysFromPokemon,
|
||||||
} from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
} from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||||
import PokemonData from "#app/system/pokemon-data";
|
import PokemonData from "#app/system/pokemon-data";
|
||||||
import { isNullOrUndefined, randSeedInt } from "#app/utils";
|
import { isNullOrUndefined, randSeedInt } from "#app/utils/common";
|
||||||
import type { Moves } from "#enums/moves";
|
import type { Moves } from "#enums/moves";
|
||||||
import { BattlerIndex } from "#app/battle";
|
import { BattlerIndex } from "#app/battle";
|
||||||
import { SelfStatusMove } from "#app/data/moves/move";
|
import { SelfStatusMove } from "#app/data/moves/move";
|
||||||
@ -37,7 +37,7 @@ import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encoun
|
|||||||
import { BerryModifier } from "#app/modifier/modifier";
|
import { BerryModifier } from "#app/modifier/modifier";
|
||||||
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
|
||||||
import { Stat } from "#enums/stat";
|
import { Stat } from "#enums/stat";
|
||||||
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/game-mode";
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
|
||||||
|
|
||||||
/** the i18n namespace for the encounter */
|
/** the i18n namespace for the encounter */
|
||||||
const namespace = "mysteryEncounters/uncommonBreed";
|
const namespace = "mysteryEncounters/uncommonBreed";
|
||||||
|
@ -17,7 +17,7 @@ import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode
|
|||||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import { PokemonMove } from "#app/field/pokemon";
|
import { PokemonMove } from "#app/field/pokemon";
|
||||||
import { NumberHolder, isNullOrUndefined, randSeedInt, randSeedShuffle } from "#app/utils";
|
import { NumberHolder, isNullOrUndefined, randSeedInt, randSeedShuffle } from "#app/utils/common";
|
||||||
import type PokemonSpecies from "#app/data/pokemon-species";
|
import type PokemonSpecies from "#app/data/pokemon-species";
|
||||||
import { allSpecies, getPokemonSpecies } from "#app/data/pokemon-species";
|
import { allSpecies, getPokemonSpecies } from "#app/data/pokemon-species";
|
||||||
import type { PokemonHeldItemModifier } from "#app/modifier/modifier";
|
import type { PokemonHeldItemModifier } from "#app/modifier/modifier";
|
||||||
|
@ -12,7 +12,7 @@ import {
|
|||||||
} from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
} from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
||||||
import type { CanLearnMoveRequirementOptions } from "./requirements/can-learn-move-requirement";
|
import type { CanLearnMoveRequirementOptions } from "./requirements/can-learn-move-requirement";
|
||||||
import { CanLearnMoveRequirement } from "./requirements/can-learn-move-requirement";
|
import { CanLearnMoveRequirement } from "./requirements/can-learn-move-requirement";
|
||||||
import { isNullOrUndefined, randSeedInt } from "#app/utils";
|
import { isNullOrUndefined, randSeedInt } from "#app/utils/common";
|
||||||
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
|
||||||
|
|
||||||
// biome-ignore lint/suspicious/noConfusingVoidType: void unions in callbacks are OK
|
// biome-ignore lint/suspicious/noConfusingVoidType: void unions in callbacks are OK
|
||||||
|
@ -9,7 +9,7 @@ import { WeatherType } from "#enums/weather-type";
|
|||||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||||
import { AttackTypeBoosterModifier } from "#app/modifier/modifier";
|
import { AttackTypeBoosterModifier } from "#app/modifier/modifier";
|
||||||
import type { AttackTypeBoosterModifierType } from "#app/modifier/modifier-type";
|
import type { AttackTypeBoosterModifierType } from "#app/modifier/modifier-type";
|
||||||
import { isNullOrUndefined } from "#app/utils";
|
import { isNullOrUndefined } from "#app/utils/common";
|
||||||
import type { Abilities } from "#enums/abilities";
|
import type { Abilities } from "#enums/abilities";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT } from "#app/data/mystery-encounters/mystery-encounters";
|
import { BASE_MYSTERY_ENCOUNTER_SPAWN_WEIGHT } from "#app/data/mystery-encounters/mystery-encounters";
|
||||||
import { isNullOrUndefined } from "#app/utils";
|
import { isNullOrUndefined } from "#app/utils/common";
|
||||||
import type { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
import type { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
|
||||||
|
|
||||||
export class SeenEncounterData {
|
export class SeenEncounterData {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
import type { EnemyPartyConfig } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
|
||||||
import type { PlayerPokemon, PokemonMove } from "#app/field/pokemon";
|
import type { PlayerPokemon, PokemonMove } from "#app/field/pokemon";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import { capitalizeFirstLetter, isNullOrUndefined } from "#app/utils";
|
import { capitalizeFirstLetter, isNullOrUndefined } from "#app/utils/common";
|
||||||
import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import type { MysteryEncounterSpriteConfig } from "#app/field/mystery-encounter-intro";
|
import type { MysteryEncounterSpriteConfig } from "#app/field/mystery-encounter-intro";
|
||||||
import MysteryEncounterIntroVisuals from "#app/field/mystery-encounter-intro";
|
import MysteryEncounterIntroVisuals from "#app/field/mystery-encounter-intro";
|
||||||
import { randSeedInt } from "#app/utils";
|
import { randSeedInt } from "#app/utils/common";
|
||||||
import type { StatusEffect } from "#enums/status-effect";
|
import type { StatusEffect } from "#enums/status-effect";
|
||||||
import type { OptionTextDisplay } from "./mystery-encounter-dialogue";
|
import type { OptionTextDisplay } from "./mystery-encounter-dialogue";
|
||||||
import type MysteryEncounterDialogue from "./mystery-encounter-dialogue";
|
import type MysteryEncounterDialogue from "./mystery-encounter-dialogue";
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import type { Moves } from "#app/enums/moves";
|
import type { Moves } from "#app/enums/moves";
|
||||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||||
import { PokemonMove } from "#app/field/pokemon";
|
import { PokemonMove } from "#app/field/pokemon";
|
||||||
import { isNullOrUndefined } from "#app/utils";
|
import { isNullOrUndefined } from "#app/utils/common";
|
||||||
import { EncounterPokemonRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
import { EncounterPokemonRequirement } from "#app/data/mystery-encounters/mystery-encounter-requirements";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import { globalScene } from "#app/global-scene";
|
|||||||
import type { TextStyle } from "#app/ui/text";
|
import type { TextStyle } from "#app/ui/text";
|
||||||
import { getTextWithColors } from "#app/ui/text";
|
import { getTextWithColors } from "#app/ui/text";
|
||||||
import { UiTheme } from "#enums/ui-theme";
|
import { UiTheme } from "#enums/ui-theme";
|
||||||
import { isNullOrUndefined } from "#app/utils";
|
import { isNullOrUndefined } from "#app/utils/common";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import type Battle from "#app/battle";
|
import type Battle from "#app/battle";
|
||||||
import { BattlerIndex, BattleType } from "#app/battle";
|
import { BattlerIndex } from "#app/battle";
|
||||||
|
import { BattleType } from "#enums/battle-type";
|
||||||
import { biomeLinks, BiomePoolTier } from "#app/data/balance/biomes";
|
import { biomeLinks, BiomePoolTier } from "#app/data/balance/biomes";
|
||||||
import type MysteryEncounterOption from "#app/data/mystery-encounters/mystery-encounter-option";
|
import type MysteryEncounterOption from "#app/data/mystery-encounters/mystery-encounter-option";
|
||||||
import {
|
import {
|
||||||
@ -29,8 +30,8 @@ import type PokemonData from "#app/system/pokemon-data";
|
|||||||
import type { OptionSelectConfig, OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
import type { OptionSelectConfig, OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
||||||
import type { PartyOption, PokemonSelectFilter } from "#app/ui/party-ui-handler";
|
import type { PartyOption, PokemonSelectFilter } from "#app/ui/party-ui-handler";
|
||||||
import { PartyUiMode } from "#app/ui/party-ui-handler";
|
import { PartyUiMode } from "#app/ui/party-ui-handler";
|
||||||
import { Mode } from "#app/ui/ui";
|
import { UiMode } from "#enums/ui-mode";
|
||||||
import { isNullOrUndefined, randSeedInt, randomString, randSeedItem } from "#app/utils";
|
import { isNullOrUndefined, randSeedInt, randomString, randSeedItem } from "#app/utils/common";
|
||||||
import type { BattlerTagType } from "#enums/battler-tag-type";
|
import type { BattlerTagType } from "#enums/battler-tag-type";
|
||||||
import { Biome } from "#enums/biome";
|
import { Biome } from "#enums/biome";
|
||||||
import type { TrainerType } from "#enums/trainer-type";
|
import type { TrainerType } from "#enums/trainer-type";
|
||||||
@ -423,6 +424,7 @@ export async function initBattleWithEnemyConfig(partyConfig: EnemyPartyConfig):
|
|||||||
console.log(
|
console.log(
|
||||||
`Pokemon: ${getPokemonNameWithAffix(enemyPokemon)}`,
|
`Pokemon: ${getPokemonNameWithAffix(enemyPokemon)}`,
|
||||||
`| Species ID: ${enemyPokemon.species.speciesId}`,
|
`| Species ID: ${enemyPokemon.species.speciesId}`,
|
||||||
|
`| Level: ${enemyPokemon.level}`,
|
||||||
`| Nature: ${getNatureName(enemyPokemon.nature, true, true, true)}`,
|
`| Nature: ${getNatureName(enemyPokemon.nature, true, true, true)}`,
|
||||||
);
|
);
|
||||||
console.log(`Stats (IVs): ${stats}`);
|
console.log(`Stats (IVs): ${stats}`);
|
||||||
@ -562,7 +564,7 @@ export function selectPokemonForOption(
|
|||||||
|
|
||||||
// Open party screen to choose pokemon
|
// Open party screen to choose pokemon
|
||||||
globalScene.ui.setMode(
|
globalScene.ui.setMode(
|
||||||
Mode.PARTY,
|
UiMode.PARTY,
|
||||||
PartyUiMode.SELECT,
|
PartyUiMode.SELECT,
|
||||||
-1,
|
-1,
|
||||||
(slotIndex: number, _option: PartyOption) => {
|
(slotIndex: number, _option: PartyOption) => {
|
||||||
@ -580,7 +582,7 @@ export function selectPokemonForOption(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// There is a second option to choose after selecting the Pokemon
|
// There is a second option to choose after selecting the Pokemon
|
||||||
globalScene.ui.setMode(Mode.MESSAGE).then(() => {
|
globalScene.ui.setMode(UiMode.MESSAGE).then(() => {
|
||||||
const displayOptions = () => {
|
const displayOptions = () => {
|
||||||
// Always appends a cancel option to bottom of options
|
// Always appends a cancel option to bottom of options
|
||||||
const fullOptions = secondaryOptions
|
const fullOptions = secondaryOptions
|
||||||
@ -622,7 +624,7 @@ export function selectPokemonForOption(
|
|||||||
if (fullOptions[0].onHover) {
|
if (fullOptions[0].onHover) {
|
||||||
fullOptions[0].onHover();
|
fullOptions[0].onHover();
|
||||||
}
|
}
|
||||||
globalScene.ui.setModeWithoutClear(Mode.OPTION_SELECT, config, null, true);
|
globalScene.ui.setModeWithoutClear(UiMode.OPTION_SELECT, config, null, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const textPromptKey =
|
const textPromptKey =
|
||||||
@ -672,20 +674,20 @@ export function selectOptionThenPokemon(
|
|||||||
const modeToSetOnExit = globalScene.ui.getMode();
|
const modeToSetOnExit = globalScene.ui.getMode();
|
||||||
|
|
||||||
const displayOptions = (config: OptionSelectConfig) => {
|
const displayOptions = (config: OptionSelectConfig) => {
|
||||||
globalScene.ui.setMode(Mode.MESSAGE).then(() => {
|
globalScene.ui.setMode(UiMode.MESSAGE).then(() => {
|
||||||
if (!optionSelectPromptKey) {
|
if (!optionSelectPromptKey) {
|
||||||
// Do hover over the starting selection option
|
// Do hover over the starting selection option
|
||||||
if (fullOptions[0].onHover) {
|
if (fullOptions[0].onHover) {
|
||||||
fullOptions[0].onHover();
|
fullOptions[0].onHover();
|
||||||
}
|
}
|
||||||
globalScene.ui.setMode(Mode.OPTION_SELECT, config);
|
globalScene.ui.setMode(UiMode.OPTION_SELECT, config);
|
||||||
} else {
|
} else {
|
||||||
showEncounterText(optionSelectPromptKey).then(() => {
|
showEncounterText(optionSelectPromptKey).then(() => {
|
||||||
// Do hover over the starting selection option
|
// Do hover over the starting selection option
|
||||||
if (fullOptions[0].onHover) {
|
if (fullOptions[0].onHover) {
|
||||||
fullOptions[0].onHover();
|
fullOptions[0].onHover();
|
||||||
}
|
}
|
||||||
globalScene.ui.setMode(Mode.OPTION_SELECT, config);
|
globalScene.ui.setMode(UiMode.OPTION_SELECT, config);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -694,7 +696,7 @@ export function selectOptionThenPokemon(
|
|||||||
const selectPokemonAfterOption = (selectedOptionIndex: number) => {
|
const selectPokemonAfterOption = (selectedOptionIndex: number) => {
|
||||||
// Open party screen to choose a Pokemon
|
// Open party screen to choose a Pokemon
|
||||||
globalScene.ui.setMode(
|
globalScene.ui.setMode(
|
||||||
Mode.PARTY,
|
UiMode.PARTY,
|
||||||
PartyUiMode.SELECT,
|
PartyUiMode.SELECT,
|
||||||
-1,
|
-1,
|
||||||
(slotIndex: number, _option: PartyOption) => {
|
(slotIndex: number, _option: PartyOption) => {
|
||||||
@ -1074,8 +1076,8 @@ export function getRandomEncounterSpecies(level: number, isBoss = false, rerollH
|
|||||||
ret.formIndex = formIndex;
|
ret.formIndex = formIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Reroll shiny for event encounters
|
//Reroll shiny or variant for event encounters
|
||||||
if (isEventEncounter && !ret.shiny) {
|
if (isEventEncounter) {
|
||||||
ret.trySetShinySeed();
|
ret.trySetShinySeed();
|
||||||
}
|
}
|
||||||
//Reroll hidden ability
|
//Reroll hidden ability
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { isNullOrUndefined, randSeedInt } from "#app/utils";
|
import { isNullOrUndefined, randSeedInt } from "#app/utils/common";
|
||||||
import { PokemonHeldItemModifier } from "#app/modifier/modifier";
|
import { PokemonHeldItemModifier } from "#app/modifier/modifier";
|
||||||
import type { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon";
|
import type { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
@ -14,7 +14,7 @@ import { PlayerGender } from "#enums/player-gender";
|
|||||||
import { addPokeballCaptureStars, addPokeballOpenParticles } from "#app/field/anims";
|
import { addPokeballCaptureStars, addPokeballOpenParticles } from "#app/field/anims";
|
||||||
import { getStatusEffectCatchRateMultiplier } from "#app/data/status-effect";
|
import { getStatusEffectCatchRateMultiplier } from "#app/data/status-effect";
|
||||||
import { achvs } from "#app/system/achv";
|
import { achvs } from "#app/system/achv";
|
||||||
import { Mode } from "#app/ui/ui";
|
import { UiMode } from "#enums/ui-mode";
|
||||||
import type { PartyOption } from "#app/ui/party-ui-handler";
|
import type { PartyOption } from "#app/ui/party-ui-handler";
|
||||||
import { PartyUiMode } from "#app/ui/party-ui-handler";
|
import { PartyUiMode } from "#app/ui/party-ui-handler";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
@ -714,7 +714,7 @@ export async function catchPokemon(
|
|||||||
() => {
|
() => {
|
||||||
globalScene.pokemonInfoContainer.makeRoomForConfirmUi(1, true);
|
globalScene.pokemonInfoContainer.makeRoomForConfirmUi(1, true);
|
||||||
globalScene.ui.setMode(
|
globalScene.ui.setMode(
|
||||||
Mode.CONFIRM,
|
UiMode.CONFIRM,
|
||||||
() => {
|
() => {
|
||||||
const newPokemon = globalScene.addPlayerPokemon(
|
const newPokemon = globalScene.addPlayerPokemon(
|
||||||
pokemon.species,
|
pokemon.species,
|
||||||
@ -729,12 +729,12 @@ export async function catchPokemon(
|
|||||||
pokemon,
|
pokemon,
|
||||||
);
|
);
|
||||||
globalScene.ui.setMode(
|
globalScene.ui.setMode(
|
||||||
Mode.SUMMARY,
|
UiMode.SUMMARY,
|
||||||
newPokemon,
|
newPokemon,
|
||||||
0,
|
0,
|
||||||
SummaryUiMode.DEFAULT,
|
SummaryUiMode.DEFAULT,
|
||||||
() => {
|
() => {
|
||||||
globalScene.ui.setMode(Mode.MESSAGE).then(() => {
|
globalScene.ui.setMode(UiMode.MESSAGE).then(() => {
|
||||||
promptRelease();
|
promptRelease();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -749,13 +749,13 @@ export async function catchPokemon(
|
|||||||
female: pokemon.gender === Gender.FEMALE,
|
female: pokemon.gender === Gender.FEMALE,
|
||||||
};
|
};
|
||||||
globalScene.ui.setOverlayMode(
|
globalScene.ui.setOverlayMode(
|
||||||
Mode.POKEDEX_PAGE,
|
UiMode.POKEDEX_PAGE,
|
||||||
pokemon.species,
|
pokemon.species,
|
||||||
pokemon.formIndex,
|
pokemon.formIndex,
|
||||||
attributes,
|
attributes,
|
||||||
null,
|
null,
|
||||||
() => {
|
() => {
|
||||||
globalScene.ui.setMode(Mode.MESSAGE).then(() => {
|
globalScene.ui.setMode(UiMode.MESSAGE).then(() => {
|
||||||
promptRelease();
|
promptRelease();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -763,11 +763,11 @@ export async function catchPokemon(
|
|||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
globalScene.ui.setMode(
|
globalScene.ui.setMode(
|
||||||
Mode.PARTY,
|
UiMode.PARTY,
|
||||||
PartyUiMode.RELEASE,
|
PartyUiMode.RELEASE,
|
||||||
0,
|
0,
|
||||||
(slotIndex: number, _option: PartyOption) => {
|
(slotIndex: number, _option: PartyOption) => {
|
||||||
globalScene.ui.setMode(Mode.MESSAGE).then(() => {
|
globalScene.ui.setMode(UiMode.MESSAGE).then(() => {
|
||||||
if (slotIndex < 6) {
|
if (slotIndex < 6) {
|
||||||
addToParty(slotIndex);
|
addToParty(slotIndex);
|
||||||
} else {
|
} else {
|
||||||
@ -778,7 +778,7 @@ export async function catchPokemon(
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
globalScene.ui.setMode(Mode.MESSAGE).then(() => {
|
globalScene.ui.setMode(UiMode.MESSAGE).then(() => {
|
||||||
removePokemon();
|
removePokemon();
|
||||||
end();
|
end();
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||||
import { getFrameMs } from "#app/utils";
|
import { getFrameMs } from "#app/utils/common";
|
||||||
import { cos, sin } from "#app/field/anims";
|
import { cos, sin } from "#app/field/anims";
|
||||||
import { getTypeRgb } from "#app/data/type";
|
import { getTypeRgb } from "#app/data/type";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { toReadableString } from "#app/utils";
|
import { toReadableString } from "#app/utils/common";
|
||||||
import { TextStyle, getBBCodeFrag } from "../ui/text";
|
import { TextStyle, getBBCodeFrag } from "../ui/text";
|
||||||
import { Nature } from "#enums/nature";
|
import { Nature } from "#enums/nature";
|
||||||
import { UiTheme } from "#enums/ui-theme";
|
import { UiTheme } from "#enums/ui-theme";
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import { CriticalCatchChanceBoosterModifier } from "#app/modifier/modifier";
|
import { CriticalCatchChanceBoosterModifier } from "#app/modifier/modifier";
|
||||||
import { NumberHolder } from "#app/utils";
|
import { NumberHolder } from "#app/utils/common";
|
||||||
import { PokeballType } from "#enums/pokeball";
|
import { PokeballType } from "#enums/pokeball";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import type Pokemon from "../field/pokemon";
|
|||||||
import { StatusEffect } from "#enums/status-effect";
|
import { StatusEffect } from "#enums/status-effect";
|
||||||
import { allMoves } from "./moves/move";
|
import { allMoves } from "./moves/move";
|
||||||
import { MoveCategory } from "#enums/MoveCategory";
|
import { MoveCategory } from "#enums/MoveCategory";
|
||||||
import type { Constructor, nil } from "#app/utils";
|
import type { Constructor, nil } from "#app/utils/common";
|
||||||
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";
|
||||||
|
@ -8,7 +8,7 @@ import type { AnySound } from "#app/battle-scene";
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import type { GameMode } from "#app/game-mode";
|
import type { GameMode } from "#app/game-mode";
|
||||||
import { DexAttr, type StarterMoveset } from "#app/system/game-data";
|
import { DexAttr, type StarterMoveset } from "#app/system/game-data";
|
||||||
import { isNullOrUndefined, capitalizeString, randSeedInt, randSeedGauss, randSeedItem } from "#app/utils";
|
import { isNullOrUndefined, capitalizeString, randSeedInt, randSeedGauss, randSeedItem } from "#app/utils/common";
|
||||||
import { uncatchableSpecies } from "#app/data/balance/biomes";
|
import { uncatchableSpecies } from "#app/data/balance/biomes";
|
||||||
import { speciesEggMoves } from "#app/data/balance/egg-moves";
|
import { speciesEggMoves } from "#app/data/balance/egg-moves";
|
||||||
import { GrowthRate } from "#app/data/exp";
|
import { GrowthRate } from "#app/data/exp";
|
||||||
@ -27,7 +27,7 @@ import {
|
|||||||
} from "#app/data/balance/pokemon-level-moves";
|
} from "#app/data/balance/pokemon-level-moves";
|
||||||
import type { Stat } from "#enums/stat";
|
import type { Stat } from "#enums/stat";
|
||||||
import type { Variant, VariantSet } from "#app/sprites/variant";
|
import type { Variant, VariantSet } from "#app/sprites/variant";
|
||||||
import { populateVariantColorCache, variantData } from "#app/sprites/variant";
|
import { populateVariantColorCache, variantColorCache, variantData } from "#app/sprites/variant";
|
||||||
import { speciesStarterCosts, POKERUS_STARTER_COUNT } from "#app/data/balance/starters";
|
import { speciesStarterCosts, POKERUS_STARTER_COUNT } from "#app/data/balance/starters";
|
||||||
import { SpeciesFormKey } from "#enums/species-form-key";
|
import { SpeciesFormKey } from "#enums/species-form-key";
|
||||||
import { starterPassiveAbilities } from "#app/data/balance/passives";
|
import { starterPassiveAbilities } from "#app/data/balance/passives";
|
||||||
@ -404,7 +404,7 @@ export abstract class PokemonSpeciesForm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Compute the sprite ID of the pokemon form. */
|
/** Compute the sprite ID of the pokemon form. */
|
||||||
getSpriteId(female: boolean, formIndex?: number, shiny?: boolean, variant = 0, back?: boolean): string {
|
getSpriteId(female: boolean, formIndex?: number, shiny?: boolean, variant = 0, back = false): string {
|
||||||
const baseSpriteKey = this.getBaseSpriteKey(female, formIndex);
|
const baseSpriteKey = this.getBaseSpriteKey(female, formIndex);
|
||||||
|
|
||||||
let config = variantData;
|
let config = variantData;
|
||||||
@ -488,6 +488,7 @@ export abstract class PokemonSpeciesForm {
|
|||||||
if (formSpriteKey.startsWith("behemoth")) {
|
if (formSpriteKey.startsWith("behemoth")) {
|
||||||
formSpriteKey = "crowned";
|
formSpriteKey = "crowned";
|
||||||
}
|
}
|
||||||
|
// biome-ignore lint/suspicious/no-fallthrough: Falls through
|
||||||
default:
|
default:
|
||||||
ret += `-${formSpriteKey}`;
|
ret += `-${formSpriteKey}`;
|
||||||
break;
|
break;
|
||||||
@ -594,6 +595,44 @@ export abstract class PokemonSpeciesForm {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the variant colors for the species into the variant color cache
|
||||||
|
*
|
||||||
|
* @param spriteKey - The sprite key to use
|
||||||
|
* @param female - Whether to load female instead of male
|
||||||
|
* @param back - Whether the back sprite is being loaded
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
async loadVariantColors(
|
||||||
|
spriteKey: string,
|
||||||
|
female: boolean,
|
||||||
|
variant: Variant,
|
||||||
|
back = false,
|
||||||
|
formIndex?: number,
|
||||||
|
): Promise<void> {
|
||||||
|
let baseSpriteKey = this.getBaseSpriteKey(female, formIndex);
|
||||||
|
if (back) {
|
||||||
|
baseSpriteKey = "back__" + baseSpriteKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (variantColorCache.hasOwnProperty(baseSpriteKey)) {
|
||||||
|
// Variant colors have already been loaded
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const variantInfo = variantData[this.getVariantDataIndex(formIndex)];
|
||||||
|
// Do nothing if there is no variant information or the variant does not have color replacements
|
||||||
|
if (!variantInfo || variantInfo[variant] !== 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await populateVariantColorCache(
|
||||||
|
"pkmn__" + baseSpriteKey,
|
||||||
|
globalScene.experimentalSprites && hasExpSprite(spriteKey),
|
||||||
|
baseSpriteKey.replace("__", "/"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async loadAssets(
|
async loadAssets(
|
||||||
female: boolean,
|
female: boolean,
|
||||||
formIndex?: number,
|
formIndex?: number,
|
||||||
@ -606,15 +645,9 @@ export abstract class PokemonSpeciesForm {
|
|||||||
const spriteKey = this.getSpriteKey(female, formIndex, shiny, variant, back);
|
const spriteKey = this.getSpriteKey(female, formIndex, shiny, variant, back);
|
||||||
globalScene.loadPokemonAtlas(spriteKey, this.getSpriteAtlasPath(female, formIndex, shiny, variant, back));
|
globalScene.loadPokemonAtlas(spriteKey, this.getSpriteAtlasPath(female, formIndex, shiny, variant, back));
|
||||||
globalScene.load.audio(this.getCryKey(formIndex), `audio/${this.getCryKey(formIndex)}.m4a`);
|
globalScene.load.audio(this.getCryKey(formIndex), `audio/${this.getCryKey(formIndex)}.m4a`);
|
||||||
|
if (!isNullOrUndefined(variant)) {
|
||||||
const baseSpriteKey = this.getBaseSpriteKey(female, formIndex);
|
await this.loadVariantColors(spriteKey, female, variant, back, formIndex);
|
||||||
|
}
|
||||||
// Force the variant color cache to be loaded for the form
|
|
||||||
await populateVariantColorCache(
|
|
||||||
"pkmn__" + baseSpriteKey,
|
|
||||||
globalScene.experimentalSprites && hasExpSprite(spriteKey),
|
|
||||||
baseSpriteKey,
|
|
||||||
);
|
|
||||||
return new Promise<void>(resolve => {
|
return new Promise<void>(resolve => {
|
||||||
globalScene.load.once(Phaser.Loader.Events.COMPLETE, () => {
|
globalScene.load.once(Phaser.Loader.Events.COMPLETE, () => {
|
||||||
const originalWarn = console.warn;
|
const originalWarn = console.warn;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { randIntRange } from "#app/utils";
|
import { randIntRange } from "#app/utils/common";
|
||||||
import { StatusEffect } from "#enums/status-effect";
|
import { StatusEffect } from "#enums/status-effect";
|
||||||
import type { ParseKeys } from "i18next";
|
import type { ParseKeys } from "i18next";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
@ -59,7 +59,7 @@ export class Terrain {
|
|||||||
// Cancels move if the move has positive priority and targets a Pokemon grounded on the Psychic Terrain
|
// Cancels move if the move has positive priority and targets a Pokemon grounded on the Psychic Terrain
|
||||||
return (
|
return (
|
||||||
move.getPriority(user) > 0 &&
|
move.getPriority(user) > 0 &&
|
||||||
user.getOpponents().some(o => targets.includes(o.getBattlerIndex()) && o.isGrounded())
|
user.getOpponents(true).some(o => targets.includes(o.getBattlerIndex()) && o.isGrounded())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { TrainerType } from "#enums/trainer-type";
|
import { TrainerType } from "#enums/trainer-type";
|
||||||
import { toReadableString } from "#app/utils";
|
import { toReadableString } from "#app/utils/common";
|
||||||
|
|
||||||
class TrainerNameConfig {
|
class TrainerNameConfig {
|
||||||
public urls: string[];
|
public urls: string[];
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import { startingWave } from "#app/battle-scene";
|
import { startingWave } from "#app/starting-wave";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import { PartyMemberStrength } from "#enums/party-member-strength";
|
import { PartyMemberStrength } from "#enums/party-member-strength";
|
||||||
|
import { GameModes } from "#app/game-mode";
|
||||||
|
import { ClassicFixedBossWaves } from "#enums/fixed-boss-waves";
|
||||||
|
|
||||||
export class TrainerPartyTemplate {
|
export class TrainerPartyTemplate {
|
||||||
public size: number;
|
public size: number;
|
||||||
@ -222,19 +224,18 @@ export const trainerPartyTemplates = {
|
|||||||
*/
|
*/
|
||||||
export function getEvilGruntPartyTemplate(): TrainerPartyTemplate {
|
export function getEvilGruntPartyTemplate(): TrainerPartyTemplate {
|
||||||
const waveIndex = globalScene.currentBattle?.waveIndex;
|
const waveIndex = globalScene.currentBattle?.waveIndex;
|
||||||
if (waveIndex < 40) {
|
switch (waveIndex) {
|
||||||
return trainerPartyTemplates.TWO_AVG;
|
case ClassicFixedBossWaves.EVIL_GRUNT_1:
|
||||||
|
return trainerPartyTemplates.TWO_AVG;
|
||||||
|
case ClassicFixedBossWaves.EVIL_GRUNT_2:
|
||||||
|
return trainerPartyTemplates.THREE_AVG;
|
||||||
|
case ClassicFixedBossWaves.EVIL_GRUNT_3:
|
||||||
|
return trainerPartyTemplates.TWO_AVG_ONE_STRONG;
|
||||||
|
case ClassicFixedBossWaves.EVIL_ADMIN_1:
|
||||||
|
return trainerPartyTemplates.GYM_LEADER_4; // 3avg 1 strong 1 stronger
|
||||||
|
default:
|
||||||
|
return trainerPartyTemplates.GYM_LEADER_5; // 3 avg 2 strong 1 stronger
|
||||||
}
|
}
|
||||||
if (waveIndex < 63) {
|
|
||||||
return trainerPartyTemplates.THREE_AVG;
|
|
||||||
}
|
|
||||||
if (waveIndex < 65) {
|
|
||||||
return trainerPartyTemplates.TWO_AVG_ONE_STRONG;
|
|
||||||
}
|
|
||||||
if (waveIndex < 112) {
|
|
||||||
return trainerPartyTemplates.GYM_LEADER_4; // 3avg 1 strong 1 stronger
|
|
||||||
}
|
|
||||||
return trainerPartyTemplates.GYM_LEADER_5; // 3 avg 2 strong 1 stronger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getWavePartyTemplate(...templates: TrainerPartyTemplate[]) {
|
export function getWavePartyTemplate(...templates: TrainerPartyTemplate[]) {
|
||||||
@ -245,11 +246,36 @@ export function getWavePartyTemplate(...templates: TrainerPartyTemplate[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getGymLeaderPartyTemplate() {
|
export function getGymLeaderPartyTemplate() {
|
||||||
return getWavePartyTemplate(
|
const { currentBattle, gameMode } = globalScene;
|
||||||
trainerPartyTemplates.GYM_LEADER_1,
|
switch (gameMode.modeId) {
|
||||||
trainerPartyTemplates.GYM_LEADER_2,
|
case GameModes.DAILY:
|
||||||
trainerPartyTemplates.GYM_LEADER_3,
|
if (currentBattle?.waveIndex <= 20) {
|
||||||
trainerPartyTemplates.GYM_LEADER_4,
|
return trainerPartyTemplates.GYM_LEADER_2
|
||||||
trainerPartyTemplates.GYM_LEADER_5,
|
}
|
||||||
);
|
return trainerPartyTemplates.GYM_LEADER_3;
|
||||||
|
case GameModes.CHALLENGE: // In the future, there may be a ChallengeType to call here. For now, use classic's.
|
||||||
|
case GameModes.CLASSIC:
|
||||||
|
if (currentBattle?.waveIndex <= 20) {
|
||||||
|
return trainerPartyTemplates.GYM_LEADER_1; // 1 avg 1 strong
|
||||||
|
}
|
||||||
|
else if (currentBattle?.waveIndex <= 30) {
|
||||||
|
return trainerPartyTemplates.GYM_LEADER_2; // 1 avg 1 strong 1 stronger
|
||||||
|
}
|
||||||
|
else if (currentBattle?.waveIndex <= 60) { // 50 and 60
|
||||||
|
return trainerPartyTemplates.GYM_LEADER_3; // 2 avg 1 strong 1 stronger
|
||||||
|
}
|
||||||
|
else if (currentBattle?.waveIndex <= 90) { // 80 and 90
|
||||||
|
return trainerPartyTemplates.GYM_LEADER_4; // 3 avg 1 strong 1 stronger
|
||||||
|
}
|
||||||
|
// 110+
|
||||||
|
return trainerPartyTemplates.GYM_LEADER_5; // 3 avg 2 strong 1 stronger
|
||||||
|
default:
|
||||||
|
return getWavePartyTemplate(
|
||||||
|
trainerPartyTemplates.GYM_LEADER_1,
|
||||||
|
trainerPartyTemplates.GYM_LEADER_2,
|
||||||
|
trainerPartyTemplates.GYM_LEADER_3,
|
||||||
|
trainerPartyTemplates.GYM_LEADER_4,
|
||||||
|
trainerPartyTemplates.GYM_LEADER_5,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,7 @@ import type Pokemon from "../field/pokemon";
|
|||||||
import { PokemonType } from "#enums/pokemon-type";
|
import { PokemonType } from "#enums/pokemon-type";
|
||||||
import type Move from "./moves/move";
|
import type Move from "./moves/move";
|
||||||
import { AttackMove } from "./moves/move";
|
import { AttackMove } from "./moves/move";
|
||||||
import { randSeedInt } from "#app/utils";
|
import { randSeedInt } from "#app/utils/common";
|
||||||
import { SuppressWeatherEffectAbAttr } from "./abilities/ability";
|
import { SuppressWeatherEffectAbAttr } from "./abilities/ability";
|
||||||
import { TerrainType, getTerrainName } from "./terrain";
|
import { TerrainType, getTerrainName } from "./terrain";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
@ -369,6 +369,7 @@ export function getRandomWeatherType(arena: Arena): WeatherType {
|
|||||||
if (hasSun) {
|
if (hasSun) {
|
||||||
weatherPool.push({ weatherType: WeatherType.SUNNY, weight: 2 });
|
weatherPool.push({ weatherType: WeatherType.SUNNY, weight: 2 });
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case Biome.VOLCANO:
|
case Biome.VOLCANO:
|
||||||
weatherPool = [
|
weatherPool = [
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
export enum MoveEffectTrigger {
|
export enum MoveEffectTrigger {
|
||||||
PRE_APPLY,
|
PRE_APPLY,
|
||||||
POST_APPLY,
|
POST_APPLY,
|
||||||
HIT,
|
|
||||||
/** Triggers one time after all target effects have applied */
|
/** Triggers one time after all target effects have applied */
|
||||||
POST_TARGET
|
POST_TARGET
|
||||||
}
|
}
|
||||||
|
6
src/enums/battle-type.ts
Normal file
6
src/enums/battle-type.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export enum BattleType {
|
||||||
|
WILD,
|
||||||
|
TRAINER,
|
||||||
|
CLEAR,
|
||||||
|
MYSTERY_ENCOUNTER
|
||||||
|
}
|
22
src/enums/fixed-boss-waves.ts
Normal file
22
src/enums/fixed-boss-waves.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
export enum ClassicFixedBossWaves {
|
||||||
|
TOWN_YOUNGSTER = 5,
|
||||||
|
RIVAL_1 = 8,
|
||||||
|
RIVAL_2 = 25,
|
||||||
|
EVIL_GRUNT_1 = 35,
|
||||||
|
RIVAL_3 = 55,
|
||||||
|
EVIL_GRUNT_2 = 62,
|
||||||
|
EVIL_GRUNT_3 = 64,
|
||||||
|
EVIL_ADMIN_1 = 66,
|
||||||
|
RIVAL_4 = 95,
|
||||||
|
EVIL_GRUNT_4 = 112,
|
||||||
|
EVIL_ADMIN_2 = 114,
|
||||||
|
EVIL_BOSS_1 = 115,
|
||||||
|
RIVAL_5 = 145,
|
||||||
|
EVIL_BOSS_2 = 165,
|
||||||
|
ELITE_FOUR_1 = 182,
|
||||||
|
ELITE_FOUR_2 = 184,
|
||||||
|
ELITE_FOUR_3 = 186,
|
||||||
|
ELITE_FOUR_4 = 188,
|
||||||
|
CHAMPION = 190,
|
||||||
|
RIVAL_6 = 195
|
||||||
|
}
|
23
src/enums/hit-check-result.ts
Normal file
23
src/enums/hit-check-result.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/** The result of a hit check calculation */
|
||||||
|
export const HitCheckResult = {
|
||||||
|
/** Hit checks haven't been evaluated yet in this pass */
|
||||||
|
PENDING: 0,
|
||||||
|
/** The move hits the target successfully */
|
||||||
|
HIT: 1,
|
||||||
|
/** The move has no effect on the target */
|
||||||
|
NO_EFFECT: 2,
|
||||||
|
/** The move has no effect on the target, but doesn't proc the default "no effect" message */
|
||||||
|
NO_EFFECT_NO_MESSAGE: 3,
|
||||||
|
/** The target protected itself against the move */
|
||||||
|
PROTECTED: 4,
|
||||||
|
/** The move missed the target */
|
||||||
|
MISS: 5,
|
||||||
|
/** The move is reflected by magic coat or magic bounce */
|
||||||
|
REFLECTED: 6,
|
||||||
|
/** The target is no longer on the field */
|
||||||
|
TARGET_NOT_ON_FIELD: 7,
|
||||||
|
/** The move failed unexpectedly */
|
||||||
|
ERROR: 8,
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type HitCheckResult = typeof HitCheckResult[keyof typeof HitCheckResult];
|
47
src/enums/ui-mode.ts
Normal file
47
src/enums/ui-mode.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
export enum UiMode {
|
||||||
|
MESSAGE,
|
||||||
|
TITLE,
|
||||||
|
COMMAND,
|
||||||
|
FIGHT,
|
||||||
|
BALL,
|
||||||
|
TARGET_SELECT,
|
||||||
|
MODIFIER_SELECT,
|
||||||
|
SAVE_SLOT,
|
||||||
|
PARTY,
|
||||||
|
SUMMARY,
|
||||||
|
STARTER_SELECT,
|
||||||
|
EVOLUTION_SCENE,
|
||||||
|
EGG_HATCH_SCENE,
|
||||||
|
EGG_HATCH_SUMMARY,
|
||||||
|
CONFIRM,
|
||||||
|
OPTION_SELECT,
|
||||||
|
MENU,
|
||||||
|
MENU_OPTION_SELECT,
|
||||||
|
SETTINGS,
|
||||||
|
SETTINGS_DISPLAY,
|
||||||
|
SETTINGS_AUDIO,
|
||||||
|
SETTINGS_GAMEPAD,
|
||||||
|
GAMEPAD_BINDING,
|
||||||
|
SETTINGS_KEYBOARD,
|
||||||
|
KEYBOARD_BINDING,
|
||||||
|
ACHIEVEMENTS,
|
||||||
|
GAME_STATS,
|
||||||
|
EGG_LIST,
|
||||||
|
EGG_GACHA,
|
||||||
|
POKEDEX,
|
||||||
|
POKEDEX_SCAN,
|
||||||
|
POKEDEX_PAGE,
|
||||||
|
LOGIN_FORM,
|
||||||
|
REGISTRATION_FORM,
|
||||||
|
LOADING,
|
||||||
|
SESSION_RELOAD,
|
||||||
|
UNAVAILABLE,
|
||||||
|
CHALLENGE_SELECT,
|
||||||
|
RENAME_POKEMON,
|
||||||
|
RUN_HISTORY,
|
||||||
|
RUN_INFO,
|
||||||
|
TEST_DIALOGUE,
|
||||||
|
AUTO_COMPLETE,
|
||||||
|
ADMIN,
|
||||||
|
MYSTERY_ENCOUNTER
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import { PokeballType } from "#enums/pokeball";
|
import { PokeballType } from "#enums/pokeball";
|
||||||
import type { Variant } from "#app/sprites/variant";
|
import type { Variant } from "#app/sprites/variant";
|
||||||
import { getFrameMs, randGauss } from "#app/utils";
|
import { getFrameMs, randGauss } from "#app/utils/common";
|
||||||
|
|
||||||
export function addPokeballOpenParticles(x: number, y: number, pokeballType: PokeballType): void {
|
export function addPokeballOpenParticles(x: number, y: number, pokeballType: PokeballType): void {
|
||||||
switch (pokeballType) {
|
switch (pokeballType) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import type { BiomeTierTrainerPools, PokemonPools } from "#app/data/balance/biomes";
|
import type { BiomeTierTrainerPools, PokemonPools } from "#app/data/balance/biomes";
|
||||||
import { biomePokemonPools, BiomePoolTier, biomeTrainerPools } from "#app/data/balance/biomes";
|
import { biomePokemonPools, BiomePoolTier, biomeTrainerPools } from "#app/data/balance/biomes";
|
||||||
import { randSeedInt, NumberHolder, isNullOrUndefined, type Constructor } from "#app/utils";
|
import { randSeedInt, NumberHolder, isNullOrUndefined, type Constructor } from "#app/utils/common";
|
||||||
import type PokemonSpecies from "#app/data/pokemon-species";
|
import type PokemonSpecies from "#app/data/pokemon-species";
|
||||||
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
import { getPokemonSpecies } from "#app/data/pokemon-species";
|
||||||
import {
|
import {
|
||||||
|
@ -2,7 +2,7 @@ import { TextStyle, addTextObject } from "../ui/text";
|
|||||||
import type { DamageResult } from "./pokemon";
|
import type { DamageResult } from "./pokemon";
|
||||||
import type Pokemon from "./pokemon";
|
import type Pokemon from "./pokemon";
|
||||||
import { HitResult } from "./pokemon";
|
import { HitResult } from "./pokemon";
|
||||||
import { formatStat, fixedInt } from "#app/utils";
|
import { formatStat, fixedInt } from "#app/utils/common";
|
||||||
import type { BattlerIndex } from "../battle";
|
import type { BattlerIndex } from "../battle";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import type { GameObjects } from "phaser";
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
import type MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
|
||||||
import type { Species } from "#enums/species";
|
import type { Species } from "#enums/species";
|
||||||
import { isNullOrUndefined } from "#app/utils";
|
import { isNullOrUndefined } from "#app/utils/common";
|
||||||
import { getSpriteKeysFromSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
import { getSpriteKeysFromSpecies } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
|
||||||
import type { Variant } from "#app/sprites/variant";
|
import type { Variant } from "#app/sprites/variant";
|
||||||
import { doShinySparkleAnim } from "#app/field/anims";
|
import { doShinySparkleAnim } from "#app/field/anims";
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import Pokemon from "./pokemon";
|
import Pokemon from "./pokemon";
|
||||||
import { fixedInt, randInt } from "#app/utils";
|
import { fixedInt, randInt } from "#app/utils/common";
|
||||||
|
|
||||||
export default class PokemonSpriteSparkleHandler {
|
export default class PokemonSpriteSparkleHandler {
|
||||||
private sprites: Set<Phaser.GameObjects.Sprite>;
|
private sprites: Set<Phaser.GameObjects.Sprite>;
|
||||||
|
@ -12,7 +12,6 @@ import BattleInfo, {
|
|||||||
import type Move from "#app/data/moves/move";
|
import type Move from "#app/data/moves/move";
|
||||||
import {
|
import {
|
||||||
HighCritAttr,
|
HighCritAttr,
|
||||||
StatChangeBeforeDmgCalcAttr,
|
|
||||||
HitsTagAttr,
|
HitsTagAttr,
|
||||||
applyMoveAttrs,
|
applyMoveAttrs,
|
||||||
FixedDamageAttr,
|
FixedDamageAttr,
|
||||||
@ -55,7 +54,7 @@ import {
|
|||||||
getStarterValueFriendshipCap,
|
getStarterValueFriendshipCap,
|
||||||
speciesStarterCosts,
|
speciesStarterCosts,
|
||||||
} from "#app/data/balance/starters";
|
} from "#app/data/balance/starters";
|
||||||
import { NumberHolder, randSeedInt, getIvsFromId, BooleanHolder, randSeedItem, isNullOrUndefined, getEnumValues, toDmgValue, fixedInt, rgbaToInt, rgbHexToRgba, rgbToHsv, deltaRgb, isBetween, type nil, type Constructor } from "#app/utils";
|
import { NumberHolder, randSeedInt, getIvsFromId, BooleanHolder, randSeedItem, isNullOrUndefined, getEnumValues, toDmgValue, fixedInt, rgbaToInt, rgbHexToRgba, rgbToHsv, deltaRgb, isBetween, type nil, type Constructor } from "#app/utils/common";
|
||||||
import type { TypeDamageMultiplier } from "#app/data/type";
|
import type { TypeDamageMultiplier } from "#app/data/type";
|
||||||
import { getTypeDamageMultiplier, getTypeRgb } from "#app/data/type";
|
import { getTypeDamageMultiplier, getTypeRgb } from "#app/data/type";
|
||||||
import { PokemonType } from "#enums/pokemon-type";
|
import { PokemonType } from "#enums/pokemon-type";
|
||||||
@ -70,10 +69,8 @@ import {
|
|||||||
EFFECTIVE_STATS,
|
EFFECTIVE_STATS,
|
||||||
} from "#enums/stat";
|
} from "#enums/stat";
|
||||||
import {
|
import {
|
||||||
DamageMoneyRewardModifier,
|
|
||||||
EnemyDamageBoosterModifier,
|
EnemyDamageBoosterModifier,
|
||||||
EnemyDamageReducerModifier,
|
EnemyDamageReducerModifier,
|
||||||
EnemyEndureChanceModifier,
|
|
||||||
EnemyFusionChanceModifier,
|
EnemyFusionChanceModifier,
|
||||||
HiddenAbilityRateBoosterModifier,
|
HiddenAbilityRateBoosterModifier,
|
||||||
BaseStatModifier,
|
BaseStatModifier,
|
||||||
@ -119,7 +116,6 @@ import {
|
|||||||
TypeImmuneTag,
|
TypeImmuneTag,
|
||||||
getBattlerTag,
|
getBattlerTag,
|
||||||
SemiInvulnerableTag,
|
SemiInvulnerableTag,
|
||||||
TypeBoostTag,
|
|
||||||
MoveRestrictionBattlerTag,
|
MoveRestrictionBattlerTag,
|
||||||
ExposedTag,
|
ExposedTag,
|
||||||
DragonCheerTag,
|
DragonCheerTag,
|
||||||
@ -188,12 +184,12 @@ import {
|
|||||||
PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr,
|
PreLeaveFieldRemoveSuppressAbilitiesSourceAbAttr,
|
||||||
applyAllyStatMultiplierAbAttrs,
|
applyAllyStatMultiplierAbAttrs,
|
||||||
AllyStatMultiplierAbAttr,
|
AllyStatMultiplierAbAttr,
|
||||||
MoveAbilityBypassAbAttr
|
MoveAbilityBypassAbAttr,
|
||||||
} from "#app/data/abilities/ability";
|
} from "#app/data/abilities/ability";
|
||||||
import { allAbilities } from "#app/data/data-lists";
|
import { allAbilities } from "#app/data/data-lists";
|
||||||
import type PokemonData from "#app/system/pokemon-data";
|
import type PokemonData from "#app/system/pokemon-data";
|
||||||
import { BattlerIndex } from "#app/battle";
|
import { BattlerIndex } from "#app/battle";
|
||||||
import { Mode } from "#app/ui/ui";
|
import { UiMode } from "#enums/ui-mode";
|
||||||
import type { PartyOption } from "#app/ui/party-ui-handler";
|
import type { PartyOption } from "#app/ui/party-ui-handler";
|
||||||
import PartyUiHandler, { PartyUiMode } from "#app/ui/party-ui-handler";
|
import PartyUiHandler, { PartyUiMode } from "#app/ui/party-ui-handler";
|
||||||
import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
|
import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
|
||||||
@ -202,7 +198,7 @@ import {
|
|||||||
EVOLVE_MOVE,
|
EVOLVE_MOVE,
|
||||||
RELEARN_MOVE,
|
RELEARN_MOVE,
|
||||||
} from "#app/data/balance/pokemon-level-moves";
|
} from "#app/data/balance/pokemon-level-moves";
|
||||||
import { DamageAchv, achvs } from "#app/system/achv";
|
import { achvs } from "#app/system/achv";
|
||||||
import type { StarterDataEntry, StarterMoveset } from "#app/system/game-data";
|
import type { StarterDataEntry, StarterMoveset } from "#app/system/game-data";
|
||||||
import { DexAttr } from "#app/system/game-data";
|
import { DexAttr } from "#app/system/game-data";
|
||||||
import {
|
import {
|
||||||
@ -248,6 +244,7 @@ import { PLAYER_PARTY_MAX_SIZE } from "#app/constants";
|
|||||||
import { CustomPokemonData } from "#app/data/custom-pokemon-data";
|
import { CustomPokemonData } from "#app/data/custom-pokemon-data";
|
||||||
import { SwitchType } from "#enums/switch-type";
|
import { SwitchType } from "#enums/switch-type";
|
||||||
import { SpeciesFormKey } from "#enums/species-form-key";
|
import { SpeciesFormKey } from "#enums/species-form-key";
|
||||||
|
import { getStatusEffectOverlapText } from "#app/data/status-effect";
|
||||||
import {
|
import {
|
||||||
BASE_HIDDEN_ABILITY_CHANCE,
|
BASE_HIDDEN_ABILITY_CHANCE,
|
||||||
BASE_SHINY_CHANCE,
|
BASE_SHINY_CHANCE,
|
||||||
@ -278,6 +275,36 @@ export enum FieldPosition {
|
|||||||
RIGHT,
|
RIGHT,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Base typeclass for damage parameter methods, used for DRY */
|
||||||
|
type damageParams = {
|
||||||
|
/** The attacking {@linkcode Pokemon} */
|
||||||
|
source: Pokemon;
|
||||||
|
/** The move used in the attack */
|
||||||
|
move: Move;
|
||||||
|
/** The move's {@linkcode MoveCategory} after variable-category effects are applied */
|
||||||
|
moveCategory: MoveCategory;
|
||||||
|
/** If `true`, ignores this Pokemon's defensive ability effects */
|
||||||
|
ignoreAbility?: boolean;
|
||||||
|
/** If `true`, ignores the attacking Pokemon's ability effects */
|
||||||
|
ignoreSourceAbility?: boolean;
|
||||||
|
/** If `true`, ignores the ally Pokemon's ability effects */
|
||||||
|
ignoreAllyAbility?: boolean;
|
||||||
|
/** If `true`, ignores the ability effects of the attacking pokemon's ally */
|
||||||
|
ignoreSourceAllyAbility?: boolean;
|
||||||
|
/** If `true`, calculates damage for a critical hit */
|
||||||
|
isCritical?: boolean;
|
||||||
|
/** If `true`, suppresses changes to game state during the calculation */
|
||||||
|
simulated?: boolean;
|
||||||
|
/** If defined, used in place of calculated effectiveness values */
|
||||||
|
effectiveness?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Type for the parameters of {@linkcode Pokemon#getBaseDamage | getBaseDamage} */
|
||||||
|
type getBaseDamageParams = Omit<damageParams, "effectiveness">
|
||||||
|
|
||||||
|
/** Type for the parameters of {@linkcode Pokemon#getAttackDamage | getAttackDamage} */
|
||||||
|
type getAttackDamageParams = Omit<damageParams, "moveCategory">;
|
||||||
|
|
||||||
export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||||
public id: number;
|
public id: number;
|
||||||
public name: string;
|
public name: string;
|
||||||
@ -1112,7 +1139,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
*/
|
*/
|
||||||
getSpeciesForm(ignoreOverride?: boolean, useIllusion: boolean = false): PokemonSpeciesForm {
|
getSpeciesForm(ignoreOverride?: boolean, useIllusion: boolean = false): PokemonSpeciesForm {
|
||||||
const species: PokemonSpecies = useIllusion && !!this.summonData?.illusion ? getPokemonSpecies(this.summonData?.illusion.species) : this.species;
|
const species: PokemonSpecies = useIllusion && !!this.summonData?.illusion ? getPokemonSpecies(this.summonData?.illusion.species) : this.species;
|
||||||
|
|
||||||
const formIndex: integer = useIllusion && !!this.summonData?.illusion ? this.summonData?.illusion.formIndex : this.formIndex;
|
const formIndex: integer = useIllusion && !!this.summonData?.illusion ? this.summonData?.illusion.formIndex : this.formIndex;
|
||||||
|
|
||||||
if (!ignoreOverride && this.summonData?.speciesForm) {
|
if (!ignoreOverride && this.summonData?.speciesForm) {
|
||||||
@ -1447,25 +1473,16 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
* Calculate the critical-hit stage of a move used against this pokemon by
|
* Calculate the critical-hit stage of a move used against this pokemon by
|
||||||
* the given source
|
* the given source
|
||||||
*
|
*
|
||||||
* @param source the {@linkcode Pokemon} who using the move
|
* @param source - The {@linkcode Pokemon} who using the move
|
||||||
* @param move the {@linkcode Move} being used
|
* @param move - The {@linkcode Move} being used
|
||||||
* @returns the final critical-hit stage value
|
* @returns The final critical-hit stage value
|
||||||
*/
|
*/
|
||||||
getCritStage(source: Pokemon, move: Move): number {
|
getCritStage(source: Pokemon, move: Move): number {
|
||||||
const critStage = new NumberHolder(0);
|
const critStage = new NumberHolder(0);
|
||||||
applyMoveAttrs(HighCritAttr, source, this, move, critStage);
|
applyMoveAttrs(HighCritAttr, source, this, move, critStage);
|
||||||
globalScene.applyModifiers(
|
globalScene.applyModifiers(CritBoosterModifier, source.isPlayer(), source, critStage);
|
||||||
CritBoosterModifier,
|
globalScene.applyModifiers(TempCritBoosterModifier, source.isPlayer(), critStage);
|
||||||
source.isPlayer(),
|
applyAbAttrs(BonusCritAbAttr, source, null, false, critStage);
|
||||||
source,
|
|
||||||
critStage,
|
|
||||||
);
|
|
||||||
globalScene.applyModifiers(
|
|
||||||
TempCritBoosterModifier,
|
|
||||||
source.isPlayer(),
|
|
||||||
critStage,
|
|
||||||
);
|
|
||||||
applyAbAttrs(BonusCritAbAttr, source, null, false, critStage)
|
|
||||||
const critBoostTag = source.getTag(CritBoostTag);
|
const critBoostTag = source.getTag(CritBoostTag);
|
||||||
if (critBoostTag) {
|
if (critBoostTag) {
|
||||||
if (critBoostTag instanceof DragonCheerTag) {
|
if (critBoostTag instanceof DragonCheerTag) {
|
||||||
@ -1481,6 +1498,19 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
return critStage.value;
|
return critStage.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the category of a move when used by this pokemon after
|
||||||
|
* category-changing move effects are applied.
|
||||||
|
* @param target - The {@linkcode Pokemon} using the move
|
||||||
|
* @param move - The {@linkcode Move} being used
|
||||||
|
* @returns The given move's final category
|
||||||
|
*/
|
||||||
|
getMoveCategory(target: Pokemon, move: Move): MoveCategory {
|
||||||
|
const moveCategory = new NumberHolder(move.category);
|
||||||
|
applyMoveAttrs(VariableMoveCategoryAttr, this, target, move, moveCategory);
|
||||||
|
return moveCategory.value;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates and retrieves the final value of a stat considering any held
|
* Calculates and retrieves the final value of a stat considering any held
|
||||||
* items, move effects, opponent abilities, and whether there was a critical
|
* items, move effects, opponent abilities, and whether there was a critical
|
||||||
@ -2590,7 +2620,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
* @param simulated Whether to apply abilities via simulated calls (defaults to `true`)
|
* @param simulated Whether to apply abilities via simulated calls (defaults to `true`)
|
||||||
* @param cancelled {@linkcode BooleanHolder} Stores whether the move was cancelled by a non-type-based immunity.
|
* @param cancelled {@linkcode BooleanHolder} Stores whether the move was cancelled by a non-type-based immunity.
|
||||||
* @param useIllusion - Whether we want the attack move effectiveness on the illusion or not
|
* @param useIllusion - Whether we want the attack move effectiveness on the illusion or not
|
||||||
* Currently only used by {@linkcode Pokemon.apply} to determine whether a "No effect" message should be shown.
|
|
||||||
* @returns The type damage multiplier, indicating the effectiveness of the move
|
* @returns The type damage multiplier, indicating the effectiveness of the move
|
||||||
*/
|
*/
|
||||||
getMoveEffectiveness(
|
getMoveEffectiveness(
|
||||||
@ -3176,7 +3205,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
/**
|
/**
|
||||||
* Function that tries to set a Pokemon shiny based on seed.
|
* Function that tries to set a Pokemon shiny based on seed.
|
||||||
* For manual use only, usually to roll a Pokemon's shiny chance a second time.
|
* For manual use only, usually to roll a Pokemon's shiny chance a second time.
|
||||||
* If it rolls shiny, also sets a random variant and give the Pokemon the associated luck.
|
* If it rolls shiny, or if it's already shiny, also sets a random variant and give the Pokemon the associated luck.
|
||||||
*
|
*
|
||||||
* The base shiny odds are {@linkcode BASE_SHINY_CHANCE} / `65536`
|
* The base shiny odds are {@linkcode BASE_SHINY_CHANCE} / `65536`
|
||||||
* @param thresholdOverride number that is divided by `2^16` (`65536`) to get the shiny chance, overrides {@linkcode shinyThreshold} if set (bypassing shiny rate modifiers such as Shiny Charm)
|
* @param thresholdOverride number that is divided by `2^16` (`65536`) to get the shiny chance, overrides {@linkcode shinyThreshold} if set (bypassing shiny rate modifiers such as Shiny Charm)
|
||||||
@ -3187,29 +3216,31 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
thresholdOverride?: number,
|
thresholdOverride?: number,
|
||||||
applyModifiersToOverride?: boolean,
|
applyModifiersToOverride?: boolean,
|
||||||
): boolean {
|
): boolean {
|
||||||
const shinyThreshold = new NumberHolder(BASE_SHINY_CHANCE);
|
if (!this.shiny) {
|
||||||
if (thresholdOverride === undefined || applyModifiersToOverride) {
|
const shinyThreshold = new NumberHolder(BASE_SHINY_CHANCE);
|
||||||
if (thresholdOverride !== undefined && applyModifiersToOverride) {
|
if (thresholdOverride === undefined || applyModifiersToOverride) {
|
||||||
shinyThreshold.value = thresholdOverride;
|
if (thresholdOverride !== undefined && applyModifiersToOverride) {
|
||||||
}
|
shinyThreshold.value = thresholdOverride;
|
||||||
if (timedEventManager.isEventActive()) {
|
}
|
||||||
shinyThreshold.value *= timedEventManager.getShinyMultiplier();
|
if (timedEventManager.isEventActive()) {
|
||||||
}
|
shinyThreshold.value *= timedEventManager.getShinyMultiplier();
|
||||||
if (!this.hasTrainer()) {
|
}
|
||||||
globalScene.applyModifiers(
|
globalScene.applyModifiers(
|
||||||
ShinyRateBoosterModifier,
|
ShinyRateBoosterModifier,
|
||||||
true,
|
true,
|
||||||
shinyThreshold,
|
shinyThreshold,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
else {
|
||||||
shinyThreshold.value = thresholdOverride;
|
shinyThreshold.value = thresholdOverride;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.shiny = randSeedInt(65536) < shinyThreshold.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.shiny = randSeedInt(65536) < shinyThreshold.value;
|
|
||||||
|
|
||||||
if (this.shiny) {
|
if (this.shiny) {
|
||||||
this.variant = this.generateShinyVariant();
|
this.variant = this.variant ?? 0;
|
||||||
|
this.variant = Math.max(this.generateShinyVariant(), this.variant) as Variant; // Don't set a variant lower than the current one
|
||||||
this.luck =
|
this.luck =
|
||||||
this.variant + 1 + (this.fusionShiny ? this.fusionVariant + 1 : 0);
|
this.variant + 1 + (this.fusionShiny ? this.fusionVariant + 1 : 0);
|
||||||
this.initShinySparkle();
|
this.initShinySparkle();
|
||||||
@ -3858,12 +3889,17 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
getOpponents(): Pokemon[] {
|
/**
|
||||||
|
* Returns the pokemon that oppose this one and are active
|
||||||
|
*
|
||||||
|
* @param onField - whether to also check if the pokemon is currently on the field (defaults to true)
|
||||||
|
*/
|
||||||
|
getOpponents(onField = true): Pokemon[] {
|
||||||
return (
|
return (
|
||||||
(this.isPlayer()
|
(this.isPlayer()
|
||||||
? globalScene.getEnemyField()
|
? globalScene.getEnemyField()
|
||||||
: globalScene.getPlayerField()) as Pokemon[]
|
: globalScene.getPlayerField()) as Pokemon[]
|
||||||
).filter(p => p.isActive());
|
).filter(p => p.isActive(onField));
|
||||||
}
|
}
|
||||||
|
|
||||||
getOpponentDescriptor(): string {
|
getOpponentDescriptor(): string {
|
||||||
@ -4074,27 +4110,28 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
/**
|
/**
|
||||||
* Calculates the base damage of the given move against this Pokemon when attacked by the given source.
|
* Calculates the base damage of the given move against this Pokemon when attacked by the given source.
|
||||||
* Used during damage calculation and for Shell Side Arm's forecasting effect.
|
* Used during damage calculation and for Shell Side Arm's forecasting effect.
|
||||||
* @param source the attacking {@linkcode Pokemon}.
|
* @param source - The attacking {@linkcode Pokemon}.
|
||||||
* @param move the {@linkcode Move} used in the attack.
|
* @param move - The {@linkcode Move} used in the attack.
|
||||||
* @param moveCategory the move's {@linkcode MoveCategory} after variable-category effects are applied.
|
* @param moveCategory - The move's {@linkcode MoveCategory} after variable-category effects are applied.
|
||||||
* @param ignoreAbility if `true`, ignores this Pokemon's defensive ability effects (defaults to `false`).
|
* @param ignoreAbility - If `true`, ignores this Pokemon's defensive ability effects (defaults to `false`).
|
||||||
* @param ignoreSourceAbility if `true`, ignore's the attacking Pokemon's ability effects (defaults to `false`).
|
* @param ignoreSourceAbility - If `true`, ignore's the attacking Pokemon's ability effects (defaults to `false`).
|
||||||
* @param ignoreAllyAbility if `true`, ignores the ally Pokemon's ability effects (defaults to `false`).
|
* @param ignoreAllyAbility - If `true`, ignores the ally Pokemon's ability effects (defaults to `false`).
|
||||||
* @param ignoreSourceAllyAbility if `true`, ignores the attacking Pokemon's ally's ability effects (defaults to `false`).
|
* @param ignoreSourceAllyAbility - If `true`, ignores the attacking Pokemon's ally's ability effects (defaults to `false`).
|
||||||
* @param isCritical if `true`, calculates effective stats as if the hit were critical (defaults to `false`).
|
* @param isCritical - if `true`, calculates effective stats as if the hit were critical (defaults to `false`).
|
||||||
* @param simulated if `true`, suppresses changes to game state during calculation (defaults to `true`).
|
* @param simulated - if `true`, suppresses changes to game state during calculation (defaults to `true`).
|
||||||
* @returns The move's base damage against this Pokemon when used by the source Pokemon.
|
* @returns The move's base damage against this Pokemon when used by the source Pokemon.
|
||||||
*/
|
*/
|
||||||
getBaseDamage(
|
getBaseDamage(
|
||||||
source: Pokemon,
|
{
|
||||||
move: Move,
|
source,
|
||||||
moveCategory: MoveCategory,
|
move,
|
||||||
|
moveCategory,
|
||||||
ignoreAbility = false,
|
ignoreAbility = false,
|
||||||
ignoreSourceAbility = false,
|
ignoreSourceAbility = false,
|
||||||
ignoreAllyAbility = false,
|
ignoreAllyAbility = false,
|
||||||
ignoreSourceAllyAbility = false,
|
ignoreSourceAllyAbility = false,
|
||||||
isCritical = false,
|
isCritical = false,
|
||||||
simulated = true,
|
simulated = true}: getBaseDamageParams
|
||||||
): number {
|
): number {
|
||||||
const isPhysical = moveCategory === MoveCategory.PHYSICAL;
|
const isPhysical = moveCategory === MoveCategory.PHYSICAL;
|
||||||
|
|
||||||
@ -4221,27 +4258,27 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
/**
|
/**
|
||||||
* Calculates the damage of an attack made by another Pokemon against this Pokemon
|
* Calculates the damage of an attack made by another Pokemon against this Pokemon
|
||||||
* @param source {@linkcode Pokemon} the attacking Pokemon
|
* @param source {@linkcode Pokemon} the attacking Pokemon
|
||||||
* @param move {@linkcode Pokemon} the move used in the attack
|
* @param move The {@linkcode Move} used in the attack
|
||||||
* @param ignoreAbility If `true`, ignores this Pokemon's defensive ability effects
|
* @param ignoreAbility If `true`, ignores this Pokemon's defensive ability effects
|
||||||
* @param ignoreSourceAbility If `true`, ignores the attacking Pokemon's ability effects
|
* @param ignoreSourceAbility If `true`, ignores the attacking Pokemon's ability effects
|
||||||
* @param ignoreAllyAbility If `true`, ignores the ally Pokemon's ability effects
|
* @param ignoreAllyAbility If `true`, ignores the ally Pokemon's ability effects
|
||||||
* @param ignoreSourceAllyAbility If `true`, ignores the ability effects of the attacking pokemon's ally
|
* @param ignoreSourceAllyAbility If `true`, ignores the ability effects of the attacking pokemon's ally
|
||||||
* @param isCritical If `true`, calculates damage for a critical hit.
|
* @param isCritical If `true`, calculates damage for a critical hit.
|
||||||
* @param simulated If `true`, suppresses changes to game state during the calculation.
|
* @param simulated If `true`, suppresses changes to game state during the calculation.
|
||||||
* @returns a {@linkcode DamageCalculationResult} object with three fields:
|
* @param effectiveness If defined, used in place of calculated effectiveness values
|
||||||
* - `cancelled`: `true` if the move was cancelled by another effect.
|
* @returns The {@linkcode DamageCalculationResult}
|
||||||
* - `result`: {@linkcode HitResult} indicates the attack's type effectiveness.
|
|
||||||
* - `damage`: `number` the attack's final damage output.
|
|
||||||
*/
|
*/
|
||||||
getAttackDamage(
|
getAttackDamage(
|
||||||
source: Pokemon,
|
{
|
||||||
move: Move,
|
source,
|
||||||
ignoreAbility = false,
|
move,
|
||||||
ignoreSourceAbility = false,
|
ignoreAbility = false,
|
||||||
ignoreAllyAbility = false,
|
ignoreSourceAbility = false,
|
||||||
ignoreSourceAllyAbility = false,
|
ignoreAllyAbility = false,
|
||||||
isCritical = false,
|
ignoreSourceAllyAbility = false,
|
||||||
simulated = true,
|
isCritical = false,
|
||||||
|
simulated = true,
|
||||||
|
effectiveness}: getAttackDamageParams,
|
||||||
): DamageCalculationResult {
|
): DamageCalculationResult {
|
||||||
const damage = new NumberHolder(0);
|
const damage = new NumberHolder(0);
|
||||||
const defendingSide = this.isPlayer()
|
const defendingSide = this.isPlayer()
|
||||||
@ -4271,7 +4308,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
*
|
*
|
||||||
* Note that the source's abilities are not ignored here
|
* Note that the source's abilities are not ignored here
|
||||||
*/
|
*/
|
||||||
const typeMultiplier = this.getMoveEffectiveness(
|
const typeMultiplier = effectiveness ?? this.getMoveEffectiveness(
|
||||||
source,
|
source,
|
||||||
move,
|
move,
|
||||||
ignoreAbility,
|
ignoreAbility,
|
||||||
@ -4343,7 +4380,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
* The attack's base damage, as determined by the source's level, move power
|
* The attack's base damage, as determined by the source's level, move power
|
||||||
* and Attack stat as well as this Pokemon's Defense stat
|
* and Attack stat as well as this Pokemon's Defense stat
|
||||||
*/
|
*/
|
||||||
const baseDamage = this.getBaseDamage(
|
const baseDamage = this.getBaseDamage({
|
||||||
source,
|
source,
|
||||||
move,
|
move,
|
||||||
moveCategory,
|
moveCategory,
|
||||||
@ -4353,7 +4390,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
ignoreSourceAllyAbility,
|
ignoreSourceAllyAbility,
|
||||||
isCritical,
|
isCritical,
|
||||||
simulated,
|
simulated,
|
||||||
);
|
});
|
||||||
|
|
||||||
/** 25% damage debuff on moves hitting more than one non-fainted target (regardless of immunities) */
|
/** 25% damage debuff on moves hitting more than one non-fainted target (regardless of immunities) */
|
||||||
const { targets, multiple } = getMoveTargets(source, move.id);
|
const { targets, multiple } = getMoveTargets(source, move.id);
|
||||||
@ -4564,211 +4601,36 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Calculate whether the given move critically hits this pokemon
|
||||||
* Applies the results of a move to this pokemon
|
* @param source - The {@linkcode Pokemon} using the move
|
||||||
* @param source The {@linkcode Pokemon} using the move
|
* @param move - The {@linkcode Move} being used
|
||||||
* @param move The {@linkcode Move} being used
|
* @param simulated - If `true`, suppresses changes to game state during calculation (defaults to `true`)
|
||||||
* @returns The {@linkcode HitResult} of the attack
|
* @returns whether the move critically hits the pokemon
|
||||||
*/
|
*/
|
||||||
apply(source: Pokemon, move: Move): HitResult {
|
getCriticalHitResult(source: Pokemon, move: Move, simulated: boolean = true): boolean {
|
||||||
const defendingSide = this.isPlayer()
|
const defendingSide = this.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
|
||||||
? ArenaTagSide.PLAYER
|
const noCritTag = globalScene.arena.getTagOnSide(NoCritTag, defendingSide);
|
||||||
: ArenaTagSide.ENEMY;
|
if (noCritTag || Overrides.NEVER_CRIT_OVERRIDE || move.hasAttr(FixedDamageAttr)) {
|
||||||
const moveCategory = new NumberHolder(move.category);
|
return false;
|
||||||
applyMoveAttrs(VariableMoveCategoryAttr, source, this, move, moveCategory);
|
|
||||||
if (moveCategory.value === MoveCategory.STATUS) {
|
|
||||||
const cancelled = new BooleanHolder(false);
|
|
||||||
const typeMultiplier = this.getMoveEffectiveness(
|
|
||||||
source,
|
|
||||||
move,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
cancelled,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!cancelled.value && typeMultiplier === 0) {
|
|
||||||
globalScene.queueMessage(
|
|
||||||
i18next.t("battle:hitResultNoEffect", {
|
|
||||||
pokemonName: getPokemonNameWithAffix(this),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return typeMultiplier === 0 ? HitResult.NO_EFFECT : HitResult.STATUS;
|
|
||||||
}
|
}
|
||||||
/** Determines whether the attack critically hits */
|
const isCritical = new BooleanHolder(false);
|
||||||
let isCritical: boolean;
|
|
||||||
const critOnly = new BooleanHolder(false);
|
if (source.getTag(BattlerTagType.ALWAYS_CRIT)) {
|
||||||
const critAlways = source.getTag(BattlerTagType.ALWAYS_CRIT);
|
isCritical.value = true;
|
||||||
applyMoveAttrs(CritOnlyAttr, source, this, move, critOnly);
|
}
|
||||||
applyAbAttrs(
|
applyMoveAttrs(CritOnlyAttr, source, this, move, isCritical);
|
||||||
ConditionalCritAbAttr,
|
applyAbAttrs(ConditionalCritAbAttr, source, null, simulated, isCritical, this, move);
|
||||||
source,
|
if (!isCritical.value) {
|
||||||
null,
|
|
||||||
false,
|
|
||||||
critOnly,
|
|
||||||
this,
|
|
||||||
move,
|
|
||||||
);
|
|
||||||
if (critOnly.value || critAlways) {
|
|
||||||
isCritical = true;
|
|
||||||
} else {
|
|
||||||
const critChance = [24, 8, 2, 1][
|
const critChance = [24, 8, 2, 1][
|
||||||
Math.max(0, Math.min(this.getCritStage(source, move), 3))
|
Math.max(0, Math.min(this.getCritStage(source, move), 3))
|
||||||
];
|
];
|
||||||
isCritical =
|
isCritical.value = critChance === 1 || !globalScene.randBattleSeedInt(critChance);
|
||||||
critChance === 1 || !globalScene.randBattleSeedInt(critChance);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const noCritTag = globalScene.arena.getTagOnSide(NoCritTag, defendingSide);
|
applyAbAttrs(BlockCritAbAttr, this, null, simulated, isCritical);
|
||||||
const blockCrit = new BooleanHolder(false);
|
|
||||||
applyAbAttrs(BlockCritAbAttr, this, null, false, blockCrit);
|
|
||||||
if (noCritTag || blockCrit.value || Overrides.NEVER_CRIT_OVERRIDE) {
|
|
||||||
isCritical = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
return isCritical.value;
|
||||||
* Applies stat changes from {@linkcode move} and gives it to {@linkcode source}
|
|
||||||
* before damage calculation
|
|
||||||
*/
|
|
||||||
applyMoveAttrs(StatChangeBeforeDmgCalcAttr, source, this, move);
|
|
||||||
|
|
||||||
const {
|
|
||||||
cancelled,
|
|
||||||
result,
|
|
||||||
damage: dmg,
|
|
||||||
} = this.getAttackDamage(source, move, false, false, false, false, isCritical, false);
|
|
||||||
|
|
||||||
const typeBoost = source.findTag(
|
|
||||||
t =>
|
|
||||||
t instanceof TypeBoostTag && t.boostedType === source.getMoveType(move),
|
|
||||||
) as TypeBoostTag;
|
|
||||||
if (typeBoost?.oneUse) {
|
|
||||||
source.removeTag(typeBoost.tagType);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
cancelled ||
|
|
||||||
result === HitResult.IMMUNE ||
|
|
||||||
result === HitResult.NO_EFFECT
|
|
||||||
) {
|
|
||||||
source.stopMultiHit(this);
|
|
||||||
|
|
||||||
if (!cancelled) {
|
|
||||||
if (result === HitResult.IMMUNE) {
|
|
||||||
globalScene.queueMessage(
|
|
||||||
i18next.t("battle:hitResultImmune", {
|
|
||||||
pokemonName: getPokemonNameWithAffix(this),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
globalScene.queueMessage(
|
|
||||||
i18next.t("battle:hitResultNoEffect", {
|
|
||||||
pokemonName: getPokemonNameWithAffix(this),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// In case of fatal damage, this tag would have gotten cleared before we could lapse it.
|
|
||||||
const destinyTag = this.getTag(BattlerTagType.DESTINY_BOND);
|
|
||||||
const grudgeTag = this.getTag(BattlerTagType.GRUDGE);
|
|
||||||
|
|
||||||
if (dmg) {
|
|
||||||
this.lapseTags(BattlerTagLapseType.HIT);
|
|
||||||
|
|
||||||
const substitute = this.getTag(SubstituteTag);
|
|
||||||
const isBlockedBySubstitute =
|
|
||||||
!!substitute && move.hitsSubstitute(source, this);
|
|
||||||
if (isBlockedBySubstitute) {
|
|
||||||
substitute.hp -= dmg;
|
|
||||||
}
|
|
||||||
if (!this.isPlayer() && dmg >= this.hp) {
|
|
||||||
globalScene.applyModifiers(EnemyEndureChanceModifier, false, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We explicitly require to ignore the faint phase here, as we want to show the messages
|
|
||||||
* about the critical hit and the super effective/not very effective messages before the faint phase.
|
|
||||||
*/
|
|
||||||
const damage = this.damageAndUpdate(isBlockedBySubstitute ? 0 : dmg,
|
|
||||||
{
|
|
||||||
result: result as DamageResult,
|
|
||||||
isCritical,
|
|
||||||
ignoreFaintPhase: true,
|
|
||||||
source
|
|
||||||
});
|
|
||||||
|
|
||||||
if (damage > 0) {
|
|
||||||
if (source.isPlayer()) {
|
|
||||||
globalScene.validateAchvs(DamageAchv, new NumberHolder(damage));
|
|
||||||
if (damage > globalScene.gameData.gameStats.highestDamage) {
|
|
||||||
globalScene.gameData.gameStats.highestDamage = damage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
source.turnData.totalDamageDealt += damage;
|
|
||||||
source.turnData.singleHitDamageDealt = damage;
|
|
||||||
this.turnData.damageTaken += damage;
|
|
||||||
this.battleData.hitCount++;
|
|
||||||
|
|
||||||
const attackResult = {
|
|
||||||
move: move.id,
|
|
||||||
result: result as DamageResult,
|
|
||||||
damage: damage,
|
|
||||||
critical: isCritical,
|
|
||||||
sourceId: source.id,
|
|
||||||
sourceBattlerIndex: source.getBattlerIndex(),
|
|
||||||
};
|
|
||||||
this.turnData.attacksReceived.unshift(attackResult);
|
|
||||||
if (source.isPlayer() && !this.isPlayer()) {
|
|
||||||
globalScene.applyModifiers(
|
|
||||||
DamageMoneyRewardModifier,
|
|
||||||
true,
|
|
||||||
source,
|
|
||||||
new NumberHolder(damage),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isCritical) {
|
|
||||||
globalScene.queueMessage(i18next.t("battle:hitResultCriticalHit"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// want to include is.Fainted() in case multi hit move ends early, still want to render message
|
|
||||||
if (source.turnData.hitsLeft === 1 || this.isFainted()) {
|
|
||||||
switch (result) {
|
|
||||||
case HitResult.SUPER_EFFECTIVE:
|
|
||||||
globalScene.queueMessage(i18next.t("battle:hitResultSuperEffective"));
|
|
||||||
break;
|
|
||||||
case HitResult.NOT_VERY_EFFECTIVE:
|
|
||||||
globalScene.queueMessage(
|
|
||||||
i18next.t("battle:hitResultNotVeryEffective"),
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case HitResult.ONE_HIT_KO:
|
|
||||||
globalScene.queueMessage(i18next.t("battle:hitResultOneHitKO"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isFainted()) {
|
|
||||||
// set splice index here, so future scene queues happen before FaintedPhase
|
|
||||||
globalScene.setPhaseQueueSplice();
|
|
||||||
globalScene.unshiftPhase(
|
|
||||||
new FaintPhase(
|
|
||||||
this.getBattlerIndex(),
|
|
||||||
false,
|
|
||||||
source,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
this.destroySubstitute();
|
|
||||||
this.lapseTag(BattlerTagType.COMMANDED);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -4832,7 +4694,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by apply(), given the damage, adds a new DamagePhase and actually updates HP values, etc.
|
* Given the damage, adds a new DamagePhase and update HP values, etc.
|
||||||
|
*
|
||||||
* Checks for 'Indirect' HitResults to account for Endure/Reviver Seed applying correctly
|
* Checks for 'Indirect' HitResults to account for Endure/Reviver Seed applying correctly
|
||||||
* @param damage integer - passed to damage()
|
* @param damage integer - passed to damage()
|
||||||
* @param result an enum if it's super effective, not very, etc.
|
* @param result an enum if it's super effective, not very, etc.
|
||||||
@ -5135,8 +4998,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
/**
|
/**
|
||||||
* Gets whether the given move is currently disabled for this Pokemon.
|
* Gets whether the given move is currently disabled for this Pokemon.
|
||||||
*
|
*
|
||||||
* @param {Moves} moveId {@linkcode Moves} ID of the move to check
|
* @param moveId - The {@linkcode Moves} ID of the move to check
|
||||||
* @returns {boolean} `true` if the move is disabled for this Pokemon, otherwise `false`
|
* @returns `true` if the move is disabled for this Pokemon, otherwise `false`
|
||||||
*
|
*
|
||||||
* @see {@linkcode MoveRestrictionBattlerTag}
|
* @see {@linkcode MoveRestrictionBattlerTag}
|
||||||
*/
|
*/
|
||||||
@ -5147,9 +5010,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
/**
|
/**
|
||||||
* Gets whether the given move is currently disabled for the user based on the player's target selection
|
* Gets whether the given move is currently disabled for the user based on the player's target selection
|
||||||
*
|
*
|
||||||
* @param {Moves} moveId {@linkcode Moves} ID of the move to check
|
* @param moveId - The {@linkcode Moves} ID of the move to check
|
||||||
* @param {Pokemon} user {@linkcode Pokemon} the move user
|
* @param user - The move user
|
||||||
* @param {Pokemon} target {@linkcode Pokemon} the target of the move
|
* @param target - The target of the move
|
||||||
*
|
*
|
||||||
* @returns {boolean} `true` if the move is disabled for this Pokemon due to the player's target selection
|
* @returns {boolean} `true` if the move is disabled for this Pokemon due to the player's target selection
|
||||||
*
|
*
|
||||||
@ -5179,10 +5042,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
/**
|
/**
|
||||||
* Gets the {@link MoveRestrictionBattlerTag} that is restricting a move, if it exists.
|
* Gets the {@link MoveRestrictionBattlerTag} that is restricting a move, if it exists.
|
||||||
*
|
*
|
||||||
* @param {Moves} moveId {@linkcode Moves} ID of the move to check
|
* @param moveId - {@linkcode Moves} ID of the move to check
|
||||||
* @param {Pokemon} user {@linkcode Pokemon} the move user, optional and used when the target is a factor in the move's restricted status
|
* @param user - {@linkcode Pokemon} the move user, optional and used when the target is a factor in the move's restricted status
|
||||||
* @param {Pokemon} target {@linkcode Pokemon} the target of the move, optional and used when the target is a factor in the move's restricted status
|
* @param target - {@linkcode Pokemon} the target of the move, optional and used when the target is a factor in the move's restricted status
|
||||||
* @returns {MoveRestrictionBattlerTag | null} the first tag on this Pokemon that restricts the move, or `null` if the move is not restricted.
|
* @returns The first tag on this Pokemon that restricts the move, or `null` if the move is not restricted.
|
||||||
*/
|
*/
|
||||||
getRestrictingTag(
|
getRestrictingTag(
|
||||||
moveId: Moves,
|
moveId: Moves,
|
||||||
@ -5244,20 +5107,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
return this.summonData.moveQueue;
|
return this.summonData.moveQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* If this Pokemon is using a multi-hit move, cancels all subsequent strikes
|
|
||||||
* @param {Pokemon} target If specified, this only cancels subsequent strikes against the given target
|
|
||||||
*/
|
|
||||||
stopMultiHit(target?: Pokemon): void {
|
|
||||||
const effectPhase = globalScene.getCurrentPhase();
|
|
||||||
if (
|
|
||||||
effectPhase instanceof MoveEffectPhase &&
|
|
||||||
effectPhase.getUserPokemon() === this
|
|
||||||
) {
|
|
||||||
effectPhase.stopMultiHit(target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
changeForm(formChange: SpeciesFormChange): Promise<void> {
|
changeForm(formChange: SpeciesFormChange): Promise<void> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
this.formIndex = Math.max(
|
this.formIndex = Math.max(
|
||||||
@ -5287,13 +5136,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
sceneOverride?: BattleScene,
|
sceneOverride?: BattleScene,
|
||||||
): AnySound {
|
): AnySound {
|
||||||
const scene = sceneOverride ?? globalScene; // TODO: is `sceneOverride` needed?
|
const scene = sceneOverride ?? globalScene; // TODO: is `sceneOverride` needed?
|
||||||
const cry = this.getSpeciesForm().cry(soundConfig);
|
const cry = this.getSpeciesForm(undefined, true).cry(soundConfig);
|
||||||
let duration = cry.totalDuration * 1000;
|
let duration = cry.totalDuration * 1000;
|
||||||
if (
|
if (
|
||||||
this.fusionSpecies &&
|
this.fusionSpecies &&
|
||||||
this.getSpeciesForm() !== this.getFusionSpeciesForm()
|
this.getSpeciesForm(undefined, true) !== this.getFusionSpeciesForm(undefined, true)
|
||||||
) {
|
) {
|
||||||
let fusionCry = this.getFusionSpeciesForm().cry(soundConfig, true);
|
let fusionCry = this.getFusionSpeciesForm(undefined, true).cry(soundConfig, true);
|
||||||
duration = Math.min(duration, fusionCry.totalDuration * 1000);
|
duration = Math.min(duration, fusionCry.totalDuration * 1000);
|
||||||
fusionCry.destroy();
|
fusionCry.destroy();
|
||||||
scene.time.delayedCall(fixedInt(Math.ceil(duration * 0.4)), () => {
|
scene.time.delayedCall(fixedInt(Math.ceil(duration * 0.4)), () => {
|
||||||
@ -5303,7 +5152,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
cry,
|
cry,
|
||||||
fixedInt(Math.ceil(duration * 0.2)),
|
fixedInt(Math.ceil(duration * 0.2)),
|
||||||
);
|
);
|
||||||
fusionCry = this.getFusionSpeciesForm().cry(
|
fusionCry = this.getFusionSpeciesForm(undefined, true).cry(
|
||||||
Object.assign(
|
Object.assign(
|
||||||
{ seek: Math.max(fusionCry.totalDuration * 0.4, 0) },
|
{ seek: Math.max(fusionCry.totalDuration * 0.4, 0) },
|
||||||
soundConfig,
|
soundConfig,
|
||||||
@ -5517,6 +5366,18 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
queueImmuneMessage(quiet: boolean, effect?: StatusEffect): void {
|
||||||
|
if (!effect || quiet) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const message = effect && this.status?.effect === effect
|
||||||
|
? getStatusEffectOverlapText(effect ?? StatusEffect.NONE, getPokemonNameWithAffix(this))
|
||||||
|
: i18next.t("abilityTriggers:moveImmunity", {
|
||||||
|
pokemonNameWithAffix: getPokemonNameWithAffix(this),
|
||||||
|
});
|
||||||
|
globalScene.queueMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a status effect can be applied to the Pokemon.
|
* Checks if a status effect can be applied to the Pokemon.
|
||||||
*
|
*
|
||||||
@ -5535,6 +5396,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
): boolean {
|
): boolean {
|
||||||
if (effect !== StatusEffect.FAINT) {
|
if (effect !== StatusEffect.FAINT) {
|
||||||
if (overrideStatus ? this.status?.effect === effect : this.status) {
|
if (overrideStatus ? this.status?.effect === effect : this.status) {
|
||||||
|
this.queueImmuneMessage(quiet, effect);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
@ -5542,18 +5404,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
!ignoreField &&
|
!ignoreField &&
|
||||||
globalScene.arena.terrain?.terrainType === TerrainType.MISTY
|
globalScene.arena.terrain?.terrainType === TerrainType.MISTY
|
||||||
) {
|
) {
|
||||||
|
this.queueImmuneMessage(quiet, effect);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
|
||||||
sourcePokemon &&
|
|
||||||
sourcePokemon !== this &&
|
|
||||||
this.isSafeguarded(sourcePokemon)
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const types = this.getTypes(true, true);
|
const types = this.getTypes(true, true);
|
||||||
|
|
||||||
switch (effect) {
|
switch (effect) {
|
||||||
@ -5582,17 +5437,19 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.isOfType(PokemonType.POISON) || this.isOfType(PokemonType.STEEL)) {
|
if (this.isOfType(PokemonType.POISON) || this.isOfType(PokemonType.STEEL)) {
|
||||||
if (poisonImmunity.includes(true)) {
|
if (poisonImmunity.includes(true)) {
|
||||||
|
this.queueImmuneMessage(quiet, effect);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case StatusEffect.PARALYSIS:
|
case StatusEffect.PARALYSIS:
|
||||||
if (this.isOfType(PokemonType.ELECTRIC)) {
|
if (this.isOfType(PokemonType.ELECTRIC)) {
|
||||||
|
this.queueImmuneMessage(quiet, effect);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -5601,6 +5458,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
this.isGrounded() &&
|
this.isGrounded() &&
|
||||||
globalScene.arena.terrain?.terrainType === TerrainType.ELECTRIC
|
globalScene.arena.terrain?.terrainType === TerrainType.ELECTRIC
|
||||||
) {
|
) {
|
||||||
|
this.queueImmuneMessage(quiet, effect);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -5613,11 +5471,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
globalScene.arena.weather.weatherType,
|
globalScene.arena.weather.weatherType,
|
||||||
))
|
))
|
||||||
) {
|
) {
|
||||||
|
this.queueImmuneMessage(quiet, effect);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case StatusEffect.BURN:
|
case StatusEffect.BURN:
|
||||||
if (this.isOfType(PokemonType.FIRE)) {
|
if (this.isOfType(PokemonType.FIRE)) {
|
||||||
|
this.queueImmuneMessage(quiet, effect);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -5652,6 +5512,19 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
sourcePokemon &&
|
||||||
|
sourcePokemon !== this &&
|
||||||
|
this.isSafeguarded(sourcePokemon)
|
||||||
|
) {
|
||||||
|
if(!quiet){
|
||||||
|
globalScene.queueMessage(
|
||||||
|
i18next.t("moveTriggers:safeguard", { targetName: getPokemonNameWithAffix(this)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5661,9 +5534,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
sourcePokemon: Pokemon | null = null,
|
sourcePokemon: Pokemon | null = null,
|
||||||
turnsRemaining = 0,
|
turnsRemaining = 0,
|
||||||
sourceText: string | null = null,
|
sourceText: string | null = null,
|
||||||
overrideStatus?: boolean
|
overrideStatus?: boolean,
|
||||||
|
quiet = true,
|
||||||
): boolean {
|
): boolean {
|
||||||
if (!this.canSetStatus(effect, asPhase, overrideStatus, sourcePokemon)) {
|
if (!this.canSetStatus(effect, quiet, overrideStatus, sourcePokemon)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.isFainted() && effect !== StatusEffect.FAINT) {
|
if (this.isFainted() && effect !== StatusEffect.FAINT) {
|
||||||
@ -5675,7 +5549,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
* cancel the attack's subsequent hits.
|
* cancel the attack's subsequent hits.
|
||||||
*/
|
*/
|
||||||
if (effect === StatusEffect.SLEEP || effect === StatusEffect.FREEZE) {
|
if (effect === StatusEffect.SLEEP || effect === StatusEffect.FREEZE) {
|
||||||
this.stopMultiHit();
|
const currentPhase = globalScene.getCurrentPhase();
|
||||||
|
if (currentPhase instanceof MoveEffectPhase && currentPhase.getUserPokemon() === this) {
|
||||||
|
this.turnData.hitCount = 1;
|
||||||
|
this.turnData.hitsLeft = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asPhase) {
|
if (asPhase) {
|
||||||
@ -6587,7 +6465,7 @@ export class PlayerPokemon extends Pokemon {
|
|||||||
this.leaveField(switchType === SwitchType.SWITCH);
|
this.leaveField(switchType === SwitchType.SWITCH);
|
||||||
|
|
||||||
globalScene.ui.setMode(
|
globalScene.ui.setMode(
|
||||||
Mode.PARTY,
|
UiMode.PARTY,
|
||||||
PartyUiMode.FAINT_SWITCH,
|
PartyUiMode.FAINT_SWITCH,
|
||||||
this.getFieldIndex(),
|
this.getFieldIndex(),
|
||||||
(slotIndex: number, option: PartyOption) => {
|
(slotIndex: number, option: PartyOption) => {
|
||||||
@ -6605,7 +6483,7 @@ export class PlayerPokemon extends Pokemon {
|
|||||||
MoveEndPhase,
|
MoveEndPhase,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
globalScene.ui.setMode(Mode.MESSAGE).then(resolve);
|
globalScene.ui.setMode(UiMode.MESSAGE).then(resolve);
|
||||||
},
|
},
|
||||||
PartyUiHandler.FilterNonFainted,
|
PartyUiHandler.FilterNonFainted,
|
||||||
);
|
);
|
||||||
@ -7154,6 +7032,15 @@ export class EnemyPokemon extends Pokemon {
|
|||||||
}
|
}
|
||||||
speciesId = prevolution;
|
speciesId = prevolution;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.hasTrainer() && globalScene.currentBattle) {
|
||||||
|
const { waveIndex } = globalScene.currentBattle;
|
||||||
|
const ivs: number[] = [];
|
||||||
|
while (ivs.length < 6) {
|
||||||
|
ivs.push(this.randSeedIntRange(Math.floor(waveIndex / 10), 31));
|
||||||
|
}
|
||||||
|
this.ivs = ivs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.aiType =
|
this.aiType =
|
||||||
@ -7163,8 +7050,8 @@ export class EnemyPokemon extends Pokemon {
|
|||||||
initBattleInfo(): void {
|
initBattleInfo(): void {
|
||||||
if (!this.battleInfo) {
|
if (!this.battleInfo) {
|
||||||
this.battleInfo = new EnemyBattleInfo();
|
this.battleInfo = new EnemyBattleInfo();
|
||||||
this.battleInfo.updateBossSegments(this);
|
|
||||||
this.battleInfo.initInfo(this);
|
this.battleInfo.initInfo(this);
|
||||||
|
this.battleInfo.updateBossSegments(this);
|
||||||
} else {
|
} else {
|
||||||
this.battleInfo.updateBossSegments(this);
|
this.battleInfo.updateBossSegments(this);
|
||||||
}
|
}
|
||||||
@ -7310,14 +7197,15 @@ export class EnemyPokemon extends Pokemon {
|
|||||||
].includes(move.id);
|
].includes(move.id);
|
||||||
return (
|
return (
|
||||||
doesNotFail &&
|
doesNotFail &&
|
||||||
p.getAttackDamage(
|
p.getAttackDamage({
|
||||||
this,
|
source: this,
|
||||||
move,
|
move,
|
||||||
!p.battleData.abilityRevealed,
|
ignoreAbility: !p.battleData.abilityRevealed,
|
||||||
false,
|
ignoreSourceAbility: false,
|
||||||
!p.getAlly()?.battleData.abilityRevealed,
|
ignoreAllyAbility: !p.getAlly()?.battleData.abilityRevealed,
|
||||||
false,
|
ignoreSourceAllyAbility: false,
|
||||||
isCritical,
|
isCritical,
|
||||||
|
}
|
||||||
).damage >= p.hp
|
).damage >= p.hp
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
@ -11,7 +11,7 @@ import { TrainerSlot } from "#enums/trainer-slot";
|
|||||||
import { TrainerPoolTier } from "#enums/trainer-pool-tier";
|
import { TrainerPoolTier } from "#enums/trainer-pool-tier";
|
||||||
import { TeraAIMode } from "#enums/tera-ai-mode";
|
import { TeraAIMode } from "#enums/tera-ai-mode";
|
||||||
import type { EnemyPokemon } from "#app/field/pokemon";
|
import type { EnemyPokemon } from "#app/field/pokemon";
|
||||||
import { randSeedWeightedItem, randSeedItem, randSeedInt } from "#app/utils";
|
import { randSeedWeightedItem, randSeedItem, randSeedInt } from "#app/utils/common";
|
||||||
import type { PersistentModifier } from "#app/modifier/modifier";
|
import type { PersistentModifier } from "#app/modifier/modifier";
|
||||||
import { ArenaTagSide, ArenaTrapTag } from "#app/data/arena-tag";
|
import { ArenaTagSide, ArenaTrapTag } from "#app/data/arena-tag";
|
||||||
import { getIsInitialized, initI18n } from "#app/plugins/i18n";
|
import { getIsInitialized, initI18n } from "#app/plugins/i18n";
|
||||||
@ -223,6 +223,13 @@ export default class Trainer extends Phaser.GameObjects.Container {
|
|||||||
return this.config.doubleOnly || this.variant === TrainerVariant.DOUBLE;
|
return this.config.doubleOnly || this.variant === TrainerVariant.DOUBLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether the trainer is a duo, like Tate & Liza
|
||||||
|
*/
|
||||||
|
isPartner(): boolean {
|
||||||
|
return this.variant === TrainerVariant.DOUBLE;
|
||||||
|
}
|
||||||
|
|
||||||
getMixedBattleBgm(): string {
|
getMixedBattleBgm(): string {
|
||||||
return this.config.mixedBattleBgm;
|
return this.config.mixedBattleBgm;
|
||||||
}
|
}
|
||||||
|
@ -7,12 +7,13 @@ import type PokemonSpecies from "./data/pokemon-species";
|
|||||||
import { allSpecies } from "./data/pokemon-species";
|
import { allSpecies } from "./data/pokemon-species";
|
||||||
import type { Arena } from "./field/arena";
|
import type { Arena } from "./field/arena";
|
||||||
import Overrides from "#app/overrides";
|
import Overrides from "#app/overrides";
|
||||||
import { randSeedInt, randSeedItem } from "#app/utils";
|
import { randSeedInt, randSeedItem } from "#app/utils/common";
|
||||||
import { Biome } from "#enums/biome";
|
import { Biome } from "#enums/biome";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import { Challenges } from "./enums/challenges";
|
import { Challenges } from "./enums/challenges";
|
||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import { getDailyStartingBiome } from "./data/daily-run";
|
import { getDailyStartingBiome } from "./data/daily-run";
|
||||||
|
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES, CHALLENGE_MODE_MYSTERY_ENCOUNTER_WAVES } from "./constants";
|
||||||
|
|
||||||
export enum GameModes {
|
export enum GameModes {
|
||||||
CLASSIC,
|
CLASSIC,
|
||||||
@ -36,10 +37,6 @@ interface GameModeConfig {
|
|||||||
hasMysteryEncounters?: boolean;
|
hasMysteryEncounters?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describes min and max waves for MEs in specific game modes
|
|
||||||
export const CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES: [number, number] = [10, 180];
|
|
||||||
export const CHALLENGE_MODE_MYSTERY_ENCOUNTER_WAVES: [number, number] = [10, 180];
|
|
||||||
|
|
||||||
export class GameMode implements GameModeConfig {
|
export class GameMode implements GameModeConfig {
|
||||||
public modeId: GameModes;
|
public modeId: GameModes;
|
||||||
public isClassic: boolean;
|
public isClassic: boolean;
|
||||||
|
1
src/global-vars/bypass-login.ts
Normal file
1
src/global-vars/bypass-login.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export const bypassLogin = import.meta.env.VITE_BYPASS_LOGIN === "1";
|
4
src/global-vars/starter-colors.ts
Normal file
4
src/global-vars/starter-colors.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export const starterColors: StarterColors = {};
|
||||||
|
interface StarterColors {
|
||||||
|
[key: string]: [string, string];
|
||||||
|
}
|
@ -1,11 +1,11 @@
|
|||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { deepCopy, getEnumValues } from "#app/utils";
|
import { deepCopy, getEnumValues } from "#app/utils/common";
|
||||||
import pad_generic from "./configs/inputs/pad_generic";
|
import pad_generic from "./configs/inputs/pad_generic";
|
||||||
import pad_unlicensedSNES from "./configs/inputs/pad_unlicensedSNES";
|
import pad_unlicensedSNES from "./configs/inputs/pad_unlicensedSNES";
|
||||||
import pad_xbox360 from "./configs/inputs/pad_xbox360";
|
import pad_xbox360 from "./configs/inputs/pad_xbox360";
|
||||||
import pad_dualshock from "./configs/inputs/pad_dualshock";
|
import pad_dualshock from "./configs/inputs/pad_dualshock";
|
||||||
import pad_procon from "./configs/inputs/pad_procon";
|
import pad_procon from "./configs/inputs/pad_procon";
|
||||||
import { Mode } from "./ui/ui";
|
import { UiMode } from "#enums/ui-mode";
|
||||||
import type SettingsGamepadUiHandler from "./ui/settings/settings-gamepad-ui-handler";
|
import type SettingsGamepadUiHandler from "./ui/settings/settings-gamepad-ui-handler";
|
||||||
import type SettingsKeyboardUiHandler from "./ui/settings/settings-keyboard-ui-handler";
|
import type SettingsKeyboardUiHandler from "./ui/settings/settings-keyboard-ui-handler";
|
||||||
import cfg_keyboard_qwerty from "./configs/inputs/cfg_keyboard_qwerty";
|
import cfg_keyboard_qwerty from "./configs/inputs/cfg_keyboard_qwerty";
|
||||||
@ -235,7 +235,7 @@ export class InputsController {
|
|||||||
if (gamepadName) {
|
if (gamepadName) {
|
||||||
this.selectedDevice[Device.GAMEPAD] = gamepadName.toLowerCase();
|
this.selectedDevice[Device.GAMEPAD] = gamepadName.toLowerCase();
|
||||||
}
|
}
|
||||||
const handler = globalScene.ui?.handlers[Mode.SETTINGS_GAMEPAD] as SettingsGamepadUiHandler;
|
const handler = globalScene.ui?.handlers[UiMode.SETTINGS_GAMEPAD] as SettingsGamepadUiHandler;
|
||||||
handler?.updateChosenGamepadDisplay();
|
handler?.updateChosenGamepadDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,7 +248,7 @@ export class InputsController {
|
|||||||
if (layoutKeyboard) {
|
if (layoutKeyboard) {
|
||||||
this.selectedDevice[Device.KEYBOARD] = layoutKeyboard.toLowerCase();
|
this.selectedDevice[Device.KEYBOARD] = layoutKeyboard.toLowerCase();
|
||||||
}
|
}
|
||||||
const handler = globalScene.ui?.handlers[Mode.SETTINGS_KEYBOARD] as SettingsKeyboardUiHandler;
|
const handler = globalScene.ui?.handlers[UiMode.SETTINGS_KEYBOARD] as SettingsKeyboardUiHandler;
|
||||||
handler?.updateChosenKeyboardDisplay();
|
handler?.updateChosenKeyboardDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,7 +296,7 @@ export class InputsController {
|
|||||||
globalScene.gameData?.saveMappingConfigs(gamepadID, this.configs[gamepadID]);
|
globalScene.gameData?.saveMappingConfigs(gamepadID, this.configs[gamepadID]);
|
||||||
}
|
}
|
||||||
this.lastSource = "gamepad";
|
this.lastSource = "gamepad";
|
||||||
const handler = globalScene.ui?.handlers[Mode.SETTINGS_GAMEPAD] as SettingsGamepadUiHandler;
|
const handler = globalScene.ui?.handlers[UiMode.SETTINGS_GAMEPAD] as SettingsGamepadUiHandler;
|
||||||
handler?.updateChosenGamepadDisplay();
|
handler?.updateChosenGamepadDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,7 +406,7 @@ export class InputsController {
|
|||||||
this.lastSource = "gamepad";
|
this.lastSource = "gamepad";
|
||||||
if (
|
if (
|
||||||
!this.selectedDevice[Device.GAMEPAD] ||
|
!this.selectedDevice[Device.GAMEPAD] ||
|
||||||
(globalScene.ui.getMode() !== Mode.GAMEPAD_BINDING &&
|
(globalScene.ui.getMode() !== UiMode.GAMEPAD_BINDING &&
|
||||||
this.selectedDevice[Device.GAMEPAD] !== pad.id.toLowerCase())
|
this.selectedDevice[Device.GAMEPAD] !== pad.id.toLowerCase())
|
||||||
) {
|
) {
|
||||||
this.setChosenGamepad(pad.id);
|
this.setChosenGamepad(pad.id);
|
||||||
|
@ -4,7 +4,7 @@ import CacheBustedLoaderPlugin from "#app/plugins/cache-busted-loader-plugin";
|
|||||||
import { SceneBase } from "#app/scene-base";
|
import { SceneBase } from "#app/scene-base";
|
||||||
import { WindowVariant, getWindowVariantSuffix } from "#app/ui/ui-theme";
|
import { WindowVariant, getWindowVariantSuffix } from "#app/ui/ui-theme";
|
||||||
import { isMobile } from "#app/touch-controls";
|
import { isMobile } from "#app/touch-controls";
|
||||||
import { localPing, getEnumValues, hasAllLocalizedSprites, getEnumKeys } from "#app/utils";
|
import { localPing, getEnumValues, hasAllLocalizedSprites, getEnumKeys } from "#app/utils/common";
|
||||||
import { initPokemonPrevolutions, initPokemonStarters } from "#app/data/balance/pokemon-evolutions";
|
import { initPokemonPrevolutions, initPokemonStarters } from "#app/data/balance/pokemon-evolutions";
|
||||||
import { initBiomes } from "#app/data/balance/biomes";
|
import { initBiomes } from "#app/data/balance/biomes";
|
||||||
import { initEggMoves } from "#app/data/balance/egg-moves";
|
import { initEggMoves } from "#app/data/balance/egg-moves";
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user