mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-03-28 12:45:49 -05:00
Compare commits
No commits in common. "master" and "v0.11.9" have entirely different histories.
359
.eslintrc-no-types.json
Normal file
359
.eslintrc-no-types.json
Normal file
|
|
@ -0,0 +1,359 @@
|
|||
{
|
||||
"root": true,
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 11,
|
||||
"sourceType": "script",
|
||||
"ecmaFeatures": {
|
||||
"globalReturn": true
|
||||
}
|
||||
},
|
||||
"ignorePatterns": [
|
||||
"logs/",
|
||||
"node_modules/",
|
||||
"dist/",
|
||||
"data/**/learnsets.ts",
|
||||
"tools/set-import/importer.js",
|
||||
"tools/set-import/sets",
|
||||
"tools/modlog/converter.js",
|
||||
"server/global-variables.d.ts"
|
||||
],
|
||||
"env": {
|
||||
"es6": true,
|
||||
"node": true
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"rules": {
|
||||
// TODO: add/revisit
|
||||
// "spaced-comment": ["error", "always", {"exceptions": ["*"]}],
|
||||
// "no-use-before-define": "off",
|
||||
|
||||
// test only (should never be committed, but useful when testing)
|
||||
"no-debugger": "warn",
|
||||
"no-unused-vars": ["warn", {"args": "none"}],
|
||||
"no-warning-comments": "off",
|
||||
"prefer-const": ["warn", {"destructuring": "all"}],
|
||||
|
||||
// PS code (code specific to PS)
|
||||
"consistent-return": "off", // sim event handlers mix them for ergonomics
|
||||
"func-style": "off", // used to type event handlers
|
||||
"no-console": "off",
|
||||
"no-control-regex": "off", // used to find invalid data in chat messages
|
||||
"no-invalid-this": "off", // `this` is used to pass context to sim event handlers, chat commands, etc
|
||||
"no-loop-func": "off", // synchronous
|
||||
"no-restricted-modules": ["error", "moment", "request", "sugar"],
|
||||
"no-sync": "off",
|
||||
"no-void": "off", // used for spawning Promises only
|
||||
"strict": ["error", "global"],
|
||||
|
||||
// bad code, modern (new code patterns we don't like because they're less readable or performant)
|
||||
"no-restricted-globals": ["error", "Proxy", "Reflect", "Symbol", "WeakSet"],
|
||||
|
||||
// bad code, deprecated (deprecated/bad patterns that should be written a different way)
|
||||
"eqeqeq": "error",
|
||||
"func-names": "off", // has minor advantages but way too verbose, hurting readability
|
||||
"guard-for-in": "off", // guarding is a deprecated pattern, we just use no-extend-native instead
|
||||
"init-declarations": "off", // TypeScript lets us delay initialization safely
|
||||
"no-caller": "error",
|
||||
"no-eval": "error",
|
||||
"no-extend-native": "error",
|
||||
"no-implied-eval": "error",
|
||||
"no-inner-declarations": ["error", "functions"],
|
||||
"no-iterator": "error",
|
||||
"no-labels": ["error", {"allowLoop": true, "allowSwitch": true}],
|
||||
"no-multi-str": "error",
|
||||
"no-new-func": "error",
|
||||
"no-new-wrappers": "error",
|
||||
"no-path-concat": "off", // Windows supports `/` as a path separator; concat is more readable
|
||||
"no-proto": "error",
|
||||
"no-restricted-syntax": ["error", "WithStatement"],
|
||||
"no-sparse-arrays": "error",
|
||||
"no-var": "error",
|
||||
"no-with": "error",
|
||||
|
||||
// probably bugs (code with no reason to exist, probably typoes)
|
||||
"array-callback-return": "error",
|
||||
"block-scoped-var": "error", // not actually used; precluded by no-var
|
||||
"callback-return": [2, ["callback", "cb", "done"]],
|
||||
"consistent-this": "off", // we use arrow functions instead
|
||||
"constructor-super": "error",
|
||||
"default-case": "off", // hopefully TypeScript will let us skip `default` for things that are exhaustive
|
||||
"no-bitwise": "off", // used in Dashycode
|
||||
"no-case-declarations": "off", // meh, we have no-shadow
|
||||
"no-duplicate-case": "error",
|
||||
"no-empty": ["error", {"allowEmptyCatch": true}],
|
||||
"no-extra-bind": "error",
|
||||
"no-extra-label": "error",
|
||||
"no-fallthrough": "error",
|
||||
"no-label-var": "error",
|
||||
"no-new-require": "error",
|
||||
"no-new": "error",
|
||||
"no-redeclare": "error",
|
||||
"no-return-await": "error",
|
||||
"no-self-compare": "error",
|
||||
"no-sequences": "error",
|
||||
"no-shadow-restricted-names": "error",
|
||||
"no-shadow": "off",
|
||||
"no-template-curly-in-string": "error",
|
||||
"no-throw-literal": "error",
|
||||
"no-undef": "off",
|
||||
"no-unmodified-loop-condition": "error",
|
||||
"no-unused-expressions": "error",
|
||||
"no-unsafe-finally": "error",
|
||||
"no-unused-labels": "error",
|
||||
"use-isnan": "error",
|
||||
"valid-typeof": "error",
|
||||
|
||||
// style choices
|
||||
"no-constant-condition": ["error", {"checkLoops": false}],
|
||||
"no-lonely-if": "off",
|
||||
"radix": ["error", "as-needed"],
|
||||
|
||||
// naming style
|
||||
"camelcase": "off", // mostly only so we can import `child_process`
|
||||
"id-length": "off",
|
||||
"id-match": "off",
|
||||
"new-cap": ["error", {"newIsCap": true, "capIsNew": false}],
|
||||
"no-underscore-dangle": "off",
|
||||
|
||||
// syntax style (local syntactical, usually autofixable formatting decisions)
|
||||
"arrow-parens": "off",
|
||||
"arrow-body-style": "error",
|
||||
"brace-style": ["error", "1tbs", {"allowSingleLine": true}],
|
||||
"comma-dangle": ["error", {"arrays": "always-multiline", "objects": "always-multiline", "imports": "always-multiline", "exports": "always-multiline", "functions": "ignore"}],
|
||||
"comma-style": ["error", "last"],
|
||||
"curly": ["error", "multi-line", "consistent"],
|
||||
"dot-notation": "off",
|
||||
"new-parens": "error",
|
||||
"no-array-constructor": "error",
|
||||
"no-div-regex": "error",
|
||||
"no-duplicate-imports": "error",
|
||||
"no-extra-parens": "off",
|
||||
"no-floating-decimal": "error",
|
||||
"no-mixed-requires": "error",
|
||||
"no-multi-spaces": "error",
|
||||
"no-new-object": "error",
|
||||
"no-octal-escape": "error",
|
||||
"no-return-assign": ["error", "except-parens"],
|
||||
"no-undef-init": "off",
|
||||
"no-unneeded-ternary": "error",
|
||||
"no-useless-call": "error",
|
||||
"no-useless-computed-key": "error",
|
||||
"no-useless-concat": "off",
|
||||
"no-useless-rename": "error",
|
||||
"object-shorthand": ["error", "methods"],
|
||||
"one-var": "off",
|
||||
"operator-assignment": "off",
|
||||
"prefer-arrow-callback": "off",
|
||||
"quote-props": "off",
|
||||
"quotes": "off",
|
||||
"semi": ["error", "always"],
|
||||
"sort-vars": "off",
|
||||
"vars-on-top": "off",
|
||||
"wrap-iife": ["error", "inside"],
|
||||
"wrap-regex": "off",
|
||||
"yoda": ["error", "never", { "exceptRange": true }],
|
||||
|
||||
// whitespace
|
||||
"array-bracket-spacing": ["error", "never"],
|
||||
"arrow-spacing": ["error", {"before": true, "after": true}],
|
||||
"block-spacing": ["error", "always"],
|
||||
"comma-spacing": ["error", {"before": false, "after": true}],
|
||||
"computed-property-spacing": ["error", "never"],
|
||||
"dot-location": ["error", "property"],
|
||||
"eol-last": ["error", "always"],
|
||||
"func-call-spacing": "error",
|
||||
"function-paren-newline": ["error", "consistent"],
|
||||
"indent": ["error", "tab", {"flatTernaryExpressions": true}],
|
||||
"key-spacing": "error",
|
||||
"keyword-spacing": ["error", {"before": true, "after": true}],
|
||||
"lines-around-comment": "off",
|
||||
"no-mixed-spaces-and-tabs": ["error", "smart-tabs"],
|
||||
"no-multiple-empty-lines": ["error", {"max": 2, "maxEOF": 1}],
|
||||
"no-trailing-spaces": ["error", {"ignoreComments": false}],
|
||||
"object-curly-spacing": ["error", "never"],
|
||||
"operator-linebreak": ["error", "after"],
|
||||
"padded-blocks": ["error", "never"],
|
||||
"padding-line-between-statements": "off",
|
||||
"rest-spread-spacing": ["error", "never"],
|
||||
"semi-spacing": ["error", {"before": false, "after": true}],
|
||||
"space-before-blocks": ["error", "always"],
|
||||
"space-before-function-paren": ["error", {"anonymous": "always", "named": "never"}],
|
||||
"space-in-parens": ["error", "never"],
|
||||
"space-infix-ops": "error",
|
||||
"space-unary-ops": ["error", {"words": true, "nonwords": false}],
|
||||
"template-curly-spacing": ["error", "never"]
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"./config/*.ts", "./data/**/*.ts", "./lib/*.ts", "./server/**/*.ts", "./server/**/*.tsx", "./sim/**/*.ts",
|
||||
"./tools/set-import/*.ts", "./tools/modlog/*.ts", "./translations/**/*.ts"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 11,
|
||||
"sourceType": "module",
|
||||
"tsconfigRootDir": ".",
|
||||
"project": ["./tsconfig.json"]
|
||||
},
|
||||
"extends": [
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"rules": {
|
||||
// TODO revisit
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
"@typescript-eslint/member-ordering": "off",
|
||||
// "@typescript-eslint/no-extraneous-class": "error",
|
||||
// "@typescript-eslint/no-type-alias": "error",
|
||||
"@typescript-eslint/prefer-optional-chain": "off",
|
||||
// "@typescript-eslint/consistent-type-imports": "error", // TODO after no-duplicate-imports fix
|
||||
|
||||
// test only (should never be committed, but useful when testing)
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": ["warn", {"args": "none"}],
|
||||
"max-len": ["warn", {
|
||||
"code": 120, "tabWidth": 0,
|
||||
// see bottom of file for source
|
||||
"ignorePattern": "^\\s*(?:\\/\\/ \\s*)?(?:(?:export )?(?:let |const |readonly )?[a-zA-Z0-9_$.]+(?: \\+?=>? )|[a-zA-Z0-9$]+: \\[?|(?:return |throw )?(?:new )?(?:[a-zA-Z0-9$.]+\\()?)?(?:Utils\\.html|(?:this\\.)?(?:room\\.)?tr|\\$\\()?['\"`/]"
|
||||
}],
|
||||
"prefer-const": ["warn", {"destructuring": "all"}], // typescript-eslint/recommended forces this so we need to re-override
|
||||
|
||||
// PS code (code specific to PS)
|
||||
"@typescript-eslint/no-namespace": "off",
|
||||
"@typescript-eslint/unbound-method": "off", // used for sim event handlers, command handlers, etc
|
||||
"new-parens": "off", // used for the `new class {...}` pattern
|
||||
"no-prototype-builtins": "off",
|
||||
"no-shadow": "off",
|
||||
"@typescript-eslint/no-shadow": "error",
|
||||
"@typescript-eslint/no-var-requires": "off",
|
||||
|
||||
// typescript-eslint defaults too strict
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"@typescript-eslint/no-empty-function": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"@typescript-eslint/no-use-before-define": "off",
|
||||
"@typescript-eslint/no-unsafe-argument": "off",
|
||||
|
||||
// probably bugs
|
||||
"@typescript-eslint/ban-types": ["error", {
|
||||
"extendDefaults": true,
|
||||
"types": {
|
||||
"object": false
|
||||
}
|
||||
}],
|
||||
"@typescript-eslint/no-dupe-class-members": "error",
|
||||
"@typescript-eslint/no-empty-interface": "error",
|
||||
"@typescript-eslint/no-extra-non-null-assertion": "error",
|
||||
"@typescript-eslint/no-misused-new": "error",
|
||||
"@typescript-eslint/no-non-null-asserted-optional-chain": "error",
|
||||
"no-dupe-class-members": "off",
|
||||
"no-unused-expressions": "off", // ternary is used to convert callbacks to Promises
|
||||
"@typescript-eslint/no-unused-expressions": ["error", {"allowTernary": true}], // ternary is used to convert callbacks to Promises
|
||||
|
||||
// naming style
|
||||
"@typescript-eslint/naming-convention": ["error", {
|
||||
"selector": ["class", "interface", "typeAlias"],
|
||||
"format": ["PascalCase"]
|
||||
}],
|
||||
|
||||
// syntax style (local syntactical, usually autofixable formatting decisions)
|
||||
"@typescript-eslint/adjacent-overload-signatures": "error",
|
||||
"@typescript-eslint/array-type": "error",
|
||||
"@typescript-eslint/consistent-type-assertions": ["error", {"assertionStyle": "as"}],
|
||||
"@typescript-eslint/consistent-type-definitions": ["error", "interface"],
|
||||
"@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
|
||||
"@typescript-eslint/member-delimiter-style": ["error", {"overrides": {"typeLiteral": {
|
||||
"multiline": {"delimiter": "comma", "requireLast": true},
|
||||
"singleline": {"delimiter": "comma", "requireLast": false}
|
||||
}}}],
|
||||
"@typescript-eslint/no-parameter-properties": "error",
|
||||
// `source` and `target` are frequently used as variables that may point to `this`
|
||||
// or to another `Pokemon` object, depending on how the given method is invoked
|
||||
"@typescript-eslint/no-this-alias": ["error", {"allowedNames": ["source", "target"]}],
|
||||
"@typescript-eslint/prefer-as-const": "error",
|
||||
"@typescript-eslint/prefer-for-of": "error",
|
||||
"@typescript-eslint/prefer-function-type": "error",
|
||||
"@typescript-eslint/prefer-includes": "error",
|
||||
"@typescript-eslint/prefer-namespace-keyword": "error",
|
||||
"prefer-object-spread": "error",
|
||||
"@typescript-eslint/triple-slash-reference": "error",
|
||||
"@typescript-eslint/unified-signatures": "error",
|
||||
|
||||
// syntax style, overriding base
|
||||
"quotes": "off",
|
||||
"@typescript-eslint/quotes": "off",
|
||||
"semi": "off",
|
||||
"@typescript-eslint/semi": ["error", "always"],
|
||||
"func-call-spacing": "off",
|
||||
"@typescript-eslint/func-call-spacing": "error",
|
||||
|
||||
// whitespace
|
||||
"@typescript-eslint/type-annotation-spacing": "error",
|
||||
"spaced-comment": ["error", "always", {"exceptions": ["*", "/"]}],
|
||||
|
||||
// whitespace, overriding base
|
||||
"indent": "off",
|
||||
"@typescript-eslint/indent": ["error", "tab", {"flatTernaryExpressions": true}]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["./translations/**/*.ts"],
|
||||
"rules": {
|
||||
"no-template-curly-in-string": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"env": {
|
||||
"mocha": true
|
||||
},
|
||||
"files": ["test/**/*.js"]
|
||||
},
|
||||
{
|
||||
"files": ["build"],
|
||||
"rules": {
|
||||
"no-var": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["server/chat-plugins/private/*"],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2021
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
/*
|
||||
REGEXFREE SOURCE FOR IGNOREPATTERN: https://zarel.github.io/regexfree/
|
||||
|
||||
# indentation
|
||||
^\s*
|
||||
# possibly commented out
|
||||
(\/\/\ \s*)?
|
||||
|
||||
(
|
||||
# define a variable, append to a variable, or define a single-arg arrow function
|
||||
(export\ )? (let\ |const\ |readonly\ )? [a-zA-Z0-9_$.]+ (\ \+?=>?\ )
|
||||
|
|
||||
# define a property (oversize arrays are only allowed in properties)
|
||||
[a-zA-Z0-9$]+:\ \[?
|
||||
|
|
||||
# optionally return or throw
|
||||
(return\ |throw\ )?
|
||||
# call a function or constructor
|
||||
(new\ )?([a-zA-Z0-9$.]+\()?
|
||||
)?
|
||||
|
||||
(
|
||||
Utils\.html
|
||||
|
|
||||
(this\.)?(room\.)?tr
|
||||
|
|
||||
\$\(
|
||||
)?
|
||||
|
||||
# start of string or regex
|
||||
['"`\/]
|
||||
*/
|
||||
51
.eslintrc.json
Normal file
51
.eslintrc.json
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
{
|
||||
"extends": "./.eslintrc-no-types.json",
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["./config/*.ts", "./data/**/*.ts", "./lib/*.ts", "./server/**/*.ts", "./server/**/*.tsx", "./sim/**/*.ts", "./tools/set-import/*.ts"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 11,
|
||||
"sourceType": "module",
|
||||
"tsconfigRootDir": ".",
|
||||
"project": ["./tsconfig.json"]
|
||||
},
|
||||
"extends": [
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:@typescript-eslint/recommended-requiring-type-checking",
|
||||
"./.eslintrc-no-types.json"
|
||||
],
|
||||
"rules": {
|
||||
// TODO investigate
|
||||
"@typescript-eslint/restrict-plus-operands": "off",
|
||||
// "@typescript-eslint/restrict-plus-operands": ["error", {"checkCompoundAssignments": true}],
|
||||
// "@typescript-eslint/switch-exhaustiveness-check": "error",
|
||||
|
||||
// typescript-eslint defaults too strict
|
||||
"@typescript-eslint/no-unsafe-assignment": "off",
|
||||
"@typescript-eslint/no-unsafe-call": "off",
|
||||
"@typescript-eslint/no-unsafe-member-access": "off",
|
||||
"@typescript-eslint/no-unsafe-return": "off",
|
||||
"@typescript-eslint/restrict-template-expressions": "off",
|
||||
|
||||
// probably bugs
|
||||
"@typescript-eslint/no-floating-promises": "error",
|
||||
"@typescript-eslint/no-for-in-array": "error",
|
||||
"@typescript-eslint/no-misused-promises": "error",
|
||||
"@typescript-eslint/no-throw-literal": "error",
|
||||
"@typescript-eslint/no-unnecessary-condition": "off", // sadly, we use not-null assertions so commonly that these are often necessary
|
||||
|
||||
// syntax style (local syntactical, usually autofixable formatting decisions)
|
||||
"@typescript-eslint/no-unnecessary-qualifier": "off",
|
||||
|
||||
// Disabled because of a bug in typescript-eslint.
|
||||
// See https://github.com/typescript-eslint/typescript-eslint/issues/4554
|
||||
"@typescript-eslint/no-unnecessary-type-arguments": "off",
|
||||
|
||||
"@typescript-eslint/no-unnecessary-type-assertion": "error",
|
||||
"@typescript-eslint/prefer-regexp-exec": "error",
|
||||
"@typescript-eslint/prefer-string-starts-ends-with": "error"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
14
.github/workflows/publish.yml
vendored
14
.github/workflows/publish.yml
vendored
|
|
@ -15,23 +15,23 @@ jobs:
|
|||
last_version: ${{ steps.last_version.outputs.version }}
|
||||
token_exists: ${{ steps.check_token.outputs.token }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 50
|
||||
# Check if the package.json version field has changed since the last push
|
||||
- name: Get current version from package.json
|
||||
id: current_version
|
||||
run: |
|
||||
echo "version=$(jq -r .version package.json)" >> "$GITHUB_OUTPUT"
|
||||
echo "version=$(jq -r .version package.json)" >> $GITHUB_OUTPUT
|
||||
- name: Get the version from the last push
|
||||
id: last_version
|
||||
run: |
|
||||
git checkout ${{ github.event.before }}
|
||||
echo "version=$(jq -r .version package.json)" >> "$GITHUB_OUTPUT"
|
||||
echo "version=$(jq -r .version package.json)" >> $GITHUB_OUTPUT
|
||||
- name: Check if NPM_TOKEN exists
|
||||
id: check_token
|
||||
run: |
|
||||
echo "token=$(if [ -n "${{ secrets.NPM_TOKEN }}" ]; then echo true; else echo false; fi)" >> "$GITHUB_OUTPUT"
|
||||
echo "token=$(if [ -n "${{ secrets.NPM_TOKEN }}" ]; then echo true; else echo false; fi)" >> $GITHUB_OUTPUT
|
||||
npm-publish:
|
||||
needs:
|
||||
- test
|
||||
|
|
@ -40,14 +40,14 @@ jobs:
|
|||
# We only want to publish if the package.json version field has changed
|
||||
if: needs.get-version.outputs.current_version != needs.get-version.outputs.last_version && needs.get-version.outputs.token_exists == 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-node@v6
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
cache: 'npm'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
- run: npm ci
|
||||
- run: npm run build-npm
|
||||
- run: npm run build
|
||||
- run: npm publish
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
64
.github/workflows/test.yml
vendored
64
.github/workflows/test.yml
vendored
|
|
@ -17,72 +17,16 @@ jobs:
|
|||
|
||||
strategy:
|
||||
matrix:
|
||||
# Testing multiple Node versions makes CI take forever, and basically
|
||||
# never actually finds anything we care about. Testing one is enough.
|
||||
#
|
||||
# This number should be left at the oldest Node LTS version capable of
|
||||
# running Node without errors (it doesn't matter if it's unsupported).
|
||||
# Please freely bump this version (and the check in `pokemon-showdown`
|
||||
# and `server/index.ts`) if you want to use features from newer versions;
|
||||
# this is purely for our own reference, not to constrain programmers.
|
||||
node-version: ['18.x']
|
||||
node-version: [16.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 100 # assumes PR/push to master is no larger than 100 commits. Other solutions are needlessly complex.
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'npm'
|
||||
|
||||
- run: npm ci
|
||||
|
||||
- name: Determine which files to lint (if pull request)
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
id: changed-files
|
||||
uses: tj-actions/changed-files@v47
|
||||
with:
|
||||
files: |
|
||||
./config/*.ts
|
||||
./data/**/*.ts
|
||||
./lib/*.ts
|
||||
./server/**/*.ts
|
||||
./server/**/*.tsx
|
||||
./sim/**/*.ts
|
||||
./tools/set-import/*.ts
|
||||
files_ignore: |
|
||||
./logs/
|
||||
./node_modules/
|
||||
./dist/
|
||||
./data/**/learnsets.ts
|
||||
./tools/set-import/importer.js
|
||||
./tools/set-import/sets
|
||||
./tools/modlog/converter.js
|
||||
./server/global-variables.d.ts
|
||||
|
||||
- name: Determine whether test/sim or test/random-battles need to run (if pull request)
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
id: changed-directories
|
||||
uses: tj-actions/changed-files@v47
|
||||
with:
|
||||
files: |
|
||||
config/formats.ts
|
||||
data/**
|
||||
sim/**
|
||||
|
||||
- name: Run selective lint & necessary tests (if pull request)
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
run: npm run full-test-ci
|
||||
env:
|
||||
CI: true
|
||||
FILES: ${{ steps.changed-files.outputs.all_changed_and_modified_files }}
|
||||
SKIPSIMTESTS: ${{ steps.changed-directories.outputs.all_changed_and_modified_files == '' }}
|
||||
|
||||
- name: Run full lint & test (if push to master)
|
||||
run: npm run full-test
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||
- run: npm run full-test
|
||||
env:
|
||||
CI: true
|
||||
|
|
|
|||
29
.github/workflows/update_version.yml
vendored
29
.github/workflows/update_version.yml
vendored
|
|
@ -3,12 +3,12 @@ name: Update the npm package version
|
|||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
required: true
|
||||
type: choice
|
||||
description: Version type
|
||||
default: patch
|
||||
options:
|
||||
version:
|
||||
required: true
|
||||
type: choice
|
||||
description: Version type
|
||||
default: patch
|
||||
options:
|
||||
- major
|
||||
- minor
|
||||
- patch
|
||||
|
|
@ -16,30 +16,27 @@ on:
|
|||
- preminor
|
||||
- prepatch
|
||||
- prerelease
|
||||
|
||||
jobs:
|
||||
update_version:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-node@v6
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
cache: 'npm'
|
||||
|
||||
- id: bump_version
|
||||
run: |
|
||||
echo "old_version=$(jq -r .version package.json)" >> "$GITHUB_OUTPUT"
|
||||
echo "old_version=$(jq -r .version package.json)" >> $GITHUB_OUTPUT
|
||||
npm version ${{ github.event.inputs.version }} --no-git-tag-version
|
||||
echo "new_version=$(jq -r .version package.json)" >> "$GITHUB_OUTPUT"
|
||||
echo "new_version=$(jq -r .version package.json)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: peter-evans/create-pull-request@v8
|
||||
- uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
title: Bump package.json version to v${{ steps.bump_version.outputs.new_version }}
|
||||
title: Bump package.json version to v${{ steps.bump_version.outputs.new_version }}}
|
||||
body: |
|
||||
Bump package.json version from `v${{ steps.bump_version.outputs.old_version }}` to `v${{ steps.bump_version.outputs.new_version }}`
|
||||
commit-message: Bump package.json version to v${{ steps.bump_version.outputs.new_version }}
|
||||
branch: npm-version-bump
|
||||
base: master
|
||||
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,6 +1,6 @@
|
|||
/config/*
|
||||
!/config/formats.ts
|
||||
/logs/**/*
|
||||
/logs/*
|
||||
/test/modlogs
|
||||
/test/replays/*.html
|
||||
/node_modules
|
||||
|
|
|
|||
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
|
|
@ -1,6 +1,10 @@
|
|||
{
|
||||
"editor.insertSpaces": false,
|
||||
"editor.formatOnSave": false,
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": false,
|
||||
"typescript.format.semicolons": "insert"
|
||||
"typescript.format.semicolons": "insert",
|
||||
"eslint.options": {
|
||||
"configFile": ".eslintrc.json"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,19 +3,11 @@ Pokemon Showdown architecture
|
|||
|
||||
At the highest level, PS is split into three parts:
|
||||
|
||||
- Game server (**[smogon/pokemon-showdown](https://github.com/smogon/pokemon-showdown)**)
|
||||
- Client (**[smogon/pokemon-showdown-client](https://github.com/smogon/pokemon-showdown-client)**)
|
||||
- Login server (**[smogon/pokemon-showdown-loginserver](https://github.com/smogon/pokemon-showdown-loginserver)**)
|
||||
- Client
|
||||
- Login server
|
||||
- Game server
|
||||
|
||||
All three communicate directly with each other.
|
||||
|
||||
A user starts by visiting `https://play.pokemonshowdown.com/`. This is handled by an Apache server (in the Client), which serves mostly static files but uses some PHP (legacy, intended to be migrated to Loginserver).
|
||||
|
||||
The user's web browser (running Client code) will then communicate with the Login server (mounted at `https://play.pokemonshowdown.com/api/` to handle logins mostly, or otherwise interface with the Client databases one way or another).
|
||||
|
||||
The user's web browser will also connect to the Game server, through SockJS. The Game server handles the chat rooms, matchmaking, and actual battle simulation.
|
||||
|
||||
The Game server also communicates with the Login server, to handle replay uploads (and, for the main server, ladder updates).
|
||||
The game server is in this repository, **[smogon/pokemon-showdown](https://github.com/smogon/pokemon-showdown)**, while the client and login server are in **[smogon/pokemon-showdown-client](https://github.com/smogon/pokemon-showdown-client)**. All three communicate directly with each other.
|
||||
|
||||
|
||||
Game server
|
||||
|
|
@ -33,7 +25,7 @@ Its entry point is [server/index.ts](./server/index.ts), which launches several
|
|||
|
||||
- [server/chat.ts](./server/chat.ts) sets up `Chat`, which handles chat commands and messages coming in from users (all client-to-server commands are routed through there)
|
||||
|
||||
`Rooms` also includes support for battle rooms, which is where the server connects to the game simulator itself. Game simulation code is in [sim/](./sim/).
|
||||
`Rooms` also includes support for battle rooms, which is where the game simulation itself is done. Game simulation code is in [sim/](./sim/).
|
||||
|
||||
|
||||
Client
|
||||
|
|
@ -41,16 +33,14 @@ Client
|
|||
|
||||
The client is built in a mix of TypeScript and JavaScript, with a mostly hand-rolled framework built on Backbone. There’s a rewrite to migrate it to Preact but it’s very stalled.
|
||||
|
||||
Its entry point is [index.template.html](https://github.com/smogon/pokemon-showdown-client/blob/master/play.pokemonshowdown.com/index.template.html)
|
||||
Its entry point is [index.template.html](https://github.com/smogon/pokemon-showdown-client/blob/master/index.template.html).
|
||||
|
||||
It was written long ago, so instead of a single JS entry point, it includes a lot of JS files. Everything important is launched from [js/client.js](https://github.com/smogon/pokemon-showdown-client/blob/master/play.pokemonshowdown.com/js/client.js)
|
||||
It was written long ago, so instead of a single JS entry point, it includes a lot of JS files. Everything important is launched from [js/client.js](https://github.com/smogon/pokemon-showdown-client/blob/master/js/client.js).
|
||||
|
||||
|
||||
Login server
|
||||
------------
|
||||
|
||||
The client’s login server, which handles logins and most database interaction, is written in TypeScript. The backend is currently split between a MySQL InnoDB database (for users, ladder, and most other things) and a Postgres (technically Cockroach) database (for Replays).
|
||||
The client’s login server, which handles logins and most database interaction, is written in PHP, with a rewrite to TypeScript in progress. The backend is split between a MySQL InnoDB database and a Percona database, with a migration to Postgres planned.
|
||||
|
||||
Its entry point is [server.ts](https://github.com/smogon/pokemon-showdown-loginserver/blob/master/src/server.ts).
|
||||
|
||||
It's intended to replace all of the old PHP code in the Client, but that migration is only halfway done at the moment.
|
||||
Its entry point is [action.php](https://github.com/smogon/pokemon-showdown-client/blob/master/action.php).
|
||||
|
|
|
|||
18
CODEOWNERS
18
CODEOWNERS
|
|
@ -1,31 +1,27 @@
|
|||
config/formats.ts @KrisXV @Marty-D
|
||||
data/mods/gen9ssb/ @HoeenCoder @HisuianZoroark @KrisXV
|
||||
data/random-battles/ @KrisXV @MathyFurret @ACakeWearingAHat @livid-washed @adrivrie
|
||||
data/mods/*/random-teams.ts @AnnikaCodes
|
||||
data/mods/ssb/ @HoeenCoder @KrisXV
|
||||
data/random-sets.json @MathyFurret @ACakeWearingAHat @livid-washed @adrivrie
|
||||
data/random-teams.ts @AnnikaCodes @KrisXV @MathyFurret @ACakeWearingAHat @livid-washed @adrivrie
|
||||
data/text/ @Marty-D
|
||||
databases/ @monsanto
|
||||
lib/sql.ts @mia-pi-git
|
||||
server/artemis/* @mia-pi-git
|
||||
server/chat-plugins/random-battles/ @KrisXV @AnnikaCodes
|
||||
server/chat-plugins/abuse-monitor.ts @mia-pi-git
|
||||
server/chat-plugins/auction.ts @Karthik99999
|
||||
server/chat-plugins/datasearch.ts @KrisXV
|
||||
server/chat-plugins/friends.ts @mia-pi-git
|
||||
server/chat-plugins/github.ts @mia-pi-git
|
||||
server/chat-plugins/hosts.ts @AnnikaCodes
|
||||
server/chat-plugins/helptickets*.ts @mia-pi-git
|
||||
server/chat-plugins/laddertours.ts @mia-pi-git
|
||||
server/chat-plugins/mafia.ts @HoeenCoder
|
||||
server/chat-plugins/othermetas.ts @KrisXV
|
||||
server/chat-plugins/permalocks.ts @mia-pi-git
|
||||
server/chat-plugins/quotes.ts @mia-pi-git @KrisXV
|
||||
server/chat-plugins/random-battles.ts @KrisXV @AnnikaCodes
|
||||
server/chat-plugins/repeats.ts @AnnikaCodes
|
||||
server/chat-plugins/responder.ts @mia-pi-git
|
||||
server/chat-plugins/rock-paper-scissors.ts @mia-pi-git
|
||||
server/chat-plugins/sample-teams.ts @KrisXV
|
||||
server/chat-plugins/scavenger*.ts @xfix @sparkychildcharlie @PartMan7
|
||||
sever/chat-plugins/teams.ts @mia-pi-git
|
||||
server/chat-plugins/the-studio.ts @KrisXV
|
||||
server/friends.ts @mia-pi-git
|
||||
server/private-messages/* @mia-pi-git
|
||||
server/chat-plugins/trivia/ @AnnikaCodes
|
||||
server/chat-plugins/username-prefixes.ts @AnnikaCodes
|
||||
server/chat-plugins/wifi.ts @KrisXV
|
||||
server/friends.ts @mia-pi-git
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ Note: Commands that ask for a team want the team in [packed team format](./sim/T
|
|||
- Simulates a battle, taking input to stdin and writing output to stdout
|
||||
|
||||
Using Pokémon Showdown as a command-line simulator is documented at:
|
||||
[sim/README.md](./sim/README.md)
|
||||
[sim/README.md](./README.md)
|
||||
|
||||
`./pokemon-showdown json-team`
|
||||
|
||||
|
|
|
|||
|
|
@ -128,14 +128,14 @@ BAD:
|
|||
|
||||
```ts
|
||||
// if ten seconds have passed and the user is staff
|
||||
if (now > then + 10_000 && '~@%'.includes(user.tempGroup)) {
|
||||
if (now > then + 10_000 && '&@%'.includes(user.tempGroup)) {
|
||||
```
|
||||
|
||||
GOOD:
|
||||
|
||||
```ts
|
||||
const tenSecondsPassed = now > then + 10_000;
|
||||
const userIsStaff = '~@%'.includes(user.tempGroup);
|
||||
const userIsStaff = '&@%'.includes(user.tempGroup);
|
||||
if (tenSecondsPassed && userIsStaff) {
|
||||
```
|
||||
|
||||
|
|
@ -247,7 +247,7 @@ Our current quote convention is to use:
|
|||
- `'` as in `'fireblast'` for any string not meant to be displayed to the user; i.e. IDs
|
||||
- `"` as in `"Fire Blast"` for any string meant to be displayed verbatim to the user; i.e. names (i.e. usernames, move names, etc), most English text, and help entries of chat commands
|
||||
|
||||
As far as I know, we don't use strings for anything else, but if you need to use strings in a way that doesn't conform to the above three, ask Zarel on Discord to decide (and default to `` ` `` in lieu of a decision).
|
||||
As far as I know, we don't use strings for anything else, but if you need to use strings in a way that doesn't conform to the above three, ask Zarel in the Development chatroom to decide (and default to `` ` `` in lieu of a decision).
|
||||
|
||||
Unfortunately, since this is not a convention the linter can test for (and also because our older string standards predate PS), a lot of existing code is wrong on this, so you can't look at surrounding code to get an idea of what the convention should be. Refer to the above paragraph as the definitive rule.
|
||||
|
||||
|
|
@ -279,14 +279,14 @@ If Water Absorb doesn't absorb Thunder Wave, Water Absorb's TryHit handler retur
|
|||
|
||||
We prefer using `||` instead of `??` for fallback, for a few reasons:
|
||||
|
||||
- `sucrase` (our TypeScript to JavaScript compiler) makes `??` rather more complicated than ideal.
|
||||
|
||||
- We rarely treat `0` or `''` differently from `null` (the same reason we use `!foo` instead of `foo == null` for null checks)
|
||||
|
||||
- TypeScript does not actually allow us to have "non-empty strings" or "positive integers" as a type, so we have to deal with those cases no matter what.
|
||||
|
||||
If, at a future point, TypeScript does allow us to constrain types better, we might consider using `??` for clarity. But for now, I see no reason to use `??` except in very niche situations where the difference matters.
|
||||
|
||||
It is, of course, completely fine to use `??` in the cases where we don't want `0` or `''` or `false` to fall back to something else.
|
||||
|
||||
|
||||
Modern JavaScript/TypeScript syntax convention
|
||||
------------------------------------------------------------------------
|
||||
|
|
@ -299,15 +299,15 @@ In general, we prefer modern ways of writing things as long as they're supported
|
|||
|
||||
- `.reduce`: we usually prefer `for`...`of` for readability, but you can use it in code that you code-own if you really want to
|
||||
|
||||
- Multiline template strings: A frequent source of bugs (and also weird for readability), so we prefer to explicitly use `\n` and concatenate over multiple lines.
|
||||
- Multiline template strings: A frequent source of bugs, so we prefer to explicitly use `\n` and concatenate over multiple lines.
|
||||
|
||||
- `async`/`await`: We prefer it for readability, but in certain cases we use raw Promises or even callbacks for performance. Don't worry about it too much; we usually won't nitpick code that uses either async implementation (although we might insist on `async`/`await` if the readability difference is huge).
|
||||
- `async`/`await`: We prefer it for readability, but in certain cases we use raw Promises or even callbacks for performance. Don't worry about it too much; we usually won't nitpick code that uses any async implementation (although we might insist on `async`/`await` if the reability difference is huge).
|
||||
|
||||
- getters/setters/`Proxy`: We are generally very anti-magic. There are certain places in the code we do use magic where it's massively DRYer (or for historical reasons), but we prefer to explicitly mark that setting a variable is actually running a function with many and varied side effects. Please have a better reason than "`.foo` is less visual clutter than `.getFoo()`".
|
||||
|
||||
- Constant Enums: Don't use; we prefer constant union types, like `type Category = 'Physical' | 'Special' | 'Status'`
|
||||
|
||||
- Default Properties: Use.
|
||||
- Default Properties: Mediocre performance when compiled with `sucrase`. This is fine for objects that are rarely created, but prefer setting properties directly in a constructor, for objects created in inner loops.
|
||||
|
||||
|
||||
Dependencies
|
||||
|
|
@ -317,9 +317,7 @@ We oppose the usual JavaScript culture of casually adding dependencies from NPM.
|
|||
|
||||
There are, of course, a lot of libraries like SockJS doing valuable things that we shouldn't reimplement ourselves. However, most libraries on NPM have very different priorities than we do (not caring about performance or bugs in subdependencies).
|
||||
|
||||
A common reason given for preferring dependencies is because someone else is more likely to have encountered and fixed bugs. But in practice many dependencies are worse-maintained than Showdown. And many bugs come from misusing a dependency.
|
||||
|
||||
In practice, for any dependency we could reimplement in around 30 lines of code, we'll write it ourselves and maintain it in `lib/`. Such maintenance is usually worth avoiding a `left-pad` situation, and also is generally better for performance, and also helps us easily craft the API to be most convenient for our own use-case.
|
||||
But in practice, for any dependency we could reimplement in around 30 lines of code, we'll write it ourselves and maintain it in `lib/`. Such maintenance is usually worth avoiding a `left-pad` situation, and also is generally better for performance, and also helps us easily craft the API to be most convenient for our own use-case.
|
||||
|
||||
To be clear, we're not _opposed_ to new dependencies and will accept them where they make sense. But we try to avoid them more most than other Node projects do.
|
||||
|
||||
|
|
@ -327,4 +325,18 @@ To be clear, we're not _opposed_ to new dependencies and will accept them where
|
|||
`package-lock.json`
|
||||
------------------------------------------------------------------------
|
||||
|
||||
In the past, we didn't use `package-lock`. The reasons are historical. We do now. If you see a project without package-lock, feel free to add it.
|
||||
We don't use `package-lock`. This is against NPM's (and most others') official advice that we should.
|
||||
|
||||
: First, what's `package-lock` and why is it recommended? `package-lock.json` is basically a snapshot of the `node_modules/` directory. You can think of it like `node_modules.zip`, except more human-readable, and requires an internet connection to unzip.
|
||||
|
||||
: The main advantage of adding it to Git is that it lets you know exactly the state of `node_modules/` at the time the programmer commits it. So if a dependency breaks, it's easier to trace exactly when it broke.
|
||||
|
||||
: It also makes sure `node_modules/` is exactly the same between different development environments, so differences don't cause bugs to appear for some developers but not others.
|
||||
|
||||
This comes with a number of disadvantages. The biggest one is that it causes package-lock changes to appear in random commits, which can outright lead to merge conflicts. It also makes diffs in general significantly less readable. It also [introduces security vulnerabilities](https://snyk.io/blog/why-npm-lockfiles-can-be-a-security-blindspot-for-injecting-malicious-modules/).
|
||||
|
||||
The biggest supposed advantage (ensure everyone's on the same version) isn't even an advantage! We'd specify the versions as `4.15.4` instead of `^4.15.4` if we wanted everyone on the same version, rather than the latest version. Writing `^4.15.4` is an explicit choice to opt into automatic updating.
|
||||
|
||||
We can still have everyone on the same version if we all re-run `npm install`, which we would STILL have to do if we were using a package-lock file. The package-lock file does not improve this situation.
|
||||
|
||||
(The last time we polled our developers, most supported not having a `package-lock` file.)
|
||||
|
|
|
|||
2
LICENSE
2
LICENSE
|
|
@ -1,6 +1,6 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2011-2026 Guangcong Luo and other contributors http://pokemonshowdown.com/
|
||||
Copyright (c) 2011-2022 Guangcong Luo and other contributors http://pokemonshowdown.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
|
|
|
|||
10
PROTOCOL.md
10
PROTOCOL.md
|
|
@ -40,7 +40,7 @@ Messages from the user to the server are in the form:
|
|||
|
||||
`ROOMID` can optionally be left blank if unneeded (commands like `/join lobby`
|
||||
can be sent anywhere). Responses will be sent to a PM box with no username
|
||||
(so `|/command` is equivalent to `|/pm ~, /command`).
|
||||
(so `|/command` is equivalent to `|/pm &, /command`).
|
||||
|
||||
`TEXT` can contain newlines, in which case it'll be treated the same
|
||||
way as if each line were sent to the room separately.
|
||||
|
|
@ -144,7 +144,7 @@ represented by a space), and the rest of the string being their username.
|
|||
|
||||
`|uhtml|NAME|HTML`
|
||||
|
||||
> We received an HTML message (NAME) that can change what it's displaying,
|
||||
> We recieved an HTML message (NAME) that can change what it's displaying,
|
||||
> this is used in things like our Polls system, for example.
|
||||
|
||||
`|uhtmlchange|NAME|HTML`
|
||||
|
|
@ -305,7 +305,7 @@ represented by a space), and the rest of the string being their username.
|
|||
`|tournament|update|JSON`
|
||||
|
||||
> `JSON` is a JSON object representing the changes in the tournament
|
||||
> since the last update you received or the start of the tournament.
|
||||
> since the last update you recieved or the start of the tournament.
|
||||
> These include:
|
||||
>
|
||||
format: the tournament's custom name or the format being used
|
||||
|
|
@ -478,9 +478,7 @@ If the challenge is accepted, you will receive a room initialization message.
|
|||
`JSON.searching` will be an array of format IDs you're currently searching for
|
||||
games in.
|
||||
|
||||
`JSON.games` will be a `{roomid: title}` table of games you're currently in,
|
||||
or `null` if you're in no games.
|
||||
|
||||
`JSON.games` will be a `{roomid: title}` table of games you're currently in.
|
||||
Note that this includes ALL games, so `|updatesearch|` will be sent when you
|
||||
start/end challenge battles, and even non-Pokémon games like Mafia.
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ Pokémon Showdown is many things:
|
|||
|
||||
- [server/README.md](./server/README.md)
|
||||
|
||||
Pokémon Showdown simulates singles, doubles and triples battles in all the games out so far (Generations 1 through 9).
|
||||
Pokémon Showdown simulates singles, doubles and triples battles in all the games out so far (Generations 1 through 8).
|
||||
|
||||
|
||||
Documentation quick links
|
||||
|
|
@ -89,10 +89,8 @@ Staff
|
|||
- Andrew Werner [HoeenHero] - Development
|
||||
- Annika L. [Annika] - Development
|
||||
- Chris Monsanto [chaos] - Development, Sysadmin
|
||||
- Kris Johnson [dhelmise] - Development
|
||||
- Leonard Craft III [DaWoblefet] - Research (game mechanics)
|
||||
- Leonard Craft III - Research (game mechanics)
|
||||
- Mathieu Dias-Martins [Marty-D] - Research (game mechanics), Development
|
||||
- Mia A [Mia] - Development
|
||||
|
||||
Contributors
|
||||
|
||||
|
|
|
|||
17
build
17
build
|
|
@ -2,12 +2,10 @@
|
|||
"use strict";
|
||||
|
||||
try {
|
||||
// fetch was introduced in Node 18, which is EOL,
|
||||
// so we'll ask for the most recent "Active LTS" with it to be safe
|
||||
// https://nodejs.org/en/about/previous-releases
|
||||
fetch;
|
||||
// technically this was introduced in Node 15, but we'll ask for the most recent LTS with it to be safe
|
||||
Promise.any([null]);
|
||||
} catch (e) {
|
||||
console.error("We require Node.js version 22 or later; you're using " + process.version);
|
||||
console.log("We require Node.js version 16 or later; you're using " + process.version);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
|
@ -24,10 +22,13 @@ function shell(cmd) {
|
|||
|
||||
// Check to make sure the most recently added or updated dependency is installed at the correct version
|
||||
try {
|
||||
require.resolve('ts-chacha20');
|
||||
var version = require('esbuild').version.split('.');
|
||||
if (parseInt(version[1]) < 16) {
|
||||
throw new Error("esbuild version too old");
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Installing dependencies...');
|
||||
shell('npm ci');
|
||||
shell('npm install');
|
||||
}
|
||||
|
||||
// Make sure config.js exists. If not, copy it over synchronously from
|
||||
|
|
@ -47,5 +48,7 @@ try {
|
|||
// for some reason, esbuild won't be requirable until a tick has passed
|
||||
// see https://stackoverflow.com/questions/53270058/node-cant-find-certain-modules-after-synchronous-install
|
||||
setImmediate(() => {
|
||||
// npm package, don't rebuild
|
||||
if (process.argv[2] === 'postinstall' && fs.existsSync('dist')) return;
|
||||
require('./tools/build-utils').transpile(force, decl);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ Pokémon Showdown supports custom rules in three ways:
|
|||
|
||||
- Tournaments, using the command `/tour rules RULES` (see the [Tournament command help][tour-help])
|
||||
|
||||
- Custom formats on your side server, by editing `config/formats.ts`
|
||||
- Custom formats on your side server, by editing `config/formats.js`
|
||||
|
||||
[tour-help]: https://www.smogon.com/forums/threads/pok%C3%A9mon-showdown-forum-rules-resources-read-here-first.3570628/#post-6777489
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ Bans are just a `-` followed by the thing you want to ban.
|
|||
|
||||
`- Future` - ban things that only appears in a future generation (such as Arceus in Gen 1)
|
||||
|
||||
`- Custom` - (DEPRECATED) ban miscellaneous other things
|
||||
`- Custom` - ban made-up things other than CAP (such as Magikarp's Revenge, or Staff Bros moves)
|
||||
|
||||
`- Nonexistent` - catch-all to ban all nonexistent Pokémon, items, etc. Includes: `- CAP, - Past, - Future, - LGPE`
|
||||
|
||||
|
|
@ -83,20 +83,10 @@ Syntax is identical to bans, just replace `-` with `+`, like:
|
|||
|
||||
More specific always trumps less specific:
|
||||
|
||||
`- all pokemon, + Uber, - Giratina, + Giratina-Altered` - allow only Ubers other than Giratina-Origin
|
||||
|
||||
`- all pokemon, + Giratina-Altered, - Giratina, + Uber` - allow only Ubers other than Giratina-Origin
|
||||
`- all Pokemon, + Uber, - Giratina, + Giratina-Altered` - allow only Ubers other than Giratina-Origin
|
||||
|
||||
`- Nonexistent, + Necturna` - don't allow anything from outside the game, except the CAP Necturna
|
||||
|
||||
Except `all pokemon`, which removes all bans/unbans of pokemon before it:
|
||||
|
||||
`- all pokemon, + Pikachu, + Raichu` - allow Pikachu and Raichu
|
||||
|
||||
`+ Pikachu, - all pokemon, + Raichu` - allow only Raichu
|
||||
|
||||
(Note that `all pokemon` does not affect obtainability rules. `+ all pokemon` will not allow CAPs or anything like that.)
|
||||
|
||||
For equally specific rules, the last rule wins:
|
||||
|
||||
`- Pikachu, - Pikachu, + Pikachu` - allow Pikachu
|
||||
|
|
@ -138,7 +128,7 @@ Whitelisting
|
|||
|
||||
Instead of a banlist, you can have a list of allowed things:
|
||||
|
||||
`- all pokemon, + Charmander, + Squirtle, + Bulbasaur` - allow only Kanto starters
|
||||
`- all Pokemon, + Charmander, + Squirtle, + Bulbasaur` - allow only Kanto starters
|
||||
|
||||
`- all moves, + move: Metronome` - allow only the move Metronome
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,23 @@ exports.port = 8000;
|
|||
*/
|
||||
exports.bindaddress = '0.0.0.0';
|
||||
|
||||
/**
|
||||
* workers - the number of networking child processes to spawn
|
||||
* This should be no greater than the number of threads available on your
|
||||
* server's CPU. If you're not sure how many you have, you can check from a
|
||||
* terminal by running:
|
||||
*
|
||||
* $ node -e "console.log(require('os').cpus().length)"
|
||||
*
|
||||
* Using more workers than there are available threads will cause performance
|
||||
* issues. Keeping a couple threads available for use for OS-related work and
|
||||
* other PS processes will likely give you the best performance, if your
|
||||
* server's CPU is capable of multithreading. If you don't know what any of
|
||||
* this means or you are unfamiliar with PS' networking code, leave this set
|
||||
* to 1.
|
||||
*/
|
||||
exports.workers = 1;
|
||||
|
||||
/**
|
||||
* wsdeflate - compresses WebSocket messages
|
||||
* Toggles use of the Sec-WebSocket-Extension permessage-deflate extension.
|
||||
|
|
@ -25,15 +42,6 @@ exports.bindaddress = '0.0.0.0';
|
|||
*/
|
||||
exports.wsdeflate = null;
|
||||
|
||||
/**
|
||||
* lazysockets - disables eager initialization of network services
|
||||
* Turn this on if you'd prefer to manually connect Showdown to the network,
|
||||
* or you intend to run it offline.
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
exports.lazysockets = false;
|
||||
|
||||
/*
|
||||
// example:
|
||||
exports.wsdeflate = {
|
||||
|
|
@ -84,50 +92,6 @@ Main's SSL deploy script from Let's Encrypt looks like:
|
|||
*/
|
||||
exports.proxyip = false;
|
||||
|
||||
// subprocesses - the number of child processes to use for various tasks.
|
||||
// Can be set to `0` instead of `{...}` to stop using subprocesses, if you're running out of RAM.
|
||||
exports.subprocesses = {
|
||||
/**
|
||||
* network - the number of networking child processes to spawn
|
||||
* This should be no greater than the number of threads available on your
|
||||
* server's CPU. If you're not sure how many you have, you can check from a
|
||||
* terminal by running:
|
||||
*
|
||||
* $ node -e "console.log(require('os').cpus().length)"
|
||||
*
|
||||
* Using more workers than there are available threads will cause performance
|
||||
* issues. Keeping a couple threads available for use for OS-related work and
|
||||
* other PS processes will likely give you the best performance, if your
|
||||
* server's CPU is capable of multithreading. If you don't know what any of
|
||||
* this means or you are unfamiliar with PS' networking code, leave this set
|
||||
* to 1.
|
||||
*/
|
||||
network: 1,
|
||||
/**
|
||||
* for simulating battles
|
||||
* You should leave this at 1 unless your server has a very large
|
||||
* amount of traffic (i.e. hundreds of concurrent battles).
|
||||
*/
|
||||
simulator: 1,
|
||||
|
||||
// beyond this point, it'd be very weird if you needed more than one of each of these
|
||||
|
||||
/** for validating teams */
|
||||
validator: 1,
|
||||
/** for user authentication */
|
||||
verifier: 1,
|
||||
localartemis: 1,
|
||||
remoteartemis: 1,
|
||||
friends: 1,
|
||||
chatdb: 1,
|
||||
modlog: 1,
|
||||
pm: 1,
|
||||
/** for the battlesearch chat plugin */
|
||||
battlesearch: 1,
|
||||
/** datasearch - for the datasearch chat plugin */
|
||||
datasearch: 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* Various debug options
|
||||
*
|
||||
|
|
@ -281,7 +245,6 @@ exports.reportjoinsperiod = 0;
|
|||
* report battles - shows messages like "OU battle started" in the lobby
|
||||
* This feature can lag larger servers - turn this off if your server is
|
||||
* getting more than 160 or so users.
|
||||
* @type {boolean | string[] | string}
|
||||
*/
|
||||
exports.reportbattles = true;
|
||||
|
||||
|
|
@ -437,6 +400,15 @@ exports.logchallenges = false;
|
|||
*/
|
||||
exports.loguserstats = 1000 * 60 * 10; // 10 minutes
|
||||
|
||||
/**
|
||||
* validatorprocesses - the number of processes to use for validating teams
|
||||
* simulatorprocesses - the number of processes to use for handling battles
|
||||
* You should leave both of these at 1 unless your server has a very large
|
||||
* amount of traffic (i.e. hundreds of concurrent battles).
|
||||
*/
|
||||
exports.validatorprocesses = 1;
|
||||
exports.simulatorprocesses = 1;
|
||||
|
||||
/**
|
||||
* inactiveuserthreshold - how long a user must be inactive before being pruned
|
||||
* from the `users` array. The default is 1 hour.
|
||||
|
|
@ -527,7 +499,7 @@ exports.lastfmkey = '';
|
|||
exports.chatlogreader = 'fs';
|
||||
/**
|
||||
* permissions and groups:
|
||||
* Each entry in `grouplist` is a separate group. Some of the members are "special"
|
||||
* Each entry in `grouplist` is a seperate group. Some of the members are "special"
|
||||
* while the rest is just a normal permission.
|
||||
* The order of the groups determines their ranking.
|
||||
* The special members are as follows:
|
||||
|
|
@ -582,7 +554,7 @@ exports.chatlogreader = 'fs';
|
|||
*/
|
||||
exports.grouplist = [
|
||||
{
|
||||
symbol: '~',
|
||||
symbol: '&',
|
||||
id: "admin",
|
||||
name: "Administrator",
|
||||
inherit: '@',
|
||||
|
|
@ -592,7 +564,7 @@ exports.grouplist = [
|
|||
console: true,
|
||||
bypassall: true,
|
||||
lockdown: true,
|
||||
promote: '~u',
|
||||
promote: '&u',
|
||||
roomowner: true,
|
||||
roombot: true,
|
||||
roommod: true,
|
||||
|
|
@ -678,7 +650,7 @@ exports.grouplist = [
|
|||
timer: true,
|
||||
modlog: true,
|
||||
alts: '%u',
|
||||
bypassblocks: 'u%@~',
|
||||
bypassblocks: 'u%@&~',
|
||||
receiveauthmessages: true,
|
||||
gamemoderation: true,
|
||||
jeopardy: true,
|
||||
|
|
@ -687,6 +659,13 @@ exports.grouplist = [
|
|||
modchat: true,
|
||||
hiderank: true,
|
||||
},
|
||||
{
|
||||
symbol: '\u00a7',
|
||||
id: "sectionleader",
|
||||
name: "Section Leader",
|
||||
inherit: '+',
|
||||
jurisdiction: 'u',
|
||||
},
|
||||
{
|
||||
// Bots are ranked below Driver/Mod so that Global Bots can be kept out
|
||||
// of modjoin % rooms (namely, Staff).
|
||||
|
|
|
|||
5492
config/formats.ts
5492
config/formats.ts
File diff suppressed because it is too large
Load Diff
|
|
@ -113,7 +113,7 @@ Some Pokémon change forme in the middle of a battle. These forme changes do res
|
|||
|
||||
List of all in-battle forme changes:
|
||||
|
||||
- Ash-Greninja (Battle Bond)
|
||||
- Ash Greninja (Battle Bond)
|
||||
- Mimikyu (Disguise)
|
||||
- Cherrim (Flower Gift)
|
||||
- Castform (Forecast)
|
||||
|
|
@ -127,7 +127,6 @@ List of all in-battle forme changes:
|
|||
- Darmanitan (Zen Mode)
|
||||
- Meloetta (Relic Song)
|
||||
- Shaymin-Sky (Frozen status)
|
||||
- Ramnarok (Polar Flare)
|
||||
- Mega evolutions
|
||||
- Primal reversions
|
||||
- Ultra Burst
|
||||
|
|
|
|||
1499
data/abilities.ts
1499
data/abilities.ts
File diff suppressed because it is too large
Load Diff
2010
data/aliases.ts
2010
data/aliases.ts
File diff suppressed because it is too large
Load Diff
70
data/cg-team-data.ts
Normal file
70
data/cg-team-data.ts
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
// Data for computer-generated teams
|
||||
|
||||
export const MOVE_PAIRINGS: {[moveID: string]: string} = {
|
||||
rest: 'sleeptalk',
|
||||
sleeptalk: 'rest',
|
||||
};
|
||||
|
||||
// Bonuses to move ratings by ability
|
||||
export const ABILITY_MOVE_BONUSES: {[abilityID: string]: {[moveID: string]: number}} = {
|
||||
drought: {sunnyday: 0.2, solarbeam: 2},
|
||||
};
|
||||
// Bonuses to move ratings by move type
|
||||
export const ABILITY_MOVE_TYPE_BONUSES: {[abilityID: string]: {[typeID: string]: number}} = {
|
||||
darkaura: {Dark: 1.33},
|
||||
fairyaura: {Fairy: 1.33},
|
||||
|
||||
// -ate moves
|
||||
pixilate: {Normal: 1.5 * 1.2},
|
||||
refrigerate: {Normal: 1.5 * 1.2},
|
||||
aerilate: {Normal: 1.5 * 1.2},
|
||||
normalize: {Normal: 1.2},
|
||||
|
||||
// weather
|
||||
drizzle: {Water: 1.4, Fire: 0.6},
|
||||
drought: {Fire: 1.4, Water: 0.6},
|
||||
};
|
||||
// For moves whose quality isn't obvious from data
|
||||
// USE SPARINGLY!
|
||||
export const HARDCODED_MOVE_WEIGHTS: {[moveID: string]: number} = {
|
||||
// Fails unless user is asleep
|
||||
snore: 0,
|
||||
// Hard to use
|
||||
lastresort: 0.1, dreameater: 0.1,
|
||||
// Useless without Berry + sucks even then
|
||||
belch: 0.2,
|
||||
|
||||
// Power increases in conditions within our control
|
||||
acrobatics: 1.75, // not 2 because of the opportunity cost of forgoing an item
|
||||
facade: 1.5, // not 2 because we forgo an item AND get badly poisoned
|
||||
|
||||
// Power increases in conditions out of our control that may occur
|
||||
avalanche: 1.2,
|
||||
hex: 1.2,
|
||||
|
||||
// screens
|
||||
lightscreen: 3, reflect: 3, auroraveil: 3, // TODO: make sure AVeil always gets Snow?
|
||||
|
||||
// hazard removal
|
||||
defog: 2, rapidspin: 1.2,
|
||||
|
||||
// mess with the opponent
|
||||
taunt: 2, disable: 2, encore: 3,
|
||||
|
||||
// healing moves
|
||||
// TODO: should healing moves be more common on bulkier pokemon?
|
||||
// 25%
|
||||
junglehealing: 3, lifedew: 3,
|
||||
// 50%
|
||||
milkdrink: 5, moonlight: 5, morningsun: 5, recover: 5, roost: 5,
|
||||
shoreup: 5, slackoff: 5, softboiled: 5, synthesis: 5,
|
||||
// delayed/consequence
|
||||
rest: 3, // has sleeptalk potential
|
||||
wish: 2,
|
||||
|
||||
// requires terrain
|
||||
steelroller: 0.1,
|
||||
};
|
||||
|
||||
export const WEIGHT_BASED_MOVES = ['heatcrash', 'heavyslam', 'lowkick', 'grassknot'];
|
||||
export const SPEED_BASED_MOVES = ['gyroball', 'electroball'];
|
||||
668
data/cg-teams.ts
Normal file
668
data/cg-teams.ts
Normal file
|
|
@ -0,0 +1,668 @@
|
|||
/**
|
||||
* Computer-Generated Teams
|
||||
*
|
||||
* Generates teams based on heuristics, most of which carry over across generations.
|
||||
* Teams generated will not always be competitively great, but they will have variety
|
||||
* and be fun to play (i.e., tries to avoid awful sets).
|
||||
*
|
||||
* The [Gen 9] Computer-Generated Teams format is personally maintained by Annika,
|
||||
* and is not part of any official Smogon or PS format selection. If you enjoy playing
|
||||
* with teams you didn't make yourself, you may want to check out Random Battles, Battle Factory,
|
||||
* and/or the sample teams for usage-based formats like OU.
|
||||
*
|
||||
* The core of the generator is the weightedRandomPick function, which chooses from an array
|
||||
* of options based on a weight associated with each option. This way, better/stronger/more useful options
|
||||
* are more likely to be chosen, but there's still an opportunity for weaker, more situational,
|
||||
* or higher-risk/higher-reward options to be chosen. However, for moves, the 'worst' moves are excluded
|
||||
* altogether, both to reduce the likelihood of a bad moveset and improve generator performance.
|
||||
*
|
||||
* Certain less-relevant aspects of the set are not randomized at all, such as:
|
||||
* - IVs (all 31s, with 0 Attack IV if the Pokémon has no Physical moves in case of Confusion)
|
||||
* - EVs (84 per stat, for +21 to each)
|
||||
* - Nature (always Quirky, which has no effect)
|
||||
* - Happiness (there are no Happiness-based moves in Gen IX)
|
||||
*
|
||||
* Currently, leveling is based on a Pokémon's position within Smogon's usage-based tiers,
|
||||
* but an automatic leveling system is planned for the future. This would involve storing win and loss
|
||||
* data by Pokémon species in a database, and increasing and decreasing the levels of Pokémon species
|
||||
* each day based on their win/loss ratio. For example, if 60% of matches with a Pokémon species are wins,
|
||||
* the species is probably overleveled!
|
||||
*
|
||||
* Other aspects of the team generator that may be worth implementing in the future include:
|
||||
* - Explicit support for weather-oriented teams (boosting moves and typings that synergize with that weather)
|
||||
* - Tracking type coverage to make it more likely that a moveset can hit every type
|
||||
*/
|
||||
|
||||
import {Dex, PRNG, SQL} from '../sim';
|
||||
import {
|
||||
ABILITY_MOVE_BONUSES,
|
||||
ABILITY_MOVE_TYPE_BONUSES,
|
||||
HARDCODED_MOVE_WEIGHTS,
|
||||
MOVE_PAIRINGS,
|
||||
SPEED_BASED_MOVES,
|
||||
WEIGHT_BASED_MOVES,
|
||||
} from './cg-team-data';
|
||||
|
||||
interface TeamStats {
|
||||
hazardSetters: {[moveid: string]: number};
|
||||
typeWeaknesses: {[type: string]: number};
|
||||
}
|
||||
|
||||
// We put a limit on the number of Pokémon on a team that can be weak to a given type.
|
||||
const MAX_WEAK_TO_SAME_TYPE = 3;
|
||||
|
||||
const levelOverride: {[speciesID: string]: number} = {};
|
||||
export let levelUpdateInterval: NodeJS.Timeout | null = null;
|
||||
|
||||
async function updateLevels(database: SQL.DatabaseManager) {
|
||||
const updateSpecies = await database.prepare(
|
||||
'UPDATE gen9computergeneratedteams SET wins = 0, losses = 0, level = ? WHERE species_id = ?'
|
||||
);
|
||||
const updateHistory = await database.prepare(
|
||||
`INSERT INTO gen9_historical_levels (level, species_id, timestamp) VALUES (?, ?, ${Date.now()})`
|
||||
);
|
||||
const data = await database.all('SELECT species_id, wins, losses, level FROM gen9computergeneratedteams');
|
||||
for (let {species_id, wins, losses, level} of data) {
|
||||
const total = wins + losses;
|
||||
|
||||
if (total > 10) {
|
||||
if (wins / total >= 0.55) level--;
|
||||
if (wins / total <= 0.45) level++;
|
||||
level = Math.max(1, Math.min(100, level));
|
||||
await updateSpecies?.run([level, species_id]);
|
||||
await updateHistory?.run([level, species_id]);
|
||||
}
|
||||
|
||||
levelOverride[species_id] = level;
|
||||
}
|
||||
}
|
||||
|
||||
if (global.Config && Config.usesqlite && Config.usesqliteleveling) {
|
||||
const database = SQL(module, {file: './databases/battlestats.db'});
|
||||
|
||||
// update every 2 hours
|
||||
void updateLevels(database);
|
||||
levelUpdateInterval = setInterval(() => void updateLevels(database), 1000 * 60 * 60 * 2);
|
||||
}
|
||||
|
||||
export default class TeamGenerator {
|
||||
dex: ModdedDex;
|
||||
format: Format;
|
||||
teamSize: number;
|
||||
forceLevel?: number;
|
||||
prng: PRNG;
|
||||
itemPool: Item[];
|
||||
|
||||
constructor(format: Format | string, seed: PRNG | PRNGSeed | null) {
|
||||
this.dex = Dex.forFormat(format);
|
||||
this.format = Dex.formats.get(format);
|
||||
this.teamSize = this.format.ruleTable?.maxTeamSize || 6;
|
||||
this.prng = seed instanceof PRNG ? seed : new PRNG(seed);
|
||||
this.itemPool = this.dex.items.all().filter(i => i.exists && i.isNonstandard !== 'Past' && !i.isPokeball);
|
||||
|
||||
const rules = Dex.formats.getRuleTable(this.format);
|
||||
if (rules.adjustLevel) this.forceLevel = rules.adjustLevel;
|
||||
}
|
||||
|
||||
getTeam(): PokemonSet[] {
|
||||
let speciesPool = this.dex.species.all().filter(s => {
|
||||
if (!s.exists) return false;
|
||||
if (s.isNonstandard || s.isNonstandard === 'Unobtainable') return false;
|
||||
if (s.nfe) return false;
|
||||
if (s.battleOnly && !s.requiredItems?.length) return false;
|
||||
|
||||
return true;
|
||||
});
|
||||
const teamStats: TeamStats = {
|
||||
hazardSetters: {},
|
||||
typeWeaknesses: {},
|
||||
};
|
||||
|
||||
const team: PokemonSet[] = [];
|
||||
while (team.length < this.teamSize && speciesPool.length) {
|
||||
const species = this.prng.sample(speciesPool);
|
||||
|
||||
const haveRoomToReject = speciesPool.length >= (this.teamSize - team.length);
|
||||
const isGoodFit = this.speciesIsGoodFit(species, teamStats);
|
||||
if (haveRoomToReject && !isGoodFit) continue;
|
||||
|
||||
speciesPool = speciesPool.filter(s => s.baseSpecies !== species.baseSpecies);
|
||||
team.push(this.makeSet(species, teamStats));
|
||||
}
|
||||
|
||||
return team;
|
||||
}
|
||||
|
||||
protected makeSet(species: Species, teamStats: TeamStats): PokemonSet {
|
||||
const abilityPool = Object.values(species.abilities);
|
||||
const abilityWeights = abilityPool.map(a => this.getAbilityWeight(this.dex.abilities.get(a)));
|
||||
const ability = this.weightedRandomPick(abilityPool, abilityWeights);
|
||||
|
||||
const moves: Move[] = [];
|
||||
|
||||
let learnset = this.dex.species.getLearnset(species.id);
|
||||
let movePool: string[] = [];
|
||||
let learnsetSpecies = species;
|
||||
if (!learnset || species.id === 'gastrodoneast') {
|
||||
learnsetSpecies = this.dex.species.get(species.baseSpecies);
|
||||
learnset = this.dex.species.getLearnset(learnsetSpecies.id);
|
||||
}
|
||||
if (learnset) {
|
||||
movePool = Object.keys(learnset).filter(
|
||||
moveid => learnset![moveid].find(learned => learned.startsWith('9'))
|
||||
);
|
||||
}
|
||||
if (learnset && learnsetSpecies === species && species.changesFrom) {
|
||||
const changesFrom = this.dex.species.get(species.changesFrom);
|
||||
learnset = this.dex.species.getLearnset(changesFrom.id);
|
||||
for (const moveid in learnset) {
|
||||
if (!movePool.includes(moveid) && learnset[moveid].some(source => source.startsWith('9'))) {
|
||||
movePool.push(moveid);
|
||||
}
|
||||
}
|
||||
}
|
||||
const evoRegion = learnsetSpecies.evoRegion;
|
||||
while (learnsetSpecies.prevo) {
|
||||
learnsetSpecies = this.dex.species.get(learnsetSpecies.prevo);
|
||||
for (const moveid in learnset) {
|
||||
if (!movePool.includes(moveid) &&
|
||||
learnset[moveid].some(source => source.startsWith('9') && !evoRegion)) {
|
||||
movePool.push(moveid);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!movePool.length) throw new Error(`No moves for ${species.id}`);
|
||||
|
||||
// Consider either the top 15 moves or top 30% of moves, whichever is greater.
|
||||
const numberOfMovesToConsider = Math.min(movePool.length, Math.max(15, Math.trunc(movePool.length * 0.3)));
|
||||
let movePoolIsTrimmed = false;
|
||||
while (moves.length < 4 && movePool.length) {
|
||||
let weights;
|
||||
if (!movePoolIsTrimmed) {
|
||||
const interimMovePool = [];
|
||||
for (const move of movePool) {
|
||||
const weight = this.getMoveWeight(this.dex.moves.get(move), teamStats, species, moves, ability);
|
||||
interimMovePool.push({move, weight});
|
||||
}
|
||||
|
||||
interimMovePool.sort((a, b) => b.weight - a.weight);
|
||||
|
||||
movePool = [];
|
||||
weights = [];
|
||||
|
||||
for (let i = 0; i < numberOfMovesToConsider; i++) {
|
||||
movePool.push(interimMovePool[i].move);
|
||||
weights.push(interimMovePool[i].weight);
|
||||
}
|
||||
movePoolIsTrimmed = true;
|
||||
} else {
|
||||
weights = movePool.map(m => this.getMoveWeight(this.dex.moves.get(m), teamStats, species, moves, ability));
|
||||
}
|
||||
|
||||
const moveID = this.weightedRandomPick(movePool, weights, {remove: true});
|
||||
|
||||
// add paired moves, like RestTalk
|
||||
const pairedMove = MOVE_PAIRINGS[moveID];
|
||||
const alreadyHavePairedMove = moves.some(m => m.id === pairedMove);
|
||||
if (
|
||||
moves.length < 3 &&
|
||||
pairedMove &&
|
||||
!alreadyHavePairedMove &&
|
||||
// We don't check movePool because sometimes paired moves are bad.
|
||||
this.dex.species.getLearnset(species.id)?.[pairedMove]
|
||||
) {
|
||||
moves.push(this.dex.moves.get(pairedMove));
|
||||
movePool.splice(movePool.indexOf(pairedMove), 1);
|
||||
}
|
||||
|
||||
moves.push(this.dex.moves.get(moveID));
|
||||
}
|
||||
|
||||
let item = '';
|
||||
if (species.requiredItem) {
|
||||
item = species.requiredItem;
|
||||
} else if (species.requiredItems) {
|
||||
item = this.prng.sample(species.requiredItems.filter(i => !this.dex.items.get(i).isNonstandard));
|
||||
} else if (moves.every(m => m.id !== 'acrobatics')) { // Don't assign an item if the set includes Acrobatics...
|
||||
const weights = [];
|
||||
const items = [];
|
||||
for (const i of this.itemPool) {
|
||||
// If the species has a special item, we should use it.
|
||||
if (i.itemUser?.includes(species.name)) {
|
||||
item = i.name;
|
||||
break;
|
||||
}
|
||||
|
||||
const weight = this.getItemWeight(i, teamStats, species, moves, ability);
|
||||
if (weight !== 0) {
|
||||
weights.push(weight);
|
||||
items.push(i.name);
|
||||
}
|
||||
}
|
||||
if (!item) item = this.weightedRandomPick(items, weights);
|
||||
} else if (['Quark Drive', 'Protosynthesis'].includes(ability)) {
|
||||
// ...unless the Pokemon can use Booster Energy
|
||||
item = 'Booster Energy';
|
||||
}
|
||||
|
||||
const ivs: PokemonSet['ivs'] = {
|
||||
hp: 31,
|
||||
atk: moves.some(move => this.dex.moves.get(move).category === 'Physical') ? 31 : 0,
|
||||
def: 31,
|
||||
spa: 31,
|
||||
spd: 31,
|
||||
spe: 31,
|
||||
};
|
||||
|
||||
const level = this.forceLevel || TeamGenerator.getLevel(species);
|
||||
|
||||
// For Tera Type, we just pick a random type if it's got Tera Blast or no attacking moves,
|
||||
// and the type of one of its attacking moves otherwise (so it can take advantage of the boosts).
|
||||
let teraType;
|
||||
const nonStatusMoves = moves.filter(move => this.dex.moves.get(move).category !== 'Status');
|
||||
if (!moves.some(m => m.id === 'terablast') && nonStatusMoves.length) {
|
||||
teraType = this.prng.sample(nonStatusMoves.map(move => this.dex.moves.get(move).type));
|
||||
} else {
|
||||
teraType = this.prng.sample([...this.dex.types.all()]).name;
|
||||
}
|
||||
|
||||
return {
|
||||
name: species.name,
|
||||
species: species.name,
|
||||
item,
|
||||
ability,
|
||||
moves: moves.map(m => m.name),
|
||||
nature: 'Quirky',
|
||||
gender: species.gender,
|
||||
evs: {hp: 84, atk: 84, def: 84, spa: 84, spd: 84, spe: 84},
|
||||
ivs,
|
||||
level,
|
||||
teraType,
|
||||
shiny: this.prng.randomChance(1, 1024),
|
||||
happiness: 255,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns true if the Pokémon is a good fit for the team so far, and no otherwise
|
||||
*/
|
||||
protected speciesIsGoodFit(species: Species, stats: TeamStats): boolean {
|
||||
// type check
|
||||
for (const type of this.dex.types.all()) {
|
||||
const effectiveness = this.dex.getEffectiveness(type.name, species.types);
|
||||
if (effectiveness === 1) { // WEAKNESS!
|
||||
if (stats.typeWeaknesses[type.name] === undefined) {
|
||||
stats.typeWeaknesses[type.name] = 0;
|
||||
}
|
||||
if (stats.typeWeaknesses[type.name] >= MAX_WEAK_TO_SAME_TYPE) {
|
||||
// too many weaknesses to this type
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// species passes; increment counters
|
||||
for (const type of this.dex.types.all()) {
|
||||
const effectiveness = this.dex.getEffectiveness(type.name, species.types);
|
||||
if (effectiveness === 1) {
|
||||
stats.typeWeaknesses[type.name]++;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns A weighting for the Pokémon's ability.
|
||||
*/
|
||||
protected getAbilityWeight(ability: Ability): number {
|
||||
return ability.rating + 1; // Some ability ratings are -1
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns A weight for a given move on a given Pokémon.
|
||||
*/
|
||||
protected getMoveWeight(
|
||||
move: Move,
|
||||
teamStats: TeamStats,
|
||||
species: Species,
|
||||
movesSoFar: Move[],
|
||||
ability: string
|
||||
): number {
|
||||
if (!move.exists) return 0;
|
||||
// this is NOT doubles, so there will be no adjacent ally
|
||||
if (move.target === 'adjacentAlly') return 0;
|
||||
|
||||
if (move.category === 'Status') {
|
||||
// The initial value of this weight determines how valuable status moves are vs. attacking moves.
|
||||
// You can raise it to make random status moves more valuable or lower it and increase multipliers
|
||||
// to make only CERTAIN status moves valuable.
|
||||
let weight = 2500;
|
||||
|
||||
// inflicts status
|
||||
if (move.status) weight *= TeamGenerator.statusWeight(move.status) * 2;
|
||||
|
||||
// hazard setters: very important, but we don't need 2 pokemon to set the same hazard on a team
|
||||
const isHazard = (m: Move) => m.sideCondition && m.target === 'foeSide';
|
||||
if (isHazard(move) && (teamStats.hazardSetters[move.id] || 0) < 1) {
|
||||
weight *= move.id === 'spikes' ? 12 : 16;
|
||||
|
||||
// if we are ALREADY setting hazards, setting MORE is really good
|
||||
if (movesSoFar.some(m => isHazard(m))) weight *= 2;
|
||||
teamStats.hazardSetters[move.id]++;
|
||||
}
|
||||
|
||||
// boosts
|
||||
weight *= this.boostWeight(move, movesSoFar, species) * 2;
|
||||
weight *= this.opponentDebuffWeight(move) * 2;
|
||||
|
||||
// protection moves - useful for bulky/stally pokemon
|
||||
if (species.baseStats.def >= 100 || species.baseStats.spd >= 100 || species.baseStats.hp >= 100) {
|
||||
switch (move.volatileStatus) {
|
||||
case 'endure':
|
||||
weight *= 3;
|
||||
break;
|
||||
case 'protect': case 'kingsshield': case 'silktrap':
|
||||
weight *= 4;
|
||||
break;
|
||||
case 'banefulbunker': case 'spikyshield':
|
||||
weight *= 5;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Hardcoded boosts
|
||||
if (move.id in HARDCODED_MOVE_WEIGHTS) weight *= HARDCODED_MOVE_WEIGHTS[move.id];
|
||||
|
||||
// Pokémon with high Attack and Special Attack stats shouldn't have too many status moves,
|
||||
// but on bulkier Pokémon it's more likely to be worth it.
|
||||
const goodAttacker = species.baseStats.atk > 80 || species.baseStats.spa > 80;
|
||||
if (goodAttacker && movesSoFar.filter(m => m.category !== 'Status').length < 2) {
|
||||
weight *= 0.3;
|
||||
}
|
||||
|
||||
return weight;
|
||||
}
|
||||
|
||||
// For Grass Knot and friends, let's just assume they average out to around 60 base power.
|
||||
const isWeirdPowerMove = WEIGHT_BASED_MOVES.includes(move.id);
|
||||
let basePower = isWeirdPowerMove ? 60 : move.basePower;
|
||||
// not how this calc works but it should be close enough
|
||||
if (SPEED_BASED_MOVES.includes(move.id)) basePower = species.baseStats.spe / 2;
|
||||
|
||||
const baseStat = move.category === 'Physical' ? species.baseStats.atk : species.baseStats.spa;
|
||||
// 10% bonus for never-miss moves
|
||||
const accuracy = move.accuracy === true ? 1.1 : move.accuracy / 100;
|
||||
|
||||
let powerEstimate = basePower * baseStat * accuracy;
|
||||
// STAB
|
||||
if (species.types.includes(move.type)) powerEstimate *= ability === 'Adaptability' ? 2 : 1.5;
|
||||
if (ability === 'Technician' && move.basePower <= 60) powerEstimate *= 1.5;
|
||||
if (ability === 'Steely Spirit' && move.type === 'Steel') powerEstimate *= 1.5;
|
||||
if (move.multihit) {
|
||||
const numberOfHits = Array.isArray(move.multihit) ?
|
||||
(ability === 'Skill Link' ? move.multihit[1] : (move.multihit[0] + move.multihit[1]) / 2) :
|
||||
move.multihit;
|
||||
|
||||
powerEstimate *= numberOfHits;
|
||||
}
|
||||
|
||||
// If it uses the attacking stat that we don't boost, it's less useful!
|
||||
const hasSpecialSetup = movesSoFar.some(m => m.boosts?.spa || m.self?.boosts?.spa || m.selfBoost?.boosts?.spa);
|
||||
const hasPhysicalSetup = movesSoFar.some(m => m.boosts?.atk || m.self?.boosts?.atk || m.selfBoost?.boosts?.atk);
|
||||
if (move.category === 'Physical' && hasSpecialSetup) powerEstimate *= 0.7;
|
||||
if (move.category === 'Special' && hasPhysicalSetup) powerEstimate *= 0.7;
|
||||
|
||||
const abilityBonus = (
|
||||
((ABILITY_MOVE_BONUSES[ability] || {})[move.id] || 1) *
|
||||
((ABILITY_MOVE_TYPE_BONUSES[ability] || {})[move.type] || 1)
|
||||
);
|
||||
|
||||
let weight = powerEstimate * abilityBonus;
|
||||
if (move.id in HARDCODED_MOVE_WEIGHTS) weight *= HARDCODED_MOVE_WEIGHTS[move.id];
|
||||
|
||||
// priority is more useful when you're slower
|
||||
if (move.priority > 0) weight *= (Math.max(130 - species.baseStats.spe, 0) / 130) * 0.5 + 1;
|
||||
if (move.priority < 0) weight *= Math.min((1 / species.baseStats.spe) * 30, 1);
|
||||
|
||||
// flags
|
||||
if (move.flags.charge || (move.flags.recharge && ability !== 'Truant')) weight *= 0.5;
|
||||
if (move.flags.contact) {
|
||||
if (ability === 'Tough Claws') weight *= 1.3;
|
||||
if (ability === 'Unseen Fist') weight *= 1.1;
|
||||
}
|
||||
if (move.flags.bite && ability === 'Strong Jaw') weight *= 1.5;
|
||||
// 10% boost for ability to break subs
|
||||
if (move.flags.bypasssub) weight *= 1.1;
|
||||
if (move.flags.pulse && ability === 'Mega Launcher') weight *= 1.5;
|
||||
if (move.flags.punch && ability === 'Iron Fist') weight *= 1.2;
|
||||
if (!move.flags.protect) weight *= 1.1;
|
||||
if (move.flags.slicing && ability === 'Sharpness') weight *= 1.5;
|
||||
|
||||
// boosts/secondaries
|
||||
// TODO: consider more possible secondaries
|
||||
weight *= this.boostWeight(move, movesSoFar, species);
|
||||
if (move.secondary?.status) {
|
||||
weight *= TeamGenerator.statusWeight(move.secondary.status, (move.secondary.chance || 100) / 100);
|
||||
}
|
||||
|
||||
// self-inflicted confusion or locking yourself in
|
||||
if (move.self?.volatileStatus) weight *= 0.8;
|
||||
|
||||
// downweight moves if we already have an attacking move of the same type
|
||||
if (movesSoFar.some(m => m.category !== 'Status' && m.type === move.type && m.basePower >= 60)) weight *= 0.3;
|
||||
|
||||
if (move.selfdestruct) weight *= 0.3;
|
||||
if (move.recoil) weight *= 1 - (move.recoil[0] / move.recoil[1]);
|
||||
if (move.mindBlownRecoil) weight *= 0.25;
|
||||
if (move.flags['futuremove']) weight *= 0.3;
|
||||
// TODO: account for normal higher-crit-chance moves
|
||||
if (move.willCrit) weight *= 1.45;
|
||||
|
||||
if (move.drain) {
|
||||
const drainedFraction = move.drain[0] / move.drain[1];
|
||||
weight *= 1 + (drainedFraction * 0.5);
|
||||
}
|
||||
|
||||
// don't need 2 healing moves
|
||||
if (move.heal && movesSoFar.some(m => m.heal)) weight *= 0.5;
|
||||
|
||||
return weight;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns A multiplier to a move weighting based on the status it inflicts.
|
||||
*/
|
||||
protected static statusWeight(status: string, chance = 1): number {
|
||||
if (chance !== 1) return 1 + (TeamGenerator.statusWeight(status) - 1) * chance;
|
||||
|
||||
switch (status) {
|
||||
case 'brn': return 1.5;
|
||||
case 'frz': return 5;
|
||||
case 'par': return 1.5;
|
||||
case 'psn': return 1.5;
|
||||
case 'tox': return 4;
|
||||
case 'slp': return 4;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns A multiplier to a move weighting based on the boosts it produces for the user.
|
||||
*/
|
||||
protected boostWeight(move: Move, movesSoFar: Move[], species: Species): number {
|
||||
const physicalIsRelevant = (
|
||||
move.category === 'Physical' ||
|
||||
movesSoFar.some(m => m.category === 'Physical')
|
||||
);
|
||||
const specialIsRelevant = (
|
||||
move.category === 'Special' ||
|
||||
movesSoFar.some(m => m.category === 'Special')
|
||||
);
|
||||
|
||||
let weight = 1;
|
||||
for (const {chance, boosts} of [
|
||||
{chance: 1, boosts: move.boosts},
|
||||
{chance: 1, boosts: move.self?.boosts},
|
||||
{chance: 1, boosts: move.selfBoost?.boosts},
|
||||
{
|
||||
chance: move.secondary ? ((move.secondary.chance || 100) / 100) : 0,
|
||||
boosts: move.target === 'self' ? move.secondary?.boosts : move.secondary?.self?.boosts,
|
||||
},
|
||||
]) {
|
||||
if (!boosts || chance === 0) continue;
|
||||
|
||||
if (boosts.atk && physicalIsRelevant) weight += (chance || 1) * 0.5 * boosts.atk;
|
||||
if (boosts.spa && specialIsRelevant) weight += (chance || 1) * 0.5 * boosts.spa;
|
||||
|
||||
// TODO: should these scale by base stat magnitude instead of using ternaries?
|
||||
// defense/special defense boost is less useful if we have some bulk to start with
|
||||
if (boosts.def) weight += (chance || 1) * 0.5 * boosts.def * (species.baseStats.def > 75 ? 1 : 0.5);
|
||||
if (boosts.spd) weight += (chance || 1) * 0.5 * boosts.spd * (species.baseStats.spd > 75 ? 1 : 0.5);
|
||||
|
||||
// speed boost is less useful for fast pokemon
|
||||
if (boosts.spe) weight += (chance || 1) * 0.5 * boosts.spe * (species.baseStats.spe > 120 ? 0.5 : 1);
|
||||
}
|
||||
|
||||
return weight;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns A weight for a move based on how much it will reduce the opponent's stats.
|
||||
*/
|
||||
protected opponentDebuffWeight(move: Move): number {
|
||||
if (!['allAdjacentFoes', 'allAdjacent', 'foeSide', 'normal'].includes(move.target)) return 1;
|
||||
|
||||
let averageNumberOfDebuffs = 0;
|
||||
for (const {chance, boosts} of [
|
||||
{chance: 1, boosts: move.boosts},
|
||||
{
|
||||
chance: move.secondary ? ((move.secondary.chance || 100) / 100) : 0,
|
||||
boosts: move.secondary?.boosts,
|
||||
},
|
||||
]) {
|
||||
if (!boosts || chance === 0) continue;
|
||||
|
||||
const numBoosts = Object.values(boosts).filter(x => x < 0).length;
|
||||
averageNumberOfDebuffs += chance * numBoosts;
|
||||
}
|
||||
|
||||
return 1 + (0.25 * averageNumberOfDebuffs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns A weight for an item.
|
||||
*/
|
||||
protected getItemWeight(item: Item, teamStats: TeamStats, species: Species, moves: Move[], ability: string): number {
|
||||
let weight;
|
||||
switch (item.id) {
|
||||
// Choice Items
|
||||
case 'choiceband':
|
||||
return moves.every(x => x.category === 'Physical') ? 50 : 0;
|
||||
case 'choicespecs':
|
||||
return moves.every(x => x.category === 'Special') ? 50 : 0;
|
||||
case 'choicescarf':
|
||||
if (moves.some(x => x.category === 'Status')) return 0;
|
||||
if (species.baseStats.spe > 65 && species.baseStats.spe < 120) return 50;
|
||||
return 10;
|
||||
|
||||
// Generally Decent Items
|
||||
case 'lifeorb':
|
||||
return moves.filter(x => x.category !== 'Status').length * 8;
|
||||
case 'focussash':
|
||||
if (ability === 'Sturdy') return 0;
|
||||
// frail
|
||||
if (species.baseStats.hp < 80 && species.baseStats.def < 80 && species.baseStats.spd < 80) return 35;
|
||||
return 10;
|
||||
case 'heavydutyboots':
|
||||
switch (this.dex.getEffectiveness('Rock', species)) {
|
||||
case 1: return 30; // super effective
|
||||
case 0: return 10; // neutral
|
||||
}
|
||||
return 5; // not very effective/other
|
||||
case 'assaultvest':
|
||||
if (moves.some(x => x.category === 'Status')) return 0;
|
||||
return 30;
|
||||
|
||||
// status
|
||||
case 'flameorb':
|
||||
weight = ability === 'Guts' && !species.types.includes('Fire') ? 30 : 0;
|
||||
if (moves.some(m => m.id === 'facade')) weight *= 2;
|
||||
return weight;
|
||||
case 'toxicorb':
|
||||
if (species.types.includes('Poison')) return 0;
|
||||
|
||||
weight = 0;
|
||||
if (ability === 'Poison Heal') weight += 25;
|
||||
if (moves.some(m => m.id === 'facade')) weight += 25;
|
||||
|
||||
return weight;
|
||||
|
||||
// Healing
|
||||
case 'leftovers':
|
||||
return 20;
|
||||
case 'blacksludge':
|
||||
return species.types.includes('Poison') ? 40 : 0;
|
||||
|
||||
// berries
|
||||
case 'sitrusberry': case 'magoberry':
|
||||
return 20;
|
||||
|
||||
case 'throatspray':
|
||||
if (moves.some(m => m.flags.sound) && moves.some(m => m.category === 'Special')) return 30;
|
||||
return 0;
|
||||
|
||||
default:
|
||||
// probably not a very good item
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns The level a Pokémon should be.
|
||||
*/
|
||||
protected static getLevel(species: Species): number {
|
||||
if (levelOverride[species.id]) return levelOverride[species.id];
|
||||
|
||||
switch (species.tier) {
|
||||
case 'Uber': return 70;
|
||||
case 'OU': case 'Unreleased': return 80;
|
||||
case 'UU': return 90;
|
||||
case 'LC': case 'NFE': return 100;
|
||||
}
|
||||
|
||||
return 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* Picks a choice from `choices` based on the weights in `weights`.
|
||||
* `weights` must be the same length as `choices`.
|
||||
*/
|
||||
weightedRandomPick<T>(
|
||||
choices: T[],
|
||||
weights: number[],
|
||||
options?: {remove?: boolean}
|
||||
) {
|
||||
if (!choices.length) throw new Error(`Can't pick from an empty list`);
|
||||
if (choices.length !== weights.length) throw new Error(`Choices and weights must be the same length`);
|
||||
|
||||
const totalWeight = weights.reduce((a, b) => a + b, 0);
|
||||
|
||||
let randomWeight = this.prng.next(0, totalWeight);
|
||||
for (let i = 0; i < choices.length; i++) {
|
||||
randomWeight -= weights[i];
|
||||
if (randomWeight < 0) {
|
||||
const choice = choices[i];
|
||||
if (options?.remove) choices.splice(i, 1);
|
||||
return choice;
|
||||
}
|
||||
}
|
||||
|
||||
if (options?.remove && choices.length) return choices.pop()!;
|
||||
return choices[choices.length - 1];
|
||||
}
|
||||
|
||||
setSeed(seed: PRNGSeed) {
|
||||
this.prng.seed = seed;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
||||
export const Conditions: {[k: string]: ConditionData} = {
|
||||
brn: {
|
||||
name: 'brn',
|
||||
effectType: 'Status',
|
||||
|
|
@ -6,7 +6,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
if (sourceEffect && sourceEffect.id === 'flameorb') {
|
||||
this.add('-status', target, 'brn', '[from] item: Flame Orb');
|
||||
} else if (sourceEffect && sourceEffect.effectType === 'Ability') {
|
||||
this.add('-status', target, 'brn', '[from] ability: ' + sourceEffect.name, `[of] ${source}`);
|
||||
this.add('-status', target, 'brn', '[from] ability: ' + sourceEffect.name, '[of] ' + source);
|
||||
} else {
|
||||
this.add('-status', target, 'brn');
|
||||
}
|
||||
|
|
@ -22,12 +22,11 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
effectType: 'Status',
|
||||
onStart(target, source, sourceEffect) {
|
||||
if (sourceEffect && sourceEffect.effectType === 'Ability') {
|
||||
this.add('-status', target, 'par', '[from] ability: ' + sourceEffect.name, `[of] ${source}`);
|
||||
this.add('-status', target, 'par', '[from] ability: ' + sourceEffect.name, '[of] ' + source);
|
||||
} else {
|
||||
this.add('-status', target, 'par');
|
||||
}
|
||||
},
|
||||
onModifySpePriority: -101,
|
||||
onModifySpe(spe, pokemon) {
|
||||
// Paralysis occurs after all other Speed modifiers, so evaluate all modifiers up to this point first
|
||||
spe = this.finalModify(spe);
|
||||
|
|
@ -49,9 +48,9 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
effectType: 'Status',
|
||||
onStart(target, source, sourceEffect) {
|
||||
if (sourceEffect && sourceEffect.effectType === 'Ability') {
|
||||
this.add('-status', target, 'slp', '[from] ability: ' + sourceEffect.name, `[of] ${source}`);
|
||||
this.add('-status', target, 'slp', '[from] ability: ' + sourceEffect.name, '[of] ' + source);
|
||||
} else if (sourceEffect && sourceEffect.effectType === 'Move') {
|
||||
this.add('-status', target, 'slp', `[from] move: ${sourceEffect.name}`);
|
||||
this.add('-status', target, 'slp', '[from] move: ' + sourceEffect.name);
|
||||
} else {
|
||||
this.add('-status', target, 'slp');
|
||||
}
|
||||
|
|
@ -85,7 +84,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
effectType: 'Status',
|
||||
onStart(target, source, sourceEffect) {
|
||||
if (sourceEffect && sourceEffect.effectType === 'Ability') {
|
||||
this.add('-status', target, 'frz', '[from] ability: ' + sourceEffect.name, `[of] ${source}`);
|
||||
this.add('-status', target, 'frz', '[from] ability: ' + sourceEffect.name, '[of] ' + source);
|
||||
} else {
|
||||
this.add('-status', target, 'frz');
|
||||
}
|
||||
|
|
@ -95,7 +94,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
},
|
||||
onBeforeMovePriority: 10,
|
||||
onBeforeMove(pokemon, target, move) {
|
||||
if (move.flags['defrost'] && !(move.id === 'burnup' && !pokemon.hasType('Fire'))) return;
|
||||
if (move.flags['defrost']) return;
|
||||
if (this.randomChance(1, 5)) {
|
||||
pokemon.cureStatus();
|
||||
return;
|
||||
|
|
@ -105,7 +104,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
},
|
||||
onModifyMove(move, pokemon) {
|
||||
if (move.flags['defrost']) {
|
||||
this.add('-curestatus', pokemon, 'frz', `[from] move: ${move}`);
|
||||
this.add('-curestatus', pokemon, 'frz', '[from] move: ' + move);
|
||||
pokemon.clearStatus();
|
||||
}
|
||||
},
|
||||
|
|
@ -115,7 +114,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
}
|
||||
},
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (move.type === 'Fire' && move.category !== 'Status' && move.id !== 'polarflare') {
|
||||
if (move.type === 'Fire' && move.category !== 'Status') {
|
||||
target.cureStatus();
|
||||
}
|
||||
},
|
||||
|
|
@ -125,7 +124,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
effectType: 'Status',
|
||||
onStart(target, source, sourceEffect) {
|
||||
if (sourceEffect && sourceEffect.effectType === 'Ability') {
|
||||
this.add('-status', target, 'psn', '[from] ability: ' + sourceEffect.name, `[of] ${source}`);
|
||||
this.add('-status', target, 'psn', '[from] ability: ' + sourceEffect.name, '[of] ' + source);
|
||||
} else {
|
||||
this.add('-status', target, 'psn');
|
||||
}
|
||||
|
|
@ -143,7 +142,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
if (sourceEffect && sourceEffect.id === 'toxicorb') {
|
||||
this.add('-status', target, 'tox', '[from] item: Toxic Orb');
|
||||
} else if (sourceEffect && sourceEffect.effectType === 'Ability') {
|
||||
this.add('-status', target, 'tox', '[from] ability: ' + sourceEffect.name, `[of] ${source}`);
|
||||
this.add('-status', target, 'tox', '[from] ability: ' + sourceEffect.name, '[of] ' + source);
|
||||
} else {
|
||||
this.add('-status', target, 'tox');
|
||||
}
|
||||
|
|
@ -165,8 +164,6 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
onStart(target, source, sourceEffect) {
|
||||
if (sourceEffect?.id === 'lockedmove') {
|
||||
this.add('-start', target, 'confusion', '[fatigue]');
|
||||
} else if (sourceEffect?.effectType === 'Ability') {
|
||||
this.add('-start', target, 'confusion', '[from] ability: ' + sourceEffect.name, `[of] ${source}`);
|
||||
} else {
|
||||
this.add('-start', target, 'confusion');
|
||||
}
|
||||
|
|
@ -190,7 +187,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
this.activeTarget = pokemon;
|
||||
const damage = this.actions.getConfusionDamage(pokemon, 40);
|
||||
if (typeof damage !== 'number') throw new Error("Confusion damage not dealt");
|
||||
const activeMove = { id: this.toID('confused'), effectType: 'Move', type: '???' };
|
||||
const activeMove = {id: this.toID('confused'), effectType: 'Move', type: '???'};
|
||||
this.damage(damage, pokemon, pokemon, activeMove as ActiveMove);
|
||||
return false;
|
||||
},
|
||||
|
|
@ -227,7 +224,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
return this.random(5, 7);
|
||||
},
|
||||
onStart(pokemon, source) {
|
||||
this.add('-activate', pokemon, 'move: ' + this.effectState.sourceEffect, `[of] ${source}`);
|
||||
this.add('-activate', pokemon, 'move: ' + this.effectState.sourceEffect, '[of] ' + source);
|
||||
this.effectState.boundDivisor = source.hasItem('bindingband') ? 6 : 8;
|
||||
},
|
||||
onResidualOrder: 13,
|
||||
|
|
@ -270,11 +267,6 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
this.effectState.duration = 2;
|
||||
}
|
||||
},
|
||||
onAfterMove(pokemon) {
|
||||
if (this.effectState.duration === 1) {
|
||||
pokemon.removeVolatile('lockedmove');
|
||||
}
|
||||
},
|
||||
onEnd(target) {
|
||||
if (this.effectState.trueDuration > 1) return;
|
||||
target.addVolatile('confusion');
|
||||
|
|
@ -379,18 +371,8 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
futuremove: {
|
||||
// this is a slot condition
|
||||
name: 'futuremove',
|
||||
onStart(target) {
|
||||
this.effectState.targetSlot = target.getSlot();
|
||||
this.effectState.endingTurn = (this.turn - 1) + 2;
|
||||
if (this.effectState.endingTurn >= 254) {
|
||||
this.hint(`In Gen 8+, Future attacks will never resolve when used on the 255th turn or later.`);
|
||||
}
|
||||
},
|
||||
duration: 3,
|
||||
onResidualOrder: 3,
|
||||
onResidual(target: Pokemon) {
|
||||
if (this.getOverflowedTurnCount() < this.effectState.endingTurn) return;
|
||||
target.side.removeSlotCondition(this.getAtSlot(this.effectState.targetSlot), 'futuremove');
|
||||
},
|
||||
onEnd(target) {
|
||||
const data = this.effectState;
|
||||
// time's up; time to hit! :D
|
||||
|
|
@ -410,6 +392,9 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
if (data.source.hasAbility('normalize') && this.gen >= 6) {
|
||||
data.moveData.type = 'Normal';
|
||||
}
|
||||
if (data.source.hasAbility('adaptability') && this.gen >= 6) {
|
||||
data.moveData.stab = 2;
|
||||
}
|
||||
const hitMove = new this.dex.Move(data.moveData) as ActiveMove;
|
||||
|
||||
this.actions.trySpreadMoveHit([target], data.source, hitMove, true);
|
||||
|
|
@ -428,6 +413,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
this.effectState.sourceEffect = sourceEffect;
|
||||
this.add('-activate', source, 'healreplacement');
|
||||
},
|
||||
onSwitchInPriority: 1,
|
||||
onSwitchIn(target) {
|
||||
if (!target.fainted) {
|
||||
target.heal(target.maxhp);
|
||||
|
|
@ -448,7 +434,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
// this.effectState.counter should never be undefined here.
|
||||
// However, just in case, use 1 if it is undefined.
|
||||
const counter = this.effectState.counter || 1;
|
||||
this.debug(`Success chance: ${Math.round(100 / counter)}%`);
|
||||
this.debug("Success chance: " + Math.round(100 / counter) + "%");
|
||||
const success = this.randomChance(1, counter);
|
||||
if (!success) delete pokemon.volatiles['stall'];
|
||||
return success;
|
||||
|
|
@ -497,7 +483,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
onFieldStart(field, source, effect) {
|
||||
if (effect?.effectType === 'Ability') {
|
||||
if (this.gen <= 5) this.effectState.duration = 0;
|
||||
this.add('-weather', 'RainDance', '[from] ability: ' + effect.name, `[of] ${source}`);
|
||||
this.add('-weather', 'RainDance', '[from] ability: ' + effect.name, '[of] ' + source);
|
||||
} else {
|
||||
this.add('-weather', 'RainDance');
|
||||
}
|
||||
|
|
@ -532,7 +518,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
}
|
||||
},
|
||||
onFieldStart(field, source, effect) {
|
||||
this.add('-weather', 'PrimordialSea', '[from] ability: ' + effect.name, `[of] ${source}`);
|
||||
this.add('-weather', 'PrimordialSea', '[from] ability: ' + effect.name, '[of] ' + source);
|
||||
},
|
||||
onFieldResidualOrder: 1,
|
||||
onFieldResidual() {
|
||||
|
|
@ -571,7 +557,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
onFieldStart(battle, source, effect) {
|
||||
if (effect?.effectType === 'Ability') {
|
||||
if (this.gen <= 5) this.effectState.duration = 0;
|
||||
this.add('-weather', 'SunnyDay', '[from] ability: ' + effect.name, `[of] ${source}`);
|
||||
this.add('-weather', 'SunnyDay', '[from] ability: ' + effect.name, '[of] ' + source);
|
||||
} else {
|
||||
this.add('-weather', 'SunnyDay');
|
||||
}
|
||||
|
|
@ -610,7 +596,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
}
|
||||
},
|
||||
onFieldStart(field, source, effect) {
|
||||
this.add('-weather', 'DesolateLand', '[from] ability: ' + effect.name, `[of] ${source}`);
|
||||
this.add('-weather', 'DesolateLand', '[from] ability: ' + effect.name, '[of] ' + source);
|
||||
},
|
||||
onImmunity(type, pokemon) {
|
||||
if (pokemon.hasItem('utilityumbrella')) return;
|
||||
|
|
@ -646,7 +632,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
onFieldStart(field, source, effect) {
|
||||
if (effect?.effectType === 'Ability') {
|
||||
if (this.gen <= 5) this.effectState.duration = 0;
|
||||
this.add('-weather', 'Sandstorm', '[from] ability: ' + effect.name, `[of] ${source}`);
|
||||
this.add('-weather', 'Sandstorm', '[from] ability: ' + effect.name, '[of] ' + source);
|
||||
} else {
|
||||
this.add('-weather', 'Sandstorm');
|
||||
}
|
||||
|
|
@ -676,7 +662,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
onFieldStart(field, source, effect) {
|
||||
if (effect?.effectType === 'Ability') {
|
||||
if (this.gen <= 5) this.effectState.duration = 0;
|
||||
this.add('-weather', 'Hail', '[from] ability: ' + effect.name, `[of] ${source}`);
|
||||
this.add('-weather', 'Hail', '[from] ability: ' + effect.name, '[of] ' + source);
|
||||
} else {
|
||||
this.add('-weather', 'Hail');
|
||||
}
|
||||
|
|
@ -693,8 +679,8 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
this.add('-weather', 'none');
|
||||
},
|
||||
},
|
||||
snowscape: {
|
||||
name: 'Snowscape',
|
||||
snow: {
|
||||
name: 'Snow',
|
||||
effectType: 'Weather',
|
||||
duration: 5,
|
||||
durationCallback(source, effect) {
|
||||
|
|
@ -705,22 +691,22 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
},
|
||||
onModifyDefPriority: 10,
|
||||
onModifyDef(def, pokemon) {
|
||||
if (pokemon.hasType('Ice') && this.field.isWeather('snowscape')) {
|
||||
if (pokemon.hasType('Ice') && this.field.isWeather('snow')) {
|
||||
return this.modify(def, 1.5);
|
||||
}
|
||||
},
|
||||
onFieldStart(field, source, effect) {
|
||||
if (effect?.effectType === 'Ability') {
|
||||
if (this.gen <= 5) this.effectState.duration = 0;
|
||||
this.add('-weather', 'Snowscape', '[from] ability: ' + effect.name, `[of] ${source}`);
|
||||
this.add('-weather', 'Snow', '[from] ability: ' + effect.name, '[of] ' + source);
|
||||
} else {
|
||||
this.add('-weather', 'Snowscape');
|
||||
this.add('-weather', 'Snow');
|
||||
}
|
||||
},
|
||||
onFieldResidualOrder: 1,
|
||||
onFieldResidual() {
|
||||
this.add('-weather', 'Snowscape', '[upkeep]');
|
||||
if (this.field.isWeather('snowscape')) this.eachEvent('Weather');
|
||||
this.add('-weather', 'Snow', '[upkeep]');
|
||||
if (this.field.isWeather('snow')) this.eachEvent('Weather');
|
||||
},
|
||||
onFieldEnd() {
|
||||
this.add('-weather', 'none');
|
||||
|
|
@ -738,7 +724,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
}
|
||||
},
|
||||
onFieldStart(field, source, effect) {
|
||||
this.add('-weather', 'DeltaStream', '[from] ability: ' + effect.name, `[of] ${source}`);
|
||||
this.add('-weather', 'DeltaStream', '[from] ability: ' + effect.name, '[of] ' + source);
|
||||
},
|
||||
onFieldResidualOrder: 1,
|
||||
onFieldResidual() {
|
||||
|
|
@ -810,7 +796,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
name: "Commanded",
|
||||
noCopy: true,
|
||||
onStart(pokemon) {
|
||||
this.boost({ atk: 2, spa: 2, spe: 2, def: 2, spd: 2 }, pokemon);
|
||||
this.boost({atk: 2, spa: 2, spe: 2, def: 2, spd: 2}, pokemon);
|
||||
},
|
||||
onDragOutPriority: 2,
|
||||
onDragOut() {
|
||||
|
|
@ -835,9 +821,11 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
onTrapPokemon(pokemon) {
|
||||
pokemon.trapped = true;
|
||||
},
|
||||
// Dodging moves is handled in BattleActions#hitStepInvulnerabilityEvent
|
||||
// This is here for moves that manually call this event like Perish Song
|
||||
onInvulnerability: false,
|
||||
// Override No Guard
|
||||
onInvulnerabilityPriority: 2,
|
||||
onInvulnerability(target, source, move) {
|
||||
return false;
|
||||
},
|
||||
onBeforeTurn(pokemon) {
|
||||
this.queue.cancelAction(pokemon);
|
||||
},
|
||||
|
|
@ -879,71 +867,12 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
return [type];
|
||||
},
|
||||
},
|
||||
zacian: {
|
||||
name: 'Zacian',
|
||||
onBattleStart(pokemon) {
|
||||
if (pokemon.item !== 'rustedsword') return;
|
||||
const rawSpecies = this.dex.species.get('Zacian-Crowned');
|
||||
const species = pokemon.setSpecies(rawSpecies);
|
||||
if (!species) return;
|
||||
pokemon.baseSpecies = rawSpecies;
|
||||
pokemon.details = pokemon.getUpdatedDetails();
|
||||
pokemon.setAbility(species.abilities['0'], null, null, true);
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
|
||||
const ironHeadIndex = pokemon.baseMoves.indexOf('ironhead');
|
||||
if (ironHeadIndex >= 0) {
|
||||
const move = this.dex.moves.get('behemothblade');
|
||||
pokemon.baseMoveSlots[ironHeadIndex] = {
|
||||
move: move.name,
|
||||
id: move.id,
|
||||
pp: move.noPPBoosts ? move.pp : move.pp * 8 / 5,
|
||||
maxpp: move.noPPBoosts ? move.pp : move.pp * 8 / 5,
|
||||
target: move.target,
|
||||
disabled: false,
|
||||
disabledSource: '',
|
||||
used: false,
|
||||
};
|
||||
pokemon.moveSlots = pokemon.baseMoveSlots.slice();
|
||||
}
|
||||
},
|
||||
},
|
||||
zamazenta: {
|
||||
name: 'Zamazenta',
|
||||
onBattleStart(pokemon) {
|
||||
if (pokemon.item !== 'rustedshield') return;
|
||||
const rawSpecies = this.dex.species.get('Zamazenta-Crowned');
|
||||
const species = pokemon.setSpecies(rawSpecies);
|
||||
if (!species) return;
|
||||
pokemon.baseSpecies = rawSpecies;
|
||||
pokemon.details = pokemon.getUpdatedDetails();
|
||||
pokemon.setAbility(species.abilities['0'], null, null, true);
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
|
||||
const ironHeadIndex = pokemon.baseMoves.indexOf('ironhead');
|
||||
if (ironHeadIndex >= 0) {
|
||||
const move = this.dex.moves.get('behemothbash');
|
||||
pokemon.baseMoveSlots[ironHeadIndex] = {
|
||||
move: move.name,
|
||||
id: move.id,
|
||||
pp: move.noPPBoosts ? move.pp : move.pp * 8 / 5,
|
||||
maxpp: move.noPPBoosts ? move.pp : move.pp * 8 / 5,
|
||||
target: move.target,
|
||||
disabled: false,
|
||||
disabledSource: '',
|
||||
used: false,
|
||||
};
|
||||
pokemon.moveSlots = pokemon.baseMoveSlots.slice();
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
rolloutstorage: {
|
||||
name: 'rolloutstorage',
|
||||
duration: 2,
|
||||
onBasePower(relayVar, source, target, move) {
|
||||
let bp = Math.max(1, move.basePower);
|
||||
bp *= 2 ** source.volatiles['rolloutstorage'].contactHitCount;
|
||||
bp *= Math.pow(2, source.volatiles['rolloutstorage'].contactHitCount);
|
||||
if (source.volatiles['defensecurl']) {
|
||||
bp *= 2;
|
||||
}
|
||||
|
|
|
|||
2854
data/formats-data.ts
2854
data/formats-data.ts
File diff suppressed because it is too large
Load Diff
1652
data/items.ts
1652
data/items.ts
File diff suppressed because it is too large
Load Diff
36785
data/learnsets.ts
36785
data/learnsets.ts
File diff suppressed because it is too large
Load Diff
|
|
@ -1,206 +0,0 @@
|
|||
export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTable = {
|
||||
magician: {
|
||||
inherit: true,
|
||||
onAfterMoveSecondarySelf(source, target, move) {
|
||||
if (!move || source.switchFlag === true || !move.hitTargets || source.item || source.volatiles['gem'] ||
|
||||
move.id === 'fling' || move.category === 'Status') return;
|
||||
const hitTargets = move.hitTargets;
|
||||
this.speedSort(hitTargets);
|
||||
for (const pokemon of hitTargets) {
|
||||
if (pokemon !== source) {
|
||||
const yourItem = pokemon.takeItem(source);
|
||||
if (!yourItem) continue;
|
||||
if (!source.setItem(yourItem)) {
|
||||
if (!this.dex.items.get(yourItem.id).exists) {
|
||||
pokemon.setItem(yourItem.id);
|
||||
continue;
|
||||
}
|
||||
pokemon.item = yourItem.id; // bypass setItem so we don't break choicelock or anything
|
||||
continue;
|
||||
}
|
||||
this.add('-item', source, yourItem, '[from] ability: Magician', `[of] ${pokemon}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
neutralizinggas: {
|
||||
inherit: true,
|
||||
onSwitchIn(pokemon) {
|
||||
this.add('-ability', pokemon, 'Neutralizing Gas');
|
||||
pokemon.abilityState.ending = false;
|
||||
const strongWeathers = ['desolateland', 'primordialsea', 'deltastream'];
|
||||
for (const target of this.getAllActive()) {
|
||||
if (target.hasItem('Ability Shield')) {
|
||||
this.add('-block', target, 'item: Ability Shield');
|
||||
continue;
|
||||
}
|
||||
// Can't suppress a Tatsugiri inside of Dondozo already
|
||||
if (target.volatiles['commanding']) {
|
||||
continue;
|
||||
}
|
||||
if (target.illusion) {
|
||||
this.singleEvent('End', this.dex.abilities.get('Illusion'), target.abilityState, target, pokemon, 'neutralizinggas');
|
||||
}
|
||||
if (target.volatiles['slowstart']) {
|
||||
delete target.volatiles['slowstart'];
|
||||
this.add('-end', target, 'Slow Start', '[silent]');
|
||||
}
|
||||
if (strongWeathers.includes(target.getAbility().id)) {
|
||||
this.singleEvent('End', this.dex.abilities.get(target.getAbility().id), target.abilityState, target, pokemon, 'neutralizinggas');
|
||||
}
|
||||
if (!this.dex.abilities.get(target.ability).exists) {
|
||||
const isItem = (target.m.scrambled.items as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
|
||||
if (isItem >= 0) {
|
||||
target.removeVolatile('item:' + this.toID(target.m.scrambled.items[isItem].thing));
|
||||
} else if ((target.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability') >= 0) {
|
||||
const isMove = (target.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
|
||||
const indexOfMove = target.moveSlots.findIndex(m => this.toID(target.m.scrambled.moves[isMove].thing) === m.id);
|
||||
if (indexOfMove >= 0) target.moveSlots.splice(indexOfMove, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onEnd(source) {
|
||||
if (source.transformed) return;
|
||||
for (const pokemon of this.getAllActive()) {
|
||||
if (pokemon !== source && pokemon.hasAbility('Neutralizing Gas')) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.add('-end', source, 'ability: Neutralizing Gas');
|
||||
|
||||
// FIXME this happens before the pokemon switches out, should be the opposite order.
|
||||
// Not an easy fix since we cant use a supported event. Would need some kind of special event that
|
||||
// gathers events to run after the switch and then runs them when the ability is no longer accessible.
|
||||
// (If you're tackling this, do note extreme weathers have the same issue)
|
||||
|
||||
// Mark this pokemon's ability as ending so Pokemon#ignoringAbility skips it
|
||||
if (source.abilityState.ending) return;
|
||||
source.abilityState.ending = true;
|
||||
const sortedActive = this.getAllActive();
|
||||
this.speedSort(sortedActive);
|
||||
for (const pokemon of sortedActive) {
|
||||
if (pokemon !== source) {
|
||||
if (pokemon.getAbility().flags['cantsuppress']) continue; // does not interact with e.g Ice Face, Zen Mode
|
||||
if (pokemon.hasItem('abilityshield')) continue; // don't restart abilities that weren't suppressed
|
||||
|
||||
// Will be suppressed by Pokemon#ignoringAbility if needed
|
||||
this.singleEvent('Start', pokemon.getAbility(), pokemon.abilityState, pokemon);
|
||||
if (pokemon.ability === "gluttony") {
|
||||
pokemon.abilityState.gluttony = false;
|
||||
}
|
||||
}
|
||||
if (!this.dex.abilities.get(pokemon.ability).exists) {
|
||||
const isItem = (pokemon.m.scrambled.items as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
|
||||
if (isItem >= 0) {
|
||||
pokemon.addVolatile('item:' + this.toID(pokemon.m.scrambled.items[isItem].thing));
|
||||
} else if ((pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability') >= 0) {
|
||||
const findMove = (pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
|
||||
const findSlot = pokemon.baseMoveSlots.find(e => e.id === this.toID(pokemon.m.scrambled.moves[findMove].thing));
|
||||
pokemon.moveSlots.push(this.dex.deepClone(findSlot));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
pickpocket: {
|
||||
inherit: true,
|
||||
onAfterMoveSecondary(target, source, move) {
|
||||
if (source && source !== target && move?.flags['contact']) {
|
||||
if (target.item || target.switchFlag || target.forceSwitchFlag || source.switchFlag === true) {
|
||||
return;
|
||||
}
|
||||
const yourItem = source.takeItem(target);
|
||||
if (!yourItem) {
|
||||
return;
|
||||
}
|
||||
if (!target.setItem(yourItem)) {
|
||||
if (!this.dex.items.get(yourItem.id).exists) {
|
||||
target.setItem(yourItem.id);
|
||||
return;
|
||||
}
|
||||
source.item = yourItem.id;
|
||||
return;
|
||||
}
|
||||
this.add('-enditem', source, yourItem, '[silent]', '[from] ability: Pickpocket', `[of] ${source}`);
|
||||
this.add('-item', target, yourItem, '[from] ability: Pickpocket', `[of] ${source}`);
|
||||
}
|
||||
},
|
||||
},
|
||||
trace: {
|
||||
inherit: true,
|
||||
onStart(pokemon) {
|
||||
this.effectState.seek = true;
|
||||
// n.b. only affects Hackmons
|
||||
// interaction with No Ability is complicated: https://www.smogon.com/forums/threads/pokemon-sun-moon-battle-mechanics-research.3586701/page-76#post-7790209
|
||||
if (pokemon.adjacentFoes().some(foeActive => foeActive.ability === 'noability')) {
|
||||
this.effectState.seek = false;
|
||||
}
|
||||
// interaction with Ability Shield is similar to No Ability
|
||||
if (pokemon.hasItem('Ability Shield') && this.toID(pokemon.ability) === 'trace') {
|
||||
this.add('-block', pokemon, 'item: Ability Shield');
|
||||
this.effectState.seek = false;
|
||||
}
|
||||
if (this.effectState.seek) {
|
||||
this.singleEvent('Update', this.effect, this.effectState, pokemon);
|
||||
}
|
||||
},
|
||||
onUpdate(pokemon) {
|
||||
if (!this.effectState.seek) return;
|
||||
|
||||
const possibleTargets = pokemon.adjacentFoes().filter(
|
||||
target => !target.getAbility().flags['notrace'] && target.ability !== 'noability'
|
||||
);
|
||||
if (!possibleTargets.length) return;
|
||||
|
||||
const target = this.sample(possibleTargets);
|
||||
const ability = target.getAbility();
|
||||
if (this.toID(pokemon.item) === 'trace') {
|
||||
this.add('-ability', pokemon, ability.name, 'Trace');
|
||||
pokemon.setItem(ability.name);
|
||||
return;
|
||||
} else if (pokemon.volatiles['ability:trace']?.inSlot === 'Move') {
|
||||
if (this.dex.abilities.get(ability.name).exists) {
|
||||
pokemon.removeVolatile('ability:trace');
|
||||
pokemon.m.scrambled.abilities.splice(
|
||||
(pokemon.m.scrambled.abilities as { thing: string, inSlot: string }[]).findIndex(e =>
|
||||
this.toID(e.thing) === 'trace' && e.inSlot === 'Move'), 1);
|
||||
this.add('-ability', pokemon, ability.name, 'Trace');
|
||||
pokemon.addVolatile(`ability:${ability.id}`);
|
||||
pokemon.m.scrambled.abilities.push({ thing: ability.name, inSlot: 'Move' });
|
||||
} else if (this.dex.items.get(ability.name).exists) {
|
||||
pokemon.removeVolatile('ability:trace');
|
||||
pokemon.m.scrambled.abilities.splice(
|
||||
(pokemon.m.scrambled.abilities as { thing: string, inSlot: string }[]).findIndex(e =>
|
||||
this.toID(e.thing) === 'trace' && e.inSlot === 'Move'), 1);
|
||||
this.add('-ability', pokemon, ability.name, 'Trace');
|
||||
pokemon.addVolatile(`item:${ability.id}`);
|
||||
pokemon.m.scrambled.items.push({ thing: this.dex.items.get(ability.name).name, inSlot: 'Move' });
|
||||
} else {
|
||||
const move = this.dex.moves.get(ability.name);
|
||||
if (move.exists) {
|
||||
pokemon.removeVolatile('ability:trace');
|
||||
pokemon.m.scrambled.abilities.splice(
|
||||
(pokemon.m.scrambled.abilities as { thing: string, inSlot: string }[]).findIndex(e =>
|
||||
this.toID(e.thing) === 'trace' && e.inSlot === 'Move'), 1);
|
||||
this.add('-ability', pokemon, move.name, 'Trace');
|
||||
const newMove = {
|
||||
move: move.name,
|
||||
id: move.id,
|
||||
pp: move.noPPBoosts ? move.pp : move.pp * 8 / 5,
|
||||
maxpp: move.noPPBoosts ? move.pp : move.pp * 8 / 5,
|
||||
target: move.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
pokemon.baseMoveSlots.push(newMove);
|
||||
pokemon.moveSlots.push(newMove);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
pokemon.setAbility(ability, target);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDataTable = {
|
||||
choicelock: {
|
||||
inherit: true,
|
||||
onBeforeMove(pokemon, target, move) {
|
||||
const choiceItem = pokemon.getItem().isChoice ||
|
||||
Object.keys(pokemon.volatiles).some(v => (
|
||||
v.startsWith('item:') && this.dex.items.get(v.split(':')[1]).isChoice
|
||||
));
|
||||
if (!choiceItem) {
|
||||
pokemon.removeVolatile('choicelock');
|
||||
return;
|
||||
}
|
||||
if (
|
||||
!pokemon.ignoringItem() && !pokemon.volatiles['dynamax'] &&
|
||||
move.id !== this.effectState.move && move.id !== 'struggle'
|
||||
) {
|
||||
// Fails unless the Choice item is being ignored, and no PP is lost
|
||||
this.addMove('move', pokemon, move.name);
|
||||
this.attrLastMove('[still]');
|
||||
this.debug("Disabled by Choice item lock");
|
||||
this.add('-fail', pokemon);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onDisableMove(pokemon) {
|
||||
const choiceItem = pokemon.getItem().isChoice ||
|
||||
Object.keys(pokemon.volatiles).some(v => (
|
||||
v.startsWith('item:') && this.dex.items.get(v.split(':')[1]).isChoice
|
||||
));
|
||||
if (!choiceItem || !pokemon.hasMove(this.effectState.move)) {
|
||||
pokemon.removeVolatile('choicelock');
|
||||
return;
|
||||
}
|
||||
if (pokemon.ignoringItem() || pokemon.volatiles['dynamax']) {
|
||||
return;
|
||||
}
|
||||
for (const moveSlot of pokemon.moveSlots) {
|
||||
if (moveSlot.id !== this.effectState.move) {
|
||||
pokemon.disableMove(moveSlot.id, false, this.effectState.sourceEffect);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
||||
airballoon: {
|
||||
inherit: true,
|
||||
// airborneness implemented in sim/pokemon.js:Pokemon#isGrounded
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
this.add('-enditem', target, 'Air Balloon');
|
||||
if (target.item === 'airballoon') {
|
||||
target.item = '';
|
||||
this.clearEffectState(target.itemState);
|
||||
} else {
|
||||
const isBMM = target.volatiles['item:airballoon']?.inSlot;
|
||||
if (isBMM) {
|
||||
target.removeVolatile('item:airballoon');
|
||||
target.m.scrambled.items.splice((target.m.scrambled.items as { thing: string, inSlot: string }[]).findIndex(e =>
|
||||
this.toID(e.thing) === 'airballoon' && e.inSlot === isBMM), 1);
|
||||
if (isBMM === 'Ability') target.setAbility('No Ability');
|
||||
}
|
||||
}
|
||||
this.runEvent('AfterUseItem', target, null, null, this.dex.items.get('airballoon'));
|
||||
},
|
||||
onAfterSubDamage(damage, target, source, effect) {
|
||||
this.debug('effect: ' + effect.id);
|
||||
if (effect.effectType === 'Move') {
|
||||
this.add('-enditem', target, 'Air Balloon');
|
||||
if (target.item === 'airballoon') {
|
||||
target.item = '';
|
||||
this.clearEffectState(target.itemState);
|
||||
} else {
|
||||
const isBMM = target.volatiles['item:airballoon']?.inSlot;
|
||||
if (isBMM) {
|
||||
target.removeVolatile('item:airballoon');
|
||||
target.m.scrambled.items.splice((target.m.scrambled.items as { thing: string, inSlot: string }[]).findIndex(e =>
|
||||
this.toID(e.thing) === 'airballoon' && e.inSlot === isBMM), 1);
|
||||
if (isBMM === 'Ability') target.setAbility('No Ability');
|
||||
}
|
||||
}
|
||||
this.runEvent('AfterUseItem', target, null, null, this.dex.items.get('airballoon'));
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -1,419 +0,0 @@
|
|||
export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
||||
// Remember, everything deals with SLOTS not with properties as they are!
|
||||
covet: {
|
||||
inherit: true,
|
||||
onAfterHit(target, source, move) {
|
||||
if (source.item || source.volatiles['gem']) {
|
||||
return;
|
||||
}
|
||||
const yourItem = target.takeItem(source);
|
||||
if (!yourItem) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
!this.singleEvent('TakeItem', yourItem, target.itemState, source, target, move, yourItem) ||
|
||||
!source.setItem(yourItem)
|
||||
) {
|
||||
if (!this.dex.items.get(yourItem.id).exists) {
|
||||
target.setItem(yourItem.id);
|
||||
return;
|
||||
}
|
||||
target.item = yourItem.id; // bypass setItem so we don't break choicelock or anything
|
||||
return;
|
||||
}
|
||||
this.add('-item', source, yourItem, '[from] move: Covet', `[of] ${target}`);
|
||||
},
|
||||
},
|
||||
embargo: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
duration: 5,
|
||||
onStart(pokemon) {
|
||||
this.add('-start', pokemon, 'Embargo');
|
||||
this.singleEvent('End', pokemon.getItem(), pokemon.itemState, pokemon);
|
||||
if (!this.dex.items.get(pokemon.item).exists) {
|
||||
const isAbil = (pokemon.m.scrambled.abilities as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
|
||||
if (isAbil >= 0) {
|
||||
pokemon.removeVolatile('ability:' + this.toID(pokemon.m.scrambled.abilities[isAbil].thing));
|
||||
} else if ((pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item') >= 0) {
|
||||
const isMove = (pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
|
||||
const slotNo = pokemon.moveSlots.findIndex(m => this.toID(pokemon.m.scrambled.moves[isMove].thing) === m.id);
|
||||
if (slotNo >= 0) pokemon.moveSlots.splice(slotNo, 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
// Item suppression implemented in Pokemon.ignoringItem() within sim/pokemon.js
|
||||
onResidualOrder: 21,
|
||||
onEnd(pokemon) {
|
||||
this.add('-end', pokemon, 'Embargo');
|
||||
if (!this.dex.items.get(pokemon.item).exists) {
|
||||
const isAbil = (pokemon.m.scrambled.abilities as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
|
||||
if (isAbil >= 0) {
|
||||
pokemon.addVolatile('ability:' + this.toID(pokemon.m.scrambled.abilities[isAbil].thing));
|
||||
} else if ((pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item') >= 0) {
|
||||
const findMove = (pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
|
||||
const findSlot = pokemon.baseMoveSlots.find(e => e.id === this.toID(pokemon.m.scrambled.moves[findMove].thing));
|
||||
pokemon.moveSlots.push(this.dex.deepClone(findSlot));
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
magicroom: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
duration: 5,
|
||||
durationCallback(source, effect) {
|
||||
if (source?.hasAbility('persistent')) {
|
||||
this.add('-activate', source, 'ability: Persistent', '[move] Magic Room');
|
||||
return 7;
|
||||
}
|
||||
return 5;
|
||||
},
|
||||
onFieldStart(target, source) {
|
||||
if (source?.hasAbility('persistent')) {
|
||||
this.add('-fieldstart', 'move: Magic Room', `[of] ${source}`, '[persistent]');
|
||||
} else {
|
||||
this.add('-fieldstart', 'move: Magic Room', `[of] ${source}`);
|
||||
}
|
||||
for (const mon of this.getAllActive()) {
|
||||
this.singleEvent('End', mon.getItem(), mon.itemState, mon);
|
||||
if (!this.dex.items.get(mon.item).exists) {
|
||||
const isAbil = (mon.m.scrambled.abilities as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
|
||||
if (isAbil >= 0) {
|
||||
mon.removeVolatile('ability:' + this.toID(mon.m.scrambled.abilities[isAbil].thing));
|
||||
} else if ((mon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item') >= 0) {
|
||||
const isMove = (mon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
|
||||
const slotNo = mon.moveSlots.findIndex(m => this.toID(mon.m.scrambled.moves[isMove].thing) === m.id);
|
||||
if (slotNo >= 0) mon.moveSlots.splice(slotNo, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onFieldRestart(target, source) {
|
||||
this.field.removePseudoWeather('magicroom');
|
||||
},
|
||||
// Item suppression implemented in Pokemon.ignoringItem() within sim/pokemon.js
|
||||
onFieldResidualOrder: 27,
|
||||
onFieldResidualSubOrder: 6,
|
||||
onFieldEnd() {
|
||||
this.add('-fieldend', 'move: Magic Room', '[of] ' + this.effectState.source);
|
||||
for (const pokemon of this.getAllActive()) {
|
||||
if (!this.dex.items.get(pokemon.item).exists) {
|
||||
const isAbil = (pokemon.m.scrambled.abilities as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
|
||||
if (isAbil >= 0) {
|
||||
pokemon.addVolatile('ability:' + this.toID(pokemon.m.scrambled.abilities[isAbil].thing));
|
||||
} else if ((pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item') >= 0) {
|
||||
const findMove = (pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
|
||||
const findSlot = pokemon.baseMoveSlots.find(e => e.id === this.toID(pokemon.m.scrambled.moves[findMove].thing));
|
||||
pokemon.moveSlots.push(this.dex.deepClone(findSlot));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
gastroacid: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
// Ability suppression implemented in Pokemon.ignoringAbility() within sim/pokemon.js
|
||||
onStart(pokemon) {
|
||||
this.add('-endability', pokemon);
|
||||
this.singleEvent('End', pokemon.getAbility(), pokemon.abilityState, pokemon, pokemon, 'gastroacid');
|
||||
if (!this.dex.abilities.get(pokemon.ability).exists) {
|
||||
const isItem = (pokemon.m.scrambled.items as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
|
||||
if (isItem >= 0) {
|
||||
pokemon.removeVolatile('item:' + this.toID(pokemon.m.scrambled.items[isItem].thing));
|
||||
} else if ((pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability') >= 0) {
|
||||
const isMove = (pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
|
||||
const slotNo = pokemon.moveSlots.findIndex(m => this.toID(pokemon.m.scrambled.moves[isMove].thing) === m.id);
|
||||
if (slotNo >= 0) pokemon.moveSlots.splice(slotNo, 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
trick: {
|
||||
inherit: true,
|
||||
onHit(target, source, move) {
|
||||
const yourItem = target.takeItem(source);
|
||||
const myItem = source.takeItem();
|
||||
if (target.item || source.item || (!yourItem && !myItem)) {
|
||||
if (yourItem) {
|
||||
if (!this.dex.items.get(yourItem.id).exists) {
|
||||
target.setItem(yourItem.id);
|
||||
} else {
|
||||
target.item = yourItem.id;
|
||||
}
|
||||
}
|
||||
if (myItem) {
|
||||
if (!this.dex.items.get(myItem.id).exists) {
|
||||
source.setItem(myItem.id);
|
||||
} else {
|
||||
source.item = myItem.id;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
(myItem && !this.singleEvent('TakeItem', myItem, source.itemState, target, source, move, myItem)) ||
|
||||
(yourItem && !this.singleEvent('TakeItem', yourItem, target.itemState, source, target, move, yourItem))
|
||||
) {
|
||||
if (yourItem) {
|
||||
if (!this.dex.items.get(yourItem.id).exists) {
|
||||
target.setItem(yourItem.id);
|
||||
} else {
|
||||
target.item = yourItem.id;
|
||||
}
|
||||
}
|
||||
if (myItem) {
|
||||
if (!this.dex.items.get(myItem.id).exists) {
|
||||
source.setItem(myItem.id);
|
||||
} else {
|
||||
source.item = myItem.id;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
this.add('-activate', source, 'move: Trick', `[of] ${target}`);
|
||||
if (myItem) {
|
||||
target.setItem(myItem);
|
||||
this.add('-item', target, myItem, '[from] move: Trick');
|
||||
} else {
|
||||
this.add('-enditem', target, yourItem, '[silent]', '[from] move: Trick');
|
||||
}
|
||||
if (yourItem) {
|
||||
source.setItem(yourItem);
|
||||
this.add('-item', source, yourItem, '[from] move: Trick');
|
||||
} else {
|
||||
this.add('-enditem', source, myItem, '[silent]', '[from] move: Trick');
|
||||
}
|
||||
},
|
||||
},
|
||||
sketch: {
|
||||
inherit: true,
|
||||
onHit(target, source) {
|
||||
const move = target.lastMove;
|
||||
if (source.transformed || !move || source.moves.includes(move.id)) return false;
|
||||
if (move.flags['nosketch'] || move.isZ || move.isMax) return false;
|
||||
const sketchIndex = source.moves.indexOf('sketch');
|
||||
if (sketchIndex < 0) return false;
|
||||
if (this.toID(source.item) === 'sketch') {
|
||||
source.setItem(move.name);
|
||||
this.add('-activate', source, 'move: Sketch', move.name);
|
||||
return;
|
||||
} else if (this.toID(source.ability) === 'sketch') {
|
||||
source.setAbility(move.name);
|
||||
this.add('-activate', source, 'move: Sketch', move.name);
|
||||
return;
|
||||
}
|
||||
const sketchedMove = {
|
||||
move: move.name,
|
||||
id: move.id,
|
||||
pp: move.pp,
|
||||
maxpp: move.pp,
|
||||
target: move.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
source.moveSlots[sketchIndex] = sketchedMove;
|
||||
source.baseMoveSlots[sketchIndex] = sketchedMove;
|
||||
this.add('-activate', source, 'move: Sketch', move.name);
|
||||
},
|
||||
},
|
||||
skillswap: {
|
||||
inherit: true,
|
||||
onTryHit(target, source) {
|
||||
const targetAbility = target.getAbility();
|
||||
const sourceAbility = source.getAbility();
|
||||
if (sourceAbility.flags['failskillswap'] || targetAbility.flags['failskillswap'] || target.volatiles['dynamax']) {
|
||||
return false;
|
||||
}
|
||||
let sourceCanBeSet = this.runEvent('SetAbility', source, source, this.effect, targetAbility);
|
||||
if (!this.dex.abilities.get(sourceAbility).exists && this.dex.items.get(sourceAbility.id).exists) {
|
||||
sourceCanBeSet = this.runEvent('TakeItem', source, source, this.effect, this.dex.items.get(sourceAbility.id));
|
||||
}
|
||||
|
||||
if (!sourceCanBeSet) return sourceCanBeSet;
|
||||
let targetCanBeSet = this.runEvent('SetAbility', target, source, this.effect, sourceAbility);
|
||||
if (!this.dex.abilities.get(targetAbility).exists && this.dex.items.get(targetAbility.id).exists) {
|
||||
targetCanBeSet = this.runEvent('TakeItem', target, source, this.effect, this.dex.items.get(targetAbility.id));
|
||||
}
|
||||
if (!targetCanBeSet) return targetCanBeSet;
|
||||
},
|
||||
onHit(target, source, move) {
|
||||
const targetAbility = target.getAbility();
|
||||
const sourceAbility = source.getAbility();
|
||||
const sourceIsBMM = !this.dex.abilities.get(sourceAbility).exists;
|
||||
const targetIsBMM = !this.dex.abilities.get(targetAbility).exists;
|
||||
if (target.isAlly(source)) {
|
||||
this.add('-activate', source, 'move: Skill Swap', '', '', `[of] ${target}`);
|
||||
} else {
|
||||
this.add('-activate', source, 'move: Skill Swap', targetAbility, sourceAbility, `[of] ${target}`);
|
||||
}
|
||||
this.singleEvent('End', sourceAbility, source.abilityState, source);
|
||||
if (sourceIsBMM) {
|
||||
const isItem = (source.m.scrambled.items as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
|
||||
if (isItem >= 0) {
|
||||
source.removeVolatile('item:' + this.toID(source.m.scrambled.items[isItem].thing));
|
||||
source.m.scrambled.items.splice(isItem, 1);
|
||||
} else if ((source.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability') >= 0) {
|
||||
const isMove = (source.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
|
||||
source.baseMoveSlots.splice(
|
||||
source.baseMoveSlots.findIndex(m => this.toID(source.m.scrambled.moves[isMove].thing) === m.id), 1);
|
||||
source.moveSlots.splice(source.moveSlots.findIndex(m => this.toID(source.m.scrambled.moves[isMove].thing) === m.id), 1);
|
||||
source.m.scrambled.moves.splice(isMove, 1);
|
||||
}
|
||||
}
|
||||
this.singleEvent('End', targetAbility, target.abilityState, target);
|
||||
if (targetIsBMM) {
|
||||
const isItem = (target.m.scrambled.items as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
|
||||
if (isItem >= 0) {
|
||||
target.removeVolatile('item:' + this.toID(target.m.scrambled.items[isItem].thing));
|
||||
target.m.scrambled.items.splice(isItem, 1);
|
||||
} else if ((target.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability') >= 0) {
|
||||
const isMove = (target.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
|
||||
target.baseMoveSlots.splice(
|
||||
target.baseMoveSlots.findIndex(m => this.toID(target.m.scrambled.moves[isMove].thing) === m.id), 1);
|
||||
target.moveSlots.splice(target.moveSlots.findIndex(m => this.toID(target.m.scrambled.moves[isMove].thing) === m.id), 1);
|
||||
target.m.scrambled.moves.splice(isMove, 1);
|
||||
}
|
||||
}
|
||||
|
||||
source.ability = source.baseAbility = targetAbility.id;
|
||||
target.ability = target.baseAbility = sourceAbility.id;
|
||||
source.abilityState = this.initEffectState({ id: this.toID(source.ability), target: source });
|
||||
target.abilityState = this.initEffectState({ id: this.toID(target.ability), target });
|
||||
|
||||
source.volatileStaleness = undefined;
|
||||
if (!target.isAlly(source)) target.volatileStaleness = 'external';
|
||||
|
||||
this.singleEvent('Start', targetAbility, source.abilityState, source);
|
||||
if (targetIsBMM) {
|
||||
if (this.dex.items.get(targetAbility.id).exists) {
|
||||
source.m.scrambled.items.push({ thing: targetAbility.id, inSlot: 'Ability' });
|
||||
const effect = 'item:' + this.toID(targetAbility.id);
|
||||
source.addVolatile(effect);
|
||||
source.volatiles[effect].inSlot = 'Ability';
|
||||
} else {
|
||||
source.m.scrambled.moves.push({ thing: targetAbility.id, inSlot: 'Ability' });
|
||||
const bmmMove = Dex.moves.get(targetAbility.id);
|
||||
const newMove = {
|
||||
move: bmmMove.name,
|
||||
id: bmmMove.id,
|
||||
pp: bmmMove.noPPBoosts ? bmmMove.pp : bmmMove.pp * 8 / 5,
|
||||
maxpp: bmmMove.noPPBoosts ? bmmMove.pp : bmmMove.pp * 8 / 5,
|
||||
target: bmmMove.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
source.baseMoveSlots.push(newMove);
|
||||
source.moveSlots.push(newMove);
|
||||
}
|
||||
}
|
||||
this.singleEvent('Start', sourceAbility, target.abilityState, target);
|
||||
if (sourceIsBMM) {
|
||||
if (this.dex.items.get(sourceAbility.id).exists) {
|
||||
target.m.scrambled.items.push({ thing: sourceAbility.id, inSlot: 'Ability' });
|
||||
const effect = 'item:' + this.toID(sourceAbility.id);
|
||||
target.addVolatile(effect);
|
||||
target.volatiles[effect].inSlot = 'Ability';
|
||||
} else {
|
||||
target.m.scrambled.moves.push({ thing: sourceAbility.id, inSlot: 'Ability' });
|
||||
const bmmMove = Dex.moves.get(sourceAbility.id);
|
||||
const newMove = {
|
||||
move: bmmMove.name,
|
||||
id: bmmMove.id,
|
||||
pp: bmmMove.noPPBoosts ? bmmMove.pp : bmmMove.pp * 8 / 5,
|
||||
maxpp: bmmMove.noPPBoosts ? bmmMove.pp : bmmMove.pp * 8 / 5,
|
||||
target: bmmMove.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
target.baseMoveSlots.push(newMove);
|
||||
target.moveSlots.push(newMove);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
switcheroo: {
|
||||
inherit: true,
|
||||
onHit(target, source, move) {
|
||||
const yourItem = target.takeItem(source);
|
||||
const myItem = source.takeItem();
|
||||
if (target.item || source.item || (!yourItem && !myItem)) {
|
||||
if (yourItem) {
|
||||
if (!this.dex.items.get(yourItem.id).exists) {
|
||||
target.setItem(yourItem.id);
|
||||
} else {
|
||||
target.item = yourItem.id;
|
||||
}
|
||||
}
|
||||
if (myItem) {
|
||||
if (!this.dex.items.get(myItem.id).exists) {
|
||||
source.setItem(myItem.id);
|
||||
} else {
|
||||
source.item = myItem.id;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
(myItem && !this.singleEvent('TakeItem', myItem, source.itemState, target, source, move, myItem)) ||
|
||||
(yourItem && !this.singleEvent('TakeItem', yourItem, target.itemState, source, target, move, yourItem))
|
||||
) {
|
||||
if (yourItem) {
|
||||
if (!this.dex.items.get(yourItem.id).exists) {
|
||||
target.setItem(yourItem.id);
|
||||
} else {
|
||||
target.item = yourItem.id;
|
||||
}
|
||||
}
|
||||
if (myItem) {
|
||||
if (!this.dex.items.get(myItem.id).exists) {
|
||||
source.setItem(myItem.id);
|
||||
} else {
|
||||
source.item = myItem.id;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
this.add('-activate', source, 'move: Trick', `[of] ${target}`);
|
||||
if (myItem) {
|
||||
target.setItem(myItem);
|
||||
this.add('-item', target, myItem, '[from] move: Switcheroo');
|
||||
} else {
|
||||
this.add('-enditem', target, yourItem, '[silent]', '[from] move: Switcheroo');
|
||||
}
|
||||
if (yourItem) {
|
||||
source.setItem(yourItem);
|
||||
this.add('-item', source, yourItem, '[from] move: Switcheroo');
|
||||
} else {
|
||||
this.add('-enditem', source, myItem, '[silent]', '[from] move: Switcheroo');
|
||||
}
|
||||
},
|
||||
},
|
||||
thief: {
|
||||
inherit: true,
|
||||
onAfterHit(target, source, move) {
|
||||
if (source.item || source.volatiles['gem']) {
|
||||
return;
|
||||
}
|
||||
const yourItem = target.takeItem(source);
|
||||
if (!yourItem) {
|
||||
return;
|
||||
}
|
||||
if (!this.singleEvent('TakeItem', yourItem, target.itemState, source, target, move, yourItem) ||
|
||||
!source.setItem(yourItem)) {
|
||||
if (!this.dex.items.get(yourItem.id).exists) {
|
||||
target.setItem(yourItem.id);
|
||||
return;
|
||||
}
|
||||
target.item = yourItem.id; // bypass setItem so we don't break choicelock or anything
|
||||
return;
|
||||
}
|
||||
this.add('-enditem', target, yourItem, '[silent]', '[from] move: Thief', `[of] ${source}`);
|
||||
this.add('-item', source, yourItem, '[from] move: Thief', `[of] ${target}`);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -1,584 +0,0 @@
|
|||
import { RESTORATIVE_BERRIES } from "../../../sim/pokemon";
|
||||
|
||||
export const Scripts: ModdedBattleScriptsData = {
|
||||
pokemon: {
|
||||
isGrounded(negateImmunity) {
|
||||
if ('gravity' in this.battle.field.pseudoWeather) return true;
|
||||
if ('ingrain' in this.volatiles && this.battle.gen >= 4) return true;
|
||||
if ('smackdown' in this.volatiles) return true;
|
||||
const item = (this.ignoringItem() ? '' : this.item);
|
||||
if (item === 'ironball' || (this.volatiles['item:ironball'] && !this.ignoringItem())) return true;
|
||||
// If a Fire/Flying type uses Burn Up and Roost, it becomes ???/Flying-type, but it's still grounded.
|
||||
if (!negateImmunity && this.hasType('Flying') && !(this.hasType('???') && 'roost' in this.volatiles)) return false;
|
||||
if (this.hasAbility('levitate') && !this.battle.suppressingAbility(this)) return null;
|
||||
if ('magnetrise' in this.volatiles) return false;
|
||||
if ('telekinesis' in this.volatiles) return false;
|
||||
if (item === 'airballoon' || (this.volatiles['item:airballoon'] && !this.ignoringItem())) return false;
|
||||
return true;
|
||||
},
|
||||
getAbility() {
|
||||
const ability = this.battle.dex.abilities.getByID(this.ability);
|
||||
if (ability.exists) return ability;
|
||||
let abil = this.battle.dex.items.getByID(this.ability) as Item | Move;
|
||||
if (!abil.exists) abil = this.battle.dex.moves.getByID(this.ability);
|
||||
return {
|
||||
id: this.ability,
|
||||
name: abil.name || this.ability,
|
||||
flags: {},
|
||||
effectType: "Ability",
|
||||
toString() {
|
||||
return abil.name || this.id;
|
||||
},
|
||||
} as Ability;
|
||||
},
|
||||
hasAbility(ability) {
|
||||
if (this.ignoringAbility()) return false;
|
||||
if (Array.isArray(ability)) return ability.some(abil => this.hasAbility(abil));
|
||||
const abilityid = this.battle.toID(ability);
|
||||
return this.ability === abilityid || !!this.volatiles['ability:' + abilityid];
|
||||
},
|
||||
ignoringAbility() {
|
||||
// Check if any active pokemon have the ability Neutralizing Gas
|
||||
let neutralizinggas = false;
|
||||
for (const pokemon of this.battle.getAllActive()) {
|
||||
// can't use hasAbility because it would lead to infinite recursion
|
||||
if (
|
||||
(pokemon.ability === ('neutralizinggas' as ID) ||
|
||||
(pokemon.m.scrambled.abilities as { thing: string }[]).some(
|
||||
abils => this.battle.toID(abils.thing) === 'neutralizinggas')) &&
|
||||
!pokemon.volatiles['gastroacid'] && !pokemon.abilityState.ending
|
||||
) {
|
||||
neutralizinggas = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return !!(
|
||||
(this.battle.gen >= 5 && !this.isActive) ||
|
||||
((this.volatiles['gastroacid'] ||
|
||||
(neutralizinggas && (this.ability !== ('neutralizinggas' as ID) ||
|
||||
(this.m.scrambled.abilities as { thing: string }[]).some(abils => this.battle.toID(abils.thing) === 'neutralizinggas'))
|
||||
)) && !this.getAbility().flags['cantsuppress']
|
||||
)
|
||||
);
|
||||
},
|
||||
setAbility(ability, source, sourceEffect, isFromFormeChange = false, isTransform = false) {
|
||||
const allThings = new Set([
|
||||
...(this.m.scrambled.abilities as { thing: string }[]).map(e => e.thing),
|
||||
...(this.m.scrambled.items as { thing: string }[]).map(e => e.thing),
|
||||
...(this.m.scrambled.moves as { thing: string }[]).map(e => e.thing),
|
||||
this.ability, ...this.moveSlots.map(e => e.move), this.item,
|
||||
].map(this.battle.toID));
|
||||
|
||||
let isBMMAbil = false;
|
||||
let isOldBMMAbil = false;
|
||||
if (!this.hp) return false;
|
||||
if (typeof ability === 'string') {
|
||||
if (this.battle.dex.abilities.get(ability).exists) {
|
||||
ability = this.battle.dex.abilities.get(ability);
|
||||
} else {
|
||||
const abilString = ability;
|
||||
let abil = this.battle.dex.items.get(abilString) as Item | Move;
|
||||
if (!abil.exists) abil = this.battle.dex.moves.get(abilString);
|
||||
ability = {
|
||||
id: abil.id || abilString,
|
||||
name: abil.name || abilString,
|
||||
flags: {},
|
||||
effectType: "Ability",
|
||||
toString() {
|
||||
return abil.name || abilString;
|
||||
},
|
||||
} as Ability;
|
||||
}
|
||||
}
|
||||
if (ability.name.length && !this.battle.dex.abilities.get(ability).exists) isBMMAbil = true;
|
||||
if (!sourceEffect && this.battle.effect) sourceEffect = this.battle.effect;
|
||||
let oldAbility;
|
||||
if (this.battle.dex.abilities.get(this.ability).exists) {
|
||||
oldAbility = this.battle.dex.abilities.get(this.ability);
|
||||
} else {
|
||||
let abil = this.battle.dex.items.getByID(this.ability) as Item | Move;
|
||||
if (!abil.exists) {
|
||||
abil = this.battle.dex.moves.getByID(this.ability);
|
||||
} else {
|
||||
if (!this.battle.runEvent('TakeItem', this, source, null, abil as Item)) return false;
|
||||
}
|
||||
oldAbility = {
|
||||
id: this.ability,
|
||||
name: abil.name || this.ability,
|
||||
flags: {},
|
||||
effectType: "Ability",
|
||||
toString() {
|
||||
return abil.name || this.id;
|
||||
},
|
||||
} as Ability;
|
||||
isOldBMMAbil = true;
|
||||
}
|
||||
|
||||
if (allThings.has(ability.id)) return false;
|
||||
|
||||
if (!isFromFormeChange) {
|
||||
if (ability.flags['cantsuppress'] || this.getAbility().flags['cantsuppress']) return false;
|
||||
}
|
||||
if (!isFromFormeChange && !isTransform) {
|
||||
const setAbilityEvent: boolean | null = this.battle.runEvent('SetAbility', this, source, sourceEffect, ability);
|
||||
if (!setAbilityEvent) return setAbilityEvent;
|
||||
}
|
||||
this.battle.singleEvent('End', oldAbility, this.abilityState, this, source);
|
||||
if (isOldBMMAbil) {
|
||||
const isItem = (this.m.scrambled.items as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
|
||||
if (isItem >= 0) {
|
||||
this.removeVolatile('item:' + this.battle.toID(this.m.scrambled.items[isItem].thing));
|
||||
this.m.scrambled.items.splice(isItem, 1);
|
||||
} else if ((this.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability') >= 0) {
|
||||
const isMove = (this.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
|
||||
if (!isTransform) {
|
||||
let indexOfMove = this.baseMoveSlots.findIndex(m => this.battle.toID(this.m.scrambled.moves[isMove].thing) === m.id);
|
||||
if (indexOfMove >= 0) this.baseMoveSlots.splice(indexOfMove, 1);
|
||||
if (oldAbility.id !== 'mimic') {
|
||||
indexOfMove = this.moveSlots.findIndex(m => this.battle.toID(this.m.scrambled.moves[isMove].thing) === m.id);
|
||||
}
|
||||
if (indexOfMove >= 0) this.moveSlots.splice(indexOfMove, 1);
|
||||
}
|
||||
this.m.scrambled.moves.splice(isMove, 1);
|
||||
}
|
||||
}
|
||||
this.ability = ability.id;
|
||||
// ability changes are permanent in BioMechMons
|
||||
if (!isTransform && !this.transformed) this.baseAbility = ability.id;
|
||||
this.abilityState = this.battle.initEffectState({ id: ability.id, target: this });
|
||||
if (sourceEffect && !isFromFormeChange && !isTransform) {
|
||||
if (source) {
|
||||
this.battle.add('-ability', this, ability.name, oldAbility.name, `[from] ${sourceEffect.fullname}`, `[of] ${source}`);
|
||||
} else {
|
||||
this.battle.add('-ability', this, ability.name, oldAbility.name, `[from] ${sourceEffect.fullname}`);
|
||||
}
|
||||
}
|
||||
if (ability.id && this.battle.gen > 3 &&
|
||||
(!isTransform || oldAbility.id !== ability.id || this.battle.gen <= 4)) {
|
||||
this.battle.singleEvent('Start', ability, this.abilityState, this, source);
|
||||
}
|
||||
if (isBMMAbil) {
|
||||
if (this.battle.dex.items.get(ability.id).exists) {
|
||||
this.m.scrambled.items.push({ thing: ability.id, inSlot: 'Ability' });
|
||||
const effect = 'item:' + this.battle.toID(ability.id);
|
||||
this.addVolatile(effect);
|
||||
this.volatiles[effect].inSlot = 'Ability';
|
||||
} else {
|
||||
this.m.scrambled.moves.push({ thing: ability.id, inSlot: 'Ability' });
|
||||
const move = Dex.moves.get(ability.id);
|
||||
const newMove = {
|
||||
move: move.name,
|
||||
id: move.id,
|
||||
pp: move.noPPBoosts ? move.pp : move.pp * 8 / 5,
|
||||
maxpp: move.noPPBoosts ? move.pp : move.pp * 8 / 5,
|
||||
target: move.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
if (!isTransform) {
|
||||
this.baseMoveSlots.push(newMove);
|
||||
this.moveSlots.push(newMove);
|
||||
}
|
||||
}
|
||||
}
|
||||
return oldAbility.id;
|
||||
},
|
||||
getItem() {
|
||||
const item = this.battle.dex.items.getByID(this.item);
|
||||
if (item.exists) return item;
|
||||
let bmmItem = this.battle.dex.abilities.getByID(this.item) as Ability | Move;
|
||||
if (!bmmItem.exists) bmmItem = this.battle.dex.moves.getByID(this.item);
|
||||
return {
|
||||
id: this.item,
|
||||
name: bmmItem.name || this.name,
|
||||
effectType: "Item",
|
||||
toString() {
|
||||
return bmmItem.name || this.id;
|
||||
},
|
||||
} as Item;
|
||||
},
|
||||
hasItem(item) {
|
||||
if (this.ignoringItem()) return false;
|
||||
if (Array.isArray(item)) return item.some(i => this.hasItem(i));
|
||||
const itemId = this.battle.toID(item);
|
||||
return this.item === itemId || !!this.volatiles['item:' + itemId];
|
||||
},
|
||||
takeItem(source) {
|
||||
if (!this.item) return false;
|
||||
if (!source) source = this;
|
||||
if (this.battle.gen <= 4) {
|
||||
if (source.itemKnockedOff) return false;
|
||||
if (this.battle.toID(this.ability) === 'multitype' || (this.m.scrambled.abilities as { thing: string }[])
|
||||
.findIndex(e => this.battle.toID(e.thing) === 'multitype') >= 0) {
|
||||
return false;
|
||||
}
|
||||
if (this.battle.toID(source.ability) === 'multitype' || (source.m.scrambled.abilities as { thing: string }[])
|
||||
.findIndex(e => this.battle.toID(e.thing) === 'multitype') >= 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const item = this.getItem();
|
||||
if (this.battle.runEvent('TakeItem', this, source, null, item)) {
|
||||
this.item = '';
|
||||
let wrongSlot = (this.m.scrambled.abilities as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
|
||||
if (wrongSlot >= 0) {
|
||||
const dexAbil = this.battle.dex.abilities.get(this.m.scrambled.abilities[wrongSlot].thing);
|
||||
if (dexAbil.flags['failskillswap']) return false;
|
||||
this.removeVolatile('ability:' + this.battle.toID(this.m.scrambled.abilities[wrongSlot].thing));
|
||||
this.m.scrambled.abilities.splice(wrongSlot, 1);
|
||||
} else if ((this.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item') >= 0) {
|
||||
wrongSlot = (this.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
|
||||
let indexOfMove = this.baseMoveSlots.findIndex(m => this.battle.toID(this.m.scrambled.moves[wrongSlot].thing) === m.id);
|
||||
if (indexOfMove >= 0) this.baseMoveSlots.splice(indexOfMove, 1);
|
||||
if (item.id !== 'mimic') {
|
||||
indexOfMove = this.moveSlots.findIndex(m => this.battle.toID(this.m.scrambled.moves[wrongSlot].thing) === m.id);
|
||||
}
|
||||
if (indexOfMove >= 0) this.moveSlots.splice(indexOfMove, 1);
|
||||
this.m.scrambled.moves.splice(wrongSlot, 1);
|
||||
}
|
||||
const oldItemState = this.itemState;
|
||||
this.battle.clearEffectState(this.itemState);
|
||||
this.pendingStaleness = undefined;
|
||||
this.battle.singleEvent('End', item, oldItemState, this);
|
||||
this.battle.runEvent('AfterTakeItem', this, null, null, item);
|
||||
return item;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
setItem(item, source, effect) {
|
||||
const allThings = new Set([
|
||||
...(this.m.scrambled.abilities as { thing: string }[]).map(e => e.thing),
|
||||
...(this.m.scrambled.items as { thing: string }[]).map(e => e.thing),
|
||||
...(this.m.scrambled.moves as { thing: string }[]).map(e => e.thing),
|
||||
this.ability, ...this.moveSlots.map(e => e.move), this.item,
|
||||
].map(this.battle.toID));
|
||||
|
||||
let isBMMItem = false;
|
||||
let isOldBMMItem = false;
|
||||
if (!this.hp || !this.isActive) return false;
|
||||
if (typeof item === 'string') {
|
||||
if (!item.length || this.battle.dex.items.get(item).exists) {
|
||||
item = this.battle.dex.items.get(item);
|
||||
} else {
|
||||
const itemString = item;
|
||||
let newData = this.battle.dex.abilities.get(itemString) as Ability | Move;
|
||||
if (!newData.exists) {
|
||||
newData = this.battle.dex.moves.get(itemString);
|
||||
} else {
|
||||
if ((newData as Ability).flags['failskillswap']) return false;
|
||||
}
|
||||
item = {
|
||||
id: newData.id || itemString,
|
||||
name: newData.name || itemString,
|
||||
effectType: "Item",
|
||||
toString() {
|
||||
return newData.name || itemString;
|
||||
},
|
||||
} as Item;
|
||||
}
|
||||
}
|
||||
if (item.name.length && !this.battle.dex.items.get(item).exists) isBMMItem = true;
|
||||
if (allThings.has(item.id)) return false;
|
||||
const effectid = this.battle.effect ? this.battle.effect.id : '';
|
||||
if (RESTORATIVE_BERRIES.has('leppaberry' as ID)) {
|
||||
const inflicted = ['trick', 'switcheroo'].includes(effectid);
|
||||
const external = inflicted && source && !source.isAlly(this);
|
||||
this.pendingStaleness = external ? 'external' : 'internal';
|
||||
} else {
|
||||
this.pendingStaleness = undefined;
|
||||
}
|
||||
const oldItem = this.getItem();
|
||||
if (!this.battle.dex.items.get(oldItem).exists) isOldBMMItem = true;
|
||||
const oldItemState = this.itemState;
|
||||
this.item = item.id;
|
||||
this.itemState = this.battle.initEffectState({ id: item.id, target: this });
|
||||
if (oldItem.exists) this.battle.singleEvent('End', oldItem, oldItemState, this);
|
||||
if (isOldBMMItem) {
|
||||
const isAbil = (this.m.scrambled.abilities as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
|
||||
if (isAbil >= 0) {
|
||||
this.removeVolatile('ability:' + this.battle.toID(this.m.scrambled.items[isAbil].thing));
|
||||
this.m.scrambled.abilities.splice(isAbil, 1);
|
||||
} else if ((this.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item') >= 0) {
|
||||
const isMove = (this.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
|
||||
let indexOfMove = this.baseMoveSlots.findIndex(m => this.battle.toID(this.m.scrambled.moves[isMove].thing) === m.id);
|
||||
if (indexOfMove >= 0) this.baseMoveSlots.splice(indexOfMove, 1);
|
||||
if (oldItem.id !== 'mimic') {
|
||||
indexOfMove = this.moveSlots.findIndex(m => this.battle.toID(this.m.scrambled.moves[isMove].thing) === m.id);
|
||||
}
|
||||
if (indexOfMove >= 0) this.moveSlots.splice(indexOfMove, 1);
|
||||
this.m.scrambled.moves.splice(isMove, 1);
|
||||
}
|
||||
}
|
||||
if (item.id) {
|
||||
this.battle.singleEvent('Start', item, this.itemState, this, source, effect);
|
||||
}
|
||||
if (isBMMItem) {
|
||||
if (this.battle.dex.abilities.get(item.id).exists) {
|
||||
this.m.scrambled.abilities.push({ thing: item.id, inSlot: 'Item' });
|
||||
const abileffect = 'ability:' + this.battle.toID(item.id);
|
||||
this.addVolatile(abileffect);
|
||||
this.volatiles[abileffect].inSlot = 'Item';
|
||||
} else {
|
||||
this.m.scrambled.moves.push({ thing: item.id, inSlot: 'Item' });
|
||||
const move = Dex.moves.get(item.id);
|
||||
const newMove = {
|
||||
move: move.name,
|
||||
id: move.id,
|
||||
pp: move.noPPBoosts ? move.pp : move.pp * 8 / 5,
|
||||
maxpp: move.noPPBoosts ? move.pp : move.pp * 8 / 5,
|
||||
target: move.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
this.baseMoveSlots.push(newMove);
|
||||
this.moveSlots.push(newMove);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
eatItem(force, source, sourceEffect) {
|
||||
const item = sourceEffect?.effectType === 'Item' ? sourceEffect :
|
||||
this.battle.effect.effectType === 'Item' ? this.battle.effect : this.getItem();
|
||||
if (!item) return false;
|
||||
if ((!this.hp && this.battle.toID(item.name) !== 'jabocaberry' && this.battle.toID(item.name) !== 'rowapberry') ||
|
||||
!this.isActive) return false;
|
||||
|
||||
if (!sourceEffect && this.battle.effect) sourceEffect = this.battle.effect;
|
||||
if (!source && this.battle.event?.target) source = this.battle.event.target;
|
||||
// if (sourceEffect?.effectType === 'Item' && this.item !== sourceEffect.id && source === this) {
|
||||
// // if an item is telling us to eat it but we aren't holding it, we probably shouldn't eat what we are holding
|
||||
// return false;
|
||||
// }
|
||||
if (
|
||||
this.battle.runEvent('UseItem', this, null, null, Dex.items.get(item.name)) &&
|
||||
(force || this.battle.runEvent('TryEatItem', this, null, null, Dex.items.get(item.name)))
|
||||
) {
|
||||
this.battle.add('-enditem', this, Dex.items.get(item.name), '[eat]');
|
||||
|
||||
this.battle.singleEvent('Eat', Dex.items.get(item.name), this.itemState, this, source, sourceEffect);
|
||||
this.battle.runEvent('EatItem', this, source, sourceEffect, Dex.items.get(item.name));
|
||||
|
||||
if (RESTORATIVE_BERRIES.has(item.id)) {
|
||||
switch (this.pendingStaleness) {
|
||||
case 'internal':
|
||||
if (this.staleness !== 'external') this.staleness = 'internal';
|
||||
break;
|
||||
case 'external':
|
||||
this.staleness = 'external';
|
||||
break;
|
||||
}
|
||||
this.pendingStaleness = undefined;
|
||||
}
|
||||
|
||||
const isBMM = this.volatiles[item.id]?.inSlot;
|
||||
if (isBMM) {
|
||||
const dexItem = this.battle.dex.items.get(item.name);
|
||||
this.removeVolatile(item.id);
|
||||
const itemIndex = (this.m.scrambled.items as { thing: string, inSlot: string }[]).findIndex(e =>
|
||||
this.battle.toID(e.thing) === dexItem.id && e.inSlot === isBMM);
|
||||
if (itemIndex >= 0) this.m.scrambled.items.splice(itemIndex, 1);
|
||||
if (isBMM === 'Ability') this.setAbility('No Ability');
|
||||
} else {
|
||||
this.lastItem = this.item;
|
||||
this.item = '';
|
||||
}
|
||||
this.battle.clearEffectState(this.itemState);
|
||||
this.usedItemThisTurn = true;
|
||||
this.ateBerry = true;
|
||||
this.battle.runEvent('AfterUseItem', this, null, null, Dex.items.get(item.name));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
useItem(source, sourceEffect) {
|
||||
const item = sourceEffect?.effectType === 'Item' ? sourceEffect :
|
||||
this.battle.effect.effectType === 'Item' ? this.battle.effect : this.getItem();
|
||||
if ((!this.hp && !item.isGem) || !this.isActive) return false;
|
||||
if (!item) return false;
|
||||
|
||||
if (!sourceEffect && this.battle.effect) sourceEffect = this.battle.effect;
|
||||
if (!source && this.battle.event?.target) source = this.battle.event.target;
|
||||
// const item = this.getItem();
|
||||
// if (sourceEffect?.effectType === 'Item' && this.item !== sourceEffect.id && source === this) {
|
||||
// // if an item is telling us to eat it but we aren't holding it, we probably shouldn't eat what we are holding
|
||||
// return false;
|
||||
// }
|
||||
if (this.battle.runEvent('UseItem', this, null, null, Dex.items.get(item.name))) {
|
||||
switch (item.id) {
|
||||
case 'redcard':
|
||||
this.battle.add('-enditem', this, Dex.items.get(item.name), `[of] ${source}`);
|
||||
break;
|
||||
default:
|
||||
if (item.isGem) {
|
||||
this.battle.add('-enditem', this, Dex.items.get(item.name), '[from] gem');
|
||||
} else {
|
||||
this.battle.add('-enditem', this, Dex.items.get(item.name));
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (item.boosts) {
|
||||
this.battle.boost(item.boosts, this, source, Dex.items.get(item.name));
|
||||
}
|
||||
|
||||
this.battle.singleEvent('Use', Dex.items.get(item.name), this.itemState, this, source, sourceEffect);
|
||||
|
||||
const isBMM = this.volatiles[item.id]?.inSlot;
|
||||
if (isBMM) {
|
||||
const dexItem = this.battle.dex.items.get(item.name);
|
||||
this.removeVolatile(item.id);
|
||||
const itemIndex = (this.m.scrambled.items as { thing: string, inSlot: string }[]).findIndex(e =>
|
||||
this.battle.toID(e.thing) === dexItem.id && e.inSlot === isBMM);
|
||||
if (itemIndex >= 0) this.m.scrambled.items.splice(itemIndex, 1);
|
||||
if (isBMM === 'Ability') this.setAbility('No Ability');
|
||||
} else {
|
||||
this.lastItem = this.item;
|
||||
this.item = '';
|
||||
}
|
||||
this.battle.clearEffectState(this.itemState);
|
||||
this.usedItemThisTurn = true;
|
||||
this.battle.runEvent('AfterUseItem', this, null, null, item);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
transformInto(pokemon, effect) {
|
||||
const species = pokemon.species;
|
||||
if (
|
||||
pokemon.fainted || this.illusion || pokemon.illusion || (pokemon.volatiles['substitute'] && this.battle.gen >= 5) ||
|
||||
(pokemon.transformed && this.battle.gen >= 2) || (this.transformed && this.battle.gen >= 5) ||
|
||||
species.name === 'Eternatus-Eternamax' ||
|
||||
(['Ogerpon', 'Terapagos'].includes(species.baseSpecies) && (this.terastallized || pokemon.terastallized)) ||
|
||||
this.terastallized === 'Stellar'
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.battle.dex.currentMod === 'gen1stadium' && (
|
||||
species.name === 'Ditto' ||
|
||||
(this.species.name === 'Ditto' && pokemon.moves.includes('transform'))
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.setSpecies(species, effect, true)) return false;
|
||||
|
||||
this.transformed = true;
|
||||
this.weighthg = pokemon.weighthg;
|
||||
|
||||
const types = pokemon.getTypes(true, true);
|
||||
this.setType(pokemon.volatiles['roost'] ? pokemon.volatiles['roost'].typeWas : types, true);
|
||||
this.addedType = pokemon.addedType;
|
||||
this.knownType = this.isAlly(pokemon) && pokemon.knownType;
|
||||
this.apparentType = pokemon.apparentType;
|
||||
|
||||
let statName: StatIDExceptHP;
|
||||
for (statName in this.storedStats) {
|
||||
this.storedStats[statName] = pokemon.storedStats[statName];
|
||||
if (this.modifiedStats) this.modifiedStats[statName] = pokemon.modifiedStats![statName]; // Gen 1: Copy modified stats.
|
||||
}
|
||||
this.moveSlots = [];
|
||||
this.hpType = (this.battle.gen >= 5 ? this.hpType : pokemon.hpType);
|
||||
this.hpPower = (this.battle.gen >= 5 ? this.hpPower : pokemon.hpPower);
|
||||
this.timesAttacked = pokemon.timesAttacked;
|
||||
for (const moveSlot of pokemon.moveSlots) {
|
||||
let moveName = moveSlot.move;
|
||||
if (moveSlot.id === 'hiddenpower') {
|
||||
moveName = 'Hidden Power ' + this.hpType;
|
||||
}
|
||||
this.moveSlots.push({
|
||||
move: moveName,
|
||||
id: moveSlot.id,
|
||||
pp: moveSlot.maxpp === 1 ? 1 : 5,
|
||||
maxpp: this.battle.gen >= 5 ? (moveSlot.maxpp === 1 ? 1 : 5) : moveSlot.maxpp,
|
||||
target: moveSlot.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
virtual: true,
|
||||
});
|
||||
}
|
||||
let boostName: BoostID;
|
||||
for (boostName in pokemon.boosts) {
|
||||
this.boosts[boostName] = pokemon.boosts[boostName];
|
||||
}
|
||||
if (this.battle.gen >= 6) {
|
||||
// we need to remove all of the overlapping crit volatiles before adding any of them
|
||||
const volatilesToCopy = ['dragoncheer', 'focusenergy', 'gmaxchistrike', 'laserfocus'];
|
||||
for (const volatile of volatilesToCopy) this.removeVolatile(volatile);
|
||||
for (const volatile of volatilesToCopy) {
|
||||
if (pokemon.volatiles[volatile]) {
|
||||
this.addVolatile(volatile);
|
||||
if (volatile === 'gmaxchistrike') this.volatiles[volatile].layers = pokemon.volatiles[volatile].layers;
|
||||
if (volatile === 'dragoncheer') this.volatiles[volatile].hasDragonType = pokemon.volatiles[volatile].hasDragonType;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (effect) {
|
||||
this.battle.add('-transform', this, pokemon, '[from] ' + effect.fullname);
|
||||
} else {
|
||||
this.battle.add('-transform', this, pokemon);
|
||||
}
|
||||
if (this.terastallized) {
|
||||
this.knownType = true;
|
||||
this.apparentType = this.terastallized;
|
||||
}
|
||||
if (this.battle.gen > 2) this.setAbility(pokemon.ability, this, null, true, true);
|
||||
|
||||
// Change formes based on held items (for Transform)
|
||||
// Only ever relevant in Generation 4 since Generation 3 didn't have item-based forme changes
|
||||
if (this.battle.gen === 4) {
|
||||
if (this.species.num === 487) {
|
||||
// Giratina formes
|
||||
if (this.species.name === 'Giratina' && this.item === 'griseousorb') {
|
||||
this.formeChange('Giratina-Origin');
|
||||
} else if (this.species.name === 'Giratina-Origin' && this.item !== 'griseousorb') {
|
||||
this.formeChange('Giratina');
|
||||
}
|
||||
}
|
||||
if (this.species.num === 493) {
|
||||
// Arceus formes
|
||||
const item = this.getItem();
|
||||
const targetForme = (item?.onPlate ? 'Arceus-' + item.onPlate : 'Arceus');
|
||||
if (this.species.name !== targetForme) {
|
||||
this.formeChange(targetForme);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pokemon transformed into Ogerpon cannot Terastallize
|
||||
// restoring their ability to tera after they untransform is handled ELSEWHERE
|
||||
if (['Ogerpon', 'Terapagos'].includes(this.species.baseSpecies) && this.canTerastallize) this.canTerastallize = false;
|
||||
|
||||
for (const volatile in this.volatiles) {
|
||||
if (this.volatiles[volatile].inSlot && this.volatiles[volatile].inSlot === 'Move') {
|
||||
this.removeVolatile(volatile);
|
||||
}
|
||||
}
|
||||
|
||||
for (const volatile in pokemon.volatiles) {
|
||||
if (pokemon.volatiles[volatile].inSlot && pokemon.volatiles[volatile].inSlot === 'Move') {
|
||||
this.addVolatile(volatile);
|
||||
this.volatiles[volatile].inSlot = 'Move';
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
},
|
||||
field: {
|
||||
suppressingWeather() {
|
||||
for (const pokemon of this.battle.getAllActive()) {
|
||||
const innates = Object.keys(pokemon.volatiles).filter(x => x.startsWith('ability:'));
|
||||
if (pokemon && !pokemon.ignoringAbility() &&
|
||||
(pokemon.getAbility().suppressWeather || innates.some(x => (
|
||||
this.battle.dex.abilities.get(x.replace('ability:', '')).suppressWeather
|
||||
)))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -1,993 +0,0 @@
|
|||
export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTable = {
|
||||
thickfat: {
|
||||
// prevents burning
|
||||
inherit: true,
|
||||
onUpdate(pokemon) {
|
||||
if (pokemon.status === 'brn') {
|
||||
this.add('-activate', pokemon, 'ability: Thick Fat');
|
||||
pokemon.cureStatus();
|
||||
}
|
||||
},
|
||||
onSetStatus(status, target, source, effect) {
|
||||
if (status.id !== 'brn') return;
|
||||
if ((effect as Move)?.status) {
|
||||
this.add('-immune', target, '[from] ability: Thick Fat');
|
||||
}
|
||||
return false;
|
||||
},
|
||||
shortDesc: "-50% damage from Fire and Ice. Burn immune.",
|
||||
},
|
||||
callillumise: {
|
||||
onDamagePriority: -30,
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (damage >= target.hp) {
|
||||
this.add('-ability', target, 'Call Illumise');
|
||||
this.effectState.callillumise = true;
|
||||
return target.hp - 1;
|
||||
}
|
||||
},
|
||||
onUpdate(pokemon) {
|
||||
if (!this.effectState.callillumise) return;
|
||||
|
||||
this.add('-message', `Volbeat calls upon Illumise for aid!`);
|
||||
// Define new moves
|
||||
const newMoves = ['bugbuzz', 'icebeam', 'thunderbolt', 'quiverdance'];
|
||||
// Update move slots
|
||||
pokemon.moveSlots = newMoves.map(move => {
|
||||
const moveData = this.dex.moves.get(move);
|
||||
return {
|
||||
move: moveData.name,
|
||||
id: moveData.id,
|
||||
pp: moveData.pp,
|
||||
maxpp: moveData.pp,
|
||||
target: moveData.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
});
|
||||
// this forces the UI to update move slots visually
|
||||
(pokemon as any).baseMoveSlots = pokemon.moveSlots.slice();
|
||||
// removes status/boosts
|
||||
pokemon.cureStatus();
|
||||
pokemon.clearBoosts();
|
||||
// forces the UI to update part II
|
||||
this.add('-clearboost', pokemon, '[from] ability: Call Illumise', '[silent]');
|
||||
for (const volatile in pokemon.volatiles) {
|
||||
this.add('-end', pokemon, volatile);
|
||||
}
|
||||
pokemon.clearVolatile(true);
|
||||
// form change + heal
|
||||
pokemon.formeChange('Illumise', null, true);
|
||||
this.heal(pokemon.maxhp);
|
||||
// sets new ability
|
||||
pokemon.setAbility('Tinted Lens', null, null, true);
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
this.add('-ability', pokemon, 'Tinted Lens');
|
||||
},
|
||||
flags: {
|
||||
breakable: 1, failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, notransform: 1,
|
||||
},
|
||||
name: "Call Illumise",
|
||||
rating: 5,
|
||||
num: -100,
|
||||
shortDesc: "When Volbeat gets low on HP, it calls Illumise for aid.",
|
||||
},
|
||||
callvolbeat: {
|
||||
onDamagePriority: -30,
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (damage >= target.hp) {
|
||||
this.add('-ability', target, 'Call Volbeat');
|
||||
this.effectState.callvolbeat = true;
|
||||
return target.hp - 1;
|
||||
}
|
||||
},
|
||||
onUpdate(pokemon) {
|
||||
if (!this.effectState.callvolbeat) return;
|
||||
|
||||
this.add('-message', `Illumise calls upon Volbeat for aid!`);
|
||||
// Define new moves
|
||||
const newMoves = ['victorydance', 'lunge', 'mightycleave', 'earthquake'];
|
||||
// Update move slots
|
||||
pokemon.moveSlots = newMoves.map(move => {
|
||||
const moveData = this.dex.moves.get(move);
|
||||
return {
|
||||
move: moveData.name,
|
||||
id: moveData.id,
|
||||
pp: moveData.pp,
|
||||
maxpp: moveData.pp,
|
||||
target: moveData.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
});
|
||||
// this forces the UI to update move slots visually
|
||||
(pokemon as any).baseMoveSlots = pokemon.moveSlots.slice();
|
||||
// removes status/boosts
|
||||
pokemon.cureStatus();
|
||||
pokemon.clearBoosts();
|
||||
// forces the UI to update part II
|
||||
this.add('-clearboost', pokemon, '[from] ability: Call Volbeat', '[silent]');
|
||||
for (const volatile in pokemon.volatiles) {
|
||||
this.add('-end', pokemon, volatile);
|
||||
}
|
||||
pokemon.clearVolatile(true);
|
||||
// form change + heal
|
||||
pokemon.formeChange('Volbeat', null, true);
|
||||
this.heal(pokemon.maxhp);
|
||||
// sets new ability
|
||||
pokemon.setAbility('Dancer', null, null, true);
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
this.add('-ability', pokemon, 'Dancer');
|
||||
},
|
||||
flags: {
|
||||
breakable: 1, failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, notransform: 1,
|
||||
},
|
||||
name: "Call Volbeat",
|
||||
rating: 5,
|
||||
num: -101,
|
||||
shortDesc: "When Illumise gets low on HP, it calls Volbeat for aid.",
|
||||
},
|
||||
shortfuse: {
|
||||
onDamagePriority: -30,
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (damage >= target.hp) {
|
||||
this.add('-ability', target, 'Short Fuse');
|
||||
this.effectState.shortfuse = true;
|
||||
return target.hp - 1;
|
||||
}
|
||||
},
|
||||
onUpdate(pokemon) {
|
||||
if (this.effectState.shortfuse) {
|
||||
delete this.effectState.shortfuse;
|
||||
this.actions.useMove('explosion', pokemon);
|
||||
}
|
||||
this.checkFainted();
|
||||
},
|
||||
flags: {
|
||||
breakable: 1, failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1,
|
||||
},
|
||||
name: "Short Fuse",
|
||||
rating: 5,
|
||||
num: -102,
|
||||
shortDesc: "If KO'd, use Explosion instead.",
|
||||
},
|
||||
hydroelectricdam: {
|
||||
// Copied from the code for Sand Spit
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
this.field.setWeather('raindance');
|
||||
},
|
||||
flags: {},
|
||||
name: "Hydroelectric Dam",
|
||||
rating: 5,
|
||||
num: -103,
|
||||
shortDesc: "Starts Rain Dance when hit by an attack.",
|
||||
},
|
||||
frozenarmor: {
|
||||
onTryHit(target, source, move) {
|
||||
if (move.category !== 'Status') {
|
||||
this.add('-ability', target, 'Frozen Armor');
|
||||
// reduces base power of incoming moves by 20 (math.max prevents base power from reducing below 0)
|
||||
move.basePower = Math.max(move.basePower - 20, 0);
|
||||
}
|
||||
},
|
||||
onSwitchInPriority: -1,
|
||||
onUpdate(pokemon) {
|
||||
// checks if Glastrier is below 50% HP, if so transforms into Caly-Ice and sets ability to As One
|
||||
if (pokemon.species.id !== 'glastrier' || !pokemon.hp) return;
|
||||
if (pokemon.hp < pokemon.maxhp / 2) {
|
||||
if (pokemon.species.id !== 'calyrexice' && pokemon.ability === 'frozenarmor') {
|
||||
pokemon.formeChange('Calyrex-Ice', null, true);
|
||||
this.add('-message', `Glastrier's Frozen Armor has shattered!`);
|
||||
// pokemon.setAbility('As One (Glastrier)');
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
// this.add('-ability', pokemon, 'As One');
|
||||
}
|
||||
}
|
||||
},
|
||||
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1 },
|
||||
name: "Frozen Armor",
|
||||
rating: 5,
|
||||
num: -105,
|
||||
shortDesc: "-20 BP on attacks targeting Glastrier, at 50% HP become Calyrex-Ice.",
|
||||
},
|
||||
flipflop: {
|
||||
onDamagingHitOrder: 1,
|
||||
onTryHit(target, source, move) {
|
||||
if (move.flags['contact']) {
|
||||
let flipFlopBoosts = false;
|
||||
const invertedBoosts: SparseBoostsTable = {};
|
||||
for (const stat in source.boosts) {
|
||||
if (source.boosts[stat as BoostID] > 0) {
|
||||
// checks for boosts on source of move, inverts boosts and adds them to invertedBoosts table
|
||||
invertedBoosts[stat as BoostID] = -2 * source.boosts[stat as BoostID];
|
||||
if (!flipFlopBoosts) {
|
||||
this.add('-ability', target, 'Flip Flop');
|
||||
flipFlopBoosts = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// applies boosts
|
||||
this.boost(invertedBoosts, source, target);
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Flip Flop",
|
||||
rating: 5,
|
||||
num: -104,
|
||||
shortDesc: "When hit by contact move, invert attacker’s stat boosts.",
|
||||
},
|
||||
|
||||
grasspelt: {
|
||||
inherit: true,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
this.field.setTerrain('grassyterrain');
|
||||
},
|
||||
shortDesc: "Starts Grassy Terrain on hit. 1.5x Def in Grassy Terrain.",
|
||||
},
|
||||
aquaveil: {
|
||||
onSwitchInPriority: -1,
|
||||
// fakes the effect of aqua ring volatile lel
|
||||
onStart(pokemon) {
|
||||
this.add('-start', pokemon, 'Aqua Ring');
|
||||
},
|
||||
// provides effects of Water Bubble because Aqua Ring is modified to provide Water Bubble.
|
||||
onResidualOrder: 6,
|
||||
onResidual(pokemon) {
|
||||
this.heal(pokemon.baseMaxhp / 16);
|
||||
},
|
||||
onSourceModifyAtkPriority: 5,
|
||||
onSourceModifyAtk(atk, attacker, defender, move) {
|
||||
if (move.type === 'Fire') {
|
||||
return this.chainModify(0.5);
|
||||
}
|
||||
},
|
||||
onSourceModifySpAPriority: 5,
|
||||
onSourceModifySpA(atk, attacker, defender, move) {
|
||||
if (move.type === 'Fire') {
|
||||
return this.chainModify(0.5);
|
||||
}
|
||||
},
|
||||
onModifyAtk(atk, attacker, defender, move) {
|
||||
if (move.type === 'Water') {
|
||||
return this.chainModify(2);
|
||||
}
|
||||
},
|
||||
onModifySpA(atk, attacker, defender, move) {
|
||||
if (move.type === 'Water') {
|
||||
return this.chainModify(2);
|
||||
}
|
||||
},
|
||||
// this ability is supposed to just add Aqua Ring (the volatile) to the Pokemon on switch in
|
||||
flags: { cantsuppress: 1 },
|
||||
name: "Aqua Veil",
|
||||
rating: 5,
|
||||
num: -106,
|
||||
shortDesc: "Starts Aqua Ring on switch in.",
|
||||
},
|
||||
// unaware + water absorb
|
||||
stillwater: {
|
||||
onAnyModifyBoost(boosts, pokemon) {
|
||||
const unawareUser = this.effectState.target;
|
||||
if (unawareUser === pokemon) return;
|
||||
if (unawareUser === this.activePokemon && pokemon === this.activeTarget) {
|
||||
boosts['def'] = 0;
|
||||
boosts['spd'] = 0;
|
||||
boosts['evasion'] = 0;
|
||||
}
|
||||
if (pokemon === this.activePokemon && unawareUser === this.activeTarget) {
|
||||
boosts['atk'] = 0;
|
||||
boosts['def'] = 0;
|
||||
boosts['spa'] = 0;
|
||||
boosts['accuracy'] = 0;
|
||||
}
|
||||
},
|
||||
onTryHit(target, source, move) {
|
||||
if (target !== source && move.type === 'Water') {
|
||||
if (!this.heal(target.baseMaxhp / 4)) {
|
||||
this.add('-immune', target, '[from] ability: Still Water');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
},
|
||||
flags: { breakable: 1 },
|
||||
name: "Still Water",
|
||||
rating: 5,
|
||||
num: -107,
|
||||
shortDesc: "Unaware + Water Absorb",
|
||||
},
|
||||
kingofthehill: {
|
||||
// sharpness + mountaineer + prevents hazard immunity
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (effect && effect.id === 'stealthrock') {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onTryHit(target, source, move) {
|
||||
if (move.type === 'Rock' && !target.activeTurns) {
|
||||
this.add('-immune', target, '[from] ability: King of the Hill');
|
||||
return null;
|
||||
}
|
||||
},
|
||||
// sharpness
|
||||
onBasePowerPriority: 19,
|
||||
onBasePower(basePower, attacker, defender, move) {
|
||||
if (move.flags['slicing']) {
|
||||
this.debug('Sharpness boost');
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
},
|
||||
// starts side condition for foes, side condition interacts with hazard effects
|
||||
onStart(pokemon) {
|
||||
this.add('-ability', pokemon, 'King of the Hill');
|
||||
for (const side of pokemon.side.foeSidesWithConditions()) {
|
||||
side.addSideCondition('kingofthehill');
|
||||
}
|
||||
},
|
||||
onEnd(pokemon) {
|
||||
for (const side of pokemon.side.foeSidesWithConditions()) {
|
||||
if (side.getSideCondition('kingofthehill')) {
|
||||
side.removeSideCondition('kingofthehill');
|
||||
}
|
||||
}
|
||||
},
|
||||
condition: {},
|
||||
flags: { breakable: 1 },
|
||||
name: "King of the Hill",
|
||||
rating: 5,
|
||||
num: -108,
|
||||
shortDesc: "Mountaineer + Sharpness. Opponent cannot ignore hazard damage.",
|
||||
},
|
||||
// stockpile on hit
|
||||
omnivore: {
|
||||
onDamagingHitOrder: 1,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (!target.hp) return;
|
||||
this.add('-activate', target, 'ability: Omnivore');
|
||||
target.addVolatile('stockpile');
|
||||
},
|
||||
flags: {},
|
||||
name: "Omnivore",
|
||||
rating: 5,
|
||||
num: -109,
|
||||
shortDesc: "Gain Stockpile charge when hit by attack.",
|
||||
},
|
||||
// disguise clone
|
||||
pseudowoodo: {
|
||||
onDamagePriority: 1,
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (effect?.effectType === 'Move' && ['sudowoodo'].includes(target.species.id)) {
|
||||
this.add('-activate', target, 'ability: Pseudowoodo');
|
||||
this.effectState.rock = true;
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
onCriticalHit(target, source, move) {
|
||||
if (!target) return;
|
||||
if (!['sudowoodo'].includes(target.species.id)) {
|
||||
return;
|
||||
}
|
||||
const hitSub = target.volatiles['substitute'] && !move.flags['bypasssub'] && !(move.infiltrates && this.gen >= 6);
|
||||
if (hitSub) return;
|
||||
|
||||
if (!target.runImmunity(move.type)) return;
|
||||
return false;
|
||||
},
|
||||
onEffectiveness(typeMod, target, type, move) {
|
||||
if (!target || move.category === 'Status') return;
|
||||
if (!['sudowoodo'].includes(target.species.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const hitSub = target.volatiles['substitute'] && !move.flags['bypasssub'] && !(move.infiltrates && this.gen >= 6);
|
||||
if (hitSub) return;
|
||||
|
||||
if (!target.runImmunity(move.type)) return;
|
||||
return 0;
|
||||
},
|
||||
onUpdate(pokemon) {
|
||||
if (['sudowoodo'].includes(pokemon.species.id) && this.effectState.rock) {
|
||||
const speciesid = 'Sudowoodo-Rock';
|
||||
pokemon.formeChange(speciesid, this.effect, true);
|
||||
this.damage(pokemon.baseMaxhp / 8, pokemon, pokemon, this.dex.species.get(speciesid));
|
||||
}
|
||||
},
|
||||
flags: {
|
||||
failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1,
|
||||
breakable: 1, notransform: 1,
|
||||
},
|
||||
name: "Pseudowoodo",
|
||||
rating: 5,
|
||||
num: -110,
|
||||
shortDesc: "Disguise. Becomes Rock type when it breaks.",
|
||||
},
|
||||
magicguard: {
|
||||
onDamage(damage, target, source, effect) {
|
||||
// prevents magic guard from blocking hazard damage while King of the Hill is active
|
||||
if (target.side.getSideCondition('kingofthehill')) {
|
||||
const hazards = ['stealthrock', 'spikes', 'toxicspikes', 'stickyweb'];
|
||||
if (effect && hazards.includes(effect.id)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (effect.effectType !== 'Move') {
|
||||
if (effect.effectType === 'Ability') this.add('-activate', source, 'ability: ' + effect.name);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Magic Guard",
|
||||
rating: 4,
|
||||
num: 98,
|
||||
},
|
||||
disguise: {
|
||||
onDamagePriority: 1,
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (effect?.effectType === 'Move' && ['mimikyu', 'mimikyutotem'].includes(target.species.id)) {
|
||||
this.add('-activate', target, 'ability: Disguise');
|
||||
this.effectState.busted = true;
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
onCriticalHit(target, source, move) {
|
||||
if (!target) return;
|
||||
if (!['mimikyu', 'mimikyutotem'].includes(target.species.id)) {
|
||||
return;
|
||||
}
|
||||
const hitSub = target.volatiles['substitute'] && !move.flags['bypasssub'] && !(move.infiltrates && this.gen >= 6);
|
||||
if (hitSub) return;
|
||||
|
||||
if (!target.runImmunity(move.type)) return;
|
||||
return false;
|
||||
},
|
||||
onEffectiveness(typeMod, target, type, move) {
|
||||
if (!target || move.category === 'Status') return;
|
||||
if (!['mimikyu', 'mimikyutotem'].includes(target.species.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const hitSub = target.volatiles['substitute'] && !move.flags['bypasssub'] && !(move.infiltrates && this.gen >= 6);
|
||||
if (hitSub) return;
|
||||
|
||||
if (!target.runImmunity(move.type)) return;
|
||||
return 0;
|
||||
},
|
||||
onUpdate(pokemon) {
|
||||
if (['mimikyu', 'mimikyutotem'].includes(pokemon.species.id) && this.effectState.busted) {
|
||||
const speciesid = pokemon.species.id === 'mimikyutotem' ? 'Mimikyu-Busted-Totem' : 'Mimikyu-Busted';
|
||||
pokemon.formeChange(speciesid, this.effect, true);
|
||||
this.damage(pokemon.baseMaxhp / 8, pokemon, pokemon, this.dex.species.get(speciesid));
|
||||
}
|
||||
// sets ability to perish body
|
||||
if (pokemon.species.id === 'mimikyubusted' && pokemon.ability === 'disguise') {
|
||||
pokemon.setAbility("Perish Body");
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
}
|
||||
},
|
||||
// cantsuppress flag removed to allow for ability change
|
||||
flags: {
|
||||
failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1,
|
||||
breakable: 1, notransform: 1,
|
||||
},
|
||||
name: "Disguise",
|
||||
rating: 3.5,
|
||||
num: 209,
|
||||
},
|
||||
gulpmissile: {
|
||||
inherit: true,
|
||||
onTryHit(target, source, move) {
|
||||
// Storm Drain effect while cramorant-gulping
|
||||
if (target !== source && move.type === 'Water' && target.species.id === 'cramorantgulping') {
|
||||
if (!this.boost({ spa: 1 })) {
|
||||
this.add('-immune', target, '[from] ability: Gulp Missile');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// Lightning Rod effect while cramorant-gorging
|
||||
if (target !== source && move.type === 'Electric' && target.species.id === 'cramorantgorging') {
|
||||
if (!this.boost({ spa: 1 })) {
|
||||
this.add('-immune', target, '[from] ability: Gulp Missile');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return;
|
||||
},
|
||||
},
|
||||
asoneglastrier: {
|
||||
inherit: true,
|
||||
// removing these flags allows Frozen Armor to correctly set Caly-Ice ability as As One
|
||||
flags: {},
|
||||
},
|
||||
protean: {
|
||||
inherit: true,
|
||||
onPrepareHit(source, target, move) {
|
||||
if (move.hasBounced || move.flags['futuremove'] || move.sourceEffect === 'snatch' || move.callsMove) return;
|
||||
const type = move.type;
|
||||
if (type && type !== '???' && source.getTypes().join() !== type) {
|
||||
if (!source.setType(type)) return;
|
||||
this.add('-start', source, 'typechange', type, '[from] ability: Protean');
|
||||
}
|
||||
},
|
||||
rating: 4.5,
|
||||
shortDesc: "Gen 8 Protean.",
|
||||
},
|
||||
berserk: {
|
||||
onUpdate(pokemon) {
|
||||
if (pokemon.species.id !== 'infernape' || !pokemon.hp || pokemon.m.triggeredBerserk) return;
|
||||
if (pokemon.hp < pokemon.maxhp / 2) {
|
||||
this.boost({ spa: 1 }, pokemon, pokemon);
|
||||
pokemon.m.triggeredBerserk = true;
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Berserk",
|
||||
rating: 2,
|
||||
num: 201,
|
||||
},
|
||||
bloodsoakedcrescent: {
|
||||
// modifies atk
|
||||
onStart(pokemon) {
|
||||
this.add('-ability', pokemon, 'Blood-Soaked Crescent');
|
||||
},
|
||||
onModifyAtkPriority: 1,
|
||||
onModifyAtk(atk, pokemon) {
|
||||
if (pokemon.volatiles['dynamax']) return;
|
||||
this.debug('bsc Attack boost');
|
||||
return this.chainModify(1.5);
|
||||
},
|
||||
// ends move lock properly
|
||||
onAfterMove(pokemon) {
|
||||
if (pokemon.volatiles['bloodsoakedcrescent']?.duration === 1) {
|
||||
pokemon.removeVolatile('bloodsoakedcrescent');
|
||||
this.add('-end', pokemon, 'Blood-Soaked Rage');
|
||||
}
|
||||
},
|
||||
// applies move lock
|
||||
onAfterMoveSecondarySelf(pokemon, source, move) {
|
||||
if (move.id === 'dragondance') return;
|
||||
if (!pokemon.volatiles['bloodsoakedcrescent']) {
|
||||
this.add('-start', pokemon, 'Blood-Soaked Rage');
|
||||
}
|
||||
pokemon.addVolatile('bloodsoakedcrescent');
|
||||
},
|
||||
// condition is just lockedmove with some changes
|
||||
condition: {
|
||||
// Outrage, Thrash, Petal Dance...
|
||||
duration: 2,
|
||||
onResidual(target) {
|
||||
if (target.status === 'slp') {
|
||||
// don't lock, and bypass confusion for calming
|
||||
delete target.volatiles['bloodsoakedcrescent'];
|
||||
}
|
||||
this.effectState.trueDuration--;
|
||||
},
|
||||
onStart(target, source, effect) {
|
||||
this.effectState.trueDuration = this.random(2, 4);
|
||||
this.effectState.move = this.activeMove;
|
||||
},
|
||||
onRestart() {
|
||||
if (this.effectState.trueDuration >= 2) {
|
||||
this.effectState.duration = 2;
|
||||
}
|
||||
},
|
||||
onEnd(target) {
|
||||
if (this.effectState.trueDuration > 1) return;
|
||||
target.addVolatile('confusion');
|
||||
},
|
||||
onLockMove(pokemon) {
|
||||
if (pokemon.volatiles['dynamax']) return;
|
||||
return this.effectState.move;
|
||||
},
|
||||
},
|
||||
flags: {},
|
||||
name: "Blood-Soaked Crescent",
|
||||
rating: 5,
|
||||
num: -111,
|
||||
shortDesc: "1.5x Attack, but attacks have the Outrage effect.",
|
||||
},
|
||||
powerspot: {
|
||||
onChargeMove(pokemon, target, move) {
|
||||
this.debug('power spot - remove charge turn for ' + move.id);
|
||||
this.attrLastMove('[still]');
|
||||
this.addMove('-anim', pokemon, move.name, target);
|
||||
return false; // skip charge turn
|
||||
},
|
||||
onAfterMoveSecondarySelf(pokemon, target, move) {
|
||||
if (pokemon.getVolatile('mustrecharge')) {
|
||||
pokemon.removeVolatile('mustrecharge');
|
||||
this.add('-end', pokemon, 'mustrecharge');
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Power Spot",
|
||||
rating: 5,
|
||||
num: 249,
|
||||
shortDesc: "Moves ignore charge/recharge turns.",
|
||||
},
|
||||
biogenesis: {
|
||||
onSwitchInPriority: -1,
|
||||
onBeforeSwitchIn(pokemon) {
|
||||
if (pokemon.m.didRandomMoves) return;
|
||||
const moves = this.dex.moves.all();
|
||||
const newMoves = [];
|
||||
while (newMoves.length < 8) {
|
||||
const newMove = this.sample(moves);
|
||||
if (newMove.basePower === 1) continue;
|
||||
if (newMove.isMax === true) continue;
|
||||
if (newMove.isNonstandard === "Gigantamax") continue;
|
||||
if (newMoves.map(x => x.id).includes(newMove.id)) continue;
|
||||
newMoves.push(newMove);
|
||||
}
|
||||
// Update move slots
|
||||
pokemon.moveSlots = newMoves.map(move => {
|
||||
const moveData = this.dex.moves.get(move);
|
||||
return {
|
||||
move: moveData.name,
|
||||
id: moveData.id,
|
||||
pp: moveData.pp,
|
||||
maxpp: moveData.pp,
|
||||
target: moveData.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
});
|
||||
// this forces the UI to update move slots visually
|
||||
(pokemon as any).baseMoveSlots = pokemon.moveSlots.slice();
|
||||
pokemon.m.didRandomMoves = true;
|
||||
},
|
||||
onSwitchIn(pokemon) {
|
||||
if (!pokemon) return; // Chat command
|
||||
if (!pokemon.m.hasTypeChanged) {
|
||||
this.add('-ability', pokemon, 'Biogenesis');
|
||||
this.add('-anim', pokemon, 'Growth', pokemon);
|
||||
this.add('-message', `Mew evolves into a new form with its Biogenesis!`);
|
||||
}
|
||||
const attackingMoves = pokemon.baseMoveSlots
|
||||
.map(slot => this.dex.moves.get(slot.id))
|
||||
.filter(move => move.category !== "Status");
|
||||
|
||||
// pick types of first 2 attacking moves (failsafe if there are none)
|
||||
const types = attackingMoves.length ?
|
||||
[...new Set(attackingMoves.slice(0, 2).map(move => move.type))] :
|
||||
pokemon.types;
|
||||
pokemon.setType(types);
|
||||
pokemon.baseTypes = pokemon.types;
|
||||
pokemon.m.hasTypeChanged = true;
|
||||
this.add('-start', pokemon, 'typechange', (pokemon.illusion || pokemon).getTypes(true).join('/'), '[silent]');
|
||||
},
|
||||
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1,
|
||||
breakable: 1, notransform: 1, cantsuppress: 1 },
|
||||
name: "Biogenesis",
|
||||
rating: 5,
|
||||
num: -112,
|
||||
shortDesc: "This Pokemon receives 8 completely random moves at the start of the game.",
|
||||
},
|
||||
orichalcumpulse: {
|
||||
onStart(pokemon) {
|
||||
pokemon.updateMaxHp();
|
||||
if (this.field.setWeather('sunnyday')) {
|
||||
this.add('-activate', pokemon, 'Orichalcum Pulse', '[source]');
|
||||
} else if (this.field.isWeather('sunnyday')) {
|
||||
this.add('-activate', pokemon, 'ability: Orichalcum Pulse');
|
||||
}
|
||||
},
|
||||
onModifyAtkPriority: 5,
|
||||
onModifyAtk(atk, pokemon) {
|
||||
if (['sunnyday', 'desolateland'].includes(pokemon.effectiveWeather())) {
|
||||
this.debug('Orichalcum boost');
|
||||
return this.chainModify([5461, 4096]);
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Orichalcum Pulse",
|
||||
rating: 4.5,
|
||||
num: 288,
|
||||
},
|
||||
hailmary: {
|
||||
onStart(pokemon) {
|
||||
this.add('-activate', pokemon, 'ability: Hail Mary');
|
||||
},
|
||||
onModifySpe(spe, pokemon) {
|
||||
if (this.field.isWeather(['hail', 'snowscape'])) {
|
||||
this.debug('hail mary spe boost');
|
||||
return this.chainModify(2);
|
||||
}
|
||||
},
|
||||
onModifyAtkPriority: 5,
|
||||
onModifyAtk(atk, pokemon) {
|
||||
if (this.field.isWeather(['hail', 'snowscape'])) {
|
||||
this.debug('hail mary atk boost');
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
},
|
||||
onSourceModifyAccuracyPriority: -1,
|
||||
onSourceModifyAccuracy(accuracy, target, source, move) {
|
||||
if (this.field.isWeather(['hail', 'snowscape'])) {
|
||||
if (move.category === 'Physical' && typeof accuracy === 'number') {
|
||||
return this.chainModify([3277, 4096]);
|
||||
}
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Hail Mary",
|
||||
rating: 5,
|
||||
num: -113,
|
||||
shortDesc: "In Snowscape: 2x Speed, 1.5x Attack, 0.8x accuracy.",
|
||||
},
|
||||
brainfreeze: {
|
||||
onModifyCritRatio(critRatio, source, target) {
|
||||
if (target && (target.status === 'frostbite' || this.field.isWeather('snowscape'))) return 5;
|
||||
},
|
||||
flags: {},
|
||||
name: "Brain Freeze",
|
||||
rating: 5,
|
||||
num: -114,
|
||||
shortDesc: "If Snowscape or target is Frostbitten, attacks auto Crit.",
|
||||
},
|
||||
neutralizinggas: {
|
||||
inherit: true,
|
||||
onStart(pokemon) {
|
||||
// this makes Neutralizing Gas properly show as activated in the client when Typhlosion Mega evolves
|
||||
this.add('-ability', pokemon, 'Neutralizing Gas');
|
||||
},
|
||||
},
|
||||
terawheel: {
|
||||
onStart(pokemon) {
|
||||
pokemon.canTerastallize = null;
|
||||
},
|
||||
// copied from SSB High Performance Computing
|
||||
onResidualOrder: 6,
|
||||
onResidual(source) {
|
||||
const type = this.sample(this.dex.types.names().filter(i => i !== source.getTypes()[0]));
|
||||
if (source.setType(type)) {
|
||||
this.add('-start', source, 'typechange', type, '[from] ability: Tera Wheel');
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Tera Wheel",
|
||||
rating: 5,
|
||||
num: -115,
|
||||
shortDesc: "End of turn: this Pokemon switches to a random type (including Stellar).",
|
||||
},
|
||||
download: {
|
||||
inherit: true,
|
||||
onUpdate(pokemon) {
|
||||
if (pokemon.species.name === 'Genesect-Burn' && pokemon.terastallized) {
|
||||
pokemon.setAbility('Drought', null, null, true);
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
this.add('-ability', pokemon, 'Drought');
|
||||
}
|
||||
if (pokemon.species.name === 'Genesect-Chill' && pokemon.terastallized) {
|
||||
pokemon.setAbility('Snow Warning', null, null, true);
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
this.add('-ability', pokemon, 'Snow Warning');
|
||||
}
|
||||
if (pokemon.species.name === 'Genesect-Douse' && pokemon.terastallized) {
|
||||
pokemon.setAbility('Drizzle', null, null, true);
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
this.add('-ability', pokemon, 'Drizzle');
|
||||
}
|
||||
if (pokemon.species.name === 'Genesect-Shock' && pokemon.terastallized) {
|
||||
pokemon.setAbility('Electric Surge', null, null, true);
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
this.add('-ability', pokemon, 'Electric Surge');
|
||||
}
|
||||
},
|
||||
shortDesc: "Download + Gets weather setting move when Tera.",
|
||||
},
|
||||
battlerage: {
|
||||
onDamagingHit(damage, target, source, effect) {
|
||||
this.boost({ atk: 1 });
|
||||
},
|
||||
flags: {},
|
||||
name: "Battle Rage",
|
||||
rating: 5,
|
||||
num: -116,
|
||||
shortDesc: "+1 Atk when hit by an attack.",
|
||||
},
|
||||
terrainshift: {
|
||||
onStart(source) {
|
||||
if (source.hp >= source.maxhp) {
|
||||
source.setType("Electric");
|
||||
this.field.setTerrain('electricterrain');
|
||||
this.add('-start', source, 'typechange', 'Electric', '[silent]');
|
||||
} else if (source.hp >= (2 * source.maxhp) / 3) {
|
||||
source.setType("Fairy");
|
||||
this.field.setTerrain('mistyterrain');
|
||||
this.add('-start', source, 'typechange', 'Fairy', '[silent]');
|
||||
} else if (source.hp >= source.maxhp / 3) {
|
||||
source.setType("Grass");
|
||||
this.field.setTerrain('grassyterrain');
|
||||
this.add('-start', source, 'typechange', 'Grass', '[silent]');
|
||||
} else {
|
||||
source.setType("Psychic");
|
||||
this.field.setTerrain('psychicterrain');
|
||||
this.add('-start', source, 'typechange', 'Psychic', '[silent]');
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Terrain Shift",
|
||||
rating: 5,
|
||||
num: -117,
|
||||
shortDesc: "Sets terrain depending on HP value.",
|
||||
},
|
||||
dragonsjaw: {
|
||||
onBasePower(basePower, attacker, defender, move) {
|
||||
if (defender.hasType('Dragon') && defender.hasType('Steel')) {
|
||||
return this.chainModify(1.5);
|
||||
} else if (defender.hasType('Dragon')) {
|
||||
return this.chainModify(2.25);
|
||||
} else if (defender.hasType('Steel')) {
|
||||
return;
|
||||
} else return this.chainModify(1.5);
|
||||
},
|
||||
onTryHit(target, source, move) {
|
||||
if (target.hasType('Fairy')) {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
onModifyMovePriority: -2,
|
||||
onModifyMove(move) {
|
||||
if (move.secondaries) {
|
||||
this.debug('doubling secondary chance');
|
||||
for (const secondary of move.secondaries) {
|
||||
if (secondary.chance) secondary.chance *= 2;
|
||||
}
|
||||
}
|
||||
if (move.self?.chance) move.self.chance *= 2;
|
||||
},
|
||||
flags: {},
|
||||
name: "Dragon's Jaw",
|
||||
rating: 5,
|
||||
num: -118,
|
||||
shortDesc: "Serene Grace + Bite attacks are Dragon type.",
|
||||
},
|
||||
corrosivesoul: {
|
||||
onStart(source) {
|
||||
this.field.setTerrain('corrosivesoul');
|
||||
},
|
||||
condition: {
|
||||
effectType: 'Terrain',
|
||||
duration: 5,
|
||||
durationCallback(source, effect) {
|
||||
if (source?.hasItem('terrainextender')) {
|
||||
return 8;
|
||||
}
|
||||
return 5;
|
||||
},
|
||||
onFieldStart(field, source, effect) {
|
||||
if (effect?.effectType === 'Ability') {
|
||||
this.add('-fieldstart', 'move: Corrosive Soul', '[from] ability: ' + effect.name, `[of] ${source}`);
|
||||
} else {
|
||||
this.add('-fieldstart', 'move: Corrosive Soul');
|
||||
}
|
||||
},
|
||||
onResidualOrder: 5,
|
||||
onResidualSubOrder: 2,
|
||||
onResidual(pokemon) {
|
||||
const move = this.dex.getActiveMove('smog');
|
||||
move.accuracy = 100;
|
||||
const target = pokemon.foes()[0];
|
||||
if (target && !target.fainted) {
|
||||
this.actions.useMove(move, pokemon, { target });
|
||||
}
|
||||
},
|
||||
onFieldResidualOrder: 27,
|
||||
onFieldResidualSubOrder: 7,
|
||||
onFieldEnd() {
|
||||
this.add('-fieldend', 'move: Corrosive Soul');
|
||||
},
|
||||
},
|
||||
flags: {},
|
||||
name: "Corrosive Soul",
|
||||
rating: 5,
|
||||
num: -119,
|
||||
shortDesc: "Sets Corrosive Terrian: active Pokemon hit each other with Smog.",
|
||||
},
|
||||
oceanicblessing: {
|
||||
onSwitchInPriority: -2,
|
||||
onStart(pokemon) {
|
||||
this.singleEvent('WeatherChange', this.effect, this.effectState, pokemon);
|
||||
},
|
||||
onWeatherChange(pokemon) {
|
||||
if (!pokemon.isActive || pokemon.baseSpecies.baseSpecies !== 'Kyogre' || pokemon.transformed) return;
|
||||
if (!pokemon.hp) return;
|
||||
if (['raindance', 'primordialsea'].includes(pokemon.effectiveWeather())) {
|
||||
if (pokemon.species.id !== 'kyogreprimal') {
|
||||
pokemon.formeChange('Kyogre-Primal', this.effect, false);
|
||||
}
|
||||
} else {
|
||||
if (pokemon.species.id === 'kyogreprimal') {
|
||||
pokemon.formeChange('kyogre', this.effect, false);
|
||||
}
|
||||
}
|
||||
},
|
||||
onAllyModifyAtkPriority: 3,
|
||||
onAllyModifyAtk(atk, pokemon) {
|
||||
if (this.effectState.target.baseSpecies.baseSpecies !== 'Kyogre') return;
|
||||
if (['raindance', 'primordialsea'].includes(pokemon.effectiveWeather())) {
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
},
|
||||
onAllyModifySpDPriority: 4,
|
||||
onAllyModifySpD(spd, pokemon) {
|
||||
if (this.effectState.target.baseSpecies.baseSpecies !== 'Kyogre') return;
|
||||
if (['raindance', 'primordialsea'].includes(pokemon.effectiveWeather())) {
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
},
|
||||
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, breakable: 1 },
|
||||
name: "Oceanic Blessing",
|
||||
rating: 5,
|
||||
num: -120,
|
||||
shortDesc: "Flower Gift but Kyogre",
|
||||
},
|
||||
autospin: {
|
||||
onResidual(pokemon, s, effect) {
|
||||
const move = this.dex.getActiveMove('metronome');
|
||||
const target = pokemon.foes()[0];
|
||||
if (target && !target.fainted && (pokemon.hp >= pokemon.maxhp / 2)) {
|
||||
this.actions.useMove(move, pokemon, { target, sourceEffect: effect });
|
||||
} else if (target && !target.fainted && (pokemon.hp <= pokemon.maxhp / 10)) {
|
||||
this.actions.useMove(move, pokemon, { target, sourceEffect: effect });
|
||||
this.actions.useMove(move, pokemon, { target, sourceEffect: effect });
|
||||
this.actions.useMove(move, pokemon, { target, sourceEffect: effect });
|
||||
} else if (target && !target.fainted) {
|
||||
this.actions.useMove(move, pokemon, { target, sourceEffect: effect });
|
||||
this.actions.useMove(move, pokemon, { target, sourceEffect: effect });
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Auto Spin",
|
||||
rating: 5,
|
||||
num: -121,
|
||||
shortDesc: "Use Metronome at end of turn.",
|
||||
},
|
||||
corrosion: {
|
||||
inherit: true,
|
||||
onModifyMovePriority: -5,
|
||||
onModifyMove(move) {
|
||||
if (!move.ignoreImmunity) move.ignoreImmunity = {};
|
||||
if (move.ignoreImmunity !== true) {
|
||||
move.ignoreImmunity['Poison'] = true;
|
||||
}
|
||||
},
|
||||
shortDesc: "This Pokemon can poison a Pokemon regardless of its typing and hit them with Poison moves.",
|
||||
},
|
||||
jellobody: {
|
||||
onTryHit(pokemon, target, move) {
|
||||
if (move.selfSwitch) {
|
||||
this.add('-immune', pokemon, '[from] ability: Jello Body');
|
||||
this.heal(target.baseMaxhp / 2);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
onModifyMove(move, source, target) {
|
||||
move.drain = [1, 2];
|
||||
},
|
||||
flags: { breakable: 1 },
|
||||
name: "Jello Body",
|
||||
rating: 5,
|
||||
num: -122,
|
||||
shortDesc: "Immune to pivot moves, heals 50% HP when hit by one. All moves drain 50%.",
|
||||
},
|
||||
nibblenibble: {
|
||||
onPrepareHit(source, target, move) {
|
||||
if (move.category === 'Status' || move.multihit || move.flags['noparentalbond'] || move.flags['charge'] ||
|
||||
move.flags['futuremove'] || move.spreadHit || move.isZ || move.isMax || !move.flags['bite']) return;
|
||||
move.multihit = 2;
|
||||
move.multihitType = 'parentalbond';
|
||||
},
|
||||
// Damage modifier implemented in BattleActions#modifyDamage()
|
||||
onSourceModifySecondaries(secondaries, target, source, move) {
|
||||
if (move.multihitType === 'parentalbond' && move.id === 'secretpower' && move.hit < 2) {
|
||||
// hack to prevent accidentally suppressing King's Rock/Razor Fang
|
||||
return secondaries.filter(effect => effect.volatileStatus === 'flinch');
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Nibble Nibble",
|
||||
rating: 5,
|
||||
num: -123,
|
||||
shortDesc: "Parental Bond but for Bite moves.",
|
||||
},
|
||||
};
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDataTable = {
|
||||
frostbite: {
|
||||
name: 'frostbite',
|
||||
effectType: 'Status',
|
||||
onStart(target) {
|
||||
this.add('-start', target, 'Frostbite', '[silent]');
|
||||
this.add('-message', `${target.species.name} is inflicted with frostbite!`);
|
||||
},
|
||||
onSwitchIn(pokemon) {
|
||||
this.add('-start', pokemon, 'Frostbite', '[silent]');
|
||||
},
|
||||
onResidualOrder: 10,
|
||||
onResidual(pokemon) {
|
||||
this.damage(pokemon.baseMaxhp / 16);
|
||||
},
|
||||
onBasePower(basePower, source, target) {
|
||||
return basePower / 2;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -1,150 +0,0 @@
|
|||
export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
||||
bigroot: {
|
||||
inherit: true,
|
||||
onTryHealPriority: 1,
|
||||
onTryHeal(damage, target, source, effect) {
|
||||
const heals = ['drain', 'leechseed', 'ingrain', 'aquaring', 'strengthsap'];
|
||||
if (heals.includes(effect.id)) {
|
||||
return this.chainModify([6144, 4096]);
|
||||
}
|
||||
},
|
||||
shortDesc: "Holder gains 1.5x HP from draining, Aqua Ring, Ingrain, Leech Seed, Strength Sap.",
|
||||
},
|
||||
masquerainite: {
|
||||
name: "Masquerainite",
|
||||
spritenum: 1,
|
||||
megaStone: { "Masquerain": "Masquerain-Mega" },
|
||||
itemUser: ["Masquerain"],
|
||||
onTakeItem(item, source) {
|
||||
return !item.megaStone?.[source.baseSpecies.baseSpecies];
|
||||
},
|
||||
num: -1,
|
||||
gen: 9,
|
||||
desc: "If held by a Masquerain, this item allows it to Mega Evolve in battle.",
|
||||
},
|
||||
starfberry: {
|
||||
name: "Starf Berry",
|
||||
spritenum: 472,
|
||||
isBerry: true,
|
||||
naturalGift: {
|
||||
basePower: 100,
|
||||
type: "Psychic",
|
||||
},
|
||||
onUpdate(pokemon) {
|
||||
if (pokemon.hp <= pokemon.maxhp / 2 ||
|
||||
((pokemon.hp <= pokemon.maxhp / 2 && pokemon.hasAbility('gluttony') && pokemon.abilityState.gluttony))) {
|
||||
pokemon.eatItem();
|
||||
}
|
||||
},
|
||||
onEat(pokemon) {
|
||||
const stats: BoostID[] = [];
|
||||
let stat: BoostID;
|
||||
for (stat in pokemon.boosts) {
|
||||
if (stat !== 'accuracy' && stat !== 'evasion' && pokemon.boosts[stat] < 6) {
|
||||
stats.push(stat);
|
||||
}
|
||||
}
|
||||
if (stats.length) {
|
||||
const randomStat = this.sample(stats);
|
||||
const boost: SparseBoostsTable = {};
|
||||
boost[randomStat] = 2;
|
||||
this.boost(boost);
|
||||
}
|
||||
},
|
||||
num: 207,
|
||||
gen: 3,
|
||||
},
|
||||
typhlosionite: {
|
||||
name: "Typhlosionite",
|
||||
spritenum: 1,
|
||||
megaStone: { "Typhlosion": "Typhlosion-Mega" },
|
||||
itemUser: ["Typhlosion"],
|
||||
onTakeItem(item, source) {
|
||||
return !item.megaStone?.[source.baseSpecies.baseSpecies];
|
||||
},
|
||||
num: -2,
|
||||
gen: 9,
|
||||
desc: "If held by a Typhlosion, this item allows it to Mega Evolve in battle.",
|
||||
},
|
||||
tartapple: {
|
||||
name: "Tart Apple",
|
||||
spritenum: 712,
|
||||
isBerry: true,
|
||||
fling: {
|
||||
basePower: 30,
|
||||
},
|
||||
onBasePowerPriority: 15,
|
||||
onBasePower(basePower, user, target, move) {
|
||||
if (
|
||||
move && (user.baseSpecies.num === 841) &&
|
||||
(move.type === 'Grass' || move.type === 'Ground')
|
||||
) {
|
||||
return this.chainModify([4915, 4096]);
|
||||
}
|
||||
},
|
||||
onUpdate(pokemon) {
|
||||
if (pokemon.hp <= pokemon.maxhp / 2) {
|
||||
pokemon.eatItem();
|
||||
}
|
||||
},
|
||||
onTryEatItem(item, pokemon) {
|
||||
if (!this.runEvent('TryHeal', pokemon, null, this.effect, pokemon.baseMaxhp / 4)) return false;
|
||||
},
|
||||
onEat(pokemon) {
|
||||
this.heal(pokemon.baseMaxhp / 4);
|
||||
},
|
||||
itemUser: ["Flapple"],
|
||||
num: 1117,
|
||||
gen: 8,
|
||||
desc: "Grass- and Ground-type moves have 1.2x power. Restores 1/4 max HP when at 1/2 max HP or less.",
|
||||
},
|
||||
thickclub: {
|
||||
name: "Thick Club",
|
||||
spritenum: 491,
|
||||
fling: {
|
||||
basePower: 130,
|
||||
},
|
||||
onModifyAtkPriority: 1,
|
||||
onModifyAtk(atk, pokemon) {
|
||||
if (pokemon.baseSpecies.baseSpecies === 'Mandibuzz' || pokemon.baseSpecies.baseSpecies === 'Mew') {
|
||||
return this.chainModify(2);
|
||||
}
|
||||
},
|
||||
itemUser: ["Marowak", "Marowak-Alola", "Marowak-Alola-Totem", "Cubone", "Mandibuzz", "Mew"],
|
||||
num: 258,
|
||||
gen: 2,
|
||||
desc: "Doubles Attack.",
|
||||
},
|
||||
focusband: {
|
||||
name: "Focus Band",
|
||||
spritenum: 150,
|
||||
fling: {
|
||||
basePower: 10,
|
||||
},
|
||||
onDamagePriority: -40,
|
||||
onDamage(damage, target, source, effect) {
|
||||
const chance = Math.max(Math.floor(100 - (target.maxhp - target.hp)), 10);
|
||||
if (this.randomChance(chance, 100) && damage >= target.hp && effect && effect.effectType === 'Move') {
|
||||
this.add("-activate", target, "item: Focus Band");
|
||||
return target.hp - 1;
|
||||
} else {
|
||||
return damage;
|
||||
}
|
||||
},
|
||||
num: 230,
|
||||
gen: 2,
|
||||
desc: "Chance to survive attack equal to percentage of remaining HP, minimum 10%.",
|
||||
},
|
||||
raticite: {
|
||||
name: "Raticite",
|
||||
spritenum: 1,
|
||||
megaStone: { "Raticate": "Raticate-Mega" },
|
||||
itemUser: ["Raticate"],
|
||||
onTakeItem(item, source) {
|
||||
return !item.megaStone?.[source.baseSpecies.baseSpecies];
|
||||
},
|
||||
num: -3,
|
||||
gen: 9,
|
||||
desc: "If held by a Raticate, this item allows it to Mega Evolve in battle.",
|
||||
},
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,514 +0,0 @@
|
|||
export const Pokedex: import('../../../sim/dex-species').ModdedSpeciesDataTable = {
|
||||
volcarona: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Fluffy" },
|
||||
},
|
||||
golemalola: {
|
||||
inherit: true,
|
||||
},
|
||||
lurantis: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 85, atk: 105, def: 90, spa: 95, spd: 90, spe: 75 },
|
||||
},
|
||||
ironcrown: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Queenly Majesty", H: "Battle Armor" },
|
||||
},
|
||||
mamoswine: {
|
||||
inherit: true,
|
||||
},
|
||||
ceruledge: {
|
||||
inherit: true,
|
||||
},
|
||||
carbink: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Magic Bounce" },
|
||||
},
|
||||
moltres: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Magic Guard" },
|
||||
},
|
||||
kommoo: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 75, atk: 100, def: 125, spa: 110, spd: 105, spe: 85 },
|
||||
abilities: { 0: "Punk Rock" },
|
||||
},
|
||||
illumise: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Call Volbeat" },
|
||||
},
|
||||
volbeat: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Call Illumise" },
|
||||
},
|
||||
abomasnow: {
|
||||
inherit: true,
|
||||
},
|
||||
abomasnowmega: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 90, atk: 132, def: 105, spa: 92, spd: 105, spe: 70 },
|
||||
abilities: { 0: "Slush Rush" },
|
||||
},
|
||||
dugtrio: {
|
||||
inherit: true,
|
||||
},
|
||||
altaria: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Fluffy" },
|
||||
},
|
||||
altariamega: {
|
||||
inherit: true,
|
||||
},
|
||||
tyranitar: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Sand Stream", H: "Sharpness" },
|
||||
},
|
||||
tyranitarmega: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 100, atk: 114, def: 150, spa: 155, spd: 110, spe: 71 },
|
||||
types: ["Rock", "Dragon"],
|
||||
},
|
||||
mimikyu: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 65, atk: 110, def: 80, spa: 50, spd: 105, spe: 96 },
|
||||
},
|
||||
mimikyubusted: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Perish Body" },
|
||||
baseStats: { hp: 65, atk: 90, def: 80, spa: 50, spd: 105, spe: 116 },
|
||||
},
|
||||
mesprit: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Liquid Voice" },
|
||||
types: ["Psychic", "Water"],
|
||||
},
|
||||
electrode: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Short Fuse" },
|
||||
types: ["Electric", "Normal"],
|
||||
},
|
||||
taurospaldeacombat: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Adaptability" },
|
||||
},
|
||||
chiyu: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Water Absorb" },
|
||||
baseStats: { hp: 55, atk: 135, def: 80, spa: 80, spd: 120, spe: 100 },
|
||||
},
|
||||
wochien: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Liquid Ooze" },
|
||||
types: ["Grass", "Water"],
|
||||
},
|
||||
staraptor: {
|
||||
inherit: true,
|
||||
types: ["Flying"],
|
||||
},
|
||||
archaludon: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Hydroelectric Dam", 1: "Stamina" },
|
||||
},
|
||||
malamar: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Flip Flop" },
|
||||
baseStats: { hp: 86, atk: 92, def: 88, spa: 88, spd: 75, spe: 73 },
|
||||
},
|
||||
empoleon: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Sharpness" },
|
||||
types: ["Water", "Steel", "Flying"],
|
||||
},
|
||||
glastrier: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Frozen Armor" },
|
||||
},
|
||||
calyrexice: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 100, atk: 165, def: 130, spa: 85, spd: 110, spe: 90 },
|
||||
},
|
||||
regieleki: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Galvanize" },
|
||||
},
|
||||
lycanrocmidnight: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Technician" },
|
||||
},
|
||||
lycanroc: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Drought" },
|
||||
},
|
||||
lycanrocdusk: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Strong Jaw" },
|
||||
},
|
||||
dodrio: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Speed Boost" },
|
||||
types: ["Flying", "Fighting"],
|
||||
},
|
||||
whiscash: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Regenerator" },
|
||||
baseStats: { hp: 110, atk: 78, def: 88, spa: 76, spd: 86, spe: 60 },
|
||||
},
|
||||
hippowdon: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Earth Eater" },
|
||||
},
|
||||
cramorant: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 90, atk: 85, def: 75, spa: 85, spd: 95, spe: 85 },
|
||||
},
|
||||
cramorantgulping: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 90, atk: 85, def: 75, spa: 85, spd: 95, spe: 85 },
|
||||
abilities: { 0: "Storm Drain" },
|
||||
},
|
||||
cramorantgorging: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 90, atk: 85, def: 75, spa: 85, spd: 95, spe: 85 },
|
||||
abilities: { 0: "Lightning Rod" },
|
||||
},
|
||||
grafaiai: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 83, atk: 95, def: 65, spa: 80, spd: 72, spe: 110 },
|
||||
},
|
||||
tatsugiri: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Regenerator" },
|
||||
baseStats: { hp: 78, atk: 50, def: 70, spa: 120, spd: 95, spe: 82 },
|
||||
},
|
||||
kyurem: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Skill Link" },
|
||||
},
|
||||
roaringmoon: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Shadow Shield" },
|
||||
},
|
||||
milotic: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Aqua Veil" },
|
||||
types: ["Water", "Fairy"],
|
||||
},
|
||||
gogoat: {
|
||||
inherit: true,
|
||||
types: ["Grass", "Rock"],
|
||||
},
|
||||
clodsire: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Still Water" },
|
||||
},
|
||||
masquerain: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Intimidate" },
|
||||
},
|
||||
masquerainmega: {
|
||||
num: -999,
|
||||
name: "Masquerain-Mega",
|
||||
baseSpecies: "Masquerain",
|
||||
forme: "Mega",
|
||||
types: ["Bug", "Dark"],
|
||||
genderRatio: { M: 0.5, F: 0.5 },
|
||||
baseStats: { hp: 70, atk: 60, def: 82, spa: 140, spd: 82, spe: 120 },
|
||||
abilities: { 0: "Primordial Sea" },
|
||||
heightm: 0.8,
|
||||
weightkg: 3.6,
|
||||
color: "Blue",
|
||||
eggGroups: ["Water 1", "Bug"],
|
||||
requiredItem: "Masquerainite",
|
||||
},
|
||||
kyuremblack: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Teravolt" },
|
||||
types: ["Dragon", "Ice", "Electric"],
|
||||
},
|
||||
ironthorns: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Iron Barbs" },
|
||||
},
|
||||
dudunsparce: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Earth Eater" },
|
||||
types: ["Normal", "Ground"],
|
||||
},
|
||||
dudunsparcethreesegment: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Earth Eater" },
|
||||
types: ["Normal", "Ground"],
|
||||
},
|
||||
chienpao: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Tablets of Ruin" },
|
||||
},
|
||||
pelipper: {
|
||||
inherit: true,
|
||||
},
|
||||
kleavor: {
|
||||
inherit: true,
|
||||
abilities: { 0: "King of the Hill" },
|
||||
baseStats: { hp: 120, atk: 135, def: 95, spa: 45, spd: 75, spe: 85 },
|
||||
},
|
||||
araquanid: {
|
||||
inherit: true,
|
||||
},
|
||||
avalugghisui: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Multiscale" },
|
||||
baseStats: { hp: 95, atk: 127, def: 184, spa: 68, spd: 72, spe: 76 },
|
||||
},
|
||||
swalot: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Omnivore" },
|
||||
},
|
||||
zapdosgalar: {
|
||||
inherit: true,
|
||||
types: ["Electric", "Fighting"],
|
||||
},
|
||||
phione: {
|
||||
inherit: true,
|
||||
},
|
||||
sudowoodo: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Pseudowoodo" },
|
||||
types: ["Grass"],
|
||||
baseForme: "Grass",
|
||||
otherFormes: ["Sudowoodo-Rock"],
|
||||
formeOrder: ["Sudowoodo", "Sudowoodo-Rock"],
|
||||
},
|
||||
sudowoodorock: {
|
||||
num: 185,
|
||||
name: "Sudowoodo-Rock",
|
||||
baseSpecies: "Sudowoodo",
|
||||
forme: "Rock",
|
||||
types: ["Rock"],
|
||||
baseStats: { hp: 70, atk: 100, def: 110, spa: 30, spd: 65, spe: 30 },
|
||||
abilities: { 0: "Pseudowoodo" },
|
||||
heightm: 1.7,
|
||||
weightkg: 38,
|
||||
color: "Brown",
|
||||
eggGroups: ["Mineral"],
|
||||
requiredAbility: "Pseudowoodo",
|
||||
battleOnly: "Sudowoodo",
|
||||
},
|
||||
dondozo: {
|
||||
inherit: true,
|
||||
},
|
||||
golurk: {
|
||||
inherit: true,
|
||||
},
|
||||
meowscarada: {
|
||||
inherit: true,
|
||||
},
|
||||
infernape: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Berserk" },
|
||||
},
|
||||
salamence: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Aerilate" },
|
||||
},
|
||||
salamencemega: {
|
||||
num: 373,
|
||||
name: "Salamence-Mega",
|
||||
baseSpecies: "Salamence",
|
||||
forme: "Mega",
|
||||
types: ["Dragon", "Flying"],
|
||||
baseStats: { hp: 95, atk: 145, def: 130, spa: 120, spd: 90, spe: 120 },
|
||||
abilities: { 0: "Blood-Soaked Crescent" },
|
||||
heightm: 1.8,
|
||||
weightkg: 112.6,
|
||||
color: "Blue",
|
||||
eggGroups: ["Dragon"],
|
||||
requiredItem: "Salamencite",
|
||||
},
|
||||
urshifu: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Sniper" },
|
||||
},
|
||||
urshifurapidstrike: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Sniper" },
|
||||
},
|
||||
stonjourner: {
|
||||
inherit: true,
|
||||
},
|
||||
veluza: {
|
||||
inherit: true,
|
||||
types: ["Water", "Ghost"],
|
||||
},
|
||||
ogerponhearthflame: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Intimidate" },
|
||||
},
|
||||
dachsbun: {
|
||||
inherit: true,
|
||||
},
|
||||
koraidon: {
|
||||
inherit: true,
|
||||
},
|
||||
mew: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Biogenesis" },
|
||||
},
|
||||
magneton: {
|
||||
inherit: true,
|
||||
},
|
||||
delibird: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Hail Mary" },
|
||||
baseStats: { hp: 45, atk: 90, def: 45, spa: 65, spd: 45, spe: 136 },
|
||||
},
|
||||
articunogalar: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Brain Freeze" },
|
||||
},
|
||||
vaporeon: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Marvel Scale" },
|
||||
},
|
||||
jolteon: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Quick Feet" },
|
||||
},
|
||||
flareon: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Guts" },
|
||||
baseStats: { hp: 65, atk: 130, def: 65, spa: 60, spd: 110, spe: 95 },
|
||||
},
|
||||
garganacl: {
|
||||
inherit: true,
|
||||
},
|
||||
swanna: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Serene Grace" },
|
||||
baseStats: { hp: 75, atk: 117, def: 93, spa: 117, spd: 93, spe: 128 },
|
||||
},
|
||||
typhlosion: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Magic Guard" },
|
||||
},
|
||||
typhlosionmega: {
|
||||
num: -998,
|
||||
name: "Typhlosion-Mega",
|
||||
baseSpecies: "Typhlosion",
|
||||
forme: "Mega",
|
||||
types: ["Fire", "Water"],
|
||||
genderRatio: { M: 0.5, F: 0.5 },
|
||||
baseStats: { hp: 78, atk: 103, def: 98, spa: 140, spd: 115, spe: 100 },
|
||||
abilities: { 0: "Neutralizing Gas" },
|
||||
heightm: 1.7,
|
||||
weightkg: 84.5,
|
||||
color: "Blue",
|
||||
eggGroups: ["Field"],
|
||||
requiredItem: "Typhlosionite",
|
||||
},
|
||||
terapagos: {
|
||||
inherit: true,
|
||||
},
|
||||
terapagosterastal: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Tera Wheel" },
|
||||
},
|
||||
terapagosstellar: {
|
||||
inherit: true,
|
||||
types: ["Stellar"],
|
||||
},
|
||||
flapple: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Ripen" },
|
||||
types: ["Grass", "Ground"],
|
||||
},
|
||||
genesect: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Download" },
|
||||
},
|
||||
honchkrow: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Supreme Overlord" },
|
||||
baseStats: { hp: 100, atk: 125, def: 52, spa: 125, spd: 52, spe: 71 },
|
||||
},
|
||||
primeape: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Battle Rage" },
|
||||
},
|
||||
rillaboom: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Terrain Shift" },
|
||||
},
|
||||
mandibuzz: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Weak Armor" },
|
||||
types: ["Dark", "Ground"],
|
||||
},
|
||||
feraligatr: {
|
||||
inherit: true,
|
||||
},
|
||||
feraligatrmega: {
|
||||
num: -988,
|
||||
name: "Feraligatr-Mega",
|
||||
baseSpecies: "Feraligatr",
|
||||
forme: "Mega",
|
||||
types: ["Dragon"],
|
||||
genderRatio: { M: 0.875, F: 0.125 },
|
||||
baseStats: { hp: 85, atk: 145, def: 120, spa: 99, spd: 103, spe: 78 },
|
||||
abilities: { 0: "Dragon's Jaw" },
|
||||
heightm: 2.3,
|
||||
weightkg: 108.8,
|
||||
color: "Blue",
|
||||
eggGroups: ["Monster", "Water 1"],
|
||||
requiredItem: "Feraligite",
|
||||
gen: 9,
|
||||
},
|
||||
salazzle: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Corrosive Soul" },
|
||||
},
|
||||
kyogre: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Oceanic Blessing" },
|
||||
},
|
||||
azelf: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Auto Spin" },
|
||||
types: ["Psychic", "Normal"],
|
||||
},
|
||||
decidueye: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Overgrow", 1: "Sniper" },
|
||||
},
|
||||
ogerponcornerstone: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Solid Rock" },
|
||||
},
|
||||
glimmora: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Corrosion" },
|
||||
},
|
||||
wobbuffet: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Jello Body" },
|
||||
},
|
||||
raticate: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Hustle" },
|
||||
baseStats: { hp: 90, atk: 81, def: 60, spa: 50, spd: 70, spe: 97 },
|
||||
},
|
||||
raticatemega: {
|
||||
num: -977,
|
||||
name: "Raticate-Mega",
|
||||
baseSpecies: "Raticate",
|
||||
forme: "Mega",
|
||||
types: ["Normal", "Ghost"],
|
||||
genderRatio: { M: 0.5, F: 0.5 },
|
||||
baseStats: { hp: 90, atk: 105, def: 60, spa: 50, spd: 70, spe: 173 },
|
||||
abilities: { 0: "Nibble Nibble" },
|
||||
heightm: 0.7,
|
||||
weightkg: 5,
|
||||
color: "Black",
|
||||
eggGroups: ["Field"],
|
||||
requiredItem: "Raticite",
|
||||
},
|
||||
};
|
||||
|
|
@ -1,304 +0,0 @@
|
|||
export const Scripts: ModdedBattleScriptsData = {
|
||||
gen: 9,
|
||||
|
||||
init() {
|
||||
this.modData('Learnsets', 'lurantis').learnset.icehammer = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'ironcrown').learnset.kingsshield = ['9L1'];
|
||||
this.modData('Learnsets', 'ironcrown').learnset.bodypress = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'carbink').learnset.moonlight = ['9L1'];
|
||||
this.modData('Learnsets', 'carbink').learnset.voltswitch = ['9L1'];
|
||||
this.modData('Learnsets', 'carbink').learnset.spikes = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'moltres').learnset.woodhammer = ['9L1'];
|
||||
this.modData('Learnsets', 'moltres').learnset.wavecrash = ['9L1'];
|
||||
this.modData('Learnsets', 'moltres').learnset.defog = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'kommoo').learnset.aurasphere = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'illumise').learnset.quiverdance = ['9L1'];
|
||||
this.modData('Learnsets', 'illumise').learnset.thunderbolt = ['9L1'];
|
||||
this.modData('Learnsets', 'illumise').learnset.icebeam = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'volbeat').learnset.victorydance = ['9L1'];
|
||||
this.modData('Learnsets', 'volbeat').learnset.mightycleave = ['9L1'];
|
||||
this.modData('Learnsets', 'volbeat').learnset.earthquake = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'abomasnow').learnset.glaciallance = ['9L1'];
|
||||
this.modData('Learnsets', 'abomasnow').learnset.appleacid = ['9L1'];
|
||||
this.modData('Learnsets', 'abomasnow').learnset.partingshot = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'dugtrio').learnset.mightycleave = ['9L1'];
|
||||
this.modData('Learnsets', 'dugtrio').learnset.saltcure = ['9L1'];
|
||||
this.modData('Learnsets', 'dugtrio').learnset.acrobatics = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'altaria').learnset.beakblast = ['9L1'];
|
||||
this.modData('Learnsets', 'altaria').learnset.return = ['9L1'];
|
||||
this.modData('Learnsets', 'altaria').learnset.explosion = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'tyranitar').learnset.stoneaxe = ['9L1'];
|
||||
this.modData('Learnsets', 'tyranitar').learnset.ceaselessedge = ['9L1'];
|
||||
this.modData('Learnsets', 'tyranitar').learnset.kowtowcleave = ['9L1'];
|
||||
this.modData('Learnsets', 'tyranitar').learnset.pursuit = ['9L1'];
|
||||
this.modData('Learnsets', 'tyranitar').learnset.switcheroo = ['9L1'];
|
||||
this.modData('Learnsets', 'tyranitar').learnset.accelerock = ['9L1'];
|
||||
this.modData('Learnsets', 'tyranitar').learnset.dracometeor = ['9L1'];
|
||||
this.modData('Learnsets', 'tyranitar').learnset.mysticalpower = ['9L1'];
|
||||
this.modData('Learnsets', 'tyranitar').learnset.sandsearstorm = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'mimikyu').learnset.spiritshackle = ['9L1'];
|
||||
this.modData('Learnsets', 'mimikyu').learnset.uturn = ['9L1'];
|
||||
this.modData('Learnsets', 'mimikyu').learnset.obstruct = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'mesprit').learnset.agility = ['9L1'];
|
||||
this.modData('Learnsets', 'mesprit').learnset.storedpower = ['9L1'];
|
||||
this.modData('Learnsets', 'mesprit').learnset.torchsong = ['9L1'];
|
||||
this.modData('Learnsets', 'mesprit').learnset.cosmicpower = ['9L1'];
|
||||
this.modData('Learnsets', 'mesprit').learnset.aquaring = ['9L1'];
|
||||
this.modData('Learnsets', 'mesprit').learnset.freezedry = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'electrode').learnset.encore = ['9L1'];
|
||||
this.modData('Learnsets', 'electrode').learnset.rapidspin = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'taurospaldeacombat').learnset.extremespeed = ['9L1'];
|
||||
this.modData('Learnsets', 'taurospaldeacombat').learnset.uturn = ['9L1'];
|
||||
this.modData('Learnsets', 'taurospaldeacombat').learnset.knockoff = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'chiyu').learnset.splash = ['9L1'];
|
||||
this.modData('Learnsets', 'chiyu').learnset.tripledive = ['9L1'];
|
||||
this.modData('Learnsets', 'chiyu').learnset.pyroball = ['9L1'];
|
||||
this.modData('Learnsets', 'chiyu').learnset.knockoff = ['9L1'];
|
||||
this.modData('Learnsets', 'chiyu').learnset.suckerpunch = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'wochien').learnset.partingshot = ['9L1'];
|
||||
this.modData('Learnsets', 'wochien').learnset.strengthsap = ['9L1'];
|
||||
this.modData('Learnsets', 'wochien').learnset.bouncingbubble = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'staraptor').learnset.jumpkick = ['9L1'];
|
||||
this.modData('Learnsets', 'staraptor').learnset.flareblitz = ['9L1'];
|
||||
this.modData('Learnsets', 'staraptor').learnset.wavecrash = ['9L1'];
|
||||
this.modData('Learnsets', 'staraptor').learnset.headsmash = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'archaludon').learnset.scald = ['9L1'];
|
||||
this.modData('Learnsets', 'archaludon').learnset.hydropump = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'malamar').learnset.willowisp = ['9L1'];
|
||||
this.modData('Learnsets', 'malamar').learnset.recover = ['9L1'];
|
||||
this.modData('Learnsets', 'malamar').learnset.eeriespell = ['9L1'];
|
||||
this.modData('Learnsets', 'malamar').learnset.sweetkiss = ['9L1'];
|
||||
this.modData('Learnsets', 'malamar').learnset.spiritbreak = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'empoleon').learnset.nastyplot = ['9L1'];
|
||||
this.modData('Learnsets', 'empoleon').learnset.watershuriken = ['9L1'];
|
||||
this.modData('Learnsets', 'empoleon').learnset.tachyoncutter = ['9L1'];
|
||||
this.modData('Learnsets', 'empoleon').learnset.secretsword = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'regieleki').learnset.blazingtorque = ['9L1'];
|
||||
this.modData('Learnsets', 'regieleki').learnset.soak = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'lycanrocmidnight').learnset.accelerock = ['9L1'];
|
||||
this.modData('Learnsets', 'lycanrocmidnight').learnset.bonerush = ['9L1'];
|
||||
this.modData('Learnsets', 'lycanrocmidnight').learnset.stormthrow = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'lycanroc').learnset.firelash = ['9L1'];
|
||||
this.modData('Learnsets', 'lycanroc').learnset.uturn = ['9L1'];
|
||||
this.modData('Learnsets', 'lycanroc').learnset.spikes = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'lycanrocdusk').learnset.mountainmaw = ['9L1'];
|
||||
this.modData('Learnsets', 'lycanrocdusk').learnset.icefang = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'dodrio').learnset.triplearrows = ['9L1'];
|
||||
this.modData('Learnsets', 'dodrio').learnset.obstruct = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'whiscash').learnset.toxic = ['9L1'];
|
||||
this.modData('Learnsets', 'whiscash').learnset.flipturn = ['9L1'];
|
||||
this.modData('Learnsets', 'whiscash').learnset.scald = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'hippowdon').learnset.saltcure = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'cramorant').learnset.beakblast = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'grafaiai').learnset.bulkup = ['9L1'];
|
||||
this.modData('Learnsets', 'grafaiai').learnset.scavenge = ['9L1'];
|
||||
this.modData('Learnsets', 'grafaiai').learnset.drainpunch = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'kyurem').learnset.earthquake = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'roaringmoon').learnset.firelash = ['9L1'];
|
||||
this.modData('Learnsets', 'roaringmoon').learnset.glaiverush = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'milotic').learnset.bouncybubble = ['9L1'];
|
||||
this.modData('Learnsets', 'milotic').learnset.moonblast = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'gogoat').learnset.headsmash = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'clodsire').learnset.barbbarrage = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'masquerain').learnset.roost = ['9L1'];
|
||||
this.modData('Learnsets', 'masquerain').learnset.darkpulse = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'kyuremblack').learnset.icehammer = ['9L1'];
|
||||
this.modData('Learnsets', 'kyuremblack').learnset.dragonhammer = ['9L1'];
|
||||
this.modData('Learnsets', 'kyuremblack').learnset.roost = ['9L1'];
|
||||
this.modData('Learnsets', 'kyuremblack').learnset.earthquake = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'ironthorns').learnset.ironstrike = ['9L1'];
|
||||
this.modData('Learnsets', 'ironthorns').learnset.knockoff = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'chienpao').learnset.bulkup = ['9L1'];
|
||||
this.modData('Learnsets', 'chienpao').learnset.iciclestorm = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'pelipper').learnset.bleakwindstorm = ['9L1'];
|
||||
this.modData('Learnsets', 'pelipper').learnset.sandsearstorm = ['9L1'];
|
||||
this.modData('Learnsets', 'pelipper').learnset.wildboltstorm = ['9L1'];
|
||||
this.modData('Learnsets', 'pelipper').learnset.springtidestorm = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'araquanid').learnset.surgingstrikes = ['9L1'];
|
||||
this.modData('Learnsets', 'araquanid').learnset.flipturn = ['9L1'];
|
||||
this.modData('Learnsets', 'araquanid').learnset.silktrap = ['9L1'];
|
||||
this.modData('Learnsets', 'araquanid').learnset.firstimpression = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'avalugghisui').learnset.mountainmaw = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'swalot').learnset.earthpower = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'zapdosgalar').learnset.wildcharge = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'phione').learnset.workup = ['9L1'];
|
||||
this.modData('Learnsets', 'phione').learnset.tidalsurge = ['9L1'];
|
||||
this.modData('Learnsets', 'phione').learnset.geyser = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'sudowoodo').learnset.bonsaibounce = ['9L1'];
|
||||
this.modData('Learnsets', 'sudowoodo').learnset.synthesis = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'dondozo').learnset.hornleech = ['9L1'];
|
||||
this.modData('Learnsets', 'dondozo').learnset.fishiousrend = ['9L1'];
|
||||
this.modData('Learnsets', 'dondozo').learnset.recover = ['9L1'];
|
||||
this.modData('Learnsets', 'dondozo').learnset.flipturn = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'golurk').learnset.shatteredseal = ['9L1'];
|
||||
this.modData('Learnsets', 'golurk').learnset.trickroom = ['9L1'];
|
||||
this.modData('Learnsets', 'golurk').learnset.headlongrush = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'meowscarada').learnset.encore = ['9L1'];
|
||||
this.modData('Learnsets', 'meowscarada').learnset.spectralthief = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'infernape').learnset.alloutassault = ['9L1'];
|
||||
this.modData('Learnsets', 'infernape').learnset.mindblown = ['9L1'];
|
||||
this.modData('Learnsets', 'infernape').learnset.bitterblade = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'salamence').learnset.uturn = ['9L1'];
|
||||
this.modData('Learnsets', 'salamence').learnset.dragonascent = ['9L1'];
|
||||
this.modData('Learnsets', 'salamence').learnset.bloodmoon = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'urshifu').learnset.agility = ['9L1'];
|
||||
this.modData('Learnsets', 'urshifu').learnset.aquajet = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'urshifurapidstrike').learnset.agility = ['9L1'];
|
||||
this.modData('Learnsets', 'urshifurapidstrike').learnset.suckerpunch = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'stonjourner').learnset.rockwrecker = ['9L1'];
|
||||
this.modData('Learnsets', 'stonjourner').learnset.meteorassault = ['9L1'];
|
||||
this.modData('Learnsets', 'stonjourner').learnset.skyattack = ['9L1'];
|
||||
this.modData('Learnsets', 'stonjourner').learnset.solarblade = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'veluza').learnset.ragefist = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'ogerpon').learnset.leafblade = ['9L1'];
|
||||
this.modData('Learnsets', 'ogerpon').learnset.crabhammer = ['9L1'];
|
||||
this.modData('Learnsets', 'ogerpon').learnset.stoneedge = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'dachsbun').learnset.nuzzle = ['9L1'];
|
||||
this.modData('Learnsets', 'dachsbun').learnset.spiritbreak = ['9L1'];
|
||||
this.modData('Learnsets', 'dachsbun').learnset.morningsun = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'magneton').learnset.magnetbomb = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'delibird').learnset.iciclestorm = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'hitmontop').learnset.bulletseed = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'articunogalar').learnset.aeroblast = ['9L1'];
|
||||
this.modData('Learnsets', 'articunogalar').learnset.oblivionwing = ['9L1'];
|
||||
this.modData('Learnsets', 'articunogalar').learnset.aurasphere = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'vaporeon').learnset.voltswitch = ['9L1'];
|
||||
this.modData('Learnsets', 'vaporeon').learnset.burnout = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'garganacl').learnset.thunderwave = ['9L1'];
|
||||
this.modData('Learnsets', 'garganacl').learnset.saltcurse = ['9L1'];
|
||||
this.modData('Learnsets', 'garganacl').learnset.purify = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'swanna').learnset.bleakwindstorm = ['9L1'];
|
||||
this.modData('Learnsets', 'swanna').learnset.steameruption = ['9L1'];
|
||||
this.modData('Learnsets', 'swanna').learnset.flyby = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'typhlosion').learnset.heatsink = ['9L1'];
|
||||
this.modData('Learnsets', 'typhlosion').learnset.steameruption = ['9L1'];
|
||||
this.modData('Learnsets', 'typhlosion').learnset.matchagotcha = ['9L1'];
|
||||
this.modData('Learnsets', 'typhlosion').learnset.calmmind = ['9L1'];
|
||||
this.modData('Learnsets', 'typhlosion').learnset.morningsun = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'terapagos').learnset.nastyplot = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'tatsugiri').learnset.switcheroo = ['9L1'];
|
||||
this.modData('Learnsets', 'tatsugiri').learnset.sashimishuffle = ['9L1'];
|
||||
this.modData('Learnsets', 'tatsugiri').learnset.twister = ['9L1'];
|
||||
this.modData('Learnsets', 'tatsugiri').learnset.waterspout = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'flapple').learnset.earthquake = ['9L1'];
|
||||
this.modData('Learnsets', 'flapple').learnset.grabapple = ['9L1'];
|
||||
this.modData('Learnsets', 'flapple').learnset.flareblitz = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'genesect').learnset.earthquake = ['9L1'];
|
||||
this.modData('Learnsets', 'genesect').learnset.sunsteelstrike = ['9L1'];
|
||||
this.modData('Learnsets', 'genesect').learnset.behemothblade = ['9L1'];
|
||||
this.modData('Learnsets', 'genesect').learnset.makeitrain = ['9L1'];
|
||||
this.modData('Learnsets', 'genesect').learnset.tachyoncutter = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'honchkrow').learnset.crowverload = ['9L1'];
|
||||
this.modData('Learnsets', 'honchkrow').learnset.oblivionwing = ['9L1'];
|
||||
this.modData('Learnsets', 'honchkrow').learnset.closecombat = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'primeape').learnset.knockoff = ['9L1'];
|
||||
this.modData('Learnsets', 'primeape').learnset.ironhead = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'rillaboom').learnset.naturesfury = ['9L1'];
|
||||
this.modData('Learnsets', 'rillaboom').learnset.landswrath = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'mandibuzz').learnset.fling = ['9L1'];
|
||||
this.modData('Learnsets', 'mandibuzz').learnset.scavenge = ['9L1'];
|
||||
this.modData('Learnsets', 'mandibuzz').learnset.bonemerang = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'feraligatr').learnset.firefang = ['9L1'];
|
||||
this.modData('Learnsets', 'feraligatr').learnset.thunderfang = ['9L1'];
|
||||
this.modData('Learnsets', 'feraligatr').learnset.poisonfang = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'salazzle').learnset.magmastorm = ['9L1'];
|
||||
this.modData('Learnsets', 'salazzle').learnset.malignantchain = ['9L1'];
|
||||
this.modData('Learnsets', 'salazzle').learnset.psychicnoise = ['9L1'];
|
||||
this.modData('Learnsets', 'salazzle').learnset.banefulbunker = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'kyogre').learnset.hurricane = ['9L1'];
|
||||
this.modData('Learnsets', 'kyogre').learnset.tidalsurge = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'azelf').learnset.rapidspin = ['9L1'];
|
||||
this.modData('Learnsets', 'azelf').learnset.lootbox = ['9L1'];
|
||||
this.modData('Learnsets', 'azelf').learnset.acupressure = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'decidueye').learnset.sinisterarrows = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'ogerpon').learnset.sappyseed = ['9L1'];
|
||||
this.modData('Learnsets', 'ogerpon').learnset.thousandwaves = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'glimmora').learnset.icebeam = ['9L1'];
|
||||
this.modData('Learnsets', 'glimmora').learnset.malignantchain = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'wobbuffet').learnset.nightshade = ['9L1'];
|
||||
this.modData('Learnsets', 'wobbuffet').learnset.guillotine = ['9L1'];
|
||||
this.modData('Learnsets', 'wobbuffet').learnset.shedtail = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'raticate').learnset.lastbreakfast = ['9L1'];
|
||||
},
|
||||
};
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTable = {
|
||||
export const Abilities: {[k: string]: ModdedAbilityData} = {
|
||||
unaware: {
|
||||
inherit: true,
|
||||
onAnyModifyBoost(boosts, pokemon) {
|
||||
|
|
|
|||
|
|
@ -15,8 +15,10 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
move.hit = 0;
|
||||
}
|
||||
|
||||
if (!target.runImmunity(move, !suppressMessages)) {
|
||||
return false;
|
||||
if (!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) {
|
||||
if (!target.runImmunity(move.type, !suppressMessages)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (move.ohko) return target.maxhp;
|
||||
|
|
@ -78,7 +80,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
const isPhysical = move.category === 'Physical';
|
||||
const defenseStat: StatIDExceptHP = move.overrideDefensiveStat || (isPhysical ? 'def' : 'spd');
|
||||
|
||||
const statTable: { [k in StatIDExceptHP]: string } = { atk: 'Atk', def: 'Def', spa: 'SpA', spd: 'SpD', spe: 'Spe' };
|
||||
const statTable: {[k in StatIDExceptHP]: string} = {atk: 'Atk', def: 'Def', spa: 'SpA', spd: 'SpD', spe: 'Spe'};
|
||||
|
||||
let maxAttack = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ There were only 151 Pokémon plus MissingNo, just a handful of moves, no abiliti
|
|||
EVd to the max and we had some kind of different IVs, which maxed at 15 and every point gave 2 to the stat, so in
|
||||
a similar fashion, Pokes used to have 30 IVs on each stat.
|
||||
|
||||
The following sources have been used and extremely useful when developing this mod:
|
||||
The following sources have been used and extremly useful when developing this mod:
|
||||
https://raw.github.com/po-devs/pokemon-online/master/bin/database/rby-stuff.txt
|
||||
https://www.smogon.com/rb/articles/differences
|
||||
https://www.smogon.com/forums/threads/past-gens-research-thread.3506992/#post-5878612
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
* under certain conditions and re-applied under other conditions.
|
||||
*/
|
||||
|
||||
export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDataTable = {
|
||||
export const Conditions: {[id: string]: ModdedConditionData} = {
|
||||
brn: {
|
||||
name: 'brn',
|
||||
effectType: 'Status',
|
||||
|
|
@ -41,7 +41,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
if (pokemon.removeVolatile('twoturnmove')) {
|
||||
if (pokemon.volatiles['invulnerability']) {
|
||||
this.hint(`In Gen 1, when a Dig/Fly user is fully paralyzed while semi-invulnerable, ` +
|
||||
`it will remain semi-invulnerable until it switches out or fully executes Dig/Fly`, true);
|
||||
`it will remain semi-invulnerable until it switches out or fully executes Dig/Fly`, true);
|
||||
}
|
||||
}
|
||||
pokemon.removeVolatile('partialtrappinglock');
|
||||
|
|
@ -55,7 +55,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
effectType: 'Status',
|
||||
onStart(target, source, sourceEffect) {
|
||||
if (sourceEffect && sourceEffect.effectType === 'Move') {
|
||||
this.add('-status', target, 'slp', `[from] move: ${sourceEffect.name}`);
|
||||
this.add('-status', target, 'slp', '[from] move: ' + sourceEffect.name);
|
||||
} else {
|
||||
this.add('-status', target, 'slp');
|
||||
}
|
||||
|
|
@ -155,6 +155,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
pokemon.removeVolatile('lockedmove');
|
||||
return false;
|
||||
}
|
||||
return;
|
||||
},
|
||||
},
|
||||
flinch: {
|
||||
|
|
@ -163,7 +164,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
onStart(target) {
|
||||
target.removeVolatile('mustrecharge');
|
||||
},
|
||||
onBeforeMovePriority: 8,
|
||||
onBeforeMovePriority: 4,
|
||||
onBeforeMove(pokemon) {
|
||||
if (!this.runEvent('Flinch', pokemon)) {
|
||||
return;
|
||||
|
|
@ -185,94 +186,37 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
},
|
||||
partiallytrapped: {
|
||||
name: 'partiallytrapped',
|
||||
// this is the duration of Wrap if it doesn't continue.
|
||||
// (i.e. if the attacker switches out.)
|
||||
// the full duration is tracked in partialtrappinglock
|
||||
duration: 2,
|
||||
// defender still takes PSN damage, etc
|
||||
// TODO: research exact mechanics
|
||||
onBeforeMovePriority: 9,
|
||||
onBeforeMovePriority: 4,
|
||||
onBeforeMove(pokemon) {
|
||||
this.add('cant', pokemon, 'partiallytrapped');
|
||||
return false;
|
||||
},
|
||||
onRestart() {
|
||||
this.effectState.duration = 2;
|
||||
},
|
||||
onAccuracy(accuracy, target, source, move) {
|
||||
if (source === this.effectState.source) return true;
|
||||
},
|
||||
onDisableMove(target) {
|
||||
target.maybeLocked = true;
|
||||
},
|
||||
},
|
||||
fakepartiallytrapped: {
|
||||
name: 'fakepartiallytrapped',
|
||||
// Wrap ended this turn, but you don't know that
|
||||
// until you try to use an attack
|
||||
duration: 2,
|
||||
onDisableMove(target) {
|
||||
target.maybeLocked = true;
|
||||
},
|
||||
},
|
||||
partialtrappinglock: {
|
||||
name: 'partialtrappinglock',
|
||||
durationCallback() {
|
||||
return this.sample([2, 2, 2, 3, 3, 3, 4, 5]);
|
||||
const duration = this.sample([2, 2, 2, 3, 3, 3, 4, 5]);
|
||||
return duration;
|
||||
},
|
||||
onStart(target, source, effect) {
|
||||
const foe = target.foes()[0];
|
||||
if (!foe) return false;
|
||||
|
||||
this.effectState.move = effect.id;
|
||||
this.effectState.totalDuration = this.effectState.duration!;
|
||||
this.effectState.damage = this.lastDamage;
|
||||
this.effectState.locked = foe;
|
||||
foe.addVolatile('partiallytrapped', target, effect);
|
||||
},
|
||||
onOverrideAction(pokemon, target, move) {
|
||||
return this.effectState.move;
|
||||
},
|
||||
onBeforeMove(pokemon, target, move) {
|
||||
if (target !== this.effectState.locked) {
|
||||
pokemon.removeVolatile('partialtrappinglock');
|
||||
}
|
||||
},
|
||||
onAfterMove(pokemon, target, move) {
|
||||
if (target && target.hp <= 0) {
|
||||
delete pokemon.volatiles['partialtrappinglock'];
|
||||
return;
|
||||
}
|
||||
if (this.effectState.duration === 1) {
|
||||
if (this.effectState.totalDuration !== 5) {
|
||||
pokemon.addVolatile('fakepartiallytrapped');
|
||||
pokemon.volatiles['fakepartiallytrapped'].counterpart = target;
|
||||
target.addVolatile('fakepartiallytrapped');
|
||||
target.volatiles['fakepartiallytrapped'].counterpart = pokemon;
|
||||
}
|
||||
} else {
|
||||
target.addVolatile('partiallytrapped', pokemon, move);
|
||||
}
|
||||
},
|
||||
onLockMove() {
|
||||
return this.effectState.move;
|
||||
},
|
||||
onDisableMove(pokemon) {
|
||||
pokemon.maybeLocked = true;
|
||||
if (!pokemon.hasMove(this.effectState.move)) {
|
||||
return;
|
||||
}
|
||||
for (const moveSlot of pokemon.moveSlots) {
|
||||
if (moveSlot.id !== this.effectState.move) {
|
||||
pokemon.disableMove(moveSlot.id);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
mustrecharge: {
|
||||
inherit: true,
|
||||
duration: 0,
|
||||
onBeforeMovePriority: 7,
|
||||
onStart: undefined, // no inherit
|
||||
onAfterMove(pokemon, target, move) {
|
||||
if (target && target.hp <= 0) {
|
||||
delete pokemon.volatiles['mustrecharge'];
|
||||
return;
|
||||
}
|
||||
this.add('-mustrecharge', pokemon);
|
||||
},
|
||||
onStart() {},
|
||||
},
|
||||
lockedmove: {
|
||||
// Thrash and Petal Dance.
|
||||
|
|
@ -289,12 +233,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
const move = this.dex.moves.get(this.effectState.move);
|
||||
if (move.id) {
|
||||
this.debug('Forcing into ' + move.id);
|
||||
this.queue.changeAction(pokemon, { choice: 'move', moveid: move.id });
|
||||
}
|
||||
},
|
||||
onAfterMove(pokemon) {
|
||||
if (pokemon.volatiles['lockedmove'].time <= 0) {
|
||||
pokemon.removeVolatile('lockedmove');
|
||||
this.queue.changeAction(pokemon, {choice: 'move', moveid: move.id});
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormatsDataTable = {
|
||||
export const FormatsData: {[k: string]: ModdedSpeciesFormatsData} = {
|
||||
bulbasaur: {
|
||||
tier: "LC",
|
||||
},
|
||||
|
|
@ -6,7 +6,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
venusaur: {
|
||||
tier: "PU",
|
||||
tier: "UU",
|
||||
},
|
||||
charmander: {
|
||||
tier: "LC",
|
||||
|
|
@ -33,7 +33,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
butterfree: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
weedle: {
|
||||
tier: "LC",
|
||||
|
|
@ -42,7 +42,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
beedrill: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
pidgey: {
|
||||
tier: "LC",
|
||||
|
|
@ -63,25 +63,25 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
fearow: {
|
||||
tier: "NU",
|
||||
tier: "PU",
|
||||
},
|
||||
ekans: {
|
||||
tier: "LC",
|
||||
},
|
||||
arbok: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
pikachu: {
|
||||
tier: "LC",
|
||||
},
|
||||
raichu: {
|
||||
tier: "UU",
|
||||
tier: "NUBL",
|
||||
},
|
||||
sandshrew: {
|
||||
tier: "LC",
|
||||
},
|
||||
sandslash: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
nidoranf: {
|
||||
tier: "LC",
|
||||
|
|
@ -90,7 +90,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
nidoqueen: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
nidoranm: {
|
||||
tier: "LC",
|
||||
|
|
@ -99,31 +99,31 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
nidoking: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
clefairy: {
|
||||
tier: "LC",
|
||||
},
|
||||
clefable: {
|
||||
tier: "UU",
|
||||
tier: "NU",
|
||||
},
|
||||
vulpix: {
|
||||
tier: "LC",
|
||||
},
|
||||
ninetales: {
|
||||
tier: "UU",
|
||||
tier: "NU",
|
||||
},
|
||||
jigglypuff: {
|
||||
tier: "LC",
|
||||
},
|
||||
wigglytuff: {
|
||||
tier: "ZU",
|
||||
tier: "NU",
|
||||
},
|
||||
zubat: {
|
||||
tier: "LC",
|
||||
},
|
||||
golbat: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
oddish: {
|
||||
tier: "LC",
|
||||
|
|
@ -132,13 +132,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
vileplume: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
paras: {
|
||||
tier: "LC",
|
||||
},
|
||||
parasect: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
venonat: {
|
||||
tier: "LC",
|
||||
|
|
@ -162,7 +162,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
golduck: {
|
||||
tier: "PU",
|
||||
tier: "NUBL",
|
||||
},
|
||||
mankey: {
|
||||
tier: "LC",
|
||||
|
|
@ -174,22 +174,22 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
arcanine: {
|
||||
tier: "NU",
|
||||
},
|
||||
poliwag: {
|
||||
tier: "ZU",
|
||||
},
|
||||
poliwhirl: {
|
||||
tier: "NU",
|
||||
},
|
||||
poliwrath: {
|
||||
tier: "NU",
|
||||
},
|
||||
abra: {
|
||||
tier: "PU",
|
||||
},
|
||||
poliwag: {
|
||||
tier: "LC",
|
||||
},
|
||||
poliwhirl: {
|
||||
tier: "NUBL",
|
||||
},
|
||||
poliwrath: {
|
||||
tier: "NUBL",
|
||||
},
|
||||
abra: {
|
||||
tier: "LC",
|
||||
},
|
||||
kadabra: {
|
||||
tier: "NU",
|
||||
tier: "UU",
|
||||
},
|
||||
alakazam: {
|
||||
tier: "OU",
|
||||
|
|
@ -201,7 +201,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
machamp: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
bellsprout: {
|
||||
tier: "LC",
|
||||
|
|
@ -210,19 +210,19 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
victreebel: {
|
||||
tier: "NU",
|
||||
tier: "UU",
|
||||
},
|
||||
tentacool: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
tentacruel: {
|
||||
tier: "NU",
|
||||
tier: "UU",
|
||||
},
|
||||
geodude: {
|
||||
tier: "LC",
|
||||
},
|
||||
graveler: {
|
||||
tier: "PU",
|
||||
tier: "NFE",
|
||||
},
|
||||
golem: {
|
||||
tier: "NU",
|
||||
|
|
@ -231,22 +231,22 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
rapidash: {
|
||||
tier: "UU",
|
||||
tier: "PU",
|
||||
},
|
||||
slowpoke: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
slowbro: {
|
||||
tier: "UU",
|
||||
tier: "OU",
|
||||
},
|
||||
magnemite: {
|
||||
tier: "LC",
|
||||
},
|
||||
magneton: {
|
||||
tier: "NU",
|
||||
tier: "PU",
|
||||
},
|
||||
farfetchd: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
doduo: {
|
||||
tier: "LC",
|
||||
|
|
@ -258,13 +258,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
dewgong: {
|
||||
tier: "NU",
|
||||
tier: "UU",
|
||||
},
|
||||
grimer: {
|
||||
tier: "LC",
|
||||
},
|
||||
muk: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
shellder: {
|
||||
tier: "LC",
|
||||
|
|
@ -273,7 +273,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "OU",
|
||||
},
|
||||
gastly: {
|
||||
tier: "PU",
|
||||
tier: "LC",
|
||||
},
|
||||
haunter: {
|
||||
tier: "UU",
|
||||
|
|
@ -282,10 +282,10 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "OU",
|
||||
},
|
||||
onix: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
drowzee: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
hypno: {
|
||||
tier: "UU",
|
||||
|
|
@ -294,7 +294,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
kingler: {
|
||||
tier: "ZU",
|
||||
tier: "NU",
|
||||
},
|
||||
voltorb: {
|
||||
tier: "LC",
|
||||
|
|
@ -303,7 +303,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NU",
|
||||
},
|
||||
exeggcute: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
exeggutor: {
|
||||
tier: "OU",
|
||||
|
|
@ -312,22 +312,22 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
marowak: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
hitmonlee: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
hitmonchan: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
lickitung: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
koffing: {
|
||||
tier: "LC",
|
||||
},
|
||||
weezing: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
rhyhorn: {
|
||||
tier: "LC",
|
||||
|
|
@ -339,7 +339,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "OU",
|
||||
},
|
||||
tangela: {
|
||||
tier: "NU",
|
||||
tier: "UU",
|
||||
},
|
||||
kangaskhan: {
|
||||
tier: "UU",
|
||||
|
|
@ -357,7 +357,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "PU",
|
||||
},
|
||||
staryu: {
|
||||
tier: "PU",
|
||||
tier: "LC",
|
||||
},
|
||||
starmie: {
|
||||
tier: "OU",
|
||||
|
|
@ -378,7 +378,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "PU",
|
||||
},
|
||||
pinsir: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
tauros: {
|
||||
tier: "OU",
|
||||
|
|
@ -393,28 +393,28 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
ditto: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
eevee: {
|
||||
tier: "LC",
|
||||
},
|
||||
vaporeon: {
|
||||
tier: "NU",
|
||||
tier: "UU",
|
||||
},
|
||||
jolteon: {
|
||||
tier: "OU",
|
||||
},
|
||||
flareon: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
porygon: {
|
||||
tier: "PU",
|
||||
},
|
||||
omanyte: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
omastar: {
|
||||
tier: "NU",
|
||||
tier: "UU",
|
||||
},
|
||||
kabuto: {
|
||||
tier: "LC",
|
||||
|
|
@ -423,7 +423,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NU",
|
||||
},
|
||||
aerodactyl: {
|
||||
tier: "NU",
|
||||
tier: "UU",
|
||||
},
|
||||
snorlax: {
|
||||
tier: "OU",
|
||||
|
|
@ -435,13 +435,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "OU",
|
||||
},
|
||||
moltres: {
|
||||
tier: "UU",
|
||||
tier: "NU",
|
||||
},
|
||||
dratini: {
|
||||
tier: "LC",
|
||||
},
|
||||
dragonair: {
|
||||
tier: "ZU",
|
||||
tier: "NFE",
|
||||
},
|
||||
dragonite: {
|
||||
tier: "UU",
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* Some moves have had major changes, such as Bite's typing.
|
||||
*/
|
||||
|
||||
export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
||||
export const Moves: {[k: string]: ModdedMoveData} = {
|
||||
acid: {
|
||||
inherit: true,
|
||||
secondary: {
|
||||
|
|
@ -53,7 +53,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
return false;
|
||||
}
|
||||
const target = this.getRandomTarget(pokemon, 'Pound');
|
||||
this.actions.moveHit(target, pokemon, currentMove, { damage: this.effectState.damage * 2 } as ActiveMove);
|
||||
this.actions.moveHit(target, pokemon, currentMove, {damage: this.effectState.damage * 2} as ActiveMove);
|
||||
pokemon.removeVolatile('bide');
|
||||
return false;
|
||||
}
|
||||
|
|
@ -76,13 +76,22 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
bind: {
|
||||
inherit: true,
|
||||
ignoreImmunity: true,
|
||||
volatileStatus: 'partiallytrapped',
|
||||
self: {
|
||||
volatileStatus: 'partialtrappinglock',
|
||||
},
|
||||
onTryMove(source, target) {
|
||||
if (target.volatiles['mustrecharge']) {
|
||||
target.removeVolatile('mustrecharge');
|
||||
this.hint("In Gen 1, partial trapping moves negate the recharge turn of Hyper Beam, even if they miss.", true);
|
||||
// FIXME: onBeforeMove(pokemon, target) {target.removeVolatile('mustrecharge')}
|
||||
onHit(target, source) {
|
||||
/**
|
||||
* The duration of the partially trapped must be always renewed to 2
|
||||
* so target doesn't move on trapper switch out as happens in gen 1.
|
||||
* However, this won't happen if there's no switch and the trapper is
|
||||
* about to end its partial trapping.
|
||||
**/
|
||||
if (target.volatiles['partiallytrapped']) {
|
||||
if (source.volatiles['partialtrappinglock'] && source.volatiles['partialtrappinglock'].duration > 1) {
|
||||
target.volatiles['partiallytrapped'].duration = 2;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
@ -123,13 +132,22 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
accuracy: 75,
|
||||
pp: 10,
|
||||
volatileStatus: 'partiallytrapped',
|
||||
self: {
|
||||
volatileStatus: 'partialtrappinglock',
|
||||
},
|
||||
onTryMove(source, target) {
|
||||
if (target.volatiles['mustrecharge']) {
|
||||
target.removeVolatile('mustrecharge');
|
||||
this.hint("In Gen 1, partial trapping moves negate the recharge turn of Hyper Beam, even if they miss.", true);
|
||||
// FIXME: onBeforeMove(pokemon, target) {target.removeVolatile('mustrecharge')}
|
||||
onHit(target, source) {
|
||||
/**
|
||||
* The duration of the partially trapped must be always renewed to 2
|
||||
* so target doesn't move on trapper switch out as happens in gen 1.
|
||||
* However, this won't happen if there's no switch and the trapper is
|
||||
* about to end its partial trapping.
|
||||
**/
|
||||
if (target.volatiles['partiallytrapped']) {
|
||||
if (source.volatiles['partialtrappinglock'] && source.volatiles['partialtrappinglock'].duration > 1) {
|
||||
target.volatiles['partiallytrapped'].duration = 2;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
@ -147,7 +165,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
target: "normal",
|
||||
onHit(target, source) {
|
||||
source.setType(target.getTypes(true));
|
||||
this.add('-start', source, 'typechange', source.types.join('/'), '[from] move: Conversion', `[of] ${target}`);
|
||||
this.add('-start', source, 'typechange', source.types.join('/'), '[from] move: Conversion', '[of] ' + target);
|
||||
},
|
||||
},
|
||||
counter: {
|
||||
|
|
@ -162,14 +180,14 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
// - if Counter is used by the opponent, it will succeed if the player's last selected move is Counterable
|
||||
// - (Counter will thus desync if the target's last used move is not as counterable as the target's last selected move)
|
||||
// - if Counter succeeds it will deal twice the last move damage dealt in battle (even if it's from a different pokemon because of a switch)
|
||||
const isCounterable = (move: Move | null) => move && move.basePower > 0 &&
|
||||
['Normal', 'Fighting'].includes(move.type) && move.id !== 'counter';
|
||||
|
||||
const lastMove = target.side.lastMove && this.dex.moves.get(target.side.lastMove.id);
|
||||
const lastMoveIsCounterable = isCounterable(lastMove);
|
||||
const lastMoveIsCounterable = lastMove && lastMove.basePower > 0 &&
|
||||
['Normal', 'Fighting'].includes(lastMove.type) && lastMove.id !== 'counter';
|
||||
|
||||
const lastSelectedMove = target.side.lastSelectedMove && this.dex.moves.get(target.side.lastSelectedMove);
|
||||
const lastSelectedMoveIsCounterable = isCounterable(lastSelectedMove || null);
|
||||
const lastSelectedMoveIsCounterable = lastSelectedMove && lastSelectedMove.basePower > 0 &&
|
||||
['Normal', 'Fighting'].includes(lastSelectedMove.type) && lastSelectedMove.id !== 'counter';
|
||||
|
||||
if (!lastMoveIsCounterable && !lastSelectedMoveIsCounterable) {
|
||||
this.debug("Gen 1 Counter: last move was not Counterable");
|
||||
|
|
@ -189,7 +207,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
|
||||
return 2 * this.lastDamage;
|
||||
},
|
||||
flags: { contact: 1, protect: 1, metronome: 1 },
|
||||
},
|
||||
crabhammer: {
|
||||
inherit: true,
|
||||
|
|
@ -211,24 +228,34 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
},
|
||||
disable: {
|
||||
inherit: true,
|
||||
num: 50,
|
||||
accuracy: 55,
|
||||
basePower: 0,
|
||||
category: "Status",
|
||||
name: "Disable",
|
||||
pp: 20,
|
||||
priority: 0,
|
||||
flags: {protect: 1, mirror: 1, bypasssub: 1},
|
||||
volatileStatus: 'disable',
|
||||
onTryHit(target) {
|
||||
return target.moveSlots.some(ms => ms.pp > 0);
|
||||
// This function should not return if the checks are met. Adding && undefined ensures this happens.
|
||||
return target.moveSlots.some(ms => ms.pp > 0) &&
|
||||
!('disable' in target.volatiles) &&
|
||||
undefined;
|
||||
},
|
||||
condition: {
|
||||
inherit: true,
|
||||
durationCallback: undefined, // no inherit
|
||||
onStart(pokemon) {
|
||||
// disable can only select moves that have pp > 0, hence the onTryHit modification
|
||||
const [slotIndex, moveSlot] = this.sample(Array.from(pokemon.moveSlots.entries()).filter(([i, ms]) => ms.pp > 0));
|
||||
this.debug(`Disable: disabling move ${moveSlot.move} in slot ${slotIndex}`);
|
||||
const moveSlot = this.sample(pokemon.moveSlots.filter(ms => ms.pp > 0));
|
||||
this.add('-start', pokemon, 'Disable', moveSlot.move);
|
||||
this.effectState.move = moveSlot.id;
|
||||
this.effectState.slotIndex = slotIndex;
|
||||
// 1-8 turns (which will in effect translate to 0-7 missed turns for the target)
|
||||
this.effectState.time = this.random(1, 9);
|
||||
},
|
||||
onBeforeMovePriority: 6,
|
||||
onEnd(pokemon) {
|
||||
this.add('-end', pokemon, 'Disable');
|
||||
},
|
||||
onBeforeMovePriority: 7,
|
||||
onBeforeMove(pokemon, target, move) {
|
||||
pokemon.volatiles['disable'].time--;
|
||||
if (!pokemon.volatiles['disable'].time) {
|
||||
|
|
@ -243,17 +270,20 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
}
|
||||
},
|
||||
onDisableMove(pokemon) {
|
||||
// disable the move slot
|
||||
if (pokemon.moveSlots.length > this.effectState.slotIndex) {
|
||||
pokemon.moveSlots[this.effectState.slotIndex].disabled = true;
|
||||
pokemon.moveSlots[this.effectState.slotIndex].disabledSource = this.effect.name;
|
||||
for (const moveSlot of pokemon.moveSlots) {
|
||||
if (moveSlot.id === this.effectState.move) {
|
||||
pokemon.disableMove(moveSlot.id);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
secondary: null,
|
||||
target: "normal",
|
||||
type: "Normal",
|
||||
},
|
||||
dizzypunch: {
|
||||
inherit: true,
|
||||
secondary: undefined, // no inherit
|
||||
secondary: null,
|
||||
},
|
||||
doubleedge: {
|
||||
inherit: true,
|
||||
|
|
@ -279,13 +309,22 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
accuracy: 70,
|
||||
basePower: 15,
|
||||
volatileStatus: 'partiallytrapped',
|
||||
self: {
|
||||
volatileStatus: 'partialtrappinglock',
|
||||
},
|
||||
onTryMove(source, target) {
|
||||
if (target.volatiles['mustrecharge']) {
|
||||
target.removeVolatile('mustrecharge');
|
||||
this.hint("In Gen 1, partial trapping moves negate the recharge turn of Hyper Beam, even if they miss.", true);
|
||||
// FIXME: onBeforeMove(pokemon, target) {target.removeVolatile('mustrecharge')}
|
||||
onHit(target, source) {
|
||||
/**
|
||||
* The duration of the partially trapped must be always renewed to 2
|
||||
* so target doesn't move on trapper switch out as happens in gen 1.
|
||||
* However, this won't happen if there's no switch and the trapper is
|
||||
* about to end its partial trapping.
|
||||
**/
|
||||
if (target.volatiles['partiallytrapped']) {
|
||||
if (source.volatiles['partialtrappinglock'] && source.volatiles['partialtrappinglock'].duration > 1) {
|
||||
target.volatiles['partiallytrapped'].duration = 2;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
@ -306,9 +345,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
focusenergy: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
onStart(pokemon) {
|
||||
this.add('-start', pokemon, 'move: Focus Energy');
|
||||
},
|
||||
// This does nothing as it's dealt with on critical hit calculation.
|
||||
onModifyCritRatio: undefined, // no inherit
|
||||
onModifyMove() {},
|
||||
},
|
||||
},
|
||||
glare: {
|
||||
|
|
@ -345,7 +386,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
// in-game, so it is equivalent to just clear it.
|
||||
const silentHack = '|[silent]';
|
||||
const silentHackVolatiles = ['disable', 'confusion'];
|
||||
const hazeVolatiles: { [key: string]: string } = {
|
||||
const hazeVolatiles: {[key: string]: string} = {
|
||||
'disable': '',
|
||||
'confusion': '',
|
||||
'mist': 'Mist',
|
||||
|
|
@ -391,9 +432,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
leechseed: {
|
||||
inherit: true,
|
||||
onHit: undefined, // no inherit
|
||||
onHit() {},
|
||||
condition: {
|
||||
inherit: true,
|
||||
onStart(target) {
|
||||
this.add('-start', target, 'move: Leech Seed');
|
||||
},
|
||||
onAfterMoveSelfPriority: 1,
|
||||
onAfterMoveSelf(pokemon) {
|
||||
const leecher = this.getAtSlot(pokemon.volatiles['leechseed'].sourceSlot);
|
||||
|
|
@ -419,9 +462,15 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
},
|
||||
lightscreen: {
|
||||
inherit: true,
|
||||
num: 113,
|
||||
accuracy: true,
|
||||
basePower: 0,
|
||||
category: "Status",
|
||||
name: "Light Screen",
|
||||
pp: 30,
|
||||
priority: 0,
|
||||
flags: {},
|
||||
volatileStatus: 'lightscreen',
|
||||
sideCondition: undefined, // no inherit
|
||||
onTryHit(pokemon) {
|
||||
if (pokemon.volatiles['lightscreen']) {
|
||||
return false;
|
||||
|
|
@ -433,28 +482,17 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
},
|
||||
target: "self",
|
||||
type: "Psychic",
|
||||
},
|
||||
metronome: {
|
||||
inherit: true,
|
||||
onHit(pokemon) {
|
||||
const moves = this.dex.moves.all().filter(move => (
|
||||
(!move.isNonstandard || move.isNonstandard === 'Unobtainable') && move.flags['metronome']
|
||||
));
|
||||
let randomMove = '';
|
||||
if (moves.length) {
|
||||
moves.sort((a, b) => a.num - b.num);
|
||||
randomMove = this.sample(moves).id;
|
||||
}
|
||||
if (!randomMove) return false;
|
||||
pokemon.side.lastSelectedMove = this.toID(randomMove);
|
||||
this.actions.useMove(randomMove, pokemon);
|
||||
},
|
||||
noMetronome: ["Metronome", "Struggle"],
|
||||
},
|
||||
mimic: {
|
||||
inherit: true,
|
||||
flags: { protect: 1, bypasssub: 1, metronome: 1 },
|
||||
onHit(target, source) {
|
||||
const moveslot = source.side.lastSelectedMoveSlot;
|
||||
const moveslot = source.moves.indexOf('mimic');
|
||||
if (moveslot < 0) return false;
|
||||
const moves = target.moves;
|
||||
const moveid = this.sample(moves);
|
||||
if (!moveid) return false;
|
||||
|
|
@ -472,13 +510,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
this.add('-start', source, 'Mimic', move.name);
|
||||
},
|
||||
},
|
||||
minimize: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
onSourceModifyDamage: undefined, // no inherit
|
||||
},
|
||||
},
|
||||
mirrormove: {
|
||||
inherit: true,
|
||||
onHit(pokemon) {
|
||||
|
|
@ -493,7 +524,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
mist: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
onStart(pokemon) {
|
||||
this.add('-start', pokemon, 'Mist');
|
||||
},
|
||||
onTryBoost(boost, target, source, effect) {
|
||||
if (effect.effectType === 'Move' && effect.category !== 'Status') return;
|
||||
if (source && target !== source) {
|
||||
|
|
@ -519,7 +552,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
petaldance: {
|
||||
inherit: true,
|
||||
onMoveFail: undefined, // no inherit
|
||||
onMoveFail() {},
|
||||
},
|
||||
poisonsting: {
|
||||
inherit: true,
|
||||
|
|
@ -542,15 +575,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
basePower: 1,
|
||||
damageCallback(pokemon) {
|
||||
if ([0, 1, 171].includes(pokemon.level)) {
|
||||
this.hint("Desync Clause Mod activated!");
|
||||
this.hint("In Gen 1, if a Pokémon at level 0, 1 or 171 uses Psywave, the game softlocks.");
|
||||
return false;
|
||||
}
|
||||
const psywaveDamage = (this.random(0, this.trunc(1.5 * pokemon.level)));
|
||||
if (psywaveDamage <= 0) {
|
||||
this.hint("Desync Clause Mod activated!");
|
||||
this.hint("In Gen 1, Psywave can roll 0 damage.");
|
||||
return false;
|
||||
}
|
||||
return psywaveDamage;
|
||||
|
|
@ -571,7 +598,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
onHit(target, source, move) {
|
||||
// Disable and exploding moves boost Rage even if they miss/fail, so they are dealt with separately.
|
||||
if (target.boosts.atk < 6 && (move.category !== 'Status' && !move.selfdestruct)) {
|
||||
this.boost({ atk: 1 });
|
||||
this.boost({atk: 1});
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
@ -597,27 +624,27 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
recover: {
|
||||
inherit: true,
|
||||
heal: undefined, // no inherit
|
||||
heal: null,
|
||||
onHit(target) {
|
||||
if (target.hp === target.maxhp) return false;
|
||||
// Fail when health is 255 or 511 less than max, unless it is divisible by 256
|
||||
if (
|
||||
target.hp === target.maxhp ||
|
||||
((target.hp === (target.maxhp - 255) || target.hp === (target.maxhp - 511)) && target.hp % 256 !== 0)
|
||||
) {
|
||||
this.hint(
|
||||
"In Gen 1, recovery moves fail if (user's maximum HP - user's current HP + 1) is divisible by 256, " +
|
||||
"unless the current hp is also divisible by 256."
|
||||
);
|
||||
// Fail when health is 255 or 511 less than max
|
||||
if (target.hp === (target.maxhp - 255) || target.hp === (target.maxhp - 511) || target.hp === target.maxhp) {
|
||||
this.hint("In Gen 1, recovery moves fail if (user's maximum HP - user's current HP + 1) is divisible by 256.");
|
||||
return false;
|
||||
}
|
||||
this.heal(Math.floor(target.maxhp / 2), target, target);
|
||||
},
|
||||
},
|
||||
reflect: {
|
||||
inherit: true,
|
||||
num: 115,
|
||||
accuracy: true,
|
||||
basePower: 0,
|
||||
category: "Status",
|
||||
name: "Reflect",
|
||||
pp: 20,
|
||||
priority: 0,
|
||||
flags: {},
|
||||
volatileStatus: 'reflect',
|
||||
sideCondition: undefined, // no inherit
|
||||
onTryHit(pokemon) {
|
||||
if (pokemon.volatiles['reflect']) {
|
||||
return false;
|
||||
|
|
@ -628,22 +655,18 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
this.add('-start', pokemon, 'Reflect');
|
||||
},
|
||||
},
|
||||
secondary: null,
|
||||
target: "self",
|
||||
type: "Psychic",
|
||||
},
|
||||
rest: {
|
||||
inherit: true,
|
||||
onTry: undefined, // no inherit
|
||||
onTry() {},
|
||||
onHit(target, source, move) {
|
||||
if (target.hp === target.maxhp) return false;
|
||||
// Fail when health is 255 or 511 less than max, unless it is divisible by 256
|
||||
if (
|
||||
target.hp === target.maxhp ||
|
||||
((target.hp === (target.maxhp - 255) || target.hp === (target.maxhp - 511)) && target.hp % 256 !== 0)
|
||||
) {
|
||||
this.hint(
|
||||
"In Gen 1, recovery moves fail if (user's maximum HP - user's current HP + 1) is divisible by 256, " +
|
||||
"unless the current hp is also divisible by 256."
|
||||
);
|
||||
// Fail when health is 255 or 511 less than max
|
||||
if (target.hp === (target.maxhp - 255) || target.hp === (target.maxhp - 511)) {
|
||||
this.hint("In Gen 1, recovery moves fail if (user's maximum HP - user's current HP + 1) is divisible by 256.");
|
||||
return false;
|
||||
}
|
||||
if (!target.setStatus('slp', source, move)) return false;
|
||||
|
|
@ -655,12 +678,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
roar: {
|
||||
inherit: true,
|
||||
forceSwitch: false,
|
||||
onTryHit: undefined, // no inherit
|
||||
onTryHit() {},
|
||||
priority: 0,
|
||||
},
|
||||
rockslide: {
|
||||
inherit: true,
|
||||
secondary: undefined, // no inherit
|
||||
secondary: null,
|
||||
target: "normal",
|
||||
},
|
||||
rockthrow: {
|
||||
|
|
@ -736,18 +759,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
softboiled: {
|
||||
inherit: true,
|
||||
heal: undefined, // no inherit
|
||||
heal: null,
|
||||
onHit(target) {
|
||||
if (target.hp === target.maxhp) return false;
|
||||
// Fail when health is 255 or 511 less than max, unless it is divisible by 256
|
||||
if (
|
||||
target.hp === target.maxhp ||
|
||||
((target.hp === (target.maxhp - 255) || target.hp === (target.maxhp - 511)) && target.hp % 256 !== 0)
|
||||
) {
|
||||
this.hint(
|
||||
"In Gen 1, recovery moves fail if (user's maximum HP - user's current HP + 1) is divisible by 256, " +
|
||||
"unless the current hp is also divisible by 256."
|
||||
);
|
||||
// Fail when health is 255 or 511 less than max
|
||||
if (target.hp === (target.maxhp - 255) || target.hp === (target.maxhp - 511) || target.hp === target.maxhp) {
|
||||
this.hint("In Gen 1, recovery moves fail if (user's maximum HP - user's current HP + 1) is divisible by 256.");
|
||||
return false;
|
||||
}
|
||||
this.heal(Math.floor(target.maxhp / 2), target, target);
|
||||
|
|
@ -757,10 +774,17 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
pp: 10,
|
||||
recoil: [1, 2],
|
||||
onModifyMove: undefined, // no inherit
|
||||
onModifyMove() {},
|
||||
},
|
||||
substitute: {
|
||||
inherit: true,
|
||||
num: 164,
|
||||
accuracy: true,
|
||||
basePower: 0,
|
||||
category: "Status",
|
||||
name: "Substitute",
|
||||
pp: 10,
|
||||
priority: 0,
|
||||
volatileStatus: 'substitute',
|
||||
onTryHit(target) {
|
||||
if (target.volatiles['substitute']) {
|
||||
this.add('-fail', target, 'move: Substitute');
|
||||
|
|
@ -780,16 +804,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
}
|
||||
},
|
||||
condition: {
|
||||
inherit: true,
|
||||
onStart(target) {
|
||||
this.add('-start', target, 'Substitute');
|
||||
this.effectState.hp = Math.floor(target.maxhp / 4) + 1;
|
||||
if (target.volatiles['partiallytrapped']) {
|
||||
this.add('-end', target, target.volatiles['partiallytrapped'].sourceEffect, '[partiallytrapped]', '[silent]');
|
||||
delete target.volatiles['partiallytrapped'];
|
||||
}
|
||||
delete target.volatiles['partiallytrapped'];
|
||||
},
|
||||
onTryPrimaryHit: undefined, // no inherit
|
||||
onTryHitPriority: -1,
|
||||
onTryHit(target, source, move) {
|
||||
if (move.category === 'Status') {
|
||||
|
|
@ -811,6 +830,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
let uncappedDamage = move.hit > 1 ? this.lastDamage : this.actions.getDamage(source, target, move);
|
||||
if (move.id === 'bide') uncappedDamage = source.volatiles['bide'].damage * 2;
|
||||
if (!uncappedDamage && uncappedDamage !== 0) return null;
|
||||
uncappedDamage = this.runEvent('SubDamage', target, source, move, uncappedDamage);
|
||||
if (!uncappedDamage && uncappedDamage !== 0) return uncappedDamage;
|
||||
this.lastDamage = uncappedDamage;
|
||||
target.volatiles['substitute'].hp -= uncappedDamage > target.volatiles['substitute'].hp ?
|
||||
target.volatiles['substitute'].hp : uncappedDamage;
|
||||
|
|
@ -823,8 +844,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
// Drain/recoil/secondary effect confusion do not happen if the substitute breaks
|
||||
if (target.volatiles['substitute']) {
|
||||
if (move.recoil) {
|
||||
this.damage(this.clampIntRange(Math.floor(uncappedDamage * move.recoil[0] / move.recoil[1]), 1),
|
||||
source, target, 'recoil');
|
||||
this.damage(this.clampIntRange(Math.floor(uncappedDamage * move.recoil[0] / move.recoil[1]), 1)
|
||||
, source, target, 'recoil');
|
||||
}
|
||||
if (move.drain) {
|
||||
const amount = this.clampIntRange(Math.floor(uncappedDamage * move.drain[0] / move.drain[1]), 1);
|
||||
|
|
@ -846,14 +867,21 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
// Add here counter damage
|
||||
const lastAttackedBy = target.getLastAttackedBy();
|
||||
if (!lastAttackedBy) {
|
||||
target.attackedBy.push({ source, move: move.id, damage: uncappedDamage, slot: source.getSlot(), thisTurn: true });
|
||||
target.attackedBy.push({source: source, move: move.id, damage: uncappedDamage, slot: source.getSlot(), thisTurn: true});
|
||||
} else {
|
||||
lastAttackedBy.move = move.id;
|
||||
lastAttackedBy.damage = uncappedDamage;
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
onEnd(target) {
|
||||
this.add('-end', target, 'Substitute');
|
||||
},
|
||||
},
|
||||
secondary: null,
|
||||
target: "self",
|
||||
type: "Normal",
|
||||
flags: {},
|
||||
},
|
||||
superfang: {
|
||||
inherit: true,
|
||||
|
|
@ -862,7 +890,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
thrash: {
|
||||
inherit: true,
|
||||
onMoveFail: undefined, // no inherit
|
||||
onMoveFail() {},
|
||||
},
|
||||
thunder: {
|
||||
inherit: true,
|
||||
|
|
@ -873,14 +901,14 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
triattack: {
|
||||
inherit: true,
|
||||
onHit: undefined, // no inherit
|
||||
secondary: undefined, // no inherit
|
||||
onHit() {},
|
||||
secondary: null,
|
||||
},
|
||||
whirlwind: {
|
||||
inherit: true,
|
||||
accuracy: 85,
|
||||
forceSwitch: false,
|
||||
onTryHit: undefined, // no inherit
|
||||
onTryHit() {},
|
||||
priority: 0,
|
||||
},
|
||||
wingattack: {
|
||||
|
|
@ -891,13 +919,22 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
accuracy: 85,
|
||||
ignoreImmunity: true,
|
||||
volatileStatus: 'partiallytrapped',
|
||||
self: {
|
||||
volatileStatus: 'partialtrappinglock',
|
||||
},
|
||||
onTryMove(source, target) {
|
||||
if (target.volatiles['mustrecharge']) {
|
||||
target.removeVolatile('mustrecharge');
|
||||
this.hint("In Gen 1, partial trapping moves negate the recharge turn of Hyper Beam, even if they miss.", true);
|
||||
// FIXME: onBeforeMove(pokemon, target) {target.removeVolatile('mustrecharge')}
|
||||
onHit(target, source) {
|
||||
/**
|
||||
* The duration of the partially trapped must be always renewed to 2
|
||||
* so target doesn't move on trapper switch out as happens in gen 1.
|
||||
* However, this won't happen if there's no switch and the trapper is
|
||||
* about to end its partial trapping.
|
||||
**/
|
||||
if (target.volatiles['partiallytrapped']) {
|
||||
if (source.volatiles['partialtrappinglock'] && source.volatiles['partialtrappinglock'].duration > 1) {
|
||||
target.volatiles['partiallytrapped'].duration = 2;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,612 +1,612 @@
|
|||
export const Pokedex: import('../../../sim/dex-species').ModdedSpeciesDataTable = {
|
||||
export const Pokedex: {[k: string]: ModdedSpeciesData} = {
|
||||
missingno: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 33, atk: 136, def: 0, spa: 6, spd: 6, spe: 29 },
|
||||
baseStats: {hp: 33, atk: 136, def: 0, spa: 6, spd: 6, spe: 29},
|
||||
},
|
||||
bulbasaur: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 45, atk: 49, def: 49, spa: 65, spd: 65, spe: 45 },
|
||||
baseStats: {hp: 45, atk: 49, def: 49, spa: 65, spd: 65, spe: 45},
|
||||
},
|
||||
ivysaur: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 60, atk: 62, def: 63, spa: 80, spd: 80, spe: 60 },
|
||||
baseStats: {hp: 60, atk: 62, def: 63, spa: 80, spd: 80, spe: 60},
|
||||
},
|
||||
venusaur: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 80, atk: 82, def: 83, spa: 100, spd: 100, spe: 80 },
|
||||
baseStats: {hp: 80, atk: 82, def: 83, spa: 100, spd: 100, spe: 80},
|
||||
},
|
||||
charmander: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 39, atk: 52, def: 43, spa: 50, spd: 50, spe: 65 },
|
||||
baseStats: {hp: 39, atk: 52, def: 43, spa: 50, spd: 50, spe: 65},
|
||||
},
|
||||
charmeleon: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 58, atk: 64, def: 58, spa: 65, spd: 65, spe: 80 },
|
||||
baseStats: {hp: 58, atk: 64, def: 58, spa: 65, spd: 65, spe: 80},
|
||||
},
|
||||
charizard: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 78, atk: 84, def: 78, spa: 85, spd: 85, spe: 100 },
|
||||
baseStats: {hp: 78, atk: 84, def: 78, spa: 85, spd: 85, spe: 100},
|
||||
},
|
||||
squirtle: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 44, atk: 48, def: 65, spa: 50, spd: 50, spe: 43 },
|
||||
baseStats: {hp: 44, atk: 48, def: 65, spa: 50, spd: 50, spe: 43},
|
||||
},
|
||||
wartortle: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 59, atk: 63, def: 80, spa: 65, spd: 65, spe: 58 },
|
||||
baseStats: {hp: 59, atk: 63, def: 80, spa: 65, spd: 65, spe: 58},
|
||||
},
|
||||
blastoise: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 79, atk: 83, def: 100, spa: 85, spd: 85, spe: 78 },
|
||||
baseStats: {hp: 79, atk: 83, def: 100, spa: 85, spd: 85, spe: 78},
|
||||
},
|
||||
caterpie: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 45, atk: 30, def: 35, spa: 20, spd: 20, spe: 45 },
|
||||
baseStats: {hp: 45, atk: 30, def: 35, spa: 20, spd: 20, spe: 45},
|
||||
},
|
||||
metapod: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 50, atk: 20, def: 55, spa: 25, spd: 25, spe: 30 },
|
||||
baseStats: {hp: 50, atk: 20, def: 55, spa: 25, spd: 25, spe: 30},
|
||||
},
|
||||
butterfree: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 60, atk: 45, def: 50, spa: 80, spd: 80, spe: 70 },
|
||||
baseStats: {hp: 60, atk: 45, def: 50, spa: 80, spd: 80, spe: 70},
|
||||
},
|
||||
weedle: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 40, atk: 35, def: 30, spa: 20, spd: 20, spe: 50 },
|
||||
baseStats: {hp: 40, atk: 35, def: 30, spa: 20, spd: 20, spe: 50},
|
||||
},
|
||||
kakuna: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 45, atk: 25, def: 50, spa: 25, spd: 25, spe: 35 },
|
||||
baseStats: {hp: 45, atk: 25, def: 50, spa: 25, spd: 25, spe: 35},
|
||||
},
|
||||
beedrill: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 65, atk: 80, def: 40, spa: 45, spd: 45, spe: 75 },
|
||||
baseStats: {hp: 65, atk: 80, def: 40, spa: 45, spd: 45, spe: 75},
|
||||
},
|
||||
pidgey: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 40, atk: 45, def: 40, spa: 35, spd: 35, spe: 56 },
|
||||
baseStats: {hp: 40, atk: 45, def: 40, spa: 35, spd: 35, spe: 56},
|
||||
},
|
||||
pidgeotto: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 63, atk: 60, def: 55, spa: 50, spd: 50, spe: 71 },
|
||||
baseStats: {hp: 63, atk: 60, def: 55, spa: 50, spd: 50, spe: 71},
|
||||
},
|
||||
pidgeot: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 83, atk: 80, def: 75, spa: 70, spd: 70, spe: 91 },
|
||||
baseStats: {hp: 83, atk: 80, def: 75, spa: 70, spd: 70, spe: 91},
|
||||
},
|
||||
rattata: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 30, atk: 56, def: 35, spa: 25, spd: 25, spe: 72 },
|
||||
baseStats: {hp: 30, atk: 56, def: 35, spa: 25, spd: 25, spe: 72},
|
||||
},
|
||||
raticate: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 55, atk: 81, def: 60, spa: 50, spd: 50, spe: 97 },
|
||||
baseStats: {hp: 55, atk: 81, def: 60, spa: 50, spd: 50, spe: 97},
|
||||
},
|
||||
spearow: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 40, atk: 60, def: 30, spa: 31, spd: 31, spe: 70 },
|
||||
baseStats: {hp: 40, atk: 60, def: 30, spa: 31, spd: 31, spe: 70},
|
||||
},
|
||||
fearow: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 65, atk: 90, def: 65, spa: 61, spd: 61, spe: 100 },
|
||||
baseStats: {hp: 65, atk: 90, def: 65, spa: 61, spd: 61, spe: 100},
|
||||
},
|
||||
ekans: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 35, atk: 60, def: 44, spa: 40, spd: 40, spe: 55 },
|
||||
baseStats: {hp: 35, atk: 60, def: 44, spa: 40, spd: 40, spe: 55},
|
||||
},
|
||||
arbok: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 60, atk: 85, def: 69, spa: 65, spd: 65, spe: 80 },
|
||||
baseStats: {hp: 60, atk: 85, def: 69, spa: 65, spd: 65, spe: 80},
|
||||
},
|
||||
pikachu: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 35, atk: 55, def: 30, spa: 50, spd: 50, spe: 90 },
|
||||
baseStats: {hp: 35, atk: 55, def: 30, spa: 50, spd: 50, spe: 90},
|
||||
},
|
||||
raichu: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 60, atk: 90, def: 55, spa: 90, spd: 90, spe: 100 },
|
||||
baseStats: {hp: 60, atk: 90, def: 55, spa: 90, spd: 90, spe: 100},
|
||||
},
|
||||
sandshrew: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 50, atk: 75, def: 85, spa: 30, spd: 30, spe: 40 },
|
||||
baseStats: {hp: 50, atk: 75, def: 85, spa: 30, spd: 30, spe: 40},
|
||||
},
|
||||
sandslash: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 75, atk: 100, def: 110, spa: 55, spd: 55, spe: 65 },
|
||||
baseStats: {hp: 75, atk: 100, def: 110, spa: 55, spd: 55, spe: 65},
|
||||
},
|
||||
nidoranf: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 55, atk: 47, def: 52, spa: 40, spd: 40, spe: 41 },
|
||||
baseStats: {hp: 55, atk: 47, def: 52, spa: 40, spd: 40, spe: 41},
|
||||
},
|
||||
nidorina: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 70, atk: 62, def: 67, spa: 55, spd: 55, spe: 56 },
|
||||
baseStats: {hp: 70, atk: 62, def: 67, spa: 55, spd: 55, spe: 56},
|
||||
},
|
||||
nidoqueen: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 90, atk: 82, def: 87, spa: 75, spd: 75, spe: 76 },
|
||||
baseStats: {hp: 90, atk: 82, def: 87, spa: 75, spd: 75, spe: 76},
|
||||
},
|
||||
nidoranm: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 46, atk: 57, def: 40, spa: 40, spd: 40, spe: 50 },
|
||||
baseStats: {hp: 46, atk: 57, def: 40, spa: 40, spd: 40, spe: 50},
|
||||
},
|
||||
nidorino: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 61, atk: 72, def: 57, spa: 55, spd: 55, spe: 65 },
|
||||
baseStats: {hp: 61, atk: 72, def: 57, spa: 55, spd: 55, spe: 65},
|
||||
},
|
||||
nidoking: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 81, atk: 92, def: 77, spa: 75, spd: 75, spe: 85 },
|
||||
baseStats: {hp: 81, atk: 92, def: 77, spa: 75, spd: 75, spe: 85},
|
||||
},
|
||||
clefairy: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 70, atk: 45, def: 48, spa: 60, spd: 60, spe: 35 },
|
||||
baseStats: {hp: 70, atk: 45, def: 48, spa: 60, spd: 60, spe: 35},
|
||||
},
|
||||
clefable: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 95, atk: 70, def: 73, spa: 85, spd: 85, spe: 60 },
|
||||
baseStats: {hp: 95, atk: 70, def: 73, spa: 85, spd: 85, spe: 60},
|
||||
},
|
||||
vulpix: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 38, atk: 41, def: 40, spa: 65, spd: 65, spe: 65 },
|
||||
baseStats: {hp: 38, atk: 41, def: 40, spa: 65, spd: 65, spe: 65},
|
||||
},
|
||||
ninetales: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 73, atk: 76, def: 75, spa: 100, spd: 100, spe: 100 },
|
||||
baseStats: {hp: 73, atk: 76, def: 75, spa: 100, spd: 100, spe: 100},
|
||||
},
|
||||
jigglypuff: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 115, atk: 45, def: 20, spa: 25, spd: 25, spe: 20 },
|
||||
baseStats: {hp: 115, atk: 45, def: 20, spa: 25, spd: 25, spe: 20},
|
||||
},
|
||||
wigglytuff: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 140, atk: 70, def: 45, spa: 50, spd: 50, spe: 45 },
|
||||
baseStats: {hp: 140, atk: 70, def: 45, spa: 50, spd: 50, spe: 45},
|
||||
},
|
||||
zubat: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 40, atk: 45, def: 35, spa: 40, spd: 40, spe: 55 },
|
||||
baseStats: {hp: 40, atk: 45, def: 35, spa: 40, spd: 40, spe: 55},
|
||||
},
|
||||
golbat: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 75, atk: 80, def: 70, spa: 75, spd: 75, spe: 90 },
|
||||
baseStats: {hp: 75, atk: 80, def: 70, spa: 75, spd: 75, spe: 90},
|
||||
},
|
||||
oddish: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 45, atk: 50, def: 55, spa: 75, spd: 75, spe: 30 },
|
||||
baseStats: {hp: 45, atk: 50, def: 55, spa: 75, spd: 75, spe: 30},
|
||||
},
|
||||
gloom: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 60, atk: 65, def: 70, spa: 85, spd: 85, spe: 40 },
|
||||
baseStats: {hp: 60, atk: 65, def: 70, spa: 85, spd: 85, spe: 40},
|
||||
},
|
||||
vileplume: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 75, atk: 80, def: 85, spa: 100, spd: 100, spe: 50 },
|
||||
baseStats: {hp: 75, atk: 80, def: 85, spa: 100, spd: 100, spe: 50},
|
||||
},
|
||||
paras: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 35, atk: 70, def: 55, spa: 55, spd: 55, spe: 25 },
|
||||
baseStats: {hp: 35, atk: 70, def: 55, spa: 55, spd: 55, spe: 25},
|
||||
},
|
||||
parasect: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 60, atk: 95, def: 80, spa: 80, spd: 80, spe: 30 },
|
||||
baseStats: {hp: 60, atk: 95, def: 80, spa: 80, spd: 80, spe: 30},
|
||||
},
|
||||
venonat: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 60, atk: 55, def: 50, spa: 40, spd: 40, spe: 45 },
|
||||
baseStats: {hp: 60, atk: 55, def: 50, spa: 40, spd: 40, spe: 45},
|
||||
},
|
||||
venomoth: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 70, atk: 65, def: 60, spa: 90, spd: 90, spe: 90 },
|
||||
baseStats: {hp: 70, atk: 65, def: 60, spa: 90, spd: 90, spe: 90},
|
||||
},
|
||||
diglett: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 10, atk: 55, def: 25, spa: 45, spd: 45, spe: 95 },
|
||||
baseStats: {hp: 10, atk: 55, def: 25, spa: 45, spd: 45, spe: 95},
|
||||
},
|
||||
dugtrio: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 35, atk: 80, def: 50, spa: 70, spd: 70, spe: 120 },
|
||||
baseStats: {hp: 35, atk: 80, def: 50, spa: 70, spd: 70, spe: 120},
|
||||
},
|
||||
meowth: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 40, atk: 45, def: 35, spa: 40, spd: 40, spe: 90 },
|
||||
baseStats: {hp: 40, atk: 45, def: 35, spa: 40, spd: 40, spe: 90},
|
||||
},
|
||||
persian: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 65, atk: 70, def: 60, spa: 65, spd: 65, spe: 115 },
|
||||
baseStats: {hp: 65, atk: 70, def: 60, spa: 65, spd: 65, spe: 115},
|
||||
},
|
||||
psyduck: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 50, atk: 52, def: 48, spa: 50, spd: 50, spe: 55 },
|
||||
baseStats: {hp: 50, atk: 52, def: 48, spa: 50, spd: 50, spe: 55},
|
||||
},
|
||||
golduck: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 80, atk: 82, def: 78, spa: 80, spd: 80, spe: 85 },
|
||||
baseStats: {hp: 80, atk: 82, def: 78, spa: 80, spd: 80, spe: 85},
|
||||
},
|
||||
mankey: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 40, atk: 80, def: 35, spa: 35, spd: 35, spe: 70 },
|
||||
baseStats: {hp: 40, atk: 80, def: 35, spa: 35, spd: 35, spe: 70},
|
||||
},
|
||||
primeape: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 65, atk: 105, def: 60, spa: 60, spd: 60, spe: 95 },
|
||||
baseStats: {hp: 65, atk: 105, def: 60, spa: 60, spd: 60, spe: 95},
|
||||
},
|
||||
growlithe: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 55, atk: 70, def: 45, spa: 50, spd: 50, spe: 60 },
|
||||
baseStats: {hp: 55, atk: 70, def: 45, spa: 50, spd: 50, spe: 60},
|
||||
},
|
||||
arcanine: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 90, atk: 110, def: 80, spa: 80, spd: 80, spe: 95 },
|
||||
baseStats: {hp: 90, atk: 110, def: 80, spa: 80, spd: 80, spe: 95},
|
||||
},
|
||||
poliwag: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 40, atk: 50, def: 40, spa: 40, spd: 40, spe: 90 },
|
||||
baseStats: {hp: 40, atk: 50, def: 40, spa: 40, spd: 40, spe: 90},
|
||||
},
|
||||
poliwhirl: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 65, atk: 65, def: 65, spa: 50, spd: 50, spe: 90 },
|
||||
baseStats: {hp: 65, atk: 65, def: 65, spa: 50, spd: 50, spe: 90},
|
||||
},
|
||||
poliwrath: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 90, atk: 85, def: 95, spa: 70, spd: 70, spe: 70 },
|
||||
baseStats: {hp: 90, atk: 85, def: 95, spa: 70, spd: 70, spe: 70},
|
||||
},
|
||||
abra: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 25, atk: 20, def: 15, spa: 105, spd: 105, spe: 90 },
|
||||
baseStats: {hp: 25, atk: 20, def: 15, spa: 105, spd: 105, spe: 90},
|
||||
},
|
||||
kadabra: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 40, atk: 35, def: 30, spa: 120, spd: 120, spe: 105 },
|
||||
baseStats: {hp: 40, atk: 35, def: 30, spa: 120, spd: 120, spe: 105},
|
||||
},
|
||||
alakazam: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 55, atk: 50, def: 45, spa: 135, spd: 135, spe: 120 },
|
||||
baseStats: {hp: 55, atk: 50, def: 45, spa: 135, spd: 135, spe: 120},
|
||||
},
|
||||
machop: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 70, atk: 80, def: 50, spa: 35, spd: 35, spe: 35 },
|
||||
baseStats: {hp: 70, atk: 80, def: 50, spa: 35, spd: 35, spe: 35},
|
||||
},
|
||||
machoke: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 80, atk: 100, def: 70, spa: 50, spd: 50, spe: 45 },
|
||||
baseStats: {hp: 80, atk: 100, def: 70, spa: 50, spd: 50, spe: 45},
|
||||
},
|
||||
machamp: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 90, atk: 130, def: 80, spa: 65, spd: 65, spe: 55 },
|
||||
baseStats: {hp: 90, atk: 130, def: 80, spa: 65, spd: 65, spe: 55},
|
||||
},
|
||||
bellsprout: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 50, atk: 75, def: 35, spa: 70, spd: 70, spe: 40 },
|
||||
baseStats: {hp: 50, atk: 75, def: 35, spa: 70, spd: 70, spe: 40},
|
||||
},
|
||||
weepinbell: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 65, atk: 90, def: 50, spa: 85, spd: 85, spe: 55 },
|
||||
baseStats: {hp: 65, atk: 90, def: 50, spa: 85, spd: 85, spe: 55},
|
||||
},
|
||||
victreebel: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 80, atk: 105, def: 65, spa: 100, spd: 100, spe: 70 },
|
||||
baseStats: {hp: 80, atk: 105, def: 65, spa: 100, spd: 100, spe: 70},
|
||||
},
|
||||
tentacool: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 40, atk: 40, def: 35, spa: 100, spd: 100, spe: 70 },
|
||||
baseStats: {hp: 40, atk: 40, def: 35, spa: 100, spd: 100, spe: 70},
|
||||
},
|
||||
tentacruel: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 80, atk: 70, def: 65, spa: 120, spd: 120, spe: 100 },
|
||||
baseStats: {hp: 80, atk: 70, def: 65, spa: 120, spd: 120, spe: 100},
|
||||
},
|
||||
geodude: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 40, atk: 80, def: 100, spa: 30, spd: 30, spe: 20 },
|
||||
baseStats: {hp: 40, atk: 80, def: 100, spa: 30, spd: 30, spe: 20},
|
||||
},
|
||||
graveler: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 55, atk: 95, def: 115, spa: 45, spd: 45, spe: 35 },
|
||||
baseStats: {hp: 55, atk: 95, def: 115, spa: 45, spd: 45, spe: 35},
|
||||
},
|
||||
golem: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 80, atk: 110, def: 130, spa: 55, spd: 55, spe: 45 },
|
||||
baseStats: {hp: 80, atk: 110, def: 130, spa: 55, spd: 55, spe: 45},
|
||||
},
|
||||
ponyta: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 50, atk: 85, def: 55, spa: 65, spd: 65, spe: 90 },
|
||||
baseStats: {hp: 50, atk: 85, def: 55, spa: 65, spd: 65, spe: 90},
|
||||
},
|
||||
rapidash: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 65, atk: 100, def: 70, spa: 80, spd: 80, spe: 105 },
|
||||
baseStats: {hp: 65, atk: 100, def: 70, spa: 80, spd: 80, spe: 105},
|
||||
},
|
||||
slowpoke: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 90, atk: 65, def: 65, spa: 40, spd: 40, spe: 15 },
|
||||
baseStats: {hp: 90, atk: 65, def: 65, spa: 40, spd: 40, spe: 15},
|
||||
},
|
||||
slowbro: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 95, atk: 75, def: 110, spa: 80, spd: 80, spe: 30 },
|
||||
baseStats: {hp: 95, atk: 75, def: 110, spa: 80, spd: 80, spe: 30},
|
||||
},
|
||||
magnemite: {
|
||||
inherit: true,
|
||||
types: ["Electric"],
|
||||
baseStats: { hp: 25, atk: 35, def: 70, spa: 95, spd: 95, spe: 45 },
|
||||
baseStats: {hp: 25, atk: 35, def: 70, spa: 95, spd: 95, spe: 45},
|
||||
},
|
||||
magneton: {
|
||||
inherit: true,
|
||||
types: ["Electric"],
|
||||
baseStats: { hp: 50, atk: 60, def: 95, spa: 120, spd: 120, spe: 70 },
|
||||
baseStats: {hp: 50, atk: 60, def: 95, spa: 120, spd: 120, spe: 70},
|
||||
},
|
||||
farfetchd: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 52, atk: 65, def: 55, spa: 58, spd: 58, spe: 60 },
|
||||
baseStats: {hp: 52, atk: 65, def: 55, spa: 58, spd: 58, spe: 60},
|
||||
},
|
||||
doduo: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 35, atk: 85, def: 45, spa: 35, spd: 35, spe: 75 },
|
||||
baseStats: {hp: 35, atk: 85, def: 45, spa: 35, spd: 35, spe: 75},
|
||||
},
|
||||
dodrio: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 60, atk: 110, def: 70, spa: 60, spd: 60, spe: 100 },
|
||||
baseStats: {hp: 60, atk: 110, def: 70, spa: 60, spd: 60, spe: 100},
|
||||
},
|
||||
seel: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 65, atk: 45, def: 55, spa: 70, spd: 70, spe: 45 },
|
||||
baseStats: {hp: 65, atk: 45, def: 55, spa: 70, spd: 70, spe: 45},
|
||||
},
|
||||
dewgong: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 90, atk: 70, def: 80, spa: 95, spd: 95, spe: 70 },
|
||||
baseStats: {hp: 90, atk: 70, def: 80, spa: 95, spd: 95, spe: 70},
|
||||
},
|
||||
grimer: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 80, atk: 80, def: 50, spa: 40, spd: 40, spe: 25 },
|
||||
baseStats: {hp: 80, atk: 80, def: 50, spa: 40, spd: 40, spe: 25},
|
||||
},
|
||||
muk: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 105, atk: 105, def: 75, spa: 65, spd: 65, spe: 50 },
|
||||
baseStats: {hp: 105, atk: 105, def: 75, spa: 65, spd: 65, spe: 50},
|
||||
},
|
||||
shellder: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 30, atk: 65, def: 100, spa: 45, spd: 45, spe: 40 },
|
||||
baseStats: {hp: 30, atk: 65, def: 100, spa: 45, spd: 45, spe: 40},
|
||||
},
|
||||
cloyster: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 50, atk: 95, def: 180, spa: 85, spd: 85, spe: 70 },
|
||||
baseStats: {hp: 50, atk: 95, def: 180, spa: 85, spd: 85, spe: 70},
|
||||
},
|
||||
gastly: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 30, atk: 35, def: 30, spa: 100, spd: 100, spe: 80 },
|
||||
baseStats: {hp: 30, atk: 35, def: 30, spa: 100, spd: 100, spe: 80},
|
||||
},
|
||||
haunter: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 45, atk: 50, def: 45, spa: 115, spd: 115, spe: 95 },
|
||||
baseStats: {hp: 45, atk: 50, def: 45, spa: 115, spd: 115, spe: 95},
|
||||
},
|
||||
gengar: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 60, atk: 65, def: 60, spa: 130, spd: 130, spe: 110 },
|
||||
baseStats: {hp: 60, atk: 65, def: 60, spa: 130, spd: 130, spe: 110},
|
||||
},
|
||||
onix: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 35, atk: 45, def: 160, spa: 30, spd: 30, spe: 70 },
|
||||
baseStats: {hp: 35, atk: 45, def: 160, spa: 30, spd: 30, spe: 70},
|
||||
},
|
||||
drowzee: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 60, atk: 48, def: 45, spa: 90, spd: 90, spe: 42 },
|
||||
baseStats: {hp: 60, atk: 48, def: 45, spa: 90, spd: 90, spe: 42},
|
||||
},
|
||||
hypno: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 85, atk: 73, def: 70, spa: 115, spd: 115, spe: 67 },
|
||||
baseStats: {hp: 85, atk: 73, def: 70, spa: 115, spd: 115, spe: 67},
|
||||
},
|
||||
krabby: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 30, atk: 105, def: 90, spa: 25, spd: 25, spe: 50 },
|
||||
baseStats: {hp: 30, atk: 105, def: 90, spa: 25, spd: 25, spe: 50},
|
||||
},
|
||||
kingler: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 55, atk: 130, def: 115, spa: 50, spd: 50, spe: 75 },
|
||||
baseStats: {hp: 55, atk: 130, def: 115, spa: 50, spd: 50, spe: 75},
|
||||
},
|
||||
voltorb: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 40, atk: 30, def: 50, spa: 55, spd: 55, spe: 100 },
|
||||
baseStats: {hp: 40, atk: 30, def: 50, spa: 55, spd: 55, spe: 100},
|
||||
},
|
||||
electrode: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 60, atk: 50, def: 70, spa: 80, spd: 80, spe: 140 },
|
||||
baseStats: {hp: 60, atk: 50, def: 70, spa: 80, spd: 80, spe: 140},
|
||||
},
|
||||
exeggcute: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 60, atk: 40, def: 80, spa: 60, spd: 60, spe: 40 },
|
||||
baseStats: {hp: 60, atk: 40, def: 80, spa: 60, spd: 60, spe: 40},
|
||||
},
|
||||
exeggutor: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 95, atk: 95, def: 85, spa: 125, spd: 125, spe: 55 },
|
||||
baseStats: {hp: 95, atk: 95, def: 85, spa: 125, spd: 125, spe: 55},
|
||||
},
|
||||
cubone: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 50, atk: 50, def: 95, spa: 40, spd: 40, spe: 35 },
|
||||
baseStats: {hp: 50, atk: 50, def: 95, spa: 40, spd: 40, spe: 35},
|
||||
},
|
||||
marowak: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 60, atk: 80, def: 110, spa: 50, spd: 50, spe: 45 },
|
||||
baseStats: {hp: 60, atk: 80, def: 110, spa: 50, spd: 50, spe: 45},
|
||||
},
|
||||
hitmonlee: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 50, atk: 120, def: 53, spa: 35, spd: 35, spe: 87 },
|
||||
baseStats: {hp: 50, atk: 120, def: 53, spa: 35, spd: 35, spe: 87},
|
||||
},
|
||||
hitmonchan: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 50, atk: 105, def: 79, spa: 35, spd: 35, spe: 76 },
|
||||
baseStats: {hp: 50, atk: 105, def: 79, spa: 35, spd: 35, spe: 76},
|
||||
},
|
||||
lickitung: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 90, atk: 55, def: 75, spa: 60, spd: 60, spe: 30 },
|
||||
baseStats: {hp: 90, atk: 55, def: 75, spa: 60, spd: 60, spe: 30},
|
||||
},
|
||||
koffing: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 40, atk: 65, def: 95, spa: 60, spd: 60, spe: 35 },
|
||||
baseStats: {hp: 40, atk: 65, def: 95, spa: 60, spd: 60, spe: 35},
|
||||
},
|
||||
weezing: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 65, atk: 90, def: 120, spa: 85, spd: 85, spe: 60 },
|
||||
baseStats: {hp: 65, atk: 90, def: 120, spa: 85, spd: 85, spe: 60},
|
||||
},
|
||||
rhyhorn: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 80, atk: 85, def: 95, spa: 30, spd: 30, spe: 25 },
|
||||
baseStats: {hp: 80, atk: 85, def: 95, spa: 30, spd: 30, spe: 25},
|
||||
},
|
||||
rhydon: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 105, atk: 130, def: 120, spa: 45, spd: 45, spe: 40 },
|
||||
baseStats: {hp: 105, atk: 130, def: 120, spa: 45, spd: 45, spe: 40},
|
||||
},
|
||||
chansey: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 250, atk: 5, def: 5, spa: 105, spd: 105, spe: 50 },
|
||||
baseStats: {hp: 250, atk: 5, def: 5, spa: 105, spd: 105, spe: 50},
|
||||
},
|
||||
tangela: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 65, atk: 55, def: 115, spa: 100, spd: 100, spe: 60 },
|
||||
baseStats: {hp: 65, atk: 55, def: 115, spa: 100, spd: 100, spe: 60},
|
||||
},
|
||||
kangaskhan: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 105, atk: 95, def: 80, spa: 40, spd: 40, spe: 90 },
|
||||
baseStats: {hp: 105, atk: 95, def: 80, spa: 40, spd: 40, spe: 90},
|
||||
},
|
||||
horsea: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 30, atk: 40, def: 70, spa: 70, spd: 70, spe: 60 },
|
||||
baseStats: {hp: 30, atk: 40, def: 70, spa: 70, spd: 70, spe: 60},
|
||||
},
|
||||
seadra: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 55, atk: 65, def: 95, spa: 95, spd: 95, spe: 85 },
|
||||
baseStats: {hp: 55, atk: 65, def: 95, spa: 95, spd: 95, spe: 85},
|
||||
},
|
||||
goldeen: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 45, atk: 67, def: 60, spa: 50, spd: 50, spe: 63 },
|
||||
baseStats: {hp: 45, atk: 67, def: 60, spa: 50, spd: 50, spe: 63},
|
||||
},
|
||||
seaking: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 80, atk: 92, def: 65, spa: 80, spd: 80, spe: 68 },
|
||||
baseStats: {hp: 80, atk: 92, def: 65, spa: 80, spd: 80, spe: 68},
|
||||
},
|
||||
staryu: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 30, atk: 45, def: 55, spa: 70, spd: 70, spe: 85 },
|
||||
baseStats: {hp: 30, atk: 45, def: 55, spa: 70, spd: 70, spe: 85},
|
||||
},
|
||||
starmie: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 60, atk: 75, def: 85, spa: 100, spd: 100, spe: 115 },
|
||||
baseStats: {hp: 60, atk: 75, def: 85, spa: 100, spd: 100, spe: 115},
|
||||
},
|
||||
mrmime: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 40, atk: 45, def: 65, spa: 100, spd: 100, spe: 90 },
|
||||
baseStats: {hp: 40, atk: 45, def: 65, spa: 100, spd: 100, spe: 90},
|
||||
},
|
||||
scyther: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 70, atk: 110, def: 80, spa: 55, spd: 55, spe: 105 },
|
||||
baseStats: {hp: 70, atk: 110, def: 80, spa: 55, spd: 55, spe: 105},
|
||||
},
|
||||
jynx: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 65, atk: 50, def: 35, spa: 95, spd: 95, spe: 95 },
|
||||
baseStats: {hp: 65, atk: 50, def: 35, spa: 95, spd: 95, spe: 95},
|
||||
},
|
||||
electabuzz: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 65, atk: 83, def: 57, spa: 85, spd: 85, spe: 105 },
|
||||
baseStats: {hp: 65, atk: 83, def: 57, spa: 85, spd: 85, spe: 105},
|
||||
},
|
||||
magmar: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 65, atk: 95, def: 57, spa: 85, spd: 85, spe: 93 },
|
||||
baseStats: {hp: 65, atk: 95, def: 57, spa: 85, spd: 85, spe: 93},
|
||||
},
|
||||
pinsir: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 65, atk: 125, def: 100, spa: 55, spd: 55, spe: 85 },
|
||||
baseStats: {hp: 65, atk: 125, def: 100, spa: 55, spd: 55, spe: 85},
|
||||
},
|
||||
tauros: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 75, atk: 100, def: 95, spa: 70, spd: 70, spe: 110 },
|
||||
baseStats: {hp: 75, atk: 100, def: 95, spa: 70, spd: 70, spe: 110},
|
||||
},
|
||||
magikarp: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 20, atk: 10, def: 55, spa: 20, spd: 20, spe: 80 },
|
||||
baseStats: {hp: 20, atk: 10, def: 55, spa: 20, spd: 20, spe: 80},
|
||||
},
|
||||
gyarados: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 95, atk: 125, def: 79, spa: 100, spd: 100, spe: 81 },
|
||||
baseStats: {hp: 95, atk: 125, def: 79, spa: 100, spd: 100, spe: 81},
|
||||
},
|
||||
lapras: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 130, atk: 85, def: 80, spa: 95, spd: 95, spe: 60 },
|
||||
baseStats: {hp: 130, atk: 85, def: 80, spa: 95, spd: 95, spe: 60},
|
||||
},
|
||||
ditto: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 48, atk: 48, def: 48, spa: 48, spd: 48, spe: 48 },
|
||||
baseStats: {hp: 48, atk: 48, def: 48, spa: 48, spd: 48, spe: 48},
|
||||
},
|
||||
eevee: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 55, atk: 55, def: 50, spa: 65, spd: 65, spe: 55 },
|
||||
baseStats: {hp: 55, atk: 55, def: 50, spa: 65, spd: 65, spe: 55},
|
||||
},
|
||||
vaporeon: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 130, atk: 65, def: 60, spa: 110, spd: 110, spe: 65 },
|
||||
baseStats: {hp: 130, atk: 65, def: 60, spa: 110, spd: 110, spe: 65},
|
||||
},
|
||||
jolteon: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 65, atk: 65, def: 60, spa: 110, spd: 110, spe: 130 },
|
||||
baseStats: {hp: 65, atk: 65, def: 60, spa: 110, spd: 110, spe: 130},
|
||||
},
|
||||
flareon: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 65, atk: 130, def: 60, spa: 110, spd: 110, spe: 65 },
|
||||
baseStats: {hp: 65, atk: 130, def: 60, spa: 110, spd: 110, spe: 65},
|
||||
},
|
||||
porygon: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 65, atk: 60, def: 70, spa: 75, spd: 75, spe: 40 },
|
||||
baseStats: {hp: 65, atk: 60, def: 70, spa: 75, spd: 75, spe: 40},
|
||||
},
|
||||
omanyte: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 35, atk: 40, def: 100, spa: 90, spd: 90, spe: 35 },
|
||||
baseStats: {hp: 35, atk: 40, def: 100, spa: 90, spd: 90, spe: 35},
|
||||
},
|
||||
omastar: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 70, atk: 60, def: 125, spa: 115, spd: 115, spe: 55 },
|
||||
baseStats: {hp: 70, atk: 60, def: 125, spa: 115, spd: 115, spe: 55},
|
||||
},
|
||||
kabuto: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 30, atk: 80, def: 90, spa: 45, spd: 45, spe: 55 },
|
||||
baseStats: {hp: 30, atk: 80, def: 90, spa: 45, spd: 45, spe: 55},
|
||||
},
|
||||
kabutops: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 60, atk: 115, def: 105, spa: 70, spd: 70, spe: 80 },
|
||||
baseStats: {hp: 60, atk: 115, def: 105, spa: 70, spd: 70, spe: 80},
|
||||
},
|
||||
aerodactyl: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 80, atk: 105, def: 65, spa: 60, spd: 60, spe: 130 },
|
||||
baseStats: {hp: 80, atk: 105, def: 65, spa: 60, spd: 60, spe: 130},
|
||||
},
|
||||
snorlax: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 160, atk: 110, def: 65, spa: 65, spd: 65, spe: 30 },
|
||||
baseStats: {hp: 160, atk: 110, def: 65, spa: 65, spd: 65, spe: 30},
|
||||
},
|
||||
articuno: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 90, atk: 85, def: 100, spa: 125, spd: 125, spe: 85 },
|
||||
baseStats: {hp: 90, atk: 85, def: 100, spa: 125, spd: 125, spe: 85},
|
||||
},
|
||||
zapdos: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 90, atk: 90, def: 85, spa: 125, spd: 125, spe: 100 },
|
||||
baseStats: {hp: 90, atk: 90, def: 85, spa: 125, spd: 125, spe: 100},
|
||||
},
|
||||
moltres: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 90, atk: 100, def: 90, spa: 125, spd: 125, spe: 90 },
|
||||
baseStats: {hp: 90, atk: 100, def: 90, spa: 125, spd: 125, spe: 90},
|
||||
},
|
||||
dratini: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 41, atk: 64, def: 45, spa: 50, spd: 50, spe: 50 },
|
||||
baseStats: {hp: 41, atk: 64, def: 45, spa: 50, spd: 50, spe: 50},
|
||||
},
|
||||
dragonair: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 61, atk: 84, def: 65, spa: 70, spd: 70, spe: 70 },
|
||||
baseStats: {hp: 61, atk: 84, def: 65, spa: 70, spd: 70, spe: 70},
|
||||
},
|
||||
dragonite: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 91, atk: 134, def: 95, spa: 100, spd: 100, spe: 80 },
|
||||
baseStats: {hp: 91, atk: 134, def: 95, spa: 100, spd: 100, spe: 80},
|
||||
},
|
||||
mewtwo: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 106, atk: 110, def: 90, spa: 154, spd: 154, spe: 130 },
|
||||
baseStats: {hp: 106, atk: 110, def: 90, spa: 154, spd: 154, spe: 130},
|
||||
},
|
||||
mew: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 100, atk: 100, def: 100, spa: 100, spd: 100, spe: 100 },
|
||||
baseStats: {hp: 100, atk: 100, def: 100, spa: 100, spd: 100, spe: 100},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
756
data/mods/gen1/random-data.json
Normal file
756
data/mods/gen1/random-data.json
Normal file
|
|
@ -0,0 +1,756 @@
|
|||
{
|
||||
"bulbasaur": {
|
||||
"level": 88,
|
||||
"moves": ["bodyslam", "sleeppowder"],
|
||||
"essentialMove": "razorleaf",
|
||||
"exclusiveMoves": ["megadrain", "swordsdance", "swordsdance"]
|
||||
},
|
||||
"ivysaur": {
|
||||
"level": 80,
|
||||
"moves": ["bodyslam", "sleeppowder", "swordsdance"],
|
||||
"essentialMove": "razorleaf"
|
||||
},
|
||||
"venusaur": {
|
||||
"level": 74,
|
||||
"moves": ["bodyslam", "hyperbeam", "sleeppowder", "swordsdance"],
|
||||
"essentialMove": "razorleaf"
|
||||
},
|
||||
"charmander": {
|
||||
"level": 88,
|
||||
"moves": ["bodyslam", "slash"],
|
||||
"essentialMove": "fireblast",
|
||||
"exclusiveMoves": ["counter", "seismictoss"],
|
||||
"comboMoves": ["bodyslam", "fireblast", "submission", "swordsdance"]
|
||||
},
|
||||
"charmeleon": {
|
||||
"level": 80,
|
||||
"moves": ["bodyslam", "slash"],
|
||||
"essentialMove": "fireblast",
|
||||
"exclusiveMoves": ["counter", "swordsdance"],
|
||||
"comboMoves": ["bodyslam", "fireblast", "submission", "swordsdance"]
|
||||
},
|
||||
"charizard": {
|
||||
"level": 77,
|
||||
"moves": ["bodyslam", "earthquake", "slash"],
|
||||
"essentialMove": "fireblast",
|
||||
"comboMoves": ["hyperbeam", "swordsdance"]
|
||||
},
|
||||
"squirtle": {
|
||||
"level": 88,
|
||||
"moves": ["blizzard", "hydropump", "seismictoss", "surf"],
|
||||
"exclusiveMoves": ["bodyslam", "counter"]
|
||||
},
|
||||
"wartortle": {
|
||||
"level": 80,
|
||||
"moves": ["blizzard", "bodyslam", "hydropump", "surf"],
|
||||
"exclusiveMoves": ["counter", "rest", "seismictoss"]
|
||||
},
|
||||
"blastoise": {
|
||||
"level": 77,
|
||||
"moves": ["blizzard", "bodyslam", "hydropump", "surf"],
|
||||
"exclusiveMoves": ["earthquake", "rest"]
|
||||
},
|
||||
"butterfree": {
|
||||
"level": 77,
|
||||
"moves": ["psychic", "sleeppowder", "stunspore"],
|
||||
"exclusiveMoves": ["megadrain", "psywave"]
|
||||
},
|
||||
"beedrill": {
|
||||
"level": 77,
|
||||
"moves": ["megadrain", "swordsdance", "twineedle"],
|
||||
"exclusiveMoves": ["doubleedge", "doubleedge", "hyperbeam"],
|
||||
"comboMoves": ["agility", "hyperbeam", "swordsdance", "twineedle"]
|
||||
},
|
||||
"pidgey": {
|
||||
"level": 88,
|
||||
"moves": ["agility", "doubleedge", "skyattack"],
|
||||
"exclusiveMoves": ["mimic", "mirrormove", "reflect", "sandattack", "substitute", "quickattack", "toxic"]
|
||||
},
|
||||
"pidgeotto": {
|
||||
"level": 80,
|
||||
"moves": ["agility", "doubleedge", "skyattack"],
|
||||
"exclusiveMoves": ["mimic", "mirrormove", "reflect", "sandattack", "substitute", "quickattack", "toxic"]
|
||||
},
|
||||
"pidgeot": {
|
||||
"level": 77,
|
||||
"moves": ["agility", "doubleedge", "hyperbeam"],
|
||||
"exclusiveMoves": ["mimic", "mirrormove", "reflect", "sandattack", "skyattack", "skyattack", "substitute", "quickattack", "toxic"]
|
||||
},
|
||||
"rattata": {
|
||||
"level": 88,
|
||||
"moves": ["blizzard", "bodyslam"],
|
||||
"essentialMove": "superfang",
|
||||
"exclusiveMoves": ["thunderbolt", "thunderbolt", "quickattack"]
|
||||
},
|
||||
"raticate": {
|
||||
"level": 77,
|
||||
"moves": ["blizzard", "bodyslam", "hyperbeam"],
|
||||
"essentialMove": "superfang"
|
||||
},
|
||||
"spearow": {
|
||||
"level": 88,
|
||||
"moves": ["agility", "doubleedge", "drillpeck"],
|
||||
"exclusiveMoves": ["leer", "mimic", "mirrormove", "substitute", "toxic"]
|
||||
},
|
||||
"fearow": {
|
||||
"level": 77,
|
||||
"moves": ["agility", "doubleedge", "drillpeck", "hyperbeam"]
|
||||
},
|
||||
"ekans": {
|
||||
"level": 88,
|
||||
"moves": ["bodyslam", "earthquake", "glare", "rockslide"]
|
||||
},
|
||||
"arbok": {
|
||||
"level": 77,
|
||||
"moves": ["earthquake", "glare", "hyperbeam"],
|
||||
"exclusiveMoves": ["bodyslam", "rockslide"]
|
||||
},
|
||||
"pikachu": {
|
||||
"level": 88,
|
||||
"moves": ["surf", "thunderwave"],
|
||||
"essentialMove": "thunderbolt",
|
||||
"exclusiveMoves": ["agility", "bodyslam", "seismictoss", "thunder"]
|
||||
},
|
||||
"raichu": {
|
||||
"level": 76,
|
||||
"moves": ["surf", "thunderwave"],
|
||||
"essentialMove": "thunderbolt",
|
||||
"exclusiveMoves": ["agility", "bodyslam", "hyperbeam", "seismictoss", "thunder"]
|
||||
},
|
||||
"sandshrew": {
|
||||
"level": 88,
|
||||
"moves": ["bodyslam", "rockslide", "swordsdance"],
|
||||
"essentialMove": "earthquake"
|
||||
},
|
||||
"sandslash": {
|
||||
"level": 77,
|
||||
"moves": ["bodyslam", "rockslide", "swordsdance"],
|
||||
"essentialMove": "earthquake"
|
||||
},
|
||||
"nidoranf": {
|
||||
"level": 88,
|
||||
"moves": ["blizzard", "bodyslam", "thunderbolt"],
|
||||
"exclusiveMoves": ["doubleedge", "doublekick"]
|
||||
},
|
||||
"nidorina": {
|
||||
"level": 80,
|
||||
"moves": ["blizzard", "bodyslam", "thunderbolt"],
|
||||
"exclusiveMoves": ["bubblebeam", "doubleedge", "doublekick"]
|
||||
},
|
||||
"nidoqueen": {
|
||||
"level": 77,
|
||||
"moves": ["blizzard", "bodyslam", "thunderbolt"],
|
||||
"essentialMove": "earthquake"
|
||||
},
|
||||
"nidoranm": {
|
||||
"level": 88,
|
||||
"moves": ["blizzard", "bodyslam", "thunderbolt"],
|
||||
"exclusiveMoves": ["doubleedge", "doublekick"]
|
||||
},
|
||||
"nidorino": {
|
||||
"level": 80,
|
||||
"moves": ["blizzard", "bodyslam", "thunderbolt"],
|
||||
"exclusiveMoves": ["bubblebeam", "doubleedge", "doublekick"]
|
||||
},
|
||||
"nidoking": {
|
||||
"level": 77,
|
||||
"moves": ["blizzard", "bodyslam"],
|
||||
"essentialMove": "earthquake",
|
||||
"exclusiveMoves": ["rockslide", "thunder", "thunderbolt"]
|
||||
},
|
||||
"clefairy": {
|
||||
"level": 88,
|
||||
"moves": ["bodyslam", "thunderbolt", "thunderwave"],
|
||||
"essentialMove": "blizzard",
|
||||
"exclusiveMoves": ["counter", "psychic", "seismictoss", "sing", "sing"]
|
||||
},
|
||||
"clefable": {
|
||||
"level": 77,
|
||||
"moves": ["bodyslam", "thunderbolt", "thunderwave"],
|
||||
"essentialMove": "blizzard",
|
||||
"exclusiveMoves": ["counter", "hyperbeam", "psychic", "sing", "sing"]
|
||||
},
|
||||
"vulpix": {
|
||||
"level": 88,
|
||||
"moves": ["bodyslam", "confuseray", "fireblast"],
|
||||
"exclusiveMoves": ["flamethrower", "reflect", "substitute"]
|
||||
},
|
||||
"ninetales": {
|
||||
"level": 77,
|
||||
"moves": ["bodyslam", "confuseray", "fireblast"],
|
||||
"exclusiveMoves": ["flamethrower", "hyperbeam", "reflect", "substitute"]
|
||||
},
|
||||
"jigglypuff": {
|
||||
"level": 88,
|
||||
"moves": ["blizzard", "bodyslam", "seismictoss", "thunderwave"],
|
||||
"exclusiveMoves": ["counter", "sing"]
|
||||
},
|
||||
"wigglytuff": {
|
||||
"level": 77,
|
||||
"moves": ["blizzard", "bodyslam", "thunderwave"],
|
||||
"exclusiveMoves": ["counter", "hyperbeam", "sing"]
|
||||
},
|
||||
"zubat": {
|
||||
"level": 88,
|
||||
"moves": ["confuseray", "doubleedge", "megadrain", "toxic"]
|
||||
},
|
||||
"golbat": {
|
||||
"level": 77,
|
||||
"moves": ["confuseray", "doubleedge", "hyperbeam", "megadrain"]
|
||||
},
|
||||
"oddish": {
|
||||
"level": 88,
|
||||
"moves": ["doubleedge", "sleeppowder"],
|
||||
"essentialMove": "megadrain",
|
||||
"exclusiveMoves": ["stunspore", "stunspore", "swordsdance"]
|
||||
},
|
||||
"gloom": {
|
||||
"level": 80,
|
||||
"moves": ["doubleedge", "sleeppowder"],
|
||||
"essentialMove": "megadrain",
|
||||
"exclusiveMoves": ["stunspore", "stunspore", "swordsdance"]
|
||||
},
|
||||
"vileplume": {
|
||||
"level": 77,
|
||||
"moves": ["bodyslam", "sleeppowder", "stunspore", "swordsdance"],
|
||||
"essentialMove": "megadrain"
|
||||
},
|
||||
"paras": {
|
||||
"level": 88,
|
||||
"moves": ["bodyslam", "megadrain"],
|
||||
"essentialMove": "spore",
|
||||
"exclusiveMoves": ["growth", "slash", "stunspore", "stunspore", "swordsdance"]
|
||||
},
|
||||
"parasect": {
|
||||
"level": 77,
|
||||
"moves": ["bodyslam", "megadrain"],
|
||||
"essentialMove": "spore",
|
||||
"exclusiveMoves": ["growth", "hyperbeam", "slash", "stunspore", "stunspore", "swordsdance"]
|
||||
},
|
||||
"venonat": {
|
||||
"level": 88,
|
||||
"moves": ["psychic", "sleeppowder", "stunspore"],
|
||||
"exclusiveMoves": ["doubleedge", "megadrain", "psywave"]
|
||||
},
|
||||
"venomoth": {
|
||||
"level": 77,
|
||||
"moves": ["psychic", "sleeppowder", "stunspore"],
|
||||
"exclusiveMoves": ["doubleedge", "megadrain", "megadrain"]
|
||||
},
|
||||
"diglett": {
|
||||
"level": 88,
|
||||
"moves": ["bodyslam", "rockslide", "slash"],
|
||||
"essentialMove": "earthquake"
|
||||
},
|
||||
"dugtrio": {
|
||||
"level": 74,
|
||||
"moves": ["bodyslam", "rockslide", "slash"],
|
||||
"essentialMove": "earthquake"
|
||||
},
|
||||
"meowth": {
|
||||
"level": 88,
|
||||
"moves": ["bodyslam", "bubblebeam"],
|
||||
"essentialMove": "slash",
|
||||
"exclusiveMoves": ["thunder", "thunderbolt"]
|
||||
},
|
||||
"persian": {
|
||||
"level": 74,
|
||||
"moves": ["bodyslam", "bubblebeam"],
|
||||
"essentialMove": "slash",
|
||||
"exclusiveMoves": ["hyperbeam", "hyperbeam", "thunder", "thunderbolt"]
|
||||
},
|
||||
"psyduck": {
|
||||
"level": 88,
|
||||
"moves": ["amnesia", "blizzard"],
|
||||
"essentialMove": "surf",
|
||||
"exclusiveMoves": ["bodyslam", "hydropump", "rest", "seismictoss"]
|
||||
},
|
||||
"golduck": {
|
||||
"level": 76,
|
||||
"moves": ["amnesia", "blizzard"],
|
||||
"essentialMove": "surf",
|
||||
"exclusiveMoves": ["bodyslam", "hydropump", "rest", "seismictoss"]
|
||||
},
|
||||
"mankey": {
|
||||
"level": 88,
|
||||
"moves": ["bodyslam", "rockslide", "submission"],
|
||||
"exclusiveMoves": ["counter", "megakick"]
|
||||
},
|
||||
"primeape": {
|
||||
"level": 77,
|
||||
"moves": ["bodyslam", "rockslide", "submission"],
|
||||
"exclusiveMoves": ["counter", "hyperbeam", "hyperbeam"]
|
||||
},
|
||||
"growlithe": {
|
||||
"level": 88,
|
||||
"moves": ["bodyslam", "fireblast", "flamethrower", "reflect"]
|
||||
},
|
||||
"arcanine": {
|
||||
"level": 77,
|
||||
"moves": ["bodyslam", "fireblast", "hyperbeam"],
|
||||
"exclusiveMoves": ["flamethrower", "reflect"]
|
||||
},
|
||||
"poliwag": {
|
||||
"level": 88,
|
||||
"moves": ["blizzard", "surf"],
|
||||
"essentialMove": "amnesia",
|
||||
"exclusiveMoves": ["hypnosis", "hypnosis", "psychic"]
|
||||
},
|
||||
"poliwhirl": {
|
||||
"level": 76,
|
||||
"moves": ["blizzard", "surf"],
|
||||
"essentialMove": "amnesia",
|
||||
"exclusiveMoves": ["counter", "hypnosis", "hypnosis", "psychic"]
|
||||
},
|
||||
"poliwrath": {
|
||||
"level": 76,
|
||||
"moves": ["blizzard", "bodyslam", "earthquake", "submission"],
|
||||
"essentialMove": "surf",
|
||||
"exclusiveMoves": ["hypnosis", "hypnosis", "psychic"],
|
||||
"comboMoves": ["amnesia", "blizzard"]
|
||||
},
|
||||
"abra": {
|
||||
"level": 88,
|
||||
"moves": ["psychic", "seismictoss", "thunderwave"],
|
||||
"exclusiveMoves": ["counter", "reflect"]
|
||||
},
|
||||
"kadabra": {
|
||||
"level": 74,
|
||||
"moves": ["psychic", "recover", "thunderwave"],
|
||||
"exclusiveMoves": ["counter", "reflect", "reflect", "seismictoss", "seismictoss"]
|
||||
},
|
||||
"alakazam": {
|
||||
"level": 68,
|
||||
"moves": ["psychic", "recover", "thunderwave"],
|
||||
"exclusiveMoves": ["counter", "reflect", "reflect", "seismictoss", "seismictoss"]
|
||||
},
|
||||
"machop": {
|
||||
"level": 88,
|
||||
"moves": ["bodyslam", "earthquake", "submission"],
|
||||
"exclusiveMoves": ["counter", "rockslide", "rockslide"]
|
||||
},
|
||||
"machoke": {
|
||||
"level": 80,
|
||||
"moves": ["bodyslam", "earthquake", "submission"],
|
||||
"exclusiveMoves": ["counter", "rockslide", "rockslide"]
|
||||
},
|
||||
"machamp": {
|
||||
"level": 77,
|
||||
"moves": ["bodyslam", "earthquake", "submission"],
|
||||
"exclusiveMoves": ["counter", "hyperbeam", "rockslide", "rockslide"]
|
||||
},
|
||||
"bellsprout": {
|
||||
"level": 88,
|
||||
"moves": ["doubleedge", "sleeppowder", "stunspore", "swordsdance"],
|
||||
"essentialMove": "razorleaf"
|
||||
},
|
||||
"weepinbell": {
|
||||
"level": 80,
|
||||
"moves": ["doubleedge", "sleeppowder", "stunspore", "swordsdance"],
|
||||
"essentialMove": "razorleaf"
|
||||
},
|
||||
"victreebel": {
|
||||
"level": 74,
|
||||
"moves": ["bodyslam", "sleeppowder", "stunspore"],
|
||||
"essentialMove": "razorleaf",
|
||||
"comboMoves": ["hyperbeam", "swordsdance"]
|
||||
},
|
||||
"tentacool": {
|
||||
"level": 88,
|
||||
"moves": ["barrier", "hydropump", "surf"],
|
||||
"essentialMove": "blizzard",
|
||||
"exclusiveMoves": ["megadrain", "megadrain"],
|
||||
"comboMoves": ["hydropump", "surf"]
|
||||
},
|
||||
"tentacruel": {
|
||||
"level": 74,
|
||||
"moves": ["blizzard", "hydropump", "hyperbeam", "surf"],
|
||||
"essentialMove": "swordsdance"
|
||||
},
|
||||
"geodude": {
|
||||
"level": 88,
|
||||
"moves": ["bodyslam", "earthquake", "explosion", "rockslide"]
|
||||
},
|
||||
"graveler": {
|
||||
"level": 80,
|
||||
"moves": ["bodyslam", "earthquake", "explosion", "rockslide"]
|
||||
},
|
||||
"golem": {
|
||||
"level": 77,
|
||||
"moves": ["bodyslam", "earthquake", "explosion", "rockslide"]
|
||||
},
|
||||
"ponyta": {
|
||||
"level": 88,
|
||||
"moves": ["agility", "bodyslam", "fireblast", "reflect"]
|
||||
},
|
||||
"rapidash": {
|
||||
"level": 77,
|
||||
"moves": ["agility", "bodyslam", "fireblast", "hyperbeam"]
|
||||
},
|
||||
"slowpoke": {
|
||||
"level": 88,
|
||||
"moves": ["earthquake", "surf"],
|
||||
"essentialMove": "thunderwave",
|
||||
"exclusiveMoves": ["blizzard", "psychic", "rest"],
|
||||
"comboMoves": ["amnesia", "surf"]
|
||||
},
|
||||
"slowbro": {
|
||||
"level": 68,
|
||||
"moves": ["amnesia", "surf", "thunderwave"],
|
||||
"exclusiveMoves": ["blizzard", "psychic", "rest", "rest"]
|
||||
},
|
||||
"magnemite": {
|
||||
"level": 88,
|
||||
"moves": ["thunder", "thunderbolt", "thunderwave"],
|
||||
"exclusiveMoves": ["doubleedge", "mimic", "substitute", "toxic"]
|
||||
},
|
||||
"magneton": {
|
||||
"level": 77,
|
||||
"moves": ["thunder", "thunderbolt", "thunderwave"],
|
||||
"exclusiveMoves": ["doubleedge", "hyperbeam", "hyperbeam", "mimic", "substitute", "toxic"]
|
||||
},
|
||||
"farfetchd": {
|
||||
"level": 77,
|
||||
"moves": ["agility", "bodyslam", "swordsdance"],
|
||||
"essentialMove": "slash"
|
||||
},
|
||||
"doduo": {
|
||||
"level": 88,
|
||||
"moves": ["agility", "bodyslam", "doubleedge", "drillpeck"]
|
||||
},
|
||||
"dodrio": {
|
||||
"level": 74,
|
||||
"moves": ["agility", "bodyslam", "drillpeck", "hyperbeam"]
|
||||
},
|
||||
"seel": {
|
||||
"level": 88,
|
||||
"moves": ["blizzard", "bodyslam", "surf"],
|
||||
"exclusiveMoves": ["mimic", "rest"]
|
||||
},
|
||||
"dewgong": {
|
||||
"level": 74,
|
||||
"moves": ["blizzard", "bodyslam", "surf"],
|
||||
"exclusiveMoves": ["hyperbeam", "mimic", "rest", "rest"]
|
||||
},
|
||||
"grimer": {
|
||||
"level": 88,
|
||||
"moves": ["bodyslam", "sludge"],
|
||||
"essentialMove": "explosion",
|
||||
"exclusiveMoves": ["fireblast", "megadrain", "megadrain", "screech"]
|
||||
},
|
||||
"muk": {
|
||||
"level": 77,
|
||||
"moves": ["bodyslam", "sludge"],
|
||||
"essentialMove": "explosion",
|
||||
"exclusiveMoves": ["fireblast", "hyperbeam", "megadrain", "megadrain"]
|
||||
},
|
||||
"shellder": {
|
||||
"level": 88,
|
||||
"moves": ["blizzard", "doubleedge", "explosion", "surf"]
|
||||
},
|
||||
"cloyster": {
|
||||
"level": 68,
|
||||
"moves": ["blizzard", "explosion", "surf"],
|
||||
"exclusiveMoves": ["doubleedge", "hyperbeam", "hyperbeam"]
|
||||
},
|
||||
"gastly": {
|
||||
"level": 88,
|
||||
"moves": ["explosion", "megadrain", "nightshade", "psychic"],
|
||||
"essentialMove": "thunderbolt",
|
||||
"exclusiveMoves": ["confuseray", "hypnosis", "hypnosis"]
|
||||
},
|
||||
"haunter": {
|
||||
"level": 74,
|
||||
"moves": ["explosion", "megadrain", "nightshade", "psychic"],
|
||||
"essentialMove": "thunderbolt",
|
||||
"exclusiveMoves": ["confuseray", "hypnosis", "hypnosis"]
|
||||
},
|
||||
"gengar": {
|
||||
"level": 68,
|
||||
"moves": ["explosion", "megadrain", "nightshade", "psychic"],
|
||||
"essentialMove": "thunderbolt",
|
||||
"exclusiveMoves": ["confuseray", "hypnosis", "hypnosis"]
|
||||
},
|
||||
"onix": {
|
||||
"level": 77,
|
||||
"moves": ["bodyslam", "earthquake", "explosion", "rockslide"]
|
||||
},
|
||||
"drowzee": {
|
||||
"level": 88,
|
||||
"moves": ["hypnosis", "psychic", "thunderwave"],
|
||||
"exclusiveMoves": ["counter", "reflect", "rest", "seismictoss", "seismictoss"]
|
||||
},
|
||||
"hypno": {
|
||||
"level": 74,
|
||||
"moves": ["hypnosis", "psychic", "thunderwave"],
|
||||
"exclusiveMoves": ["counter", "reflect", "rest", "rest", "seismictoss", "seismictoss"]
|
||||
},
|
||||
"krabby": {
|
||||
"level": 88,
|
||||
"moves": ["blizzard", "bodyslam", "crabhammer", "swordsdance"]
|
||||
},
|
||||
"kingler": {
|
||||
"level": 77,
|
||||
"moves": ["bodyslam", "crabhammer", "hyperbeam", "swordsdance"]
|
||||
},
|
||||
"voltorb": {
|
||||
"level": 88,
|
||||
"moves": ["explosion", "thunderbolt", "thunderwave"],
|
||||
"exclusiveMoves": ["screech", "thunder", "toxic"]
|
||||
},
|
||||
"electrode": {
|
||||
"level": 77,
|
||||
"moves": ["explosion", "thunderbolt", "thunderwave"],
|
||||
"exclusiveMoves": ["hyperbeam", "screech", "thunder", "toxic"]
|
||||
},
|
||||
"exeggcute": {
|
||||
"level": 77,
|
||||
"moves": ["sleeppowder", "stunspore"],
|
||||
"essentialMove": "psychic",
|
||||
"exclusiveMoves": ["doubleedge", "explosion", "explosion"]
|
||||
},
|
||||
"exeggutor": {
|
||||
"level": 68,
|
||||
"moves": ["explosion", "psychic", "sleeppowder"],
|
||||
"exclusiveMoves": ["doubleedge", "eggbomb", "hyperbeam", "megadrain", "megadrain", "stunspore", "stunspore", "stunspore"]
|
||||
},
|
||||
"cubone": {
|
||||
"level": 88,
|
||||
"moves": ["blizzard", "bodyslam", "earthquake", "seismictoss"]
|
||||
},
|
||||
"marowak": {
|
||||
"level": 77,
|
||||
"moves": ["blizzard", "bodyslam", "earthquake", "seismictoss"]
|
||||
},
|
||||
"hitmonlee": {
|
||||
"level": 77,
|
||||
"moves": ["bodyslam", "highjumpkick", "seismictoss"],
|
||||
"exclusiveMoves": ["counter", "counter", "meditate"]
|
||||
},
|
||||
"hitmonchan": {
|
||||
"level": 77,
|
||||
"moves": ["bodyslam", "seismictoss", "submission"],
|
||||
"exclusiveMoves": ["agility", "counter", "counter"]
|
||||
},
|
||||
"lickitung": {
|
||||
"level": 77,
|
||||
"moves": ["hyperbeam", "swordsdance"],
|
||||
"essentialMove": "bodyslam",
|
||||
"exclusiveMoves": ["blizzard", "earthquake", "earthquake", "earthquake"]
|
||||
},
|
||||
"koffing": {
|
||||
"level": 88,
|
||||
"moves": ["explosion", "fireblast", "sludge", "thunderbolt"]
|
||||
},
|
||||
"weezing": {
|
||||
"level": 77,
|
||||
"moves": ["explosion", "fireblast", "sludge", "thunderbolt"]
|
||||
},
|
||||
"rhyhorn": {
|
||||
"level": 88,
|
||||
"moves": ["bodyslam", "earthquake", "rockslide", "substitute"]
|
||||
},
|
||||
"rhydon": {
|
||||
"level": 68,
|
||||
"moves": ["bodyslam", "earthquake", "rockslide"],
|
||||
"exclusiveMoves": ["hyperbeam", "substitute", "substitute"]
|
||||
},
|
||||
"chansey": {
|
||||
"level": 68,
|
||||
"moves": ["icebeam", "thunderwave"],
|
||||
"essentialMove": "softboiled",
|
||||
"exclusiveMoves": ["counter", "reflect", "seismictoss", "sing", "thunderbolt", "thunderbolt", "thunderbolt"]
|
||||
},
|
||||
"tangela": {
|
||||
"level": 74,
|
||||
"moves": ["bodyslam", "sleeppowder"],
|
||||
"essentialMove": "megadrain",
|
||||
"exclusiveMoves": ["growth", "stunspore", "stunspore", "stunspore", "swordsdance", "swordsdance"]
|
||||
},
|
||||
"kangaskhan": {
|
||||
"level": 74,
|
||||
"moves": ["bodyslam", "earthquake", "hyperbeam"],
|
||||
"exclusiveMoves": ["counter", "rockslide", "rockslide", "surf"]
|
||||
},
|
||||
"horsea": {
|
||||
"level": 88,
|
||||
"moves": ["agility", "blizzard"],
|
||||
"essentialMove": "surf",
|
||||
"exclusiveMoves": ["doubleedge", "hydropump", "smokescreen"]
|
||||
},
|
||||
"seadra": {
|
||||
"level": 77,
|
||||
"moves": ["agility", "blizzard"],
|
||||
"essentialMove": "surf",
|
||||
"exclusiveMoves": ["doubleedge", "hydropump", "hyperbeam", "smokescreen"]
|
||||
},
|
||||
"goldeen": {
|
||||
"level": 88,
|
||||
"moves": ["agility", "blizzard", "doubleedge", "surf"]
|
||||
},
|
||||
"seaking": {
|
||||
"level": 77,
|
||||
"moves": ["blizzard", "doubleedge", "surf"],
|
||||
"exclusiveMoves": ["agility", "agility", "hyperbeam"]
|
||||
},
|
||||
"staryu": {
|
||||
"level": 88,
|
||||
"moves": ["blizzard", "thunderbolt", "thunderwave"],
|
||||
"essentialMove": "recover",
|
||||
"exclusiveMoves": ["hydropump", "surf", "surf"]
|
||||
},
|
||||
"starmie": {
|
||||
"level": 68,
|
||||
"moves": ["blizzard", "thunderbolt", "thunderwave"],
|
||||
"essentialMove": "recover",
|
||||
"exclusiveMoves": ["hydropump", "psychic", "surf", "surf"]
|
||||
},
|
||||
"mrmime": {
|
||||
"level": 77,
|
||||
"moves": ["psychic", "seismictoss", "thunderbolt", "thunderwave"]
|
||||
},
|
||||
"scyther": {
|
||||
"level": 77,
|
||||
"moves": ["agility", "hyperbeam", "slash", "swordsdance"]
|
||||
},
|
||||
"jynx": {
|
||||
"level": 68,
|
||||
"moves": ["blizzard", "lovelykiss", "psychic"],
|
||||
"exclusiveMoves": ["bodyslam", "counter", "counter", "mimic", "seismictoss"]
|
||||
},
|
||||
"electabuzz": {
|
||||
"level": 74,
|
||||
"moves": ["psychic", "seismictoss", "thunderbolt", "thunderwave"]
|
||||
},
|
||||
"magmar": {
|
||||
"level": 77,
|
||||
"moves": ["bodyslam", "confuseray", "fireblast"],
|
||||
"exclusiveMoves": ["hyperbeam", "psychic"]
|
||||
},
|
||||
"pinsir": {
|
||||
"level": 77,
|
||||
"moves": ["bodyslam", "hyperbeam", "swordsdance"],
|
||||
"exclusiveMoves": ["seismictoss", "submission", "submission"]
|
||||
},
|
||||
"tauros": {
|
||||
"level": 68,
|
||||
"moves": ["bodyslam", "earthquake", "hyperbeam"],
|
||||
"exclusiveMoves": ["blizzard", "blizzard", "blizzard", "thunderbolt"]
|
||||
},
|
||||
"gyarados": {
|
||||
"level": 74,
|
||||
"moves": ["blizzard", "bodyslam", "hyperbeam", "thunderbolt"],
|
||||
"exclusiveMoves": ["hydropump", "surf"]
|
||||
},
|
||||
"lapras": {
|
||||
"level": 74,
|
||||
"moves": ["bodyslam", "confuseray", "rest", "sing", "surf"],
|
||||
"essentialMove": "blizzard",
|
||||
"exclusiveMoves": ["thunderbolt", "thunderbolt"]
|
||||
},
|
||||
"ditto": {
|
||||
"level": 100,
|
||||
"moves": ["transform"]
|
||||
},
|
||||
"eevee": {
|
||||
"level": 88,
|
||||
"moves": ["doubleedge", "quickattack", "reflect"],
|
||||
"essentialMove": "bodyslam",
|
||||
"exclusiveMoves": ["bide", "mimic", "sandattack", "tailwhip"]
|
||||
},
|
||||
"vaporeon": {
|
||||
"level": 74,
|
||||
"moves": ["blizzard", "rest"],
|
||||
"essentialMove": "surf",
|
||||
"exclusiveMoves": ["bodyslam", "hydropump", "mimic"]
|
||||
},
|
||||
"jolteon": {
|
||||
"level": 68,
|
||||
"moves": ["bodyslam", "thunderbolt", "thunderwave"],
|
||||
"exclusiveMoves": ["agility", "agility", "doublekick", "pinmissile", "pinmissile"]
|
||||
},
|
||||
"flareon": {
|
||||
"level": 77,
|
||||
"moves": ["bodyslam", "fireblast", "hyperbeam", "quickattack"]
|
||||
},
|
||||
"porygon": {
|
||||
"level": 77,
|
||||
"moves": ["blizzard", "thunderwave"],
|
||||
"essentialMove": "recover",
|
||||
"exclusiveMoves": ["doubleedge", "psychic", "thunderbolt", "triattack"]
|
||||
},
|
||||
"omanyte": {
|
||||
"level": 88,
|
||||
"moves": ["bodyslam", "hydropump", "rest", "surf"],
|
||||
"essentialMove": "blizzard"
|
||||
},
|
||||
"omastar": {
|
||||
"level": 74,
|
||||
"moves": ["blizzard", "hydropump", "seismictoss", "surf"],
|
||||
"exclusiveMoves": ["bodyslam", "rest"]
|
||||
},
|
||||
"kabuto": {
|
||||
"level": 88,
|
||||
"moves": ["blizzard", "bodyslam", "slash", "surf"]
|
||||
},
|
||||
"kabutops": {
|
||||
"level": 77,
|
||||
"moves": ["hyperbeam", "surf", "swordsdance"],
|
||||
"exclusiveMoves": ["bodyslam", "slash"]
|
||||
},
|
||||
"aerodactyl": {
|
||||
"level": 74,
|
||||
"moves": ["doubleedge", "fireblast", "hyperbeam", "skyattack"]
|
||||
},
|
||||
"snorlax": {
|
||||
"level": 68,
|
||||
"moves": ["bodyslam", "rest", "selfdestruct", "thunderbolt"],
|
||||
"essentialMove": "amnesia",
|
||||
"exclusiveMoves": ["blizzard", "blizzard"],
|
||||
"comboMoves": ["bodyslam", "earthquake", "hyperbeam", "selfdestruct"]
|
||||
},
|
||||
"articuno": {
|
||||
"level": 74,
|
||||
"moves": ["agility", "hyperbeam", "icebeam", "mimic", "reflect"],
|
||||
"essentialMove": "blizzard",
|
||||
"comboMoves": ["icebeam", "reflect", "rest"]
|
||||
},
|
||||
"zapdos": {
|
||||
"level": 68,
|
||||
"moves": ["agility", "drillpeck", "thunderbolt", "thunderwave"]
|
||||
},
|
||||
"moltres": {
|
||||
"level": 77,
|
||||
"moves": ["agility", "fireblast", "hyperbeam"],
|
||||
"exclusiveMoves": ["doubleedge", "reflect", "skyattack"]
|
||||
},
|
||||
"dratini": {
|
||||
"level": 88,
|
||||
"moves": ["bodyslam", "hyperbeam", "thunderbolt", "thunderwave"],
|
||||
"essentialMove": "blizzard"
|
||||
},
|
||||
"dragonair": {
|
||||
"level": 80,
|
||||
"moves": ["bodyslam", "hyperbeam", "thunderbolt", "thunderwave"],
|
||||
"essentialMove": "blizzard"
|
||||
},
|
||||
"dragonite": {
|
||||
"level": 74,
|
||||
"moves": ["bodyslam", "hyperbeam", "thunderbolt", "thunderwave"],
|
||||
"essentialMove": "blizzard"
|
||||
},
|
||||
"mewtwo": {
|
||||
"level": 62,
|
||||
"moves": ["blizzard", "recover", "thunderbolt"],
|
||||
"essentialMove": "amnesia",
|
||||
"exclusiveMoves": ["psychic", "psychic"],
|
||||
"comboMoves": ["barrier", "rest"]
|
||||
},
|
||||
"mew": {
|
||||
"level": 65,
|
||||
"moves": ["blizzard", "earthquake", "thunderbolt", "thunderwave"],
|
||||
"essentialMove": "psychic",
|
||||
"exclusiveMoves": ["explosion", "softboiled", "softboiled"],
|
||||
"comboMoves": ["earthquake", "hyperbeam", "swordsdance"]
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import RandomGen2Teams from '../gen2/teams';
|
||||
import { Utils } from '../../../lib';
|
||||
import RandomGen2Teams from '../gen2/random-teams';
|
||||
import {Utils} from '../../../lib';
|
||||
import {MoveCounter} from '../gen8/random-teams';
|
||||
|
||||
interface HackmonsCupEntry {
|
||||
types: string[];
|
||||
|
|
@ -9,16 +10,16 @@ interface HackmonsCupEntry {
|
|||
interface Gen1RandomBattleSpecies {
|
||||
level?: number;
|
||||
moves?: ID[];
|
||||
essentialMoves?: ID[];
|
||||
essentialMove?: ID;
|
||||
exclusiveMoves?: ID[];
|
||||
comboMoves?: ID[];
|
||||
}
|
||||
|
||||
export class RandomGen1Teams extends RandomGen2Teams {
|
||||
override randomData: { [species: IDEntry]: Gen1RandomBattleSpecies } = require('./data.json');
|
||||
randomData: {[species: string]: Gen1RandomBattleSpecies} = require('./random-data.json');
|
||||
|
||||
// Challenge Cup or CC teams are basically fully random teams.
|
||||
override randomCCTeam() {
|
||||
randomCCTeam() {
|
||||
this.enforceNoDirectCustomBanlistChanges();
|
||||
|
||||
const team = [];
|
||||
|
|
@ -27,6 +28,7 @@ export class RandomGen1Teams extends RandomGen2Teams {
|
|||
|
||||
for (const pokemon of randomN) {
|
||||
const species = this.dex.species.get(pokemon);
|
||||
const learnset = this.dex.species.getLearnset(species.id);
|
||||
|
||||
// Level balance: calculate directly from stats rather than using some silly lookup table.
|
||||
const mbstmin = 1307;
|
||||
|
|
@ -77,11 +79,19 @@ export class RandomGen1Teams extends RandomGen2Teams {
|
|||
ivs["spe"] *= 2;
|
||||
|
||||
// Maxed EVs.
|
||||
const evs = { hp: 255, atk: 255, def: 255, spa: 255, spd: 255, spe: 255 };
|
||||
const evs = {hp: 255, atk: 255, def: 255, spa: 255, spd: 255, spe: 255};
|
||||
|
||||
// Four random unique moves from movepool. don't worry about "attacking" or "viable".
|
||||
// Since Gens 1 and 2 learnsets are shared, we need to weed out Gen 2 moves.
|
||||
const pool = [...this.dex.species.getMovePool(species.id)];
|
||||
const pool: string[] = [];
|
||||
if (learnset) {
|
||||
for (const move in learnset) {
|
||||
if (this.dex.moves.get(move).gen !== 1) continue;
|
||||
if (learnset[move].some(learned => learned.startsWith('1'))) {
|
||||
pool.push(move);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
team.push({
|
||||
name: species.baseSpecies,
|
||||
|
|
@ -89,8 +99,8 @@ export class RandomGen1Teams extends RandomGen2Teams {
|
|||
moves: this.multipleSamplesNoReplace(pool, 4),
|
||||
gender: false,
|
||||
ability: 'No Ability',
|
||||
evs,
|
||||
ivs,
|
||||
evs: evs,
|
||||
ivs: ivs,
|
||||
item: '',
|
||||
level,
|
||||
happiness: 0,
|
||||
|
|
@ -103,11 +113,11 @@ export class RandomGen1Teams extends RandomGen2Teams {
|
|||
}
|
||||
|
||||
// Random team generation for Gen 1 Random Battles.
|
||||
override randomTeam() {
|
||||
randomTeam() {
|
||||
this.enforceNoDirectCustomBanlistChanges();
|
||||
|
||||
// Get what we need ready.
|
||||
const seed = this.prng.getSeed();
|
||||
const seed = this.prng.seed;
|
||||
const ruleTable = this.dex.formats.getRuleTable(this.format);
|
||||
const pokemon: RandomTeamsTypes.RandomSet[] = [];
|
||||
|
||||
|
|
@ -118,17 +128,19 @@ export class RandomGen1Teams extends RandomGen2Teams {
|
|||
|
||||
/** Pokémon that are not wholly incompatible with the team, but still pretty bad */
|
||||
const rejectedButNotInvalidPool: string[] = [];
|
||||
const nuTiers = ['UU', 'UUBL', 'NFE', 'LC', 'NU'];
|
||||
const uuTiers = ['NFE', 'UU', 'UUBL', 'NU'];
|
||||
|
||||
// Now let's store what we are getting.
|
||||
const typeCount: { [k: string]: number } = {};
|
||||
const weaknessCount: { [k: string]: number } = { Electric: 0, Psychic: 0, Water: 0, Ice: 0, Ground: 0, Fire: 0 };
|
||||
let numMaxLevelPokemon = 0;
|
||||
const typeCount: {[k: string]: number} = {};
|
||||
const weaknessCount: {[k: string]: number} = {Electric: 0, Psychic: 0, Water: 0, Ice: 0, Ground: 0, Fire: 0};
|
||||
let uberCount = 0;
|
||||
let nuCount = 0;
|
||||
|
||||
const pokemonPool = Object.keys(this.getPokemonPool(type, pokemon, isMonotype, Object.keys(this.randomData))[0]);
|
||||
const pokemonPool = this.getPokemonPool(type, pokemon, isMonotype);
|
||||
while (pokemonPool.length && pokemon.length < this.maxTeamSize) {
|
||||
const species = this.dex.species.get(this.sampleNoReplace(pokemonPool));
|
||||
if (!species.exists) continue;
|
||||
|
||||
if (!species.exists || !this.randomData[species.id]?.moves) continue;
|
||||
// Only one Ditto is allowed per battle in Generation 1,
|
||||
// as it can cause an endless battle if two Dittos are forced
|
||||
// to face each other.
|
||||
|
|
@ -137,12 +149,33 @@ export class RandomGen1Teams extends RandomGen2Teams {
|
|||
// Dynamically scale limits for different team sizes. The default and minimum value is 1.
|
||||
const limitFactor = Math.round(this.maxTeamSize / 6) || 1;
|
||||
|
||||
const tier = species.tier;
|
||||
switch (tier) {
|
||||
case 'LC':
|
||||
case 'NFE':
|
||||
// Don't add pre-evo mon if already 4 or more non-OUs
|
||||
// Regardless, pre-evo mons are slightly less common.
|
||||
if (nuCount >= 4 * limitFactor || this.randomChance(1, 3)) continue;
|
||||
break;
|
||||
case 'Uber':
|
||||
// Only allow a single Uber.
|
||||
if (uberCount >= 1 * limitFactor) continue;
|
||||
break;
|
||||
default:
|
||||
// OUs are fine. Otherwise 50% chance to skip mon if already 4 or more non-OUs.
|
||||
if (uuTiers.includes(tier) && pokemonPool.length > 1 && (nuCount >= 4 * limitFactor && this.randomChance(1, 2))) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let skip = false;
|
||||
|
||||
if (!isMonotype && !this.forceMonotype) {
|
||||
// Limit two of any type
|
||||
// Limit 2 of any type as well. Diversity and minor weakness count.
|
||||
// The second of a same type has halved chance of being added.
|
||||
for (const typeName of species.types) {
|
||||
if (typeCount[typeName] >= 2 * limitFactor) {
|
||||
if (typeCount[typeName] >= 2 * limitFactor ||
|
||||
(typeCount[typeName] >= 1 * limitFactor && this.randomChance(1, 2) && pokemonPool.length > 1)) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
|
|
@ -155,7 +188,7 @@ export class RandomGen1Teams extends RandomGen2Teams {
|
|||
}
|
||||
|
||||
// We need a weakness count of spammable attacks to avoid being swept by those.
|
||||
// Spammable attacks are: Thunderbolt, Psychic, Surf, Blizzard, Earthquake, Fire Blast.
|
||||
// Spammable attacks are: Thunderbolt, Psychic, Surf, Blizzard, Earthquake.
|
||||
const pokemonWeaknesses = [];
|
||||
for (const typeName in weaknessCount) {
|
||||
const increaseCount = this.dex.getImmunity(typeName, species) && this.dex.getEffectiveness(typeName, species) > 0;
|
||||
|
|
@ -172,12 +205,6 @@ export class RandomGen1Teams extends RandomGen2Teams {
|
|||
continue;
|
||||
}
|
||||
|
||||
// Limit one level 100 Pokemon
|
||||
if (!this.adjustLevel && (this.getLevel(species) === 100) && numMaxLevelPokemon >= limitFactor) {
|
||||
rejectedButNotInvalidPool.push(species.id);
|
||||
continue;
|
||||
}
|
||||
|
||||
// The set passes the limitations.
|
||||
pokemon.push(this.randomSet(species));
|
||||
|
||||
|
|
@ -196,8 +223,12 @@ export class RandomGen1Teams extends RandomGen2Teams {
|
|||
weaknessCount[weakness]++;
|
||||
}
|
||||
|
||||
// Increment level 100 counter
|
||||
if (this.getLevel(species) === 100) numMaxLevelPokemon++;
|
||||
// Increment tier bias counters.
|
||||
if (tier === 'Uber') {
|
||||
uberCount++;
|
||||
} else if (nuTiers.includes(tier)) {
|
||||
nuCount++;
|
||||
}
|
||||
|
||||
// Ditto check
|
||||
if (species.id === 'ditto') this.battleHasDitto = true;
|
||||
|
|
@ -216,18 +247,47 @@ export class RandomGen1Teams extends RandomGen2Teams {
|
|||
return pokemon;
|
||||
}
|
||||
|
||||
shouldCullMove(move: Move, types: Set<string>, moves: Set<string>, counter: MoveCounter): {cull: boolean} {
|
||||
switch (move.id) {
|
||||
// bit redundant to have both, but neither particularly better than the other
|
||||
case 'hydropump':
|
||||
return {cull: moves.has('surf')};
|
||||
case 'surf':
|
||||
return {cull: moves.has('hydropump')};
|
||||
|
||||
// other redundancies that aren't handled within the movesets themselves
|
||||
case 'selfdestruct':
|
||||
return {cull: moves.has('rest')};
|
||||
case 'rest':
|
||||
return {cull: moves.has('selfdestruct')};
|
||||
case 'sharpen': case 'swordsdance':
|
||||
return {cull: counter.get('Special') > counter.get('Physical') || !counter.get('Physical') || moves.has('growth')};
|
||||
case 'growth':
|
||||
return {cull: counter.get('Special') < counter.get('Physical') || !counter.get('Special') || moves.has('swordsdance')};
|
||||
case 'poisonpowder': case 'stunspore': case 'sleeppowder': case 'toxic':
|
||||
return {cull: counter.get('Status') > 1};
|
||||
}
|
||||
return {cull: false};
|
||||
}
|
||||
|
||||
/**
|
||||
* Random set generation for Gen 1 Random Battles.
|
||||
*/
|
||||
override randomSet(species: string | Species): RandomTeamsTypes.RandomSet {
|
||||
const ruleTable = this.dex.formats.getRuleTable(this.format);
|
||||
|
||||
randomSet(species: string | Species): RandomTeamsTypes.RandomSet {
|
||||
species = this.dex.species.get(species);
|
||||
if (!species.exists) species = this.dex.species.get('pikachu'); // Because Gen 1.
|
||||
|
||||
const data = this.randomData[species.id];
|
||||
const movePool = data.moves?.slice() || [];
|
||||
const moves = new Set<string>();
|
||||
const types = new Set(species.types);
|
||||
|
||||
const counter = new MoveCounter();
|
||||
|
||||
// Moves that boost Attack:
|
||||
const PhysicalSetup = ['swordsdance', 'sharpen'];
|
||||
// Moves which boost Special Attack:
|
||||
const SpecialSetup = ['amnesia', 'growth'];
|
||||
|
||||
// Either add all moves or add none
|
||||
if (data.comboMoves && data.comboMoves.length <= this.maxMoveCount && this.randomChance(1, 2)) {
|
||||
|
|
@ -236,17 +296,13 @@ export class RandomGen1Teams extends RandomGen2Teams {
|
|||
|
||||
// Add one of the semi-mandatory moves
|
||||
// Often, these are used so that the Pokemon only gets one of the less useful moves
|
||||
// This is added before the essential moves so that combos containing three moves can roll an exclusive move
|
||||
if (moves.size < this.maxMoveCount && data.exclusiveMoves) {
|
||||
moves.add(this.sample(data.exclusiveMoves));
|
||||
}
|
||||
|
||||
// Add the mandatory moves.
|
||||
if (moves.size < this.maxMoveCount && data.essentialMoves) {
|
||||
for (const moveid of data.essentialMoves) {
|
||||
moves.add(moveid);
|
||||
if (moves.size === this.maxMoveCount) break;
|
||||
}
|
||||
// Add the mandatory move. SD Mew and Amnesia Snorlax are exceptions.
|
||||
if (moves.size < this.maxMoveCount && data.essentialMove) {
|
||||
moves.add(data.essentialMove);
|
||||
}
|
||||
|
||||
while (moves.size < this.maxMoveCount && movePool.length) {
|
||||
|
|
@ -255,12 +311,36 @@ export class RandomGen1Teams extends RandomGen2Teams {
|
|||
const moveid = this.sampleNoReplace(movePool);
|
||||
moves.add(moveid);
|
||||
}
|
||||
|
||||
// Only do move choosing if we have backup moves in the pool...
|
||||
if (movePool.length) {
|
||||
for (const setMoveid of moves) {
|
||||
const move = this.dex.moves.get(setMoveid);
|
||||
const moveid = move.id;
|
||||
if (!move.damage && !move.damageCallback) counter.add(move.category);
|
||||
if (PhysicalSetup.includes(moveid)) counter.add('physicalsetup');
|
||||
if (SpecialSetup.includes(moveid)) counter.add('specialsetup');
|
||||
}
|
||||
|
||||
for (const moveid of moves) {
|
||||
if (moveid === data.essentialMove) continue;
|
||||
const move = this.dex.moves.get(moveid);
|
||||
if (
|
||||
(!data.essentialMove || moveid !== data.essentialMove) &&
|
||||
this.shouldCullMove(move, types, moves, counter).cull
|
||||
) {
|
||||
moves.delete(moveid);
|
||||
break;
|
||||
}
|
||||
counter.add(move.category);
|
||||
}
|
||||
} // End of the check for more than 4 moves on moveset.
|
||||
}
|
||||
|
||||
const level = this.getLevel(species);
|
||||
const level = this.adjustLevel || data.level || 80;
|
||||
|
||||
const evs = { hp: 255, atk: 255, def: 255, spa: 255, spd: 255, spe: 255 };
|
||||
const ivs = { hp: 30, atk: 30, def: 30, spa: 30, spd: 30, spe: 30 };
|
||||
const evs = {hp: 255, atk: 255, def: 255, spa: 255, spd: 255, spe: 255};
|
||||
const ivs = {hp: 30, atk: 30, def: 30, spa: 30, spd: 30, spe: 30};
|
||||
|
||||
// Should be able to use Substitute four times from full HP without fainting
|
||||
if (moves.has('substitute')) {
|
||||
|
|
@ -277,20 +357,16 @@ export class RandomGen1Teams extends RandomGen2Teams {
|
|||
if (move.damageCallback || move.damage) return true;
|
||||
return move.category !== 'Physical';
|
||||
});
|
||||
if (noAttackStatMoves && !moves.has('mimic') && !moves.has('transform') && !ruleTable.has('forceofthefallenmod')) {
|
||||
if (noAttackStatMoves && !moves.has('mimic') && !moves.has('transform')) {
|
||||
evs.atk = 0;
|
||||
// We don't want to lower the HP DV/IV
|
||||
ivs.atk = 2;
|
||||
}
|
||||
|
||||
// shuffle moves to add more randomness to camomons
|
||||
const shuffledMoves = Array.from(moves);
|
||||
this.prng.shuffle(shuffledMoves);
|
||||
|
||||
return {
|
||||
name: species.name,
|
||||
species: species.name,
|
||||
moves: shuffledMoves,
|
||||
moves: Array.from(moves),
|
||||
ability: 'No Ability',
|
||||
evs,
|
||||
ivs,
|
||||
|
|
@ -301,7 +377,7 @@ export class RandomGen1Teams extends RandomGen2Teams {
|
|||
};
|
||||
}
|
||||
|
||||
override randomHCTeam(): PokemonSet[] {
|
||||
randomHCTeam(): PokemonSet[] {
|
||||
this.enforceNoDirectCustomBanlistChanges();
|
||||
|
||||
const team = [];
|
||||
|
|
@ -310,7 +386,7 @@ export class RandomGen1Teams extends RandomGen2Teams {
|
|||
const typesPool = ['Bird', ...this.dex.types.names()];
|
||||
|
||||
const randomN = this.randomNPokemon(this.maxTeamSize);
|
||||
const hackmonsCup: { [k: string]: HackmonsCupEntry } = {};
|
||||
const hackmonsCup: {[k: string]: HackmonsCupEntry} = {};
|
||||
|
||||
for (const forme of randomN) {
|
||||
// Choose forme
|
||||
|
|
@ -1,17 +1,8 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
standardag: {
|
||||
inherit: true,
|
||||
ruleset: [
|
||||
'Obtainable', 'Desync Clause Mod', 'HP Percentage Mod', 'Cancel Mod', 'Endless Battle Clause',
|
||||
],
|
||||
},
|
||||
export const Rulesets: {[k: string]: ModdedFormatData} = {
|
||||
standard: {
|
||||
effectType: 'ValidatorRule',
|
||||
name: 'Standard',
|
||||
ruleset: [
|
||||
'Standard AG',
|
||||
'Sleep Clause Mod', 'Freeze Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause',
|
||||
],
|
||||
ruleset: ['Obtainable', 'Desync Clause Mod', 'Sleep Clause Mod', 'Freeze Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod'],
|
||||
banlist: ['Dig', 'Fly'],
|
||||
},
|
||||
'350cupmod': {
|
||||
|
|
@ -45,7 +36,7 @@ export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable
|
|||
},
|
||||
onModifySpecies(species) {
|
||||
const newSpecies = this.dex.deepClone(species);
|
||||
const stats: { [k: string]: number } = {
|
||||
const stats: {[k: string]: number} = {
|
||||
hp: newSpecies.baseStats.spe,
|
||||
atk: newSpecies.baseStats.spa,
|
||||
def: newSpecies.baseStats.def,
|
||||
|
|
|
|||
|
|
@ -17,26 +17,14 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
gen: 1,
|
||||
init() {
|
||||
for (const i in this.data.Pokedex) {
|
||||
const poke = this.modData('Pokedex', i);
|
||||
poke.gender = 'N';
|
||||
poke.eggGroups = null;
|
||||
(this.data.Pokedex[i] as any).gender = 'N';
|
||||
(this.data.Pokedex[i] as any).eggGroups = null;
|
||||
}
|
||||
},
|
||||
// BattlePokemon scripts.
|
||||
pokemon: {
|
||||
inherit: true,
|
||||
deductPP(move, amount) {
|
||||
// deduct PP based on side.lastSelectedMoveSlot
|
||||
const ppData = this.getMoveSlot(this.side.lastSelectedMoveSlot);
|
||||
if (!ppData) return 0;
|
||||
ppData.used = true;
|
||||
|
||||
if (!amount) amount = 1;
|
||||
ppData.pp -= amount;
|
||||
return amount;
|
||||
},
|
||||
getStat(statName, unmodified) {
|
||||
// @ts-expect-error type checking prevents 'hp' from being passed, but we're paranoid
|
||||
// @ts-ignore - type checking prevents 'hp' from being passed, but we're paranoid
|
||||
if (statName === 'hp') throw new Error("Please read `maxhp` directly");
|
||||
if (unmodified) return this.baseStoredStats[statName];
|
||||
return this.modifiedStats![statName];
|
||||
|
|
@ -131,76 +119,59 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
},
|
||||
},
|
||||
actions: {
|
||||
inherit: true,
|
||||
// This function is the main one when running a move.
|
||||
// It deals with the beforeMove event.
|
||||
// It also deals with how PP reduction works on gen 1.
|
||||
runMove(moveOrMoveName, pokemon, targetLoc, options) {
|
||||
let sourceEffect = options?.sourceEffect;
|
||||
runMove(moveOrMoveName, pokemon, targetLoc, sourceEffect) {
|
||||
const target = this.battle.getTarget(pokemon, moveOrMoveName, targetLoc);
|
||||
let move = this.battle.dex.getActiveMove(moveOrMoveName);
|
||||
if (move.id !== 'struggle') {
|
||||
const changedMove = this.battle.runEvent('OverrideAction', pokemon, target, move);
|
||||
if (changedMove && changedMove !== true) {
|
||||
move = this.battle.dex.getActiveMove(changedMove);
|
||||
}
|
||||
}
|
||||
|
||||
// If a faster partial trapping move misses against a user of Hyper Beam during a recharge turn,
|
||||
// the user of Hyper Beam will automatically use Hyper Beam during that turn.
|
||||
if (move.id === 'recharge' && !pokemon.volatiles['mustrecharge'] && !pokemon.volatiles['partiallytrapped']) {
|
||||
move = this.battle.dex.getActiveMove('hyperbeam');
|
||||
this.battle.hint(`In Gen 1, partial trapping moves like Wrap remove Hyper Beam recharges. ` +
|
||||
`If the target would have recharged, it will automatically use Hyper Beam instead.`, true);
|
||||
}
|
||||
|
||||
const move = this.battle.dex.getActiveMove(moveOrMoveName);
|
||||
if (target?.subFainted) target.subFainted = null;
|
||||
|
||||
this.battle.setActiveMove(move, pokemon, target);
|
||||
|
||||
if (pokemon.moveThisTurn || move.id === 'cantmove' || !this.battle.runEvent('BeforeMove', pokemon, target, move)) {
|
||||
if (pokemon.moveThisTurn || !this.battle.runEvent('BeforeMove', pokemon, target, move)) {
|
||||
this.battle.clearActiveMove(true);
|
||||
// This is only run for sleep.
|
||||
this.battle.runEvent('AfterMoveSelf', pokemon, target, move);
|
||||
return;
|
||||
}
|
||||
if (move.beforeMoveCallback?.call(this.battle, pokemon, target, move)) {
|
||||
this.battle.clearActiveMove(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (move.id !== 'struggle') {
|
||||
const lockedMove = pokemon.getLockedMove();
|
||||
if (lockedMove) sourceEffect = move;
|
||||
|
||||
// Locked moves don't deduct PP
|
||||
// Two-turn moves like Sky Attack deduct PP on their second turn.
|
||||
if ((!lockedMove && !TWO_TURN_MOVES.includes(move.id)) || pokemon.volatiles['twoturnmove']) {
|
||||
const moveSlot = pokemon.getMoveSlot(pokemon.side.lastSelectedMoveSlot);
|
||||
if (moveSlot && pokemon.deductPP(moveSlot.id, null, target) && moveSlot.pp < 0) {
|
||||
moveSlot.pp += 64;
|
||||
this.battle.hint("In Gen 1, if a Pokémon is forced to use a move with 0 PP, the move will underflow to have 63 PP.");
|
||||
}
|
||||
}
|
||||
|
||||
if (move.id !== pokemon.getMoveSlot(pokemon.side.lastSelectedMoveSlot)?.id) {
|
||||
this.battle.hint("Desync Clause Mod activated!");
|
||||
this.battle.hint(
|
||||
"In Gen 1, a Pokémon that thaws out might try to use a move that doesn't match the move " +
|
||||
"of the slot it last selected (switches reset to the first slot).",
|
||||
);
|
||||
if (move.beforeMoveCallback) {
|
||||
if (move.beforeMoveCallback.call(this.battle, pokemon, target, move)) {
|
||||
this.battle.clearActiveMove(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.useMove(move, pokemon, { target, sourceEffect });
|
||||
let lockedMove = this.battle.runEvent('LockMove', pokemon);
|
||||
if (lockedMove === true) lockedMove = false;
|
||||
if (
|
||||
(!lockedMove &&
|
||||
(!pokemon.volatiles['partialtrappinglock'] || pokemon.volatiles['partialtrappinglock'].locked !== target))
|
||||
) {
|
||||
pokemon.deductPP(move, null, target);
|
||||
} else {
|
||||
sourceEffect = move;
|
||||
if (pokemon.volatiles['twoturnmove']) {
|
||||
// Two-turn moves like Sky Attack deduct PP on their second turn.
|
||||
pokemon.deductPP(pokemon.volatiles['twoturnmove'].originalMove, null, target);
|
||||
}
|
||||
}
|
||||
if (pokemon.volatiles['partialtrappinglock'] && target !== pokemon.volatiles['partialtrappinglock'].locked) {
|
||||
const moveSlot = pokemon.moveSlots.find(ms => ms.id === move.id);
|
||||
if (moveSlot && moveSlot.pp < 0) {
|
||||
moveSlot.pp = 63;
|
||||
this.battle.hint("In Gen 1, if a player is forced to use a move with 0 PP, the move will underflow to have 63 PP.");
|
||||
}
|
||||
}
|
||||
this.useMove(move, pokemon, target, sourceEffect);
|
||||
// Restore PP if the move is the first turn of a charging move. Save the move from which PP should be deducted if the move succeeds.
|
||||
if (pokemon.volatiles['twoturnmove']) {
|
||||
pokemon.deductPP(move, -1, target);
|
||||
pokemon.volatiles['twoturnmove'].originalMove = move.id;
|
||||
}
|
||||
},
|
||||
// This function deals with AfterMoveSelf events.
|
||||
// This leads with partial trapping moves shenanigans after the move has been used.
|
||||
useMove(moveOrMoveName, pokemon, options) {
|
||||
let sourceEffect = options?.sourceEffect;
|
||||
let target = options?.target;
|
||||
useMove(moveOrMoveName, pokemon, target, sourceEffect) {
|
||||
if (!sourceEffect && this.battle.effect.id) sourceEffect = this.battle.effect;
|
||||
const baseMove = this.battle.dex.moves.get(moveOrMoveName);
|
||||
let move = this.battle.dex.getActiveMove(baseMove);
|
||||
|
|
@ -210,11 +181,6 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
if (sourceEffect) move.sourceEffect = sourceEffect.id;
|
||||
|
||||
if (sourceEffect?.id === 'metronome' || sourceEffect?.id === 'mirrormove') {
|
||||
const moveSlot = pokemon.getMoveSlot(pokemon.side.lastSelectedMoveSlot);
|
||||
if (moveSlot) pokemon.deductPP(moveSlot.id, -1, target);
|
||||
}
|
||||
|
||||
this.battle.singleEvent('ModifyMove', move, null, pokemon, target, move, move);
|
||||
if (baseMove.target !== move.target) {
|
||||
// Target changed in ModifyMove, so we must adjust it here
|
||||
|
|
@ -228,7 +194,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
// The charging turn of a two-turn move does not update pokemon.lastMove
|
||||
if (!TWO_TURN_MOVES.includes(move.id) || pokemon.volatiles['twoturnmove']) pokemon.lastMove = move;
|
||||
|
||||
const moveResult = this.useMoveInner(moveOrMoveName, pokemon, { target, sourceEffect });
|
||||
const moveResult = this.useMoveInner(moveOrMoveName, pokemon, target, sourceEffect);
|
||||
|
||||
if (move.id !== 'metronome') {
|
||||
if (move.id !== 'mirrormove' ||
|
||||
|
|
@ -236,9 +202,37 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
// The move is our 'final' move (a failed Mirror Move, or any move that isn't Metronome or Mirror Move).
|
||||
pokemon.side.lastMove = move;
|
||||
|
||||
this.battle.runEvent('AfterMove', pokemon, target, move);
|
||||
if (!target || target.hp > 0) {
|
||||
this.battle.runEvent('AfterMoveSelf', pokemon, target, move);
|
||||
if (pokemon.volatiles['lockedmove']?.time <= 0) pokemon.removeVolatile('lockedmove');
|
||||
|
||||
// If target fainted
|
||||
if (target && target.hp <= 0) {
|
||||
// We remove recharge
|
||||
if (pokemon.volatiles['mustrecharge']) pokemon.removeVolatile('mustrecharge');
|
||||
delete pokemon.volatiles['partialtrappinglock'];
|
||||
} else {
|
||||
if (pokemon.volatiles['mustrecharge']) this.battle.add('-mustrecharge', pokemon);
|
||||
if (pokemon.hp) this.battle.runEvent('AfterMoveSelf', pokemon, target, move);
|
||||
}
|
||||
|
||||
// For partial trapping moves, we are saving the target
|
||||
if (move.volatileStatus === 'partiallytrapped' && target && target.hp > 0) {
|
||||
// Let's check if the lock exists
|
||||
if (pokemon.volatiles['partialtrappinglock'] && target.volatiles['partiallytrapped']) {
|
||||
// Here the partialtrappinglock volatile has been already applied
|
||||
const sourceVolatile = pokemon.volatiles['partialtrappinglock'];
|
||||
const targetVolatile = target.volatiles['partiallytrapped'];
|
||||
if (!sourceVolatile.locked) {
|
||||
// If it's the first hit, we save the target
|
||||
sourceVolatile.locked = target;
|
||||
} else if (target !== pokemon && target !== sourceVolatile.locked) {
|
||||
// Our target switched out! Re-roll the duration, damage, and accuracy.
|
||||
const duration = this.battle.sample([2, 2, 2, 3, 3, 3, 4, 5]);
|
||||
sourceVolatile.duration = duration;
|
||||
sourceVolatile.locked = target;
|
||||
// Duration reset thus partially trapped at 2 always.
|
||||
targetVolatile.duration = 2;
|
||||
}
|
||||
} // If we move to here, the move failed and there's no partial trapping lock.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -246,9 +240,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
},
|
||||
// This is the function that actually uses the move, running ModifyMove events.
|
||||
// It uses the move and then deals with the effects after the move.
|
||||
useMoveInner(moveOrMoveName, pokemon, options) {
|
||||
let sourceEffect = options?.sourceEffect;
|
||||
let target = options?.target;
|
||||
useMoveInner(moveOrMoveName, pokemon, target, sourceEffect) {
|
||||
if (!sourceEffect && this.battle.effect.id) sourceEffect = this.battle.effect;
|
||||
const baseMove = this.battle.dex.moves.get(moveOrMoveName);
|
||||
let move = this.battle.dex.getActiveMove(baseMove);
|
||||
|
|
@ -278,8 +270,8 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (sourceEffect) attrs += `|[from] ${this.battle.dex.conditions.get(sourceEffect).name}`;
|
||||
this.battle.addMove('move', pokemon, move.name, `${target}${attrs}`);
|
||||
if (sourceEffect) attrs += '|[from]' + this.battle.dex.conditions.get(sourceEffect);
|
||||
this.battle.addMove('move', pokemon, move.name, target + attrs);
|
||||
|
||||
if (!this.battle.singleEvent('Try', move, null, pokemon, target, move)) {
|
||||
return true;
|
||||
|
|
@ -306,9 +298,9 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
|
||||
// Disable and Selfdestruct/Explosion boost rage, regardless of whether they miss/fail.
|
||||
if (target.boosts.atk < 6 && (move.selfdestruct || move.id === 'disable') && target.volatiles['rage']) {
|
||||
this.battle.boost({ atk: 1 }, target, pokemon, this.dex.conditions.get('rage'));
|
||||
this.battle.boost({atk: 1}, target, pokemon, this.dex.conditions.get('rage'));
|
||||
this.battle.hint(`In Gen 1, using ${move.name} causes the target to build Rage, ` +
|
||||
`even if it misses or fails`, true);
|
||||
`even if it misses or fails`, true);
|
||||
}
|
||||
|
||||
// Go ahead with results of the used move.
|
||||
|
|
@ -317,8 +309,10 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
return true;
|
||||
}
|
||||
|
||||
this.battle.singleEvent('AfterMoveSecondarySelf', move, null, pokemon, target, move);
|
||||
this.battle.runEvent('AfterMoveSecondarySelf', pokemon, target, move);
|
||||
if (!move.negateSecondary) {
|
||||
this.battle.singleEvent('AfterMoveSecondarySelf', move, null, pokemon, target, move);
|
||||
this.battle.runEvent('AfterMoveSecondarySelf', pokemon, target, move);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// This function attempts a move hit and returns the attempt result before the actual hit happens.
|
||||
|
|
@ -353,7 +347,10 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
|
||||
// Then, check if the Pokémon is immune to this move.
|
||||
if (!target.runImmunity(move, true)) {
|
||||
if (
|
||||
(!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) &&
|
||||
!target.runImmunity(move.type, true)
|
||||
) {
|
||||
if (move.selfdestruct) {
|
||||
this.battle.faint(pokemon, pokemon, move);
|
||||
}
|
||||
|
|
@ -368,8 +365,13 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
// Now, let's calculate the accuracy.
|
||||
let accuracy = move.accuracy;
|
||||
|
||||
// Partial trapping moves: true accuracy while it lasts
|
||||
if (move.volatileStatus === 'partiallytrapped' && target === pokemon.volatiles['partialtrappinglock']?.locked) {
|
||||
accuracy = true;
|
||||
}
|
||||
|
||||
// If a sleep inducing move is used while the user is recharging, the accuracy is true.
|
||||
if (move.status === 'slp' && target?.volatiles['mustrecharge']) {
|
||||
if (move.status === 'slp' && target && target.volatiles['mustrecharge']) {
|
||||
accuracy = true;
|
||||
}
|
||||
|
||||
|
|
@ -474,8 +476,10 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
|
||||
if (move.ohko) this.battle.add('-ohko');
|
||||
|
||||
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
|
||||
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
|
||||
if (!move.negateSecondary) {
|
||||
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
|
||||
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
|
||||
}
|
||||
|
||||
return damage;
|
||||
},
|
||||
|
|
@ -500,6 +504,14 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
if (target) {
|
||||
hitResult = this.battle.singleEvent('TryHit', moveData, {}, target, pokemon, move);
|
||||
|
||||
// Handle here the applying of partial trapping moves to Pokémon with Substitute
|
||||
if (targetSub && moveData.volatileStatus && moveData.volatileStatus === 'partiallytrapped') {
|
||||
target.addVolatile(moveData.volatileStatus, pokemon, move);
|
||||
if (!pokemon.volatiles['partialtrappinglock'] || pokemon.volatiles['partialtrappinglock'].duration > 1) {
|
||||
target.volatiles[moveData.volatileStatus].duration = 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hitResult) {
|
||||
if (hitResult === false) this.battle.add('-fail', target);
|
||||
return false;
|
||||
|
|
@ -574,7 +586,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
didSomething = true;
|
||||
// Check the status of the Pokémon whose turn is not.
|
||||
// When a move that affects stat levels is used, if the Pokémon whose turn it is not right now is paralyzed or
|
||||
// burned, the corresponding stat penalties will be applied again to that Pokémon.
|
||||
// burned, the correspoding stat penalties will be applied again to that Pokémon.
|
||||
if (pokemon.side.foe.active[0].status) {
|
||||
// If it's paralysed, quarter its speed.
|
||||
if (pokemon.side.foe.active[0].status === 'par') {
|
||||
|
|
@ -665,6 +677,11 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
this.moveHit(pokemon, pokemon, move, moveData.self, isSecondary, true);
|
||||
}
|
||||
|
||||
// Now we can save the partial trapping damage.
|
||||
if (pokemon.volatiles['partialtrappinglock']) {
|
||||
pokemon.volatiles['partialtrappinglock'].damage = this.battle.lastDamage;
|
||||
}
|
||||
|
||||
// Apply move secondaries.
|
||||
if (moveData.secondaries && target && target.hp > 0) {
|
||||
for (const secondary of moveData.secondaries) {
|
||||
|
|
@ -711,8 +728,10 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
|
||||
// Let's see if the target is immune to the move.
|
||||
if (!target.runImmunity(move, true)) {
|
||||
return false;
|
||||
if (!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) {
|
||||
if (!target.runImmunity(move.type, true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Is it an OHKO move?
|
||||
|
|
@ -736,7 +755,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
|
||||
// If it's the first hit on a Normal-type partially trap move, it hits Ghosts anyways but damage is 0.
|
||||
if (move.self?.volatileStatus === 'partialtrappinglock' && move.type === 'Normal' && target.hasType('Ghost')) {
|
||||
if (move.volatileStatus === 'partiallytrapped' && move.type === 'Normal' && target.hasType('Ghost')) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -884,8 +903,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
// Type effectiveness.
|
||||
// In Gen 1, type effectiveness is applied against each of the target's types.
|
||||
for (const targetType of target.types) {
|
||||
let typeMod = this.battle.dex.getEffectiveness(type, targetType);
|
||||
typeMod = this.battle.runEvent('Effectiveness', this.battle, targetType, move, typeMod);
|
||||
const typeMod = this.battle.dex.getEffectiveness(type, targetType);
|
||||
if (typeMod > 0) {
|
||||
// Super effective against targetType
|
||||
damage *= 20;
|
||||
|
|
@ -929,7 +947,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
if (typeof effect === 'string') effect = this.dex.conditions.get(effect);
|
||||
if (!target?.hp) return 0;
|
||||
let success = null;
|
||||
boost = this.runEvent('TryBoost', target, source, effect, { ...boost });
|
||||
boost = this.runEvent('TryBoost', target, source, effect, {...boost});
|
||||
let i: BoostID;
|
||||
for (i in boost) {
|
||||
const currentBoost: SparseBoostsTable = {};
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
* Psychic was immune to ghost
|
||||
*/
|
||||
|
||||
export const TypeChart: import('../../../sim/dex-data').ModdedTypeDataTable = {
|
||||
export const TypeChart: {[k: string]: ModdedTypeData | null} = {
|
||||
bug: {
|
||||
damageTaken: {
|
||||
Bug: 0,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDataTable = {
|
||||
export const Conditions: {[k: string]: ModdedConditionData} = {
|
||||
invulnerability: {
|
||||
// Dig/Fly
|
||||
name: 'invulnerability',
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
* The japanese version of Blizzard in Gen 1 had a 30% chance to freeze
|
||||
*/
|
||||
|
||||
export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
||||
export const Moves: {[k: string]: ModdedMoveData} = {
|
||||
blizzard: {
|
||||
inherit: true,
|
||||
secondary: {
|
||||
|
|
@ -13,7 +13,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
substitute: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
onStart(target) {
|
||||
this.add('-start', target, 'Substitute');
|
||||
this.effectState.hp = Math.floor(target.maxhp / 4) + 1;
|
||||
delete target.volatiles['partiallytrapped'];
|
||||
},
|
||||
onTryHitPriority: -1,
|
||||
onTryHit(target, source, move) {
|
||||
if (move.drain) {
|
||||
this.add('-miss', source);
|
||||
|
|
@ -34,8 +39,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
// NOTE: In future generations the damage is capped to the remaining HP of the
|
||||
// Substitute, here we deliberately use the uncapped damage when tracking lastDamage etc.
|
||||
// Also, multi-hit moves must always deal the same damage as the first hit for any subsequent hits
|
||||
const uncappedDamage = move.hit > 1 ? this.lastDamage : this.actions.getDamage(source, target, move);
|
||||
let uncappedDamage = move.hit > 1 ? this.lastDamage : this.actions.getDamage(source, target, move);
|
||||
if (!uncappedDamage && uncappedDamage !== 0) return null;
|
||||
uncappedDamage = this.runEvent('SubDamage', target, source, move, uncappedDamage);
|
||||
if (!uncappedDamage && uncappedDamage !== 0) return uncappedDamage;
|
||||
this.lastDamage = uncappedDamage;
|
||||
target.volatiles['substitute'].hp -= uncappedDamage > target.volatiles['substitute'].hp ?
|
||||
target.volatiles['substitute'].hp : uncappedDamage;
|
||||
|
|
@ -58,7 +65,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
// Add here counter damage
|
||||
const lastAttackedBy = target.getLastAttackedBy();
|
||||
if (!lastAttackedBy) {
|
||||
target.attackedBy.push({ source, move: move.id, damage: uncappedDamage, thisTurn: true, slot: source.getSlot() });
|
||||
target.attackedBy.push({source: source, move: move.id, damage: uncappedDamage, thisTurn: true, slot: source.getSlot()});
|
||||
} else {
|
||||
lastAttackedBy.move = move.id;
|
||||
lastAttackedBy.damage = uncappedDamage;
|
||||
|
|
@ -71,6 +78,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
}
|
||||
return accuracy;
|
||||
},
|
||||
onEnd(target) {
|
||||
this.add('-end', target, 'Substitute');
|
||||
},
|
||||
},
|
||||
},
|
||||
swift: {
|
||||
|
|
|
|||
|
|
@ -1,16 +1,13 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
export const Rulesets: {[k: string]: ModdedFormatData} = {
|
||||
standard: {
|
||||
effectType: 'ValidatorRule',
|
||||
name: 'Standard',
|
||||
ruleset: [
|
||||
'Standard AG',
|
||||
'Sleep Clause Mod', 'Freeze Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause',
|
||||
],
|
||||
ruleset: ['Obtainable', 'Desync Clause Mod', 'Sleep Clause Mod', 'Freeze Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod'],
|
||||
banlist: ['Dig', 'Fly'],
|
||||
},
|
||||
nc1997movelegality: {
|
||||
nintendocup1997movelegality: {
|
||||
effectType: 'ValidatorRule',
|
||||
name: 'NC 1997 Move Legality',
|
||||
name: 'Nintendo Cup 1997 Move Legality',
|
||||
desc: "Bans move combinations on Pok\u00e9mon that would only be obtainable in Pok\u00e9mon Yellow.",
|
||||
banlist: [
|
||||
// https://www.smogon.com/forums/threads/rby-and-gsc-illegal-movesets.78638/
|
||||
|
|
@ -25,40 +22,40 @@ export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable
|
|||
'Flareon + Tackle + Growl', 'Flareon + Focus Energy + Ember',
|
||||
],
|
||||
onValidateSet(set) {
|
||||
const rgb97Legality: { [speciesid: string]: { [moveid: string]: 'illegal' | number } } = {
|
||||
charizard: { fly: 'illegal' },
|
||||
const rgb97Legality: {[speciesid: string]: {[moveid: string]: 'illegal' | number}} = {
|
||||
charizard: {fly: 'illegal'},
|
||||
butterfree: {
|
||||
confusion: 12, poisonpowder: 15, stunspore: 16, sleeppowder: 17, supersonic: 21,
|
||||
psybeam: 34, flash: 'illegal', gust: 'illegal',
|
||||
},
|
||||
fearow: { payday: 'illegal' },
|
||||
pikachu: { quickattack: 16, tailwhip: 'illegal', slam: 'illegal', lightscreen: 'illegal' },
|
||||
raichu: { quickattack: 16, tailwhip: 'illegal', slam: 'illegal', lightscreen: 'illegal' },
|
||||
nidoranf: { doublekick: 43 },
|
||||
nidorina: { doublekick: 43 },
|
||||
nidoqueen: { doublekick: 43 },
|
||||
nidoranm: { doublekick: 43 },
|
||||
nidorino: { doublekick: 43 },
|
||||
nidoking: { doublekick: 43 },
|
||||
venonat: { poisonpowder: 24, supersonic: 'illegal', confusion: 'illegal' },
|
||||
venomoth: { poisonpowder: 24, supersonic: 'illegal' },
|
||||
diglett: { cut: 'illegal' },
|
||||
dugtrio: { cut: 'illegal' },
|
||||
psyduck: { amnesia: 'illegal' },
|
||||
golduck: { amnesia: 'illegal' },
|
||||
mankey: { lowkick: 'illegal', screech: 'illegal' },
|
||||
primeape: { lowkick: 'illegal', screech: 'illegal' },
|
||||
kadabra: { kinesis: 'illegal' },
|
||||
alakazam: { kinesis: 'illegal' },
|
||||
rapidash: { payday: 'illegal' },
|
||||
cubone: { tailwhip: 'illegal', headbutt: 'illegal' },
|
||||
marowak: { tailwhip: 'illegal', headbutt: 'illegal' },
|
||||
chansey: { tailwhip: 'illegal' },
|
||||
tangela: { absorb: 29, growth: 49, vinewhip: 'illegal' },
|
||||
scyther: { wingattack: 'illegal' },
|
||||
pinsir: { bind: 'illegal' },
|
||||
magikarp: { dragonrage: 'illegal' },
|
||||
eevee: { quickattack: 27, tailwhip: 31, bite: 37, growl: 'illegal', focusenergy: 'illegal' },
|
||||
fearow: {payday: 'illegal'},
|
||||
pikachu: {quickattack: 16, tailwhip: 'illegal', slam: 'illegal', lightscreen: 'illegal'},
|
||||
raichu: {quickattack: 16, tailwhip: 'illegal', slam: 'illegal', lightscreen: 'illegal'},
|
||||
nidoranf: {doublekick: 43},
|
||||
nidorina: {doublekick: 43},
|
||||
nidoqueen: {doublekick: 43},
|
||||
nidoranm: {doublekick: 43},
|
||||
nidorino: {doublekick: 43},
|
||||
nidoking: {doublekick: 43},
|
||||
venonat: {poisonpowder: 24, supersonic: 'illegal', confusion: 'illegal'},
|
||||
venomoth: {poisonpowder: 24, supersonic: 'illegal'},
|
||||
diglett: {cut: 'illegal'},
|
||||
dugtrio: {cut: 'illegal'},
|
||||
psyduck: {amnesia: 'illegal'},
|
||||
golduck: {amnesia: 'illegal'},
|
||||
mankey: {lowkick: 'illegal', screech: 'illegal'},
|
||||
primeape: {lowkick: 'illegal', screech: 'illegal'},
|
||||
kadabra: {kinesis: 'illegal'},
|
||||
alakazam: {kinesis: 'illegal'},
|
||||
rapidash: {payday: 'illegal'},
|
||||
cubone: {tailwhip: 'illegal', headbutt: 'illegal'},
|
||||
marowak: {tailwhip: 'illegal', headbutt: 'illegal'},
|
||||
chansey: {tailwhip: 'illegal'},
|
||||
tangela: {absorb: 29, growth: 49, vinewhip: 'illegal'},
|
||||
scyther: {wingattack: 'illegal'},
|
||||
pinsir: {bind: 'illegal'},
|
||||
magikarp: {dragonrage: 'illegal'},
|
||||
eevee: {quickattack: 27, tailwhip: 31, bite: 37, growl: 'illegal', focusenergy: 'illegal'},
|
||||
vaporeon: {
|
||||
quickattack: 27, tailwhip: 31, watergun: 31, bite: 37, acidarmor: 42, haze: 44, mist: 48, hydropump: 54,
|
||||
growl: 'illegal', focusenergy: 'illegal', aurorabeam: 'illegal',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDataTable = {
|
||||
export const Conditions: {[k: string]: ModdedConditionData} = {
|
||||
brn: {
|
||||
name: 'brn',
|
||||
effectType: 'Status',
|
||||
|
|
@ -37,7 +37,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
effectType: 'Status',
|
||||
onStart(target, source, sourceEffect) {
|
||||
if (sourceEffect && sourceEffect.effectType === 'Move') {
|
||||
this.add('-status', target, 'slp', `[from] move: ${sourceEffect.name}`);
|
||||
this.add('-status', target, 'slp', '[from] move: ' + sourceEffect.name);
|
||||
} else {
|
||||
this.add('-status', target, 'slp');
|
||||
}
|
||||
|
|
@ -101,14 +101,14 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
},
|
||||
flinch: {
|
||||
inherit: true,
|
||||
onStart: undefined, // no inherit
|
||||
onStart() {},
|
||||
},
|
||||
partiallytrapped: {
|
||||
name: 'partiallytrapped',
|
||||
duration: 2,
|
||||
onBeforeMovePriority: 1,
|
||||
onStart(target, source, effect) {
|
||||
this.add('-activate', target, `move: ${effect}`, `[of] ${source}`);
|
||||
this.add('-activate', target, 'move: ' + effect, '[of] ' + source);
|
||||
},
|
||||
onBeforeMove(pokemon) {
|
||||
if (this.effectState.source && (!this.effectState.source.isActive || this.effectState.source.hp <= 0)) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormatsDataTable = {
|
||||
export const FormatsData: {[k: string]: ModdedSpeciesFormatsData} = {
|
||||
bulbasaur: {
|
||||
tier: "LC",
|
||||
},
|
||||
|
|
@ -225,7 +225,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
golem: {
|
||||
tier: "UU",
|
||||
tier: "OU",
|
||||
},
|
||||
ponyta: {
|
||||
tier: "LC",
|
||||
|
|
@ -270,7 +270,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
cloyster: {
|
||||
tier: "UU",
|
||||
tier: "OU",
|
||||
},
|
||||
gastly: {
|
||||
tier: "LC",
|
||||
|
|
@ -279,7 +279,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
gengar: {
|
||||
tier: "UU",
|
||||
tier: "OU",
|
||||
},
|
||||
onix: {
|
||||
tier: "UU",
|
||||
|
|
@ -342,7 +342,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
kangaskhan: {
|
||||
tier: "UU",
|
||||
tier: "OU",
|
||||
},
|
||||
horsea: {
|
||||
tier: "LC",
|
||||
|
|
@ -369,7 +369,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
jynx: {
|
||||
tier: "UU",
|
||||
tier: "OU",
|
||||
},
|
||||
electabuzz: {
|
||||
tier: "UU",
|
||||
|
|
@ -402,7 +402,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
jolteon: {
|
||||
tier: "UU",
|
||||
tier: "OU",
|
||||
},
|
||||
flareon: {
|
||||
tier: "UU",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
||||
export const Moves: {[k: string]: ModdedMoveData} = {
|
||||
bide: {
|
||||
inherit: true,
|
||||
priority: 0,
|
||||
|
|
@ -33,14 +33,14 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
onAfterSetStatus(status, pokemon) {
|
||||
// Sleep, freeze, and partial trap will just pause duration.
|
||||
if (pokemon.volatiles['flinch']) {
|
||||
this.effectState.duration!++;
|
||||
this.effectState.duration++;
|
||||
} else if (pokemon.volatiles['partiallytrapped']) {
|
||||
this.effectState.duration!++;
|
||||
this.effectState.duration++;
|
||||
} else {
|
||||
switch (status.id) {
|
||||
case 'slp':
|
||||
case 'frz':
|
||||
this.effectState.duration!++;
|
||||
this.effectState.duration++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -59,7 +59,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
pokemon.removeVolatile('bide');
|
||||
return false;
|
||||
}
|
||||
this.actions.moveHit(target, pokemon, move, { damage: this.effectState.totalDamage * 2 } as ActiveMove);
|
||||
this.actions.moveHit(target, pokemon, move, {damage: this.effectState.totalDamage * 2} as ActiveMove);
|
||||
pokemon.removeVolatile('bide');
|
||||
return false;
|
||||
}
|
||||
|
|
@ -160,20 +160,21 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
volatileStatus: 'rage',
|
||||
},
|
||||
condition: {
|
||||
inherit: true,
|
||||
// Rage lock
|
||||
onStart(target, source, effect) {
|
||||
this.effectState.move = 'rage';
|
||||
},
|
||||
onLockMove: 'rage',
|
||||
onHit(target, source, move) {
|
||||
if (target.boosts.atk < 6 && (move.category !== 'Status' || move.id === 'disable')) {
|
||||
this.boost({ atk: 1 });
|
||||
this.boost({atk: 1});
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
recover: {
|
||||
inherit: true,
|
||||
heal: null,
|
||||
onHit(target) {
|
||||
if (target.hp === target.maxhp) {
|
||||
return false;
|
||||
|
|
@ -196,6 +197,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
softboiled: {
|
||||
inherit: true,
|
||||
heal: null,
|
||||
onHit(target) {
|
||||
// Fail when health is 255 or 511 less than max
|
||||
if (target.hp === target.maxhp) {
|
||||
|
|
@ -218,7 +220,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
}
|
||||
},
|
||||
condition: {
|
||||
inherit: true,
|
||||
onStart(target) {
|
||||
this.add('-start', target, 'Substitute');
|
||||
this.effectState.hp = Math.floor(target.maxhp / 4);
|
||||
delete target.volatiles['partiallytrapped'];
|
||||
},
|
||||
onTryHitPriority: -1,
|
||||
onTryHit(target, source, move) {
|
||||
if (target === source) {
|
||||
this.debug('sub bypass: self hit');
|
||||
|
|
@ -242,6 +249,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
damage = target.volatiles['substitute'].hp;
|
||||
}
|
||||
if (!damage && damage !== 0) return null;
|
||||
damage = this.runEvent('SubDamage', target, source, move, damage);
|
||||
if (!damage && damage !== 0) return damage;
|
||||
target.volatiles['substitute'].hp -= damage;
|
||||
this.lastDamage = damage;
|
||||
if (target.volatiles['substitute'].hp <= 0) {
|
||||
|
|
@ -261,20 +270,24 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
// Add here counter damage
|
||||
const lastAttackedBy = target.getLastAttackedBy();
|
||||
if (!lastAttackedBy) {
|
||||
target.attackedBy.push({ source, move: move.id, damage, slot: source.getSlot(), thisTurn: true });
|
||||
target.attackedBy.push({source: source, move: move.id, damage: damage, slot: source.getSlot(), thisTurn: true});
|
||||
} else {
|
||||
lastAttackedBy.move = move.id;
|
||||
lastAttackedBy.damage = damage;
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
onEnd(target) {
|
||||
this.add('-end', target, 'Substitute');
|
||||
},
|
||||
},
|
||||
secondary: null,
|
||||
target: "self",
|
||||
type: "Normal",
|
||||
},
|
||||
struggle: {
|
||||
inherit: true,
|
||||
ignoreImmunity: { 'Normal': true },
|
||||
ignoreImmunity: {'Normal': true},
|
||||
},
|
||||
wrap: {
|
||||
inherit: true,
|
||||
|
|
|
|||
|
|
@ -1,763 +1,7 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
standardag: {
|
||||
inherit: true,
|
||||
ruleset: [
|
||||
'Obtainable', 'Exact HP Mod', 'Cancel Mod',
|
||||
],
|
||||
},
|
||||
export const Rulesets: {[k: string]: ModdedFormatData} = {
|
||||
standard: {
|
||||
effectType: 'ValidatorRule',
|
||||
name: 'Standard',
|
||||
ruleset: [
|
||||
'Standard AG',
|
||||
'Stadium Sleep Clause', 'Freeze Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause',
|
||||
],
|
||||
},
|
||||
stadiumpokecuprentals: {
|
||||
inherit: true,
|
||||
onChangeSet(set, format, setHas, teamHas) {
|
||||
set.level = 50;
|
||||
switch (this.dex.species.get(set.species).name) {
|
||||
case 'Bulbasaur':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Leech Seed', 'Toxic', 'Body Slam', 'Razor Leaf'];
|
||||
break;
|
||||
case 'Ivysaur':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Razor Leaf', 'Sleep Powder', 'Growth', 'Double-Edge'];
|
||||
break;
|
||||
case 'Venusaur':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Psychic', 'Seismic Toss', 'Reflect', 'Thunder Wave'];
|
||||
break;
|
||||
case 'Charmander':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Flamethrower', 'Slash', 'Dig', 'Fire Spin'];
|
||||
break;
|
||||
case 'Charmeleon':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Flamethrower', 'Counter', 'Seismic Toss', 'Strength'];
|
||||
break;
|
||||
case 'Charizard':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Fly', 'Swords Dance', 'Fire Spin', 'Fire Blast'];
|
||||
break;
|
||||
case 'Squirtle':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Surf', 'Blizzard', 'Body Slam', 'Dig'];
|
||||
break;
|
||||
case 'Wartortle':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Surf', 'Strength', 'Rest', 'Ice Beam'];
|
||||
break;
|
||||
case 'Blastoise':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Hydro Pump', 'Skull Bash', 'Withdraw', 'Seismic Toss'];
|
||||
break;
|
||||
case 'Caterpie':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['String Shot', 'Tackle'];
|
||||
break;
|
||||
case 'Metapod':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['String Shot', 'Tackle'];
|
||||
break;
|
||||
case 'Butterfree':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Psychic', 'Supersonic', 'Mega Drain', 'Stun Spore'];
|
||||
break;
|
||||
case 'Weedle':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['String Shot', 'Poison Sting'];
|
||||
break;
|
||||
case 'Kakuna':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['String Shot', 'Poison Sting'];
|
||||
break;
|
||||
case 'Beedrill':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Twineedle', 'Hyper Beam', 'Toxic', 'Focus Energy'];
|
||||
break;
|
||||
case 'Pidgey':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Fly', 'Toxic', 'Double-Edge', 'Double Team'];
|
||||
break;
|
||||
case 'Pidgeotto':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Fly', 'Quick Attack', 'Sand Attack', 'Take Down'];
|
||||
break;
|
||||
case 'Pidgeot':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Mirror Move', 'Fly', 'Quick Attack', 'Sand Attack'];
|
||||
break;
|
||||
case 'Rattata':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Super Fang', 'Blizzard', 'Quick Attack', 'Hyper Fang'];
|
||||
break;
|
||||
case 'Raticate':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Hyper Fang', 'Hyper Beam', 'Focus Energy', 'Thunder'];
|
||||
break;
|
||||
case 'Spearow':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Drill Peck', 'Mirror Move', 'Double Team', 'Double-Edge'];
|
||||
break;
|
||||
case 'Fearow':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Drill Peck', 'Mirror Move', 'Fury Attack', 'Swift'];
|
||||
break;
|
||||
case 'Ekans':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Earthquake', 'Acid', 'Screech', 'Body Slam'];
|
||||
break;
|
||||
case 'Arbok':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Glare', 'Wrap', 'Dig', 'Strength'];
|
||||
break;
|
||||
case 'Pikachu':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Thunderbolt', 'Slam', 'Thunder Wave', 'Seismic Toss'];
|
||||
break;
|
||||
case 'Raichu':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Thunder', 'Thunder Wave', 'Flash', 'Mega Kick'];
|
||||
break;
|
||||
case 'Sandshrew':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Earthquake', 'Slash', 'Seismic Toss', 'Sand Attack'];
|
||||
break;
|
||||
case 'Sandslash':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Dig', 'Swift', 'Seismic Toss', 'Sand Attack'];
|
||||
break;
|
||||
case 'Nidoran-F':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Toxic', 'Thunderbolt', 'Body Slam', 'Blizzard'];
|
||||
break;
|
||||
case 'Nidorina':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Toxic', 'Thunder', 'Double-Edge', 'Ice Beam'];
|
||||
break;
|
||||
case 'Nidoqueen':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Toxic', 'Double Kick', 'Bite', 'Earthquake'];
|
||||
break;
|
||||
case 'Nidoran-M':
|
||||
set.evs = { hp: 177, atk: 176, def: 176, spa: 176, spd: 176, spe: 176 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Blizzard', 'Body Slam', 'Thunderbolt', 'Focus Energy'];
|
||||
break;
|
||||
case 'Nidorino':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Double-Edge', 'Horn Drill', 'Focus Energy', 'Thunder'];
|
||||
break;
|
||||
case 'Nidoking':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Earthquake', 'Horn Drill', 'Rage', 'Substitute'];
|
||||
break;
|
||||
case 'Clefairy':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Thunderbolt', 'Psychic', 'Body Slam', 'Blizzard'];
|
||||
break;
|
||||
case 'Clefable':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Sing', 'Tri Attack', 'Minimize', 'Ice Beam'];
|
||||
break;
|
||||
case 'Vulpix':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Flamethrower', 'Dig', 'Confuse Ray', 'Double-Edge'];
|
||||
break;
|
||||
case 'Ninetales':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Fire Blast', 'Skull Bash', 'Confuse Ray', 'Tail Whip'];
|
||||
break;
|
||||
case 'Jigglypuff':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Sing', 'Body Slam', 'Seismic Toss', 'Psychic'];
|
||||
break;
|
||||
case 'Wigglytuff':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Sing', 'Double-Edge', 'Submission', 'Thunderbolt'];
|
||||
break;
|
||||
case 'Zubat':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Confuse Ray', 'Mega Drain', 'Toxic', 'Double-Edge'];
|
||||
break;
|
||||
case 'Golbat':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Confuse Ray', 'Mega Drain', 'Bite', 'Haze'];
|
||||
break;
|
||||
case 'Oddish':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Petal Dance', 'Toxic', 'Mega Drain', 'Double-Edge'];
|
||||
break;
|
||||
case 'Gloom':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Petal Dance', 'Take Down', 'Mega Drain', 'Stun Spore'];
|
||||
break;
|
||||
case 'Vileplume':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Petal Dance', 'Sleep Powder', 'Acid', 'Cut'];
|
||||
break;
|
||||
case 'Paras':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Spore', 'Slash', 'Dig', 'Mega Drain'];
|
||||
break;
|
||||
case 'Parasect':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Spore', 'Take Down', 'Dig', 'Solar Beam'];
|
||||
break;
|
||||
case 'Venonat':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Psychic', 'Mega Drain', 'Double-Edge', 'Stun Spore'];
|
||||
break;
|
||||
case 'Venomoth':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Psychic', 'Supersonic', 'Solar Beam', 'Swift'];
|
||||
break;
|
||||
case 'Diglett':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Earthquake', 'Slash', 'Sand Attack', 'Rock Slide'];
|
||||
break;
|
||||
case 'Dugtrio':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Dig', 'Sand Attack', 'Toxic', 'Hyper Beam'];
|
||||
break;
|
||||
case 'Meowth':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Slash', 'Thunderbolt', 'Swift', 'Double Team'];
|
||||
break;
|
||||
case 'Persian':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Slash', 'Bubble Beam', 'Mimic', 'Growl'];
|
||||
break;
|
||||
case 'Psyduck':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Surf', 'Confusion', 'Dig', 'Blizzard'];
|
||||
break;
|
||||
case 'Golduck':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Ice Beam', 'Surf', 'Toxic', 'Disable'];
|
||||
break;
|
||||
case 'Mankey':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Submission', 'Rock Slide', 'Seismic Toss', 'Screech'];
|
||||
break;
|
||||
case 'Primeape':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Fury Swipes', 'Rock Slide', 'Low Kick', 'Screech'];
|
||||
break;
|
||||
case 'Growlithe':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Flamethrower', 'Body Slam', 'Reflect', 'Dig'];
|
||||
break;
|
||||
case 'Arcanine':
|
||||
set.evs = { hp: 105, atk: 104, def: 104, spa: 104, spd: 104, spe: 104 };
|
||||
set.ivs = { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 };
|
||||
set.moves = ['Fire Blast', 'Take Down', 'Dragon Rage', 'Substitute'];
|
||||
break;
|
||||
case 'Poliwag':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Body Slam', 'Blizzard', 'Surf', 'Amnesia'];
|
||||
break;
|
||||
case 'Poliwhirl':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Hypnosis', 'Surf', 'Ice Beam', 'Earthquake'];
|
||||
break;
|
||||
case 'Poliwrath':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Hypnosis', 'Submission', 'Counter', 'Hydro Pump'];
|
||||
break;
|
||||
case 'Abra':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Psychic', 'Seismic Toss', 'Reflect', 'Thunder Wave'];
|
||||
break;
|
||||
case 'Kadabra':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Psychic', 'Counter', 'Recover', 'Dig'];
|
||||
break;
|
||||
case 'Alakazam':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Psybeam', 'Metronome', 'Disable', 'Tri Attack'];
|
||||
break;
|
||||
case 'Machop':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Submission', 'Rock Slide', 'Earthquake', 'Focus Energy'];
|
||||
break;
|
||||
case 'Machoke':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Submission', 'Strength', 'Rock Slide', 'Focus Energy'];
|
||||
break;
|
||||
case 'Machamp':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Low Kick', 'Strength', 'Counter', 'Focus Energy'];
|
||||
break;
|
||||
case 'Bellsprout':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Razor Leaf', 'Growth', 'Mega Drain', 'Stun Spore'];
|
||||
break;
|
||||
case 'Weepinbell':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Razor Leaf', 'Acid', 'Wrap', 'Toxic'];
|
||||
break;
|
||||
case 'Victreebel':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Solar Beam', 'Acid', 'Reflect', 'Slam'];
|
||||
break;
|
||||
case 'Tentacool':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Surf', 'Supersonic', 'Mega Drain', 'Blizzard'];
|
||||
break;
|
||||
case 'Tentacruel':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Acid', 'Supersonic', 'Hydro Pump', 'Cut'];
|
||||
break;
|
||||
case 'Geodude':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Earthquake', 'Seismic Toss', 'Rock Slide', 'Explosion'];
|
||||
break;
|
||||
case 'Graveler':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Earthquake', 'Seismic Toss', 'Strength', 'Self-Destruct'];
|
||||
break;
|
||||
case 'Golem':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Dig', 'Seismic Toss', 'Fire Blast', 'Metronome'];
|
||||
break;
|
||||
case 'Ponyta':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Fire Blast', 'Agility', 'Horn Drill', 'Body Slam'];
|
||||
break;
|
||||
case 'Rapidash':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Fire Blast', 'Stomp', 'Toxic', 'Fire Spin'];
|
||||
break;
|
||||
case 'Slowpoke':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Surf', 'Psychic', 'Thunder Wave', 'Amnesia'];
|
||||
break;
|
||||
case 'Slowbro':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Surf', 'Psychic', 'Disable', 'Withdraw'];
|
||||
break;
|
||||
case 'Magnemite':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Thunderbolt', 'Thunder Wave', 'Supersonic', 'Double-Edge'];
|
||||
break;
|
||||
case 'Magneton':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Thunderbolt', 'Screech', 'Supersonic', 'Swift'];
|
||||
break;
|
||||
case 'Farfetch\u2019d':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Slash', 'Sand Attack', 'Toxic', 'Fly'];
|
||||
break;
|
||||
case 'Doduo':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Drill Peck', 'Tri Attack', 'Double Team', 'Reflect'];
|
||||
break;
|
||||
case 'Dodrio':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Fly', 'Tri Attack', 'Agility', 'Reflect'];
|
||||
break;
|
||||
case 'Seel':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Ice Beam', 'Body Slam', 'Horn Drill', 'Surf'];
|
||||
break;
|
||||
case 'Dewgong':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Aurora Beam', 'Heabutt', 'Rest', 'Surf'];
|
||||
break;
|
||||
case 'Grimer':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Sludge', 'Body Slam', 'Explosion', 'Screech'];
|
||||
break;
|
||||
case 'Muk':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Sludge', 'Thunderbolt', 'Hyper Beam', 'Self-Destruct'];
|
||||
break;
|
||||
case 'Shellder':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Surf', 'Explosion', 'Blizzard', 'Tri Attack'];
|
||||
break;
|
||||
case 'Cloyster':
|
||||
set.evs = { hp: 105, atk: 104, def: 104, spa: 104, spd: 104, spe: 104 };
|
||||
set.ivs = { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 };
|
||||
set.moves = ['Clamp', 'Spike Cannon', 'Ice Beam', 'Supersonic'];
|
||||
break;
|
||||
case 'Gastly':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Hypnosis', 'Dream Eater', 'Psychic', 'Confuse Ray'];
|
||||
break;
|
||||
case 'Haunter':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Mega Drain', 'Psychic', 'Explosion', 'Confuse Ray'];
|
||||
break;
|
||||
case 'Gengar':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Thunderbolt', 'Night Shade', 'Hypnosis', 'Confuse Ray'];
|
||||
break;
|
||||
case 'Onix':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Earthquake', 'Rock Slide', 'Strength', 'Explosion'];
|
||||
break;
|
||||
case 'Drowzee':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Hypnois', 'Dream Eater', 'Psychic', 'Tri Attack'];
|
||||
break;
|
||||
case 'Hypno':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Hypnosis', 'Headbutt', 'Dream Eater', 'Meditate'];
|
||||
break;
|
||||
case 'Krabby':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Crabhammer', 'Guillotine', 'Double-Edge', 'Blizzard'];
|
||||
break;
|
||||
case 'Kingler':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Crabhammer', 'Guillotine', 'Stomp', 'Substitute'];
|
||||
break;
|
||||
case 'Voltorb':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Thunderbolt', 'Thunder Wave', 'Swift', 'Explosion'];
|
||||
break;
|
||||
case 'Electrode':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Thunder', 'Thunder Wave', 'Swift', 'Self-Destruct'];
|
||||
break;
|
||||
case 'Exeggcute':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Psychic', 'Explosion', 'Leech Seed', 'Toxic'];
|
||||
break;
|
||||
case 'Exeggutor':
|
||||
set.evs = { hp: 105, atk: 104, def: 104, spa: 104, spd: 104, spe: 104 };
|
||||
set.ivs = { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 };
|
||||
set.moves = ['Mega Drain', 'Stun Spore', 'Leech Seed', 'Egg Bomb'];
|
||||
break;
|
||||
case 'Cubone':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Earthquake', 'Submission', 'Blizzard', 'Strength'];
|
||||
break;
|
||||
case 'Marowak':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Bonemerang', 'Thrash', 'Fire Blast', 'Focus Energy'];
|
||||
break;
|
||||
case 'Hitmonlee':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['High Jump Kick', 'Mega Kick', 'Metronome', 'Seismic Toss'];
|
||||
break;
|
||||
case 'Hitmonchan':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Submission', 'Thunder Punch', 'Ice Punch', 'Strength'];
|
||||
break;
|
||||
case 'Lickitung':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Strength', 'Blizzard', 'Thunder', 'Fire Blast'];
|
||||
break;
|
||||
case 'Koffing':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Sludge', 'Toxic', 'Thunderbolt', 'Explosion'];
|
||||
break;
|
||||
case 'Weezing':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Sludge', 'Hyper Beam', 'Fire Blast', 'Self-Destruct'];
|
||||
break;
|
||||
case 'Rhyhorn':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Earthquake', 'Body Slam', 'Rock Slide', 'Fire Blast'];
|
||||
break;
|
||||
case 'Rhydon':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Dig', 'Strength', 'Thunder', 'Surf'];
|
||||
break;
|
||||
case 'Chansey':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Thunder', 'Fire Blast', 'Minimize', 'Rest'];
|
||||
break;
|
||||
case 'Tangela':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Mega Drain', 'Growth', 'Toxic', 'Double-Edge'];
|
||||
break;
|
||||
case 'Kangaskhan':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Dizzy Punch', 'Rock Slide', 'Surf', 'Thunderbolt'];
|
||||
break;
|
||||
case 'Horsea':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Hydro Pump', 'Toxic', 'Smokescreen', 'Ice Beam'];
|
||||
break;
|
||||
case 'Seadra':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Surf', 'Toxic', 'Smokescreen', 'Swift'];
|
||||
break;
|
||||
case 'Goldeen':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Surf', 'Supersonic', 'Horn Drill', 'Blizzard'];
|
||||
break;
|
||||
case 'Seaking':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Waterfall', 'Supersonic', 'Horn Attack', 'Ice Beam'];
|
||||
break;
|
||||
case 'Staryu':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Hydro Pump', 'Recover', 'Thunderbolt', 'Psychic'];
|
||||
break;
|
||||
case 'Starmie':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Surf', 'Thunder', 'Swift', 'Harden'];
|
||||
break;
|
||||
case 'Mr. Mime':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Barrier', 'Psychic', 'Metronome', 'Seismic Toss'];
|
||||
break;
|
||||
case 'Scyther':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Slash', 'Wing Attack', 'Leer', 'Double Team'];
|
||||
break;
|
||||
case 'Jynx':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Ice Punch', 'Mega Punch', 'Psychic', 'Lovely Kiss'];
|
||||
break;
|
||||
case 'Electabuzz':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Thunder Punch', 'Mega Punch', 'Psychic', 'Thunder Wave'];
|
||||
break;
|
||||
case 'Magmar':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Fire Punch', 'Mega Punch', 'Psychic', 'Smokescreen'];
|
||||
break;
|
||||
case 'Pinsir':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Strength', 'Harden', 'Seismic Toss', 'Guillotine'];
|
||||
break;
|
||||
case 'Tauros':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Double-Edge', 'Fire Blast', 'Tail Whip', 'Bide'];
|
||||
break;
|
||||
case 'Magikarp':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Splash', 'Tackle'];
|
||||
break;
|
||||
case 'Gyarados':
|
||||
set.evs = { hp: 105, atk: 104, def: 104, spa: 104, spd: 104, spe: 104 };
|
||||
set.ivs = { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 };
|
||||
set.moves = ['Surf', 'Dragon Rage', 'Bite', 'Fire Blast'];
|
||||
break;
|
||||
case 'Lapras':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Ice Beam', 'Solar Beam', 'Body Slam', 'Sing'];
|
||||
break;
|
||||
case 'Ditto':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Transform'];
|
||||
break;
|
||||
case 'Eevee':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Body Slam', 'Swift', 'Sand Attack', 'Toxic'];
|
||||
break;
|
||||
case 'Vaporeon':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Surf', 'Quick Attack', 'Sand Attack', 'Acid Armor'];
|
||||
break;
|
||||
case 'Jolteon':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Thunderbolt', 'Pin Missile', 'Toxic', 'Sand Attack'];
|
||||
break;
|
||||
case 'Flareon':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Fire Blast', 'Take Down', 'Smog', 'Sand Attack'];
|
||||
break;
|
||||
case 'Omanyte':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Surf', 'Ice Beam', 'Double Edge', 'Double Team'];
|
||||
break;
|
||||
case 'Omastar':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Hydro Pump', 'Submission', 'Spike Cannon', 'Withdraw'];
|
||||
break;
|
||||
case 'Kabuto':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Hydro Pump', 'Blizzard', 'Slash', 'Double Team'];
|
||||
break;
|
||||
case 'Kabutops':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Surf', 'Swords Dance', 'Mega Kick', 'Submission'];
|
||||
break;
|
||||
case 'Aerodactyl':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Fly', 'Hyper Beam', 'Supersonic', 'Dragon Rage'];
|
||||
break;
|
||||
case 'Snorlax':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Mega Kick', 'Rock Slide', 'Metronome', 'Rest'];
|
||||
break;
|
||||
case 'Articuno':
|
||||
set.evs = { hp: 97, atk: 96, def: 96, spa: 96, spd: 96, spe: 96 };
|
||||
set.ivs = { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 };
|
||||
set.moves = ['Ice Beam', 'Sky Attack', 'Razor Wind', 'Substitute'];
|
||||
break;
|
||||
case 'Zapdos':
|
||||
set.evs = { hp: 97, atk: 96, def: 96, spa: 96, spd: 96, spe: 96 };
|
||||
set.ivs = { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 };
|
||||
set.moves = ['Thunderbolt', 'Sky Attack', 'Thunder Wave', 'Flash'];
|
||||
break;
|
||||
case 'Moltres':
|
||||
set.evs = { hp: 97, atk: 96, def: 96, spa: 96, spd: 96, spe: 96 };
|
||||
set.ivs = { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 };
|
||||
set.moves = ['Fire Blast', 'Fly', 'Swift', 'Substitute'];
|
||||
break;
|
||||
case 'Dratini':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Hyper Beam', 'Body Slam', 'Thunderbolt', 'Thunder Wave'];
|
||||
break;
|
||||
case 'Dragonair':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Hyper Beam', 'Swift', 'Ice Beam', 'Thunder Wave'];
|
||||
break;
|
||||
case 'Dragonite':
|
||||
set.evs = { hp: 97, atk: 96, def: 96, spa: 96, spd: 96, spe: 96 };
|
||||
set.ivs = { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 };
|
||||
set.moves = ['Slam', 'Dragon Rage', 'Thunder', 'Agility'];
|
||||
}
|
||||
},
|
||||
ruleset: ['Obtainable', 'Stadium Sleep Clause', 'Freeze Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'Exact HP Mod', 'Cancel Mod'],
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -36,9 +36,6 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
this.modifyStat!(statName, [100, 66, 50, 40, 33, 28, 25][-this.boosts[statName]] / 100);
|
||||
}
|
||||
}
|
||||
if (this.modifiedStats![statName] > 999) {
|
||||
this.modifiedStats![statName] = 999;
|
||||
}
|
||||
}
|
||||
},
|
||||
// Stadium's fixed boosting function.
|
||||
|
|
@ -72,8 +69,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
},
|
||||
actions: {
|
||||
inherit: true,
|
||||
runMove(moveOrMoveName, pokemon, targetLoc, options) {
|
||||
let sourceEffect = options?.sourceEffect;
|
||||
runMove(moveOrMoveName, pokemon, targetLoc, sourceEffect) {
|
||||
const move = this.dex.getActiveMove(moveOrMoveName);
|
||||
const target = this.battle.getTarget(pokemon, move, targetLoc);
|
||||
if (target?.subFainted) target.subFainted = null;
|
||||
|
|
@ -81,7 +77,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
this.battle.setActiveMove(move, pokemon, target);
|
||||
|
||||
if (pokemon.moveThisTurn || !this.battle.runEvent('BeforeMove', pokemon, target, move)) {
|
||||
this.battle.debug(`${pokemon.fullname} move interrupted; movedThisTurn: ${pokemon.moveThisTurn}`);
|
||||
this.battle.debug('' + pokemon.fullname + ' move interrupted; movedThisTurn: ' + pokemon.moveThisTurn);
|
||||
this.battle.clearActiveMove(true);
|
||||
// This is only run for sleep
|
||||
this.battle.runEvent('AfterMoveSelf', pokemon, target, move);
|
||||
|
|
@ -103,14 +99,12 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
} else {
|
||||
sourceEffect = move;
|
||||
}
|
||||
this.battle.actions.useMove(move, pokemon, { target, sourceEffect });
|
||||
this.battle.actions.useMove(move, pokemon, target, sourceEffect);
|
||||
},
|
||||
// This function deals with AfterMoveSelf events.
|
||||
// This leads with partial trapping moves shenanigans after the move has been used.
|
||||
useMove(moveOrMoveName, pokemon, options) {
|
||||
let sourceEffect = options?.sourceEffect;
|
||||
let target = options?.target;
|
||||
const moveResult = this.useMoveInner(moveOrMoveName, pokemon, { target, sourceEffect });
|
||||
useMove(moveOrMoveName, pokemon, target, sourceEffect) {
|
||||
const moveResult = this.useMoveInner(moveOrMoveName, pokemon, target, sourceEffect);
|
||||
|
||||
if (!sourceEffect && this.battle.effect.id) sourceEffect = this.battle.effect;
|
||||
const baseMove = this.battle.dex.moves.get(moveOrMoveName);
|
||||
|
|
@ -167,9 +161,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
},
|
||||
// This is the function that actually uses the move, running ModifyMove events.
|
||||
// It uses the move and then deals with the effects after the move.
|
||||
useMoveInner(moveOrMoveName, pokemon, options) {
|
||||
let sourceEffect = options?.sourceEffect;
|
||||
let target = options?.target;
|
||||
useMoveInner(moveOrMoveName, pokemon, target, sourceEffect) {
|
||||
if (!sourceEffect && this.battle.effect.id) sourceEffect = this.battle.effect;
|
||||
const baseMove = this.battle.dex.moves.get(moveOrMoveName);
|
||||
let move = this.battle.dex.getActiveMove(baseMove);
|
||||
|
|
@ -199,8 +191,8 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (sourceEffect) attrs += `|[from] ${this.battle.dex.conditions.get(sourceEffect).name}`;
|
||||
this.battle.addMove('move', pokemon, move.name, `${target}${attrs}`);
|
||||
if (sourceEffect) attrs += '|[from]' + this.battle.dex.conditions.get(sourceEffect);
|
||||
this.battle.addMove('move', pokemon, move.name, target + attrs);
|
||||
|
||||
if (!this.battle.singleEvent('Try', move, null, pokemon, target, move)) {
|
||||
return true;
|
||||
|
|
@ -231,8 +223,10 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
return true;
|
||||
}
|
||||
|
||||
this.battle.singleEvent('AfterMoveSecondarySelf', move, null, pokemon, target, move);
|
||||
this.battle.runEvent('AfterMoveSecondarySelf', pokemon, target, move);
|
||||
if (!move.negateSecondary) {
|
||||
this.battle.singleEvent('AfterMoveSecondarySelf', move, null, pokemon, target, move);
|
||||
this.battle.runEvent('AfterMoveSecondarySelf', pokemon, target, move);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
tryMoveHit(target, pokemon, move) {
|
||||
|
|
@ -250,7 +244,10 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
|
||||
// Then, check if the Pokemon is immune to this move.
|
||||
if (!target.runImmunity(move, true)) {
|
||||
if (
|
||||
(!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) &&
|
||||
!target.runImmunity(move.type, true)
|
||||
) {
|
||||
if (move.selfdestruct) {
|
||||
this.battle.faint(pokemon, pokemon, move);
|
||||
}
|
||||
|
|
@ -300,16 +297,10 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
accuracy = this.battle.runEvent('Accuracy', target, pokemon, move, accuracy);
|
||||
|
||||
// Stadium attempts to fix the 1/256 miss by rerolling if the first value
|
||||
// would trigger the 1/256 miss.
|
||||
let randomValue = this.battle.random(256);
|
||||
if (randomValue === 256) randomValue = this.battle.random(256);
|
||||
if (accuracy !== true && randomValue > accuracy) {
|
||||
// Stadium fixes the 1/256 accuracy bug.
|
||||
if (accuracy !== true && !this.battle.randomChance(accuracy + 1, 256)) {
|
||||
this.battle.attrLastMove('[miss]');
|
||||
this.battle.add('-miss', pokemon);
|
||||
if (accuracy === 255) {
|
||||
this.battle.hint("In Pokemon Stadium, moves with 100% accuracy can still miss 1/65536 of the time.");
|
||||
}
|
||||
damage = false;
|
||||
this.battle.lastDamage = 0;
|
||||
}
|
||||
|
|
@ -366,8 +357,10 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
|
||||
if (move.ohko) this.battle.add('-ohko');
|
||||
|
||||
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
|
||||
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
|
||||
if (!move.negateSecondary) {
|
||||
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
|
||||
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
|
||||
}
|
||||
|
||||
return damage;
|
||||
},
|
||||
|
|
@ -390,7 +383,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
const targetHadSub = !!target.volatiles['substitute'];
|
||||
if (targetHadSub && moveData.volatileStatus && moveData.volatileStatus === 'partiallytrapped') {
|
||||
target.addVolatile(moveData.volatileStatus, pokemon, move);
|
||||
if (!pokemon.volatiles['partialtrappinglock'] || pokemon.volatiles['partialtrappinglock'].duration! > 1) {
|
||||
if (!pokemon.volatiles['partialtrappinglock'] || pokemon.volatiles['partialtrappinglock'].duration > 1) {
|
||||
target.volatiles[moveData.volatileStatus].duration = 2;
|
||||
}
|
||||
}
|
||||
|
|
@ -548,8 +541,10 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
|
||||
// Let's see if the target is immune to the move.
|
||||
if (!target.runImmunity(move, true)) {
|
||||
return false;
|
||||
if (!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) {
|
||||
if (!target.runImmunity(move.type, true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Is it an OHKO move?
|
||||
|
|
@ -606,26 +601,26 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
let critChance = source.species.baseStats['spe'] + 76;
|
||||
|
||||
// Now we right logical shift it two places, essentially dividing by 4 and flooring it.
|
||||
critChance >>= 2;
|
||||
critChance = critChance >> 2;
|
||||
|
||||
// Now we check for focus energy volatile.
|
||||
if (source.volatiles['focusenergy']) {
|
||||
// If it exists, crit chance is multiplied by 4 and floored with a logical left shift.
|
||||
critChance <<= 2;
|
||||
critChance = critChance << 2;
|
||||
// Then we add 160.
|
||||
critChance += 160;
|
||||
} else {
|
||||
// If it is not active, we left shift it by 1.
|
||||
critChance <<= 1;
|
||||
critChance = critChance << 1;
|
||||
}
|
||||
|
||||
// Now we check for the move's critical hit ratio.
|
||||
if (move.critRatio === 2) {
|
||||
// High crit ratio, we multiply the result so far by 4.
|
||||
critChance <<= 2;
|
||||
critChance = critChance << 2;
|
||||
} else if (move.critRatio === 1) {
|
||||
// Normal hit ratio, we divide the crit chance by 2 and floor the result again.
|
||||
critChance >>= 1;
|
||||
critChance = critChance >> 1;
|
||||
}
|
||||
|
||||
// Now we make sure it's a number between 1 and 255.
|
||||
|
|
@ -693,7 +688,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
|
||||
// When either attack or defense are higher than 256, they are both divided by 4 and moded by 256.
|
||||
// This is what causes the rollover bugs.
|
||||
// This is what cuases the roll over bugs.
|
||||
if (attack >= 256 || defense >= 256) {
|
||||
attack = this.battle.clampIntRange(Math.floor(attack / 4) % 256, 1);
|
||||
// Defense isn't checked on the cartridge, but we don't want those / 0 bugs on the sim.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDataTable = {
|
||||
export const Conditions: {[k: string]: ModdedConditionData} = {
|
||||
brn: {
|
||||
name: 'brn',
|
||||
effectType: 'Status',
|
||||
|
|
@ -18,7 +18,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
inherit: true,
|
||||
onBeforeMovePriority: 2,
|
||||
onBeforeMove(pokemon) {
|
||||
if (this.randomChance(63, 256)) {
|
||||
if (this.randomChance(1, 4)) {
|
||||
this.add('cant', pokemon, 'par');
|
||||
return false;
|
||||
}
|
||||
|
|
@ -29,7 +29,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
effectType: 'Status',
|
||||
onStart(target, source, sourceEffect) {
|
||||
if (sourceEffect && sourceEffect.effectType === 'Move') {
|
||||
this.add('-status', target, 'slp', `[from] move: ${sourceEffect.name}`);
|
||||
this.add('-status', target, 'slp', '[from] move: ' + sourceEffect.name);
|
||||
} else {
|
||||
this.add('-status', target, 'slp');
|
||||
}
|
||||
|
|
@ -62,8 +62,8 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
this.add('cant', pokemon, 'frz');
|
||||
return false;
|
||||
},
|
||||
onModifyMove: undefined, // no inherit
|
||||
onDamagingHit: undefined, // no inherit
|
||||
onModifyMove() {},
|
||||
onDamagingHit() {},
|
||||
onAfterMoveSecondary(target, source, move) {
|
||||
if ((move.secondary && move.secondary.status === 'brn') || move.statusRoll === 'brn') {
|
||||
target.cureStatus();
|
||||
|
|
@ -177,17 +177,12 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
onStart(target, source, effect) {
|
||||
this.effectState.move = effect.id;
|
||||
},
|
||||
onAfterMove(pokemon) {
|
||||
if (this.effectState.duration === 1) {
|
||||
pokemon.removeVolatile('lockedmove');
|
||||
}
|
||||
},
|
||||
onEnd(target) {
|
||||
// Confusion begins even if already confused
|
||||
delete target.volatiles['confusion'];
|
||||
if (!target.side.getSideCondition('safeguard')) target.addVolatile('confusion');
|
||||
},
|
||||
onLockMove() {
|
||||
onLockMove(pokemon) {
|
||||
return this.effectState.move;
|
||||
},
|
||||
onMoveAborted(pokemon) {
|
||||
|
|
@ -197,7 +192,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
const move = this.dex.moves.get(this.effectState.move);
|
||||
if (move.id) {
|
||||
this.debug('Forcing into ' + move.id);
|
||||
this.queue.changeAction(pokemon, { choice: 'move', moveid: move.id });
|
||||
this.queue.changeAction(pokemon, {choice: 'move', moveid: move.id});
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
@ -228,7 +223,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
},
|
||||
onStallMove() {
|
||||
const counter = Math.floor(this.effectState.counter) || 127;
|
||||
this.debug(`Success chance: ${Math.round(counter * 1000 / 255) / 10}% (${counter}/255)`);
|
||||
this.debug("Success chance: " + Math.round(counter * 1000 / 255) / 10 + "% (" + counter + "/255)");
|
||||
return this.randomChance(counter, 255);
|
||||
},
|
||||
onRestart() {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormatsDataTable = {
|
||||
export const FormatsData: {[k: string]: ModdedSpeciesFormatsData} = {
|
||||
bulbasaur: {
|
||||
tier: "LC",
|
||||
},
|
||||
ivysaur: {
|
||||
tier: "ZU",
|
||||
tier: "NFE",
|
||||
},
|
||||
venusaur: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -12,7 +12,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
charmeleon: {
|
||||
tier: "ZUBL",
|
||||
tier: "NFE",
|
||||
},
|
||||
charizard: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -21,7 +21,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
wartortle: {
|
||||
tier: "PU",
|
||||
tier: "NFE",
|
||||
},
|
||||
blastoise: {
|
||||
tier: "UU",
|
||||
|
|
@ -33,7 +33,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
butterfree: {
|
||||
tier: "ZU",
|
||||
tier: "NU",
|
||||
},
|
||||
weedle: {
|
||||
tier: "LC",
|
||||
|
|
@ -42,7 +42,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
beedrill: {
|
||||
tier: "ZUBL",
|
||||
tier: "NU",
|
||||
},
|
||||
pidgey: {
|
||||
tier: "LC",
|
||||
|
|
@ -57,7 +57,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
raticate: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
spearow: {
|
||||
tier: "LC",
|
||||
|
|
@ -69,7 +69,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
arbok: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
pichu: {
|
||||
tier: "LC",
|
||||
|
|
@ -90,7 +90,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
nidorina: {
|
||||
tier: "ZU",
|
||||
tier: "NFE",
|
||||
},
|
||||
nidoqueen: {
|
||||
tier: "UU",
|
||||
|
|
@ -108,7 +108,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
clefairy: {
|
||||
tier: "PU",
|
||||
tier: "NFE",
|
||||
},
|
||||
clefable: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -132,7 +132,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
golbat: {
|
||||
tier: "PU",
|
||||
tier: "NFE",
|
||||
},
|
||||
crobat: {
|
||||
tier: "UU",
|
||||
|
|
@ -153,13 +153,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
parasect: {
|
||||
tier: "ZU",
|
||||
tier: "NU",
|
||||
},
|
||||
venonat: {
|
||||
tier: "LC",
|
||||
},
|
||||
venomoth: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
diglett: {
|
||||
tier: "LC",
|
||||
|
|
@ -168,7 +168,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NU",
|
||||
},
|
||||
meowth: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
persian: {
|
||||
tier: "NU",
|
||||
|
|
@ -192,10 +192,10 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
poliwag: {
|
||||
tier: "ZUBL",
|
||||
tier: "LC",
|
||||
},
|
||||
poliwhirl: {
|
||||
tier: "PUBL",
|
||||
tier: "NU",
|
||||
},
|
||||
poliwrath: {
|
||||
tier: "NUBL",
|
||||
|
|
@ -204,19 +204,19 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
abra: {
|
||||
tier: "PU",
|
||||
tier: "LC",
|
||||
},
|
||||
kadabra: {
|
||||
tier: "UU",
|
||||
},
|
||||
alakazam: {
|
||||
tier: "OU",
|
||||
tier: "UUBL",
|
||||
},
|
||||
machop: {
|
||||
tier: "LC",
|
||||
},
|
||||
machoke: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
machamp: {
|
||||
tier: "OU",
|
||||
|
|
@ -225,19 +225,19 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
weepinbell: {
|
||||
tier: "ZU",
|
||||
tier: "NFE",
|
||||
},
|
||||
victreebel: {
|
||||
tier: "UU",
|
||||
},
|
||||
tentacool: {
|
||||
tier: "ZU",
|
||||
tier: "NU",
|
||||
},
|
||||
tentacruel: {
|
||||
tier: "UUBL",
|
||||
},
|
||||
geodude: {
|
||||
tier: "PU",
|
||||
tier: "LC",
|
||||
},
|
||||
graveler: {
|
||||
tier: "NU",
|
||||
|
|
@ -246,13 +246,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "OU",
|
||||
},
|
||||
ponyta: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
rapidash: {
|
||||
tier: "NU",
|
||||
},
|
||||
slowpoke: {
|
||||
tier: "LC",
|
||||
tier: "NU",
|
||||
},
|
||||
slowbro: {
|
||||
tier: "UU",
|
||||
|
|
@ -267,10 +267,10 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
farfetchd: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
doduo: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
dodrio: {
|
||||
tier: "UU",
|
||||
|
|
@ -282,10 +282,10 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NU",
|
||||
},
|
||||
grimer: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
muk: {
|
||||
tier: "UU",
|
||||
tier: "UUBL",
|
||||
},
|
||||
shellder: {
|
||||
tier: "LC",
|
||||
|
|
@ -294,7 +294,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "OU",
|
||||
},
|
||||
gastly: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
haunter: {
|
||||
tier: "UU",
|
||||
|
|
@ -303,13 +303,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "OU",
|
||||
},
|
||||
onix: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
steelix: {
|
||||
tier: "OU",
|
||||
},
|
||||
drowzee: {
|
||||
tier: "PU",
|
||||
tier: "LC",
|
||||
},
|
||||
hypno: {
|
||||
tier: "UU",
|
||||
|
|
@ -321,7 +321,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NU",
|
||||
},
|
||||
voltorb: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
electrode: {
|
||||
tier: "UU",
|
||||
|
|
@ -333,7 +333,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "OU",
|
||||
},
|
||||
cubone: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
marowak: {
|
||||
tier: "OU",
|
||||
|
|
@ -345,7 +345,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NU",
|
||||
},
|
||||
hitmonchan: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
hitmontop: {
|
||||
tier: "NU",
|
||||
|
|
@ -354,13 +354,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NU",
|
||||
},
|
||||
koffing: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
weezing: {
|
||||
tier: "NU",
|
||||
},
|
||||
rhyhorn: {
|
||||
tier: "PU",
|
||||
tier: "LC",
|
||||
},
|
||||
rhydon: {
|
||||
tier: "OU",
|
||||
|
|
@ -372,7 +372,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "OU",
|
||||
},
|
||||
tangela: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
kangaskhan: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -381,7 +381,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
seadra: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
kingdra: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -390,10 +390,10 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
seaking: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
staryu: {
|
||||
tier: "ZUBL",
|
||||
tier: "LC",
|
||||
},
|
||||
starmie: {
|
||||
tier: "OU",
|
||||
|
|
@ -414,13 +414,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "OU",
|
||||
},
|
||||
elekid: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
electabuzz: {
|
||||
tier: "UU",
|
||||
},
|
||||
magby: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
magmar: {
|
||||
tier: "NU",
|
||||
|
|
@ -441,16 +441,16 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UUBL",
|
||||
},
|
||||
ditto: {
|
||||
tier: "ZU",
|
||||
tier: "NU",
|
||||
},
|
||||
eevee: {
|
||||
tier: "ZUBL",
|
||||
tier: "LC",
|
||||
},
|
||||
vaporeon: {
|
||||
tier: "OU",
|
||||
},
|
||||
jolteon: {
|
||||
tier: "OU",
|
||||
tier: "UUBL",
|
||||
},
|
||||
flareon: {
|
||||
tier: "NU",
|
||||
|
|
@ -468,7 +468,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UUBL",
|
||||
},
|
||||
omanyte: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
omastar: {
|
||||
tier: "UU",
|
||||
|
|
@ -480,7 +480,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
aerodactyl: {
|
||||
tier: "UU",
|
||||
tier: "UUBL",
|
||||
},
|
||||
snorlax: {
|
||||
tier: "OU",
|
||||
|
|
@ -513,7 +513,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
bayleef: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
meganium: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -522,7 +522,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
quilava: {
|
||||
tier: "ZU",
|
||||
tier: "NFE",
|
||||
},
|
||||
typhlosion: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -531,22 +531,22 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
croconaw: {
|
||||
tier: "ZU",
|
||||
tier: "NFE",
|
||||
},
|
||||
feraligatr: {
|
||||
tier: "UU",
|
||||
tier: "NUBL",
|
||||
},
|
||||
sentret: {
|
||||
tier: "LC",
|
||||
},
|
||||
furret: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
hoothoot: {
|
||||
tier: "LC",
|
||||
},
|
||||
noctowl: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
ledyba: {
|
||||
tier: "LC",
|
||||
|
|
@ -558,7 +558,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
ariados: {
|
||||
tier: "ZUBL",
|
||||
tier: "NU",
|
||||
},
|
||||
chinchou: {
|
||||
tier: "NU",
|
||||
|
|
@ -570,7 +570,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
togetic: {
|
||||
tier: "ZU",
|
||||
tier: "NU",
|
||||
},
|
||||
natu: {
|
||||
tier: "LC",
|
||||
|
|
@ -582,7 +582,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
flaaffy: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
ampharos: {
|
||||
tier: "UU",
|
||||
|
|
@ -591,7 +591,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
azumarill: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
sudowoodo: {
|
||||
tier: "NU",
|
||||
|
|
@ -606,16 +606,16 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
aipom: {
|
||||
tier: "ZU",
|
||||
tier: "NU",
|
||||
},
|
||||
sunkern: {
|
||||
tier: "LC",
|
||||
},
|
||||
sunflora: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
yanma: {
|
||||
tier: "ZU",
|
||||
tier: "NU",
|
||||
},
|
||||
wooper: {
|
||||
tier: "LC",
|
||||
|
|
@ -624,16 +624,16 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
murkrow: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
misdreavus: {
|
||||
tier: "OU",
|
||||
},
|
||||
unown: {
|
||||
tier: "ZU",
|
||||
tier: "NU",
|
||||
},
|
||||
wobbuffet: {
|
||||
tier: "ZU",
|
||||
tier: "NU",
|
||||
},
|
||||
girafarig: {
|
||||
tier: "UU",
|
||||
|
|
@ -645,7 +645,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "OU",
|
||||
},
|
||||
dunsparce: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
gligar: {
|
||||
tier: "UU",
|
||||
|
|
@ -666,7 +666,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "OU",
|
||||
},
|
||||
sneasel: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
teddiursa: {
|
||||
tier: "LC",
|
||||
|
|
@ -678,7 +678,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
magcargo: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
swinub: {
|
||||
tier: "LC",
|
||||
|
|
@ -687,7 +687,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
corsola: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
remoraid: {
|
||||
tier: "LC",
|
||||
|
|
@ -696,16 +696,16 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NU",
|
||||
},
|
||||
delibird: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
mantine: {
|
||||
tier: "ZUBL",
|
||||
tier: "NU",
|
||||
},
|
||||
skarmory: {
|
||||
tier: "OU",
|
||||
},
|
||||
houndour: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
houndoom: {
|
||||
tier: "UUBL",
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
||||
export const Items: {[k: string]: ModdedItemData} = {
|
||||
berryjuice: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
},
|
||||
blackbelt: {
|
||||
inherit: true,
|
||||
onModifyAtk: undefined, // no inherit
|
||||
onModifyAtk() {},
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Fighting') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -14,7 +14,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
blackglasses: {
|
||||
inherit: true,
|
||||
onModifySpA: undefined, // no inherit
|
||||
onModifySpA() {},
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Dark') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -31,7 +31,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
charcoal: {
|
||||
inherit: true,
|
||||
onModifySpA: undefined, // no inherit
|
||||
onModifySpA() {},
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Fire') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -40,7 +40,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
dragonfang: {
|
||||
inherit: true,
|
||||
onModifySpA: undefined, // no inherit
|
||||
onModifySpA() {},
|
||||
},
|
||||
dragonscale: {
|
||||
inherit: true,
|
||||
|
|
@ -65,7 +65,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
hardstone: {
|
||||
inherit: true,
|
||||
onModifyAtk: undefined, // no inherit
|
||||
onModifyAtk() {},
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Rock') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -106,7 +106,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
lightball: {
|
||||
inherit: true,
|
||||
// In Gen 2 this happens in stat calculation directly.
|
||||
onModifySpA: undefined, // no inherit
|
||||
onModifySpA() {},
|
||||
},
|
||||
loveball: {
|
||||
inherit: true,
|
||||
|
|
@ -127,7 +127,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
magnet: {
|
||||
inherit: true,
|
||||
onModifySpA: undefined, // no inherit
|
||||
onModifySpA() {},
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Electric') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -136,7 +136,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
metalcoat: {
|
||||
inherit: true,
|
||||
onModifyAtk: undefined, // no inherit
|
||||
onModifyAtk() {},
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Steel') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -146,12 +146,12 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
metalpowder: {
|
||||
inherit: true,
|
||||
// In Gen 2 this happens in stat calculation directly.
|
||||
onModifyDef: undefined, // no inherit
|
||||
onModifySpD: undefined, // no inherit
|
||||
onModifyDef() {},
|
||||
onModifySpD() {},
|
||||
},
|
||||
miracleseed: {
|
||||
inherit: true,
|
||||
onModifySpA: undefined, // no inherit
|
||||
onModifySpA() {},
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Grass') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -164,7 +164,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
mysticwater: {
|
||||
inherit: true,
|
||||
onModifySpA: undefined, // no inherit
|
||||
onModifySpA() {},
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Water') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -173,7 +173,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
nevermeltice: {
|
||||
inherit: true,
|
||||
onModifySpA: undefined, // no inherit
|
||||
onModifySpA() {},
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Ice') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -182,7 +182,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
poisonbarb: {
|
||||
inherit: true,
|
||||
onModifyAtk: undefined, // no inherit
|
||||
onModifyAtk() {},
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Poison') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -191,7 +191,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
sharpbeak: {
|
||||
inherit: true,
|
||||
onModifyAtk: undefined, // no inherit
|
||||
onModifyAtk() {},
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Flying') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -200,7 +200,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
silverpowder: {
|
||||
inherit: true,
|
||||
onModifyAtk: undefined, // no inherit
|
||||
onModifyAtk() {},
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Bug') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -209,7 +209,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
softsand: {
|
||||
inherit: true,
|
||||
onModifyAtk: undefined, // no inherit
|
||||
onModifyAtk() {},
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Ground') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -218,7 +218,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
spelltag: {
|
||||
inherit: true,
|
||||
onModifyAtk: undefined, // no inherit
|
||||
onModifyAtk() {},
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Ghost') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -241,22 +241,22 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
thickclub: {
|
||||
inherit: true,
|
||||
// In Gen 2 this happens in stat calculation directly.
|
||||
onModifyAtk: undefined, // no inherit
|
||||
onModifyAtk() {},
|
||||
},
|
||||
twistedspoon: {
|
||||
inherit: true,
|
||||
onModifySpA: undefined, // no inherit
|
||||
onModifySpA() {},
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Psychic') {
|
||||
return damage * 1.1;
|
||||
}
|
||||
},
|
||||
},
|
||||
berry: {
|
||||
berserkgene: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
},
|
||||
berserkgene: {
|
||||
berry: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
},
|
||||
|
|
@ -290,7 +290,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
pinkbow: {
|
||||
inherit: true,
|
||||
onBasePower: undefined, // no inherit
|
||||
onBasePower() {},
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Normal') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -300,7 +300,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
polkadotbow: {
|
||||
inherit: true,
|
||||
onBasePower: undefined, // no inherit
|
||||
onBasePower() {},
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Normal') {
|
||||
return damage * 1.1;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const Learnsets: import('../../../sim/dex-species').ModdedLearnsetDataTable = {
|
||||
export const Learnsets: {[k: string]: ModdedLearnsetData} = {
|
||||
missingno: {
|
||||
learnset: {
|
||||
blizzard: ["1M"],
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
* Gen 2 moves
|
||||
*/
|
||||
|
||||
export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
||||
export const Moves: {[k: string]: ModdedMoveData} = {
|
||||
aeroblast: {
|
||||
inherit: true,
|
||||
critRatio: 3,
|
||||
|
|
@ -23,7 +23,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
return false;
|
||||
}
|
||||
if (target.hp <= target.maxhp / 2) {
|
||||
this.boost({ atk: 2 }, null, null, this.dex.conditions.get('bellydrum2'));
|
||||
this.boost({atk: 2}, null, null, this.dex.conditions.get('bellydrum2'));
|
||||
return false;
|
||||
}
|
||||
this.directDamage(target.maxhp / 2);
|
||||
|
|
@ -45,16 +45,70 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
}
|
||||
boosts = target.boosts.atk - originalStage;
|
||||
target.boosts.atk = originalStage;
|
||||
this.boost({ atk: boosts });
|
||||
this.boost({atk: boosts});
|
||||
},
|
||||
},
|
||||
bide: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
duration: 3,
|
||||
durationCallback(target, source, effect) {
|
||||
return this.random(3, 5);
|
||||
},
|
||||
onLockMove: 'bide',
|
||||
onStart(pokemon) {
|
||||
this.effectState.totalDamage = 0;
|
||||
this.add('-start', pokemon, 'move: Bide');
|
||||
},
|
||||
onDamagePriority: -101,
|
||||
onDamage(damage, target, source, move) {
|
||||
if (!move || move.effectType !== 'Move' || !source) return;
|
||||
this.effectState.totalDamage += damage;
|
||||
this.effectState.lastDamageSource = source;
|
||||
},
|
||||
onBeforeMove(pokemon, target, move) {
|
||||
if (this.effectState.duration === 1) {
|
||||
this.add('-end', pokemon, 'move: Bide');
|
||||
if (!this.effectState.totalDamage) {
|
||||
this.add('-fail', pokemon);
|
||||
return false;
|
||||
}
|
||||
target = this.effectState.lastDamageSource;
|
||||
if (!target) {
|
||||
this.add('-fail', pokemon);
|
||||
return false;
|
||||
}
|
||||
if (!target.isActive) {
|
||||
const possibleTarget = this.getRandomTarget(pokemon, this.dex.moves.get('pound'));
|
||||
if (!possibleTarget) {
|
||||
this.add('-miss', pokemon);
|
||||
return false;
|
||||
}
|
||||
target = possibleTarget;
|
||||
}
|
||||
const moveData = {
|
||||
id: 'bide',
|
||||
name: "Bide",
|
||||
accuracy: 100,
|
||||
damage: this.effectState.totalDamage * 2,
|
||||
category: "Physical",
|
||||
priority: 0,
|
||||
flags: {contact: 1, protect: 1},
|
||||
effectType: 'Move',
|
||||
type: 'Normal',
|
||||
} as unknown as ActiveMove;
|
||||
this.actions.tryMoveHit(target, pokemon, moveData);
|
||||
pokemon.removeVolatile('bide');
|
||||
return false;
|
||||
}
|
||||
this.add('-activate', pokemon, 'move: Bide');
|
||||
},
|
||||
onMoveAborted(pokemon) {
|
||||
pokemon.removeVolatile('bide');
|
||||
},
|
||||
onEnd(pokemon) {
|
||||
this.add('-end', pokemon, 'move: Bide', '[silent]');
|
||||
},
|
||||
},
|
||||
},
|
||||
counter: {
|
||||
|
|
@ -69,8 +123,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
}
|
||||
return false;
|
||||
},
|
||||
beforeTurnCallback: undefined, // no inherit
|
||||
onTry: undefined, // no inherit
|
||||
beforeTurnCallback() {},
|
||||
onTry() {},
|
||||
condition: {},
|
||||
priority: -1,
|
||||
},
|
||||
|
|
@ -85,12 +139,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
curse: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
onAfterMoveSelfPriority: 0, // explicit
|
||||
onStart(pokemon, source) {
|
||||
this.add('-start', pokemon, 'Curse', '[of] ' + source);
|
||||
},
|
||||
onAfterMoveSelf(pokemon) {
|
||||
this.damage(pokemon.baseMaxhp / 4);
|
||||
},
|
||||
onResidual: undefined, // no inherit
|
||||
},
|
||||
},
|
||||
detect: {
|
||||
|
|
@ -103,7 +157,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
return source.status !== 'slp';
|
||||
},
|
||||
condition: {
|
||||
inherit: true,
|
||||
duration: 2,
|
||||
onImmunity(type, pokemon) {
|
||||
if (type === 'sandstorm') return false;
|
||||
},
|
||||
onInvulnerability(target, source, move) {
|
||||
if (move.id === 'earthquake' || move.id === 'magnitude' || move.id === 'fissure') {
|
||||
return;
|
||||
|
|
@ -115,7 +172,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
if (source.volatiles['lockon'] && target === source.volatiles['lockon'].source) return;
|
||||
return false;
|
||||
},
|
||||
onSourceModifyDamage: undefined, // no inherit
|
||||
onSourceBasePower(basePower, target, source, move) {
|
||||
if (move.id === 'earthquake' || move.id === 'magnitude') {
|
||||
return this.chainModify(2);
|
||||
|
|
@ -130,19 +186,43 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
encore: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
durationCallback() {
|
||||
return this.random(3, 7);
|
||||
},
|
||||
onStart(target) {
|
||||
const lockedMove = target.lastMoveEncore?.id || '';
|
||||
const moveSlot = lockedMove ? target.getMoveData(lockedMove) : null;
|
||||
if (!moveSlot || target.lastMoveEncore?.flags['failencore'] || moveSlot.pp <= 0) {
|
||||
const moveIndex = lockedMove ? target.moves.indexOf(lockedMove) : -1;
|
||||
if (moveIndex < 0 || target.lastMoveEncore?.flags['failencore'] || target.moveSlots[moveIndex].pp <= 0) {
|
||||
// it failed
|
||||
return false;
|
||||
}
|
||||
this.effectState.move = lockedMove;
|
||||
this.add('-start', target, 'Encore');
|
||||
},
|
||||
onOverrideAction(pokemon) {
|
||||
return this.effectState.move;
|
||||
},
|
||||
onResidualOrder: 13,
|
||||
onResidualSubOrder: undefined, // no inherit
|
||||
onResidual(target) {
|
||||
const lockedMoveIndex = target.moves.indexOf(this.effectState.move);
|
||||
if (lockedMoveIndex >= 0 && target.moveSlots[lockedMoveIndex].pp <= 0) {
|
||||
// early termination if you run out of PP
|
||||
target.removeVolatile('encore');
|
||||
}
|
||||
},
|
||||
onEnd(target) {
|
||||
this.add('-end', target, 'Encore');
|
||||
},
|
||||
onDisableMove(pokemon) {
|
||||
if (!this.effectState.move || !pokemon.hasMove(this.effectState.move)) {
|
||||
return;
|
||||
}
|
||||
for (const moveSlot of pokemon.moveSlots) {
|
||||
if (moveSlot.id !== this.effectState.move) {
|
||||
pokemon.disableMove(moveSlot.id);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
endure: {
|
||||
|
|
@ -151,7 +231,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
explosion: {
|
||||
inherit: true,
|
||||
flags: { protect: 1, mirror: 1, metronome: 1, noparentalbond: 1, nosketch: 1 },
|
||||
noSketch: true,
|
||||
},
|
||||
flail: {
|
||||
inherit: true,
|
||||
|
|
@ -164,7 +244,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
return source.status !== 'slp';
|
||||
},
|
||||
condition: {
|
||||
inherit: true,
|
||||
duration: 2,
|
||||
onInvulnerability(target, source, move) {
|
||||
if (move.id === 'gust' || move.id === 'twister' || move.id === 'thunder' || move.id === 'whirlwind') {
|
||||
return;
|
||||
|
|
@ -180,7 +260,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
if (source.volatiles['lockon'] && target === source.volatiles['lockon'].source) return;
|
||||
return false;
|
||||
},
|
||||
onSourceModifyDamage: undefined, // no inherit
|
||||
onSourceBasePower(basePower, target, source, move) {
|
||||
if (move.id === 'gust' || move.id === 'twister') {
|
||||
return this.chainModify(2);
|
||||
|
|
@ -191,7 +270,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
focusenergy: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
onStart(pokemon) {
|
||||
this.add('-start', pokemon, 'move: Focus Energy');
|
||||
},
|
||||
onModifyCritRatio(critRatio) {
|
||||
return critRatio + 1;
|
||||
},
|
||||
|
|
@ -203,8 +284,17 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
if (target.volatiles['foresight']) return false;
|
||||
},
|
||||
condition: {
|
||||
inherit: true,
|
||||
noCopy: false,
|
||||
onStart(pokemon) {
|
||||
this.add('-start', pokemon, 'Foresight');
|
||||
},
|
||||
onNegateImmunity(pokemon, type) {
|
||||
if (pokemon.hasType('Ghost') && ['Normal', 'Fighting'].includes(type)) return false;
|
||||
},
|
||||
onModifyBoost(boosts) {
|
||||
if (boosts.evasion && boosts.evasion > 0) {
|
||||
boosts.evasion = 0;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
frustration: {
|
||||
|
|
@ -248,10 +338,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
leechseed: {
|
||||
inherit: true,
|
||||
onHit: undefined, // no inherit
|
||||
onHit() {},
|
||||
condition: {
|
||||
inherit: true,
|
||||
onResidual: undefined, // no inherit
|
||||
onStart(target) {
|
||||
this.add('-start', target, 'move: Leech Seed');
|
||||
},
|
||||
onAfterMoveSelfPriority: 2,
|
||||
onAfterMoveSelf(pokemon) {
|
||||
if (!pokemon.hp) return;
|
||||
|
|
@ -287,15 +378,19 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
if (target.volatiles['foresight'] || target.volatiles['lockon']) return false;
|
||||
},
|
||||
condition: {
|
||||
inherit: true,
|
||||
onSourceInvulnerability: undefined, // no inherit
|
||||
duration: 2,
|
||||
onSourceAccuracy(accuracy, target, source, move) {
|
||||
if (move && source === this.effectState.target && target === this.effectState.source) return true;
|
||||
},
|
||||
},
|
||||
},
|
||||
lowkick: {
|
||||
inherit: true,
|
||||
accuracy: 90,
|
||||
basePower: 50,
|
||||
basePowerCallback: undefined, // no inherit
|
||||
basePowerCallback() {
|
||||
return 50;
|
||||
},
|
||||
secondary: {
|
||||
chance: 30,
|
||||
volatileStatus: 'flinch',
|
||||
|
|
@ -303,16 +398,21 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
meanlook: {
|
||||
inherit: true,
|
||||
flags: { reflectable: 1, mirror: 1, metronome: 1 },
|
||||
flags: {reflectable: 1, mirror: 1},
|
||||
},
|
||||
metronome: {
|
||||
inherit: true,
|
||||
flags: { failencore: 1, nosketch: 1 },
|
||||
flags: {failencore: 1},
|
||||
noMetronome: [
|
||||
"Counter", "Destiny Bond", "Detect", "Endure", "Metronome", "Mimic", "Mirror Coat", "Protect", "Sketch", "Sleep Talk", "Struggle", "Thief",
|
||||
],
|
||||
noSketch: true,
|
||||
},
|
||||
mimic: {
|
||||
inherit: true,
|
||||
accuracy: 100,
|
||||
flags: { protect: 1, bypasssub: 1, allyanim: 1, failencore: 1, noassist: 1, nosketch: 1 },
|
||||
noSketch: true,
|
||||
flags: {protect: 1, bypasssub: 1, allyanim: 1, failencore: 1, noassist: 1},
|
||||
},
|
||||
mindreader: {
|
||||
inherit: true,
|
||||
|
|
@ -332,14 +432,14 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
}
|
||||
return false;
|
||||
},
|
||||
beforeTurnCallback: undefined, // no inherit
|
||||
onTry: undefined, // no inherit
|
||||
beforeTurnCallback() {},
|
||||
onTry() {},
|
||||
condition: {},
|
||||
priority: -1,
|
||||
},
|
||||
mirrormove: {
|
||||
inherit: true,
|
||||
flags: { metronome: 1, failencore: 1, nosketch: 1 },
|
||||
flags: {failencore: 1},
|
||||
onHit(pokemon) {
|
||||
const noMirror = ['metronome', 'mimic', 'mirrormove', 'sketch', 'sleeptalk', 'transform'];
|
||||
const target = pokemon.side.foe.active[0];
|
||||
|
|
@ -352,11 +452,18 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
}
|
||||
this.actions.useMove(lastMove, pokemon);
|
||||
},
|
||||
noSketch: true,
|
||||
},
|
||||
mist: {
|
||||
inherit: true,
|
||||
num: 54,
|
||||
accuracy: true,
|
||||
basePower: 0,
|
||||
category: "Status",
|
||||
name: "Mist",
|
||||
pp: 30,
|
||||
priority: 0,
|
||||
flags: {},
|
||||
volatileStatus: 'mist',
|
||||
sideCondition: undefined, // no inherit
|
||||
condition: {
|
||||
onStart(pokemon) {
|
||||
this.add('-start', pokemon, 'Mist');
|
||||
|
|
@ -377,7 +484,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
}
|
||||
},
|
||||
},
|
||||
secondary: null,
|
||||
target: "self",
|
||||
type: "Ice",
|
||||
},
|
||||
moonlight: {
|
||||
inherit: true,
|
||||
|
|
@ -406,8 +515,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
nightmare: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
onResidual: undefined, // no inherit
|
||||
noCopy: true,
|
||||
onStart(pokemon) {
|
||||
if (pokemon.status !== 'slp') {
|
||||
return false;
|
||||
}
|
||||
this.add('-start', pokemon, 'Nightmare');
|
||||
},
|
||||
onAfterMoveSelfPriority: 1,
|
||||
onAfterMoveSelf(pokemon) {
|
||||
if (pokemon.status === 'slp') this.damage(pokemon.baseMaxhp / 4);
|
||||
|
|
@ -419,6 +533,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
onMoveFail(target, source, move) {
|
||||
source.addVolatile('lockedmove');
|
||||
},
|
||||
onAfterMove(pokemon) {
|
||||
if (pokemon.volatiles['lockedmove'] && pokemon.volatiles['lockedmove'].duration === 1) {
|
||||
pokemon.removeVolatile('lockedmove');
|
||||
}
|
||||
},
|
||||
},
|
||||
painsplit: {
|
||||
inherit: true,
|
||||
|
|
@ -427,8 +546,16 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
perishsong: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
duration: 4,
|
||||
onEnd(target) {
|
||||
this.add('-start', target, 'perish0');
|
||||
target.faint();
|
||||
},
|
||||
onResidualOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
const duration = pokemon.volatiles['perishsong'].duration;
|
||||
this.add('-start', pokemon, 'perish' + duration);
|
||||
},
|
||||
},
|
||||
},
|
||||
petaldance: {
|
||||
|
|
@ -436,6 +563,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
onMoveFail(target, source, move) {
|
||||
source.addVolatile('lockedmove');
|
||||
},
|
||||
onAfterMove(pokemon) {
|
||||
if (pokemon.volatiles['lockedmove'] && pokemon.volatiles['lockedmove'].duration === 1) {
|
||||
pokemon.removeVolatile('lockedmove');
|
||||
}
|
||||
},
|
||||
},
|
||||
poisongas: {
|
||||
inherit: true,
|
||||
|
|
@ -457,23 +589,14 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
pursuit: {
|
||||
inherit: true,
|
||||
beforeTurnCallback(pokemon, target) {
|
||||
if (pokemon.isAlly(target)) return;
|
||||
target.addVolatile('pursuit');
|
||||
const data = target.volatiles['pursuit'];
|
||||
if (!data.sources) {
|
||||
data.sources = [];
|
||||
}
|
||||
data.sources.push(pokemon);
|
||||
},
|
||||
onModifyMove: undefined, // no inherit
|
||||
onModifyMove() {},
|
||||
condition: {
|
||||
inherit: true,
|
||||
duration: 1,
|
||||
onBeforeSwitchOut(pokemon) {
|
||||
this.debug('Pursuit start');
|
||||
let alreadyAdded = false;
|
||||
for (const source of this.effectState.sources) {
|
||||
if (source.speed < pokemon.speed || (source.speed === pokemon.speed && this.randomChance(1, 2))) {
|
||||
if (source.speed < pokemon.speed || (source.speed === pokemon.speed && this.random(2) === 0)) {
|
||||
// Destiny Bond ends if the switch action "outspeeds" the attacker, regardless of host
|
||||
pokemon.removeVolatile('destinybond');
|
||||
}
|
||||
|
|
@ -542,6 +665,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
target.statusState.source = target;
|
||||
this.heal(target.maxhp);
|
||||
},
|
||||
secondary: null,
|
||||
},
|
||||
return: {
|
||||
inherit: true,
|
||||
|
|
@ -567,17 +691,50 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
safeguard: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
duration: 5,
|
||||
durationCallback(target, source, effect) {
|
||||
if (source?.hasAbility('persistent')) {
|
||||
this.add('-activate', source, 'ability: Persistent', effect);
|
||||
return 7;
|
||||
}
|
||||
return 5;
|
||||
},
|
||||
onSetStatus(status, target, source, effect) {
|
||||
if (!effect || !source) return;
|
||||
if (effect.id === 'yawn') return;
|
||||
if (effect.effectType === 'Move' && effect.infiltrates && !target.isAlly(source)) return;
|
||||
if (target !== source) {
|
||||
this.debug('interrupting setStatus');
|
||||
if (effect.id === 'synchronize' || (effect.effectType === 'Move' && !effect.secondaries)) {
|
||||
this.add('-activate', target, 'move: Safeguard');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
},
|
||||
onTryAddVolatile(status, target, source, effect) {
|
||||
if (!effect || !source) return;
|
||||
if (effect.effectType === 'Move' && effect.infiltrates && !target.isAlly(source)) return;
|
||||
if ((status.id === 'confusion' || status.id === 'yawn') && target !== source) {
|
||||
if (effect.effectType === 'Move' && !effect.secondaries) this.add('-activate', target, 'move: Safeguard');
|
||||
return null;
|
||||
}
|
||||
},
|
||||
onSideStart(side) {
|
||||
this.add('-sidestart', side, 'Safeguard');
|
||||
},
|
||||
onSideResidualOrder: 8,
|
||||
onSideEnd(side) {
|
||||
this.add('-sideend', side, 'Safeguard');
|
||||
},
|
||||
},
|
||||
},
|
||||
selfdestruct: {
|
||||
inherit: true,
|
||||
flags: { protect: 1, mirror: 1, metronome: 1, noparentalbond: 1, nosketch: 1 },
|
||||
noSketch: true,
|
||||
},
|
||||
sketch: {
|
||||
inherit: true,
|
||||
flags: { bypasssub: 1, failencore: 1, noassist: 1, nosketch: 1 },
|
||||
flags: {bypasssub: 1, failencore: 1, noassist: 1},
|
||||
onHit() {
|
||||
// Sketch always fails in Link Battles
|
||||
this.add('-nothing');
|
||||
|
|
@ -595,7 +752,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
onPrepareHit(target, source) {
|
||||
return source.status !== 'slp';
|
||||
},
|
||||
secondary: undefined, // no inherit
|
||||
secondary: null,
|
||||
},
|
||||
slash: {
|
||||
inherit: true,
|
||||
|
|
@ -603,7 +760,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
sleeptalk: {
|
||||
inherit: true,
|
||||
flags: { failencore: 1, nosleeptalk: 1, nosketch: 1 },
|
||||
flags: {failencore: 1, nosleeptalk: 1},
|
||||
onHit(pokemon) {
|
||||
const moves = [];
|
||||
for (const moveSlot of pokemon.moveSlots) {
|
||||
|
|
@ -618,6 +775,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
if (!randomMove) return false;
|
||||
this.actions.useMove(randomMove, pokemon);
|
||||
},
|
||||
noSketch: true,
|
||||
},
|
||||
solarbeam: {
|
||||
inherit: true,
|
||||
|
|
@ -625,23 +783,40 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
return source.status !== 'slp';
|
||||
},
|
||||
// Rain weakening done directly in the damage formula
|
||||
onBasePower: undefined, // no inherit
|
||||
onBasePower() {},
|
||||
},
|
||||
spiderweb: {
|
||||
inherit: true,
|
||||
flags: { reflectable: 1, mirror: 1, metronome: 1 },
|
||||
flags: {reflectable: 1, mirror: 1},
|
||||
},
|
||||
spikes: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
onSideRestart: undefined, // no inherit
|
||||
// this is a side condition
|
||||
onSideStart(side) {
|
||||
if (!this.effectState.layers || this.effectState.layers === 0) {
|
||||
this.add('-sidestart', side, 'Spikes');
|
||||
this.effectState.layers = 1;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onSwitchIn(pokemon) {
|
||||
if (!pokemon.runImmunity('Ground')) return;
|
||||
const damageAmounts = [0, 3];
|
||||
this.damage(damageAmounts[this.effectState.layers] * pokemon.maxhp / 24);
|
||||
},
|
||||
},
|
||||
},
|
||||
substitute: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
onStart(target) {
|
||||
this.add('-start', target, 'Substitute');
|
||||
this.effectState.hp = Math.floor(target.maxhp / 4);
|
||||
delete target.volatiles['partiallytrapped'];
|
||||
},
|
||||
onTryPrimaryHitPriority: -1,
|
||||
onTryPrimaryHit(target, source, move) {
|
||||
if (move.stallingMove) {
|
||||
this.add('-fail', source);
|
||||
|
|
@ -678,6 +853,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
if (!damage) {
|
||||
return null;
|
||||
}
|
||||
damage = this.runEvent('SubDamage', target, source, move, damage);
|
||||
if (!damage) {
|
||||
return damage;
|
||||
}
|
||||
if (damage > target.volatiles['substitute'].hp) {
|
||||
damage = target.volatiles['substitute'].hp as number;
|
||||
}
|
||||
|
|
@ -694,6 +873,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
this.runEvent('AfterSubDamage', target, source, move, damage);
|
||||
return this.HIT_SUBSTITUTE;
|
||||
},
|
||||
onEnd(target) {
|
||||
this.add('-end', target, 'Substitute');
|
||||
},
|
||||
},
|
||||
},
|
||||
swagger: {
|
||||
|
|
@ -719,7 +901,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
thief: {
|
||||
inherit: true,
|
||||
onAfterHit: undefined, // no inherit
|
||||
onAfterHit() {},
|
||||
secondary: {
|
||||
chance: 100,
|
||||
onHit(target, source) {
|
||||
|
|
@ -734,7 +916,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
target.item = yourItem.id; // bypass setItem so we don't break choicelock or anything
|
||||
return;
|
||||
}
|
||||
this.add('-item', source, yourItem, '[from] move: Thief', `[of] ${target}`);
|
||||
this.add('-item', source, yourItem, '[from] move: Thief', '[of] ' + target);
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -743,6 +925,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
onMoveFail(target, source, move) {
|
||||
source.addVolatile('lockedmove');
|
||||
},
|
||||
onAfterMove(pokemon) {
|
||||
if (pokemon.volatiles['lockedmove'] && pokemon.volatiles['lockedmove'].duration === 1) {
|
||||
pokemon.removeVolatile('lockedmove');
|
||||
}
|
||||
},
|
||||
},
|
||||
toxic: {
|
||||
inherit: true,
|
||||
|
|
@ -750,7 +937,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
transform: {
|
||||
inherit: true,
|
||||
flags: { bypasssub: 1, metronome: 1, failencore: 1, nosketch: 1 },
|
||||
noSketch: true,
|
||||
},
|
||||
triattack: {
|
||||
inherit: true,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const Pokedex: import('../../../sim/dex-species').ModdedSpeciesDataTable = {
|
||||
export const Pokedex: {[k: string]: ModdedSpeciesData} = {
|
||||
unown: {
|
||||
inherit: true,
|
||||
cosmeticFormes: ["Unown-B", "Unown-C", "Unown-D", "Unown-E", "Unown-F", "Unown-G", "Unown-H", "Unown-I", "Unown-J", "Unown-K", "Unown-L", "Unown-M", "Unown-N", "Unown-O", "Unown-P", "Unown-Q", "Unown-R", "Unown-S", "Unown-T", "Unown-U", "Unown-V", "Unown-W", "Unown-X", "Unown-Y", "Unown-Z"],
|
||||
|
|
|
|||
425
data/mods/gen2/random-data.json
Normal file
425
data/mods/gen2/random-data.json
Normal file
|
|
@ -0,0 +1,425 @@
|
|||
{
|
||||
"venusaur": {
|
||||
"moves": ["growth", "hiddenpowerfire", "hiddenpowerice", "leechseed", "razorleaf", "sleeppowder", "synthesis"]
|
||||
},
|
||||
"charizard": {
|
||||
"moves": ["bellydrum", "earthquake", "fireblast", "hyperbeam", "rockslide"]
|
||||
},
|
||||
"blastoise": {
|
||||
"moves": ["icebeam", "rapidspin", "rest", "sleeptalk", "surf", "toxic", "zapcannon"]
|
||||
},
|
||||
"butterfree": {
|
||||
"moves": ["nightmare", "psychic", "sleeppowder", "stunspore", "substitute"]
|
||||
},
|
||||
"beedrill": {
|
||||
"moves": ["agility", "hiddenpowerground", "sludgebomb", "substitute", "swordsdance"]
|
||||
},
|
||||
"pidgeot": {
|
||||
"moves": ["curse", "hiddenpowerground", "reflect", "rest", "return", "sleeptalk", "toxic", "whirlwind"]
|
||||
},
|
||||
"raticate": {
|
||||
"moves": ["irontail", "rest", "return", "sleeptalk", "superfang"]
|
||||
},
|
||||
"fearow": {
|
||||
"moves": ["doubleedge", "drillpeck", "hiddenpowerground", "rest", "sleeptalk", "substitute"]
|
||||
},
|
||||
"arbok": {
|
||||
"moves": ["curse", "earthquake", "glare", "haze", "rest", "sludgebomb"]
|
||||
},
|
||||
"pikachu": {
|
||||
"moves": ["encore", "hiddenpowerice", "substitute", "surf", "thunderbolt"]
|
||||
},
|
||||
"raichu": {
|
||||
"moves": ["encore", "hiddenpowerice", "rest", "sleeptalk", "surf", "thunder", "thunderbolt"]
|
||||
},
|
||||
"sandslash": {
|
||||
"moves": ["earthquake", "hiddenpowerbug", "rockslide", "substitute", "swordsdance"]
|
||||
},
|
||||
"nidoqueen": {
|
||||
"moves": ["earthquake", "fireblast", "icebeam", "lovelykiss", "moonlight", "thunder"]
|
||||
},
|
||||
"nidoking": {
|
||||
"moves": ["earthquake", "fireblast", "icebeam", "lovelykiss", "morningsun", "thunder"]
|
||||
},
|
||||
"clefable": {
|
||||
"moves": ["bellydrum", "encore", "fireblast", "moonlight", "return", "shadowball"]
|
||||
},
|
||||
"ninetales": {
|
||||
"moves": ["confuseray", "fireblast", "hiddenpowergrass", "hypnosis", "sunnyday"]
|
||||
},
|
||||
"wigglytuff": {
|
||||
"moves": ["bodyslam", "charm", "curse", "doubleedge", "fireblast", "rest", "sleeptalk", "thunderwave"]
|
||||
},
|
||||
"vileplume": {
|
||||
"moves": ["hiddenpowergrass", "moonlight", "sleeppowder", "sludgebomb", "stunspore", "swordsdance"]
|
||||
},
|
||||
"parasect": {
|
||||
"moves": ["bodyslam", "gigadrain", "hiddenpowerbug", "spore", "swordsdance", "synthesis"]
|
||||
},
|
||||
"venomoth": {
|
||||
"moves": ["disable", "gigadrain", "psychic", "sleeppowder", "sludgebomb", "stunspore"]
|
||||
},
|
||||
"dugtrio": {
|
||||
"moves": ["earthquake", "rockslide", "sludgebomb", "substitute", "swagger"]
|
||||
},
|
||||
"persian": {
|
||||
"moves": ["bodyslam", "hypnosis", "irontail", "rest", "return", "thunder"]
|
||||
},
|
||||
"golduck": {
|
||||
"moves": ["crosschop", "hiddenpowerelectric", "hydropump", "hypnosis", "icebeam", "psychic", "surf"]
|
||||
},
|
||||
"primeape": {
|
||||
"moves": ["crosschop", "doubleedge", "hiddenpowerghost", "meditate", "rest", "rockslide", "substitute"]
|
||||
},
|
||||
"arcanine": {
|
||||
"moves": ["bodyslam", "crunch", "extremespeed", "fireblast", "hiddenpowergrass", "rest", "sleeptalk"]
|
||||
},
|
||||
"poliwrath": {
|
||||
"moves": ["bellydrum", "bodyslam", "earthquake", "lovelykiss"]
|
||||
},
|
||||
"alakazam": {
|
||||
"moves": ["encore", "firepunch", "icepunch", "psychic", "recover", "thunderpunch", "thunderwave"]
|
||||
},
|
||||
"machamp": {
|
||||
"moves": ["bodyslam", "crosschop", "curse", "earthquake", "hiddenpowerghost", "rest", "rockslide", "sleeptalk"]
|
||||
},
|
||||
"victreebel": {
|
||||
"moves": ["hiddenpowerground", "razorleaf", "sleeppowder", "sludgebomb", "swordsdance", "synthesis"]
|
||||
},
|
||||
"tentacruel": {
|
||||
"moves": ["hydropump", "sludgebomb", "substitute", "swordsdance"]
|
||||
},
|
||||
"golem": {
|
||||
"moves": ["curse", "earthquake", "explosion", "fireblast", "rapidspin", "rockslide"]
|
||||
},
|
||||
"rapidash": {
|
||||
"moves": ["bodyslam", "fireblast", "hiddenpowergrass", "hypnosis", "sunnyday"]
|
||||
},
|
||||
"slowbro": {
|
||||
"moves": ["fireblast", "psychic", "rest", "sleeptalk", "surf", "thunderwave", "toxic"]
|
||||
},
|
||||
"magneton": {
|
||||
"moves": ["hiddenpowerice", "substitute", "thunderbolt", "thunderwave"]
|
||||
},
|
||||
"farfetchd": {
|
||||
"moves": ["agility", "batonpass", "return", "swordsdance"]
|
||||
},
|
||||
"dodrio": {
|
||||
"moves": ["doubleedge", "drillpeck", "hiddenpowerground", "rest", "substitute"]
|
||||
},
|
||||
"dewgong": {
|
||||
"moves": ["bodyslam", "encore", "icebeam", "rest", "sleeptalk", "surf", "toxic"]
|
||||
},
|
||||
"muk": {
|
||||
"moves": ["curse", "explosion", "fireblast", "hiddenpowerground", "sludgebomb"]
|
||||
},
|
||||
"cloyster": {
|
||||
"moves": ["explosion", "icebeam", "spikes", "surf", "toxic"]
|
||||
},
|
||||
"gengar": {
|
||||
"moves": ["destinybond", "explosion", "firepunch", "hypnosis", "icepunch", "thunderbolt"]
|
||||
},
|
||||
"hypno": {
|
||||
"moves": ["hypnosis", "lightscreen", "psychic", "reflect", "seismictoss", "thunderwave"]
|
||||
},
|
||||
"kingler": {
|
||||
"moves": ["hiddenpowerground", "rest", "return", "surf", "swordsdance"]
|
||||
},
|
||||
"electrode": {
|
||||
"moves": ["explosion", "hiddenpowerice", "lightscreen", "reflect", "thunderbolt", "thunderwave"]
|
||||
},
|
||||
"exeggutor": {
|
||||
"moves": ["explosion", "gigadrain", "hiddenpowerfire", "psychic", "sleeppowder", "stunspore", "synthesis"]
|
||||
},
|
||||
"marowak": {
|
||||
"moves": ["earthquake", "hiddenpowerbug", "rockslide", "swordsdance"]
|
||||
},
|
||||
"hitmonlee": {
|
||||
"moves": ["bodyslam", "hiddenpowerghost", "highjumpkick", "meditate", "rest"]
|
||||
},
|
||||
"hitmonchan": {
|
||||
"moves": ["bodyslam", "counter", "curse", "hiddenpowerghost", "highjumpkick"]
|
||||
},
|
||||
"lickitung": {
|
||||
"moves": ["bodyslam", "earthquake", "fireblast", "rest", "sleeptalk", "swordsdance"]
|
||||
},
|
||||
"weezing": {
|
||||
"moves": ["explosion", "fireblast", "hiddenpowergrass", "painsplit", "sludgebomb", "thunder"]
|
||||
},
|
||||
"rhydon": {
|
||||
"moves": ["curse", "earthquake", "fireblast", "rest", "roar", "rockslide", "sleeptalk", "zapcannon"]
|
||||
},
|
||||
"tangela": {
|
||||
"moves": ["gigadrain", "growth", "hiddenpowerice", "sleeppowder", "synthesis"]
|
||||
},
|
||||
"kangaskhan": {
|
||||
"moves": ["bodyslam", "curse", "earthquake", "rest", "return", "roar", "sleeptalk"]
|
||||
},
|
||||
"seaking": {
|
||||
"moves": ["agility", "return", "substitute", "surf", "swordsdance"]
|
||||
},
|
||||
"starmie": {
|
||||
"moves": ["psychic", "rapidspin", "recover", "surf", "thunderbolt", "thunderwave"]
|
||||
},
|
||||
"mrmime": {
|
||||
"moves": ["encore", "firepunch", "hypnosis", "icepunch", "psychic", "thief", "thunderbolt", "thunderwave"]
|
||||
},
|
||||
"scyther": {
|
||||
"moves": ["batonpass", "hiddenpowerbug", "hiddenpowerground", "swordsdance", "wingattack"]
|
||||
},
|
||||
"jynx": {
|
||||
"moves": ["icebeam", "lovelykiss", "nightmare", "psychic", "substitute", "thief"]
|
||||
},
|
||||
"electabuzz": {
|
||||
"moves": ["crosschop", "icepunch", "psychic", "pursuit", "thunder", "thunderbolt"]
|
||||
},
|
||||
"magmar": {
|
||||
"moves": ["crosschop", "fireblast", "hiddenpowerground", "sunnyday", "thief", "thunderpunch"]
|
||||
},
|
||||
"pinsir": {
|
||||
"moves": ["bodyslam", "doubleedge", "hiddenpowerbug", "rest", "submission", "swordsdance"]
|
||||
},
|
||||
"tauros": {
|
||||
"moves": ["curse", "doubleedge", "earthquake", "rest", "return", "sleeptalk"]
|
||||
},
|
||||
"gyarados": {
|
||||
"moves": ["bodyslam", "doubleedge", "hiddenpowerflying", "hydropump", "rest", "sleeptalk", "thunder"]
|
||||
},
|
||||
"lapras": {
|
||||
"moves": ["icebeam", "rest", "sing", "sleeptalk", "surf", "thunder", "thunderbolt", "toxic"]
|
||||
},
|
||||
"ditto": {
|
||||
"level": 83,
|
||||
"moves": ["transform"]
|
||||
},
|
||||
"vaporeon": {
|
||||
"moves": ["growth", "hiddenpowerelectric", "icebeam", "rest", "sleeptalk", "surf"]
|
||||
},
|
||||
"jolteon": {
|
||||
"moves": ["batonpass", "growth", "hiddenpowerice", "hiddenpowerwater", "substitute", "thunderbolt", "thunderwave"]
|
||||
},
|
||||
"flareon": {
|
||||
"moves": ["batonpass", "doubleedge", "fireblast", "growth", "hiddenpowergrass", "zapcannon"]
|
||||
},
|
||||
"omastar": {
|
||||
"moves": ["hiddenpowerelectric", "icebeam", "rest", "sleeptalk", "surf"]
|
||||
},
|
||||
"kabutops": {
|
||||
"moves": ["ancientpower", "hiddenpowerground", "return", "submission", "surf", "swordsdance"]
|
||||
},
|
||||
"aerodactyl": {
|
||||
"moves": ["ancientpower", "curse", "earthquake", "hiddenpowerflying", "reflect", "whirlwind"]
|
||||
},
|
||||
"snorlax": {
|
||||
"moves": ["curse", "doubleedge", "earthquake", "fireblast", "lovelykiss", "rest", "return", "sleeptalk"]
|
||||
},
|
||||
"articuno": {
|
||||
"moves": ["hiddenpowerelectric", "icebeam", "rest", "sleeptalk", "toxic"]
|
||||
},
|
||||
"zapdos": {
|
||||
"moves": ["hiddenpowerice", "rest", "sleeptalk", "thunder"]
|
||||
},
|
||||
"moltres": {
|
||||
"moves": ["fireblast", "hiddenpowergrass", "rest", "sleeptalk", "sunnyday"]
|
||||
},
|
||||
"dragonite": {
|
||||
"moves": ["haze", "hiddenpowerflying", "icebeam", "lightscreen", "reflect", "rest", "thunder"]
|
||||
},
|
||||
"mewtwo": {
|
||||
"moves": ["fireblast", "icebeam", "psychic", "recover", "thunderbolt", "thunderwave"]
|
||||
},
|
||||
"mew": {
|
||||
"moves": ["earthquake", "explosion", "psychic", "shadowball", "softboiled", "submission", "swordsdance"]
|
||||
},
|
||||
"meganium": {
|
||||
"moves": ["hiddenpowerfire", "leechseed", "lightscreen", "razorleaf", "reflect", "synthesis"]
|
||||
},
|
||||
"typhlosion": {
|
||||
"moves": ["earthquake", "fireblast", "rest", "sleeptalk", "thunderpunch"]
|
||||
},
|
||||
"feraligatr": {
|
||||
"moves": ["crunch", "earthquake", "icebeam", "rest", "rockslide", "sleeptalk", "surf"]
|
||||
},
|
||||
"furret": {
|
||||
"moves": ["curse", "doubleedge", "rest", "shadowball", "sleeptalk", "surf"]
|
||||
},
|
||||
"noctowl": {
|
||||
"moves": ["hypnosis", "nightshade", "reflect", "thief", "toxic", "whirlwind"]
|
||||
},
|
||||
"ledian": {
|
||||
"moves": ["agility", "barrier", "batonpass", "lightscreen"]
|
||||
},
|
||||
"ariados": {
|
||||
"moves": ["batonpass", "curse", "sludgebomb", "spiderweb"]
|
||||
},
|
||||
"crobat": {
|
||||
"moves": ["gigadrain", "haze", "hiddenpowerground", "rest", "whirlwind", "wingattack"]
|
||||
},
|
||||
"lanturn": {
|
||||
"moves": ["icebeam", "raindance", "rest", "sleeptalk", "surf", "thunder"]
|
||||
},
|
||||
"togetic": {
|
||||
"moves": ["fireblast", "solarbeam", "sunnyday", "zapcannon"]
|
||||
},
|
||||
"xatu": {
|
||||
"moves": ["drillpeck", "haze", "hiddenpowergrass", "hiddenpowerwater", "psychic", "rest", "sleeptalk", "thief"]
|
||||
},
|
||||
"ampharos": {
|
||||
"moves": ["firepunch", "hiddenpowerice", "lightscreen", "reflect", "rest", "sleeptalk", "thunderbolt", "thunderwave"]
|
||||
},
|
||||
"bellossom": {
|
||||
"moves": ["doubleedge", "hiddenpowerfire", "leechseed", "moonlight", "razorleaf", "sleeppowder", "stunspore"]
|
||||
},
|
||||
"azumarill": {
|
||||
"moves": ["perishsong", "rest", "surf", "whirlpool"]
|
||||
},
|
||||
"sudowoodo": {
|
||||
"moves": ["curse", "earthquake", "rest", "rockslide", "selfdestruct", "sleeptalk"]
|
||||
},
|
||||
"politoed": {
|
||||
"moves": ["growth", "hiddenpowerelectric", "icebeam", "lovelykiss", "rest", "sleeptalk", "surf"]
|
||||
},
|
||||
"jumpluff": {
|
||||
"moves": ["gigadrain", "hiddenpowerice", "hiddenpowerwater", "leechseed", "sleeppowder", "stunspore"]
|
||||
},
|
||||
"aipom": {
|
||||
"moves": ["agility", "batonpass", "curse", "return", "shadowball"]
|
||||
},
|
||||
"sunflora": {
|
||||
"moves": ["growth", "hiddenpowerfire", "hiddenpowerwater", "razorleaf", "synthesis"]
|
||||
},
|
||||
"yanma": {
|
||||
"moves": ["gigadrain", "hiddenpowerbug", "hiddenpowerflying", "return", "screech", "thief"]
|
||||
},
|
||||
"quagsire": {
|
||||
"moves": ["bellydrum", "bodyslam", "earthquake", "rest", "surf"]
|
||||
},
|
||||
"espeon": {
|
||||
"moves": ["batonpass", "bite", "growth", "hiddenpowerfire", "morningsun", "psychic", "substitute"]
|
||||
},
|
||||
"umbreon": {
|
||||
"moves": ["batonpass", "growth", "hiddenpowerdark", "meanlook", "moonlight"]
|
||||
},
|
||||
"murkrow": {
|
||||
"moves": ["drillpeck", "haze", "hiddenpowerdark", "hiddenpowerfire", "pursuit", "thief", "toxic"]
|
||||
},
|
||||
"slowking": {
|
||||
"moves": ["fireblast", "psychic", "rest", "sleeptalk", "surf", "thunderwave", "toxic"]
|
||||
},
|
||||
"misdreavus": {
|
||||
"moves": ["meanlook", "painsplit", "perishsong", "psychic", "shadowball", "thief", "thunderbolt"]
|
||||
},
|
||||
"unown": {
|
||||
"level": 87,
|
||||
"moves": ["hiddenpowerpsychic"]
|
||||
},
|
||||
"wobbuffet": {
|
||||
"level": 83,
|
||||
"moves": ["counter", "mimic", "mirrorcoat", "safeguard"]
|
||||
},
|
||||
"girafarig": {
|
||||
"moves": ["crunch", "curse", "earthquake", "psychic", "rest", "return", "thunderbolt"]
|
||||
},
|
||||
"forretress": {
|
||||
"moves": ["doubleedge", "explosion", "hiddenpowerbug", "rapidspin", "reflect", "spikes", "toxic"]
|
||||
},
|
||||
"dunsparce": {
|
||||
"moves": ["curse", "flamethrower", "rest", "return", "sleeptalk", "thunder", "thunderbolt"]
|
||||
},
|
||||
"gligar": {
|
||||
"moves": ["counter", "earthquake", "hiddenpowerflying", "screech", "thief"]
|
||||
},
|
||||
"steelix": {
|
||||
"moves": ["curse", "earthquake", "explosion", "irontail", "rest", "roar", "sleeptalk", "toxic"]
|
||||
},
|
||||
"granbull": {
|
||||
"moves": ["curse", "healbell", "hiddenpowerground", "lovelykiss", "rest", "return", "sleeptalk"]
|
||||
},
|
||||
"qwilfish": {
|
||||
"moves": ["curse", "haze", "hydropump", "sludgebomb", "spikes"]
|
||||
},
|
||||
"scizor": {
|
||||
"moves": ["agility", "batonpass", "hiddenpowerbug", "return", "swordsdance"]
|
||||
},
|
||||
"shuckle": {
|
||||
"moves": ["defensecurl", "rest", "rollout", "toxic"]
|
||||
},
|
||||
"heracross": {
|
||||
"moves": ["curse", "earthquake", "megahorn", "rest", "seismictoss", "sleeptalk"]
|
||||
},
|
||||
"sneasel": {
|
||||
"moves": ["icebeam", "moonlight", "return", "screech", "shadowball", "thief"]
|
||||
},
|
||||
"ursaring": {
|
||||
"moves": ["curse", "earthquake", "rest", "return", "roar", "sleeptalk"]
|
||||
},
|
||||
"magcargo": {
|
||||
"moves": ["curse", "earthquake", "fireblast", "rest", "rockslide", "sleeptalk"]
|
||||
},
|
||||
"piloswine": {
|
||||
"moves": ["ancientpower", "bodyslam", "curse", "earthquake", "icebeam", "rest", "sleeptalk"]
|
||||
},
|
||||
"corsola": {
|
||||
"moves": ["curse", "recover", "rockslide", "surf", "toxic"]
|
||||
},
|
||||
"octillery": {
|
||||
"moves": ["flamethrower", "hiddenpowerelectric", "icebeam", "rest", "sleeptalk", "surf"]
|
||||
},
|
||||
"delibird": {
|
||||
"moves": ["hiddenpowerflying", "icebeam", "rapidspin", "spikes", "thief"]
|
||||
},
|
||||
"mantine": {
|
||||
"moves": ["haze", "hiddenpowerelectric", "icebeam", "rest", "sleeptalk", "surf", "toxic"]
|
||||
},
|
||||
"skarmory": {
|
||||
"moves": ["curse", "drillpeck", "rest", "sleeptalk", "toxic"]
|
||||
},
|
||||
"houndoom": {
|
||||
"moves": ["crunch", "fireblast", "pursuit", "solarbeam", "sunnyday"]
|
||||
},
|
||||
"kingdra": {
|
||||
"moves": ["dragonbreath", "hiddenpowerelectric", "icebeam", "rest", "sleeptalk", "surf"]
|
||||
},
|
||||
"donphan": {
|
||||
"moves": ["ancientpower", "curse", "earthquake", "hiddenpowerbug", "rapidspin", "rest", "roar", "sleeptalk"]
|
||||
},
|
||||
"porygon2": {
|
||||
"moves": ["curse", "doubleedge", "icebeam", "recover", "return", "thunderbolt", "thunderwave"]
|
||||
},
|
||||
"stantler": {
|
||||
"moves": ["confuseray", "curse", "earthquake", "rest", "return", "sleeptalk"]
|
||||
},
|
||||
"smeargle": {
|
||||
"moves": ["agility", "batonpass", "spikes", "spore"]
|
||||
},
|
||||
"hitmontop": {
|
||||
"moves": ["curse", "hiddenpowerghost", "highjumpkick", "rest", "sleeptalk"]
|
||||
},
|
||||
"miltank": {
|
||||
"moves": ["bodyslam", "curse", "earthquake", "healbell", "milkdrink"]
|
||||
},
|
||||
"blissey": {
|
||||
"moves": ["flamethrower", "healbell", "icebeam", "present", "sing", "softboiled", "toxic"]
|
||||
},
|
||||
"raikou": {
|
||||
"moves": ["crunch", "hiddenpowerice", "hiddenpowerwater", "reflect", "rest", "roar", "sleeptalk", "thunder", "thunderbolt"]
|
||||
},
|
||||
"entei": {
|
||||
"moves": ["fireblast", "hiddenpowerrock", "return", "solarbeam", "sunnyday"]
|
||||
},
|
||||
"suicune": {
|
||||
"moves": ["hiddenpowerelectric", "icebeam", "rest", "roar", "sleeptalk", "surf", "toxic"]
|
||||
},
|
||||
"tyranitar": {
|
||||
"moves": ["crunch", "curse", "earthquake", "fireblast", "pursuit", "rest", "roar", "rockslide", "surf"]
|
||||
},
|
||||
"lugia": {
|
||||
"moves": ["aeroblast", "curse", "earthquake", "icebeam", "recover", "whirlwind"]
|
||||
},
|
||||
"hooh": {
|
||||
"moves": ["curse", "earthquake", "hiddenpowerflying", "recover", "sacredfire", "thunder", "thunderbolt"]
|
||||
},
|
||||
"celebi": {
|
||||
"moves": ["hiddenpowergrass", "healbell", "leechseed", "psychic", "recover", "toxic"]
|
||||
}
|
||||
}
|
||||
313
data/mods/gen2/random-teams.ts
Normal file
313
data/mods/gen2/random-teams.ts
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
import RandomGen3Teams from '../gen3/random-teams';
|
||||
import {PRNG, PRNGSeed} from '../../../sim/prng';
|
||||
import type {MoveCounter, OldRandomBattleSpecies} from '../gen8/random-teams';
|
||||
|
||||
export class RandomGen2Teams extends RandomGen3Teams {
|
||||
randomData: {[species: string]: OldRandomBattleSpecies} = require('./random-data.json');
|
||||
|
||||
constructor(format: string | Format, prng: PRNG | PRNGSeed | null) {
|
||||
super(format, prng);
|
||||
this.moveEnforcementCheckers = {
|
||||
Electric: (movePool, moves, abilities, types, counter) => !counter.get('Electric'),
|
||||
Fire: (movePool, moves, abilities, types, counter) => !counter.get('Fire'),
|
||||
Flying: (movePool, moves, abilities, types, counter) => !counter.get('Flying') && types.has('Ground'),
|
||||
Ground: (movePool, moves, abilities, types, counter) => !counter.get('Ground'),
|
||||
Ice: (movePool, moves, abilities, types, counter) => !counter.get('Ice'),
|
||||
Normal: (movePool, moves, abilities, types, counter) => !counter.get('Normal') && counter.setupType === 'Physical',
|
||||
Psychic: (movePool, moves, abilities, types, counter) => !counter.get('Psychic') && types.has('Grass'),
|
||||
Rock: (movePool, moves, abilities, types, counter, species) => !counter.get('Rock') && species.baseStats.atk > 60,
|
||||
Water: (movePool, moves, abilities, types, counter) => !counter.get('Water'),
|
||||
};
|
||||
}
|
||||
|
||||
shouldCullMove(
|
||||
move: Move,
|
||||
types: Set<string>,
|
||||
moves: Set<string>,
|
||||
abilities = {},
|
||||
counter: MoveCounter,
|
||||
movePool: string[],
|
||||
teamDetails: RandomTeamsTypes.TeamDetails,
|
||||
): {cull: boolean, isSetup?: boolean} {
|
||||
const restTalk = moves.has('rest') && moves.has('sleeptalk');
|
||||
|
||||
switch (move.id) {
|
||||
// Set up once and only if we have the moves for it
|
||||
case 'bellydrum': case 'curse': case 'meditate': case 'screech': case 'swordsdance':
|
||||
return {
|
||||
cull: (
|
||||
(counter.setupType !== 'Physical' || counter.get('physicalsetup') > 1) ||
|
||||
(!counter.get('Physical') || counter.damagingMoves.size < 2 && !moves.has('batonpass') && !moves.has('sleeptalk'))
|
||||
),
|
||||
isSetup: true,
|
||||
};
|
||||
|
||||
// Not very useful without their supporting moves
|
||||
case 'batonpass':
|
||||
return {cull: !counter.setupType && !counter.get('speedsetup') && !moves.has('meanlook')};
|
||||
case 'meanlook':
|
||||
return {cull: movePool.includes('perishsong')};
|
||||
case 'nightmare':
|
||||
return {cull: !moves.has('lovelykiss') && !moves.has('sleeppowder')};
|
||||
case 'swagger':
|
||||
return {cull: !moves.has('substitute')};
|
||||
|
||||
// Bad after setup
|
||||
case 'charm': case 'counter':
|
||||
return {cull: !!counter.setupType};
|
||||
case 'haze':
|
||||
return {cull: !!counter.setupType || restTalk};
|
||||
case 'reflect': case 'lightscreen':
|
||||
return {cull: !!counter.setupType || moves.has('rest')};
|
||||
|
||||
// Ineffective to have both
|
||||
case 'doubleedge':
|
||||
return {cull: moves.has('bodyslam') || moves.has('return')};
|
||||
case 'explosion': case 'selfdestruct':
|
||||
return {cull: moves.has('softboiled') || restTalk};
|
||||
case 'extremespeed':
|
||||
return {cull: moves.has('bodyslam') || restTalk};
|
||||
case 'hyperbeam':
|
||||
return {cull: moves.has('rockslide')};
|
||||
case 'rapidspin':
|
||||
return {cull: !!teamDetails.rapidSpin || !!counter.setupType || moves.has('sleeptalk')};
|
||||
case 'return':
|
||||
return {cull: moves.has('bodyslam')};
|
||||
case 'surf':
|
||||
return {cull: moves.has('hydropump')};
|
||||
case 'thunder':
|
||||
return {cull: moves.has('thunderbolt')};
|
||||
case 'razorleaf':
|
||||
return {cull: moves.has('swordsdance') && movePool.includes('sludgebomb')};
|
||||
case 'icebeam':
|
||||
return {cull: moves.has('dragonbreath')};
|
||||
case 'seismictoss':
|
||||
return {cull: moves.has('rest') || moves.has('sleeptalk')};
|
||||
case 'destinybond':
|
||||
return {cull: moves.has('explosion')};
|
||||
case 'pursuit':
|
||||
return {cull: moves.has('crunch') && moves.has('solarbeam')};
|
||||
case 'thief':
|
||||
return {cull: moves.has('rest') || moves.has('substitute')};
|
||||
case 'irontail':
|
||||
return {cull: types.has('Ground') && movePool.includes('earthquake')};
|
||||
|
||||
// Status and illegal move rejections
|
||||
case 'confuseray': case 'encore': case 'roar': case 'whirlwind':
|
||||
return {cull: restTalk};
|
||||
case 'lovelykiss':
|
||||
return {cull: ['healbell', 'moonlight', 'morningsun', 'sleeptalk'].some(m => moves.has(m))};
|
||||
case 'sleeptalk':
|
||||
return {cull: moves.has('curse') && counter.get('stab') >= 2};
|
||||
case 'softboiled':
|
||||
return {cull: movePool.includes('swordsdance')};
|
||||
case 'spikes':
|
||||
return {cull: !!teamDetails.spikes};
|
||||
case 'substitute':
|
||||
return {cull: moves.has('agility') || moves.has('rest')};
|
||||
case 'synthesis':
|
||||
return {cull: moves.has('explosion')};
|
||||
case 'thunderwave':
|
||||
return {cull: moves.has('thunder') || moves.has('toxic')};
|
||||
}
|
||||
|
||||
return {cull: false};
|
||||
}
|
||||
|
||||
getItem(
|
||||
ability: string,
|
||||
types: Set<string>,
|
||||
moves: Set<string>,
|
||||
counter: MoveCounter,
|
||||
species: Species,
|
||||
) {
|
||||
// First, the high-priority items
|
||||
if (species.name === 'Ditto') return 'Metal Powder';
|
||||
if (species.name === 'Farfetch\u2019d') return 'Stick';
|
||||
if (species.name === 'Marowak') return 'Thick Club';
|
||||
if (species.name === 'Pikachu') return 'Light Ball';
|
||||
if (species.name === 'Unown') return 'Twisted Spoon';
|
||||
if (moves.has('thief')) return '';
|
||||
|
||||
// Medium priority
|
||||
if (moves.has('rest') && !moves.has('sleeptalk')) return 'Mint Berry';
|
||||
if (
|
||||
(moves.has('bellydrum') || moves.has('swordsdance')) &&
|
||||
species.baseStats.spe >= 60 && !types.has('Ground') &&
|
||||
!moves.has('sleeptalk') && !moves.has('substitute') &&
|
||||
this.randomChance(1, 2)
|
||||
) {
|
||||
return 'Miracle Berry';
|
||||
}
|
||||
|
||||
// Default to Leftovers
|
||||
return 'Leftovers';
|
||||
}
|
||||
|
||||
randomSet(species: string | Species, teamDetails: RandomTeamsTypes.TeamDetails = {}): RandomTeamsTypes.RandomSet {
|
||||
species = this.dex.species.get(species);
|
||||
|
||||
const data = this.randomData[species.id];
|
||||
const movePool = (data.moves || Object.keys(this.dex.species.getLearnset(species.id)!)).slice();
|
||||
const rejectedPool: string[] = [];
|
||||
const moves = new Set<string>();
|
||||
|
||||
let ivs = {hp: 30, atk: 30, def: 30, spa: 30, spd: 30, spe: 30};
|
||||
let availableHP = 0;
|
||||
for (const setMoveid of movePool) {
|
||||
if (setMoveid.startsWith('hiddenpower')) availableHP++;
|
||||
}
|
||||
|
||||
const types = new Set(species.types);
|
||||
|
||||
let counter;
|
||||
// We use a special variable to track Hidden Power
|
||||
// so that we can check for all Hidden Powers at once
|
||||
let hasHiddenPower = false;
|
||||
|
||||
do {
|
||||
// Choose next 4 moves from learnset/viable moves and add them to moves list:
|
||||
while (moves.size < this.maxMoveCount && movePool.length) {
|
||||
const moveid = this.sampleNoReplace(movePool);
|
||||
if (moveid.startsWith('hiddenpower')) {
|
||||
availableHP--;
|
||||
if (hasHiddenPower) continue;
|
||||
hasHiddenPower = true;
|
||||
}
|
||||
moves.add(moveid);
|
||||
}
|
||||
while (moves.size < this.maxMoveCount && rejectedPool.length) {
|
||||
const moveid = this.sampleNoReplace(rejectedPool);
|
||||
if (moveid.startsWith('hiddenpower')) {
|
||||
if (hasHiddenPower) continue;
|
||||
hasHiddenPower = true;
|
||||
}
|
||||
moves.add(moveid);
|
||||
}
|
||||
|
||||
counter = this.queryMoves(moves, species.types, new Set(), movePool);
|
||||
|
||||
// Iterate through the moves again, this time to cull them:
|
||||
for (const moveid of moves) {
|
||||
const move = this.dex.moves.get(moveid);
|
||||
let {cull, isSetup} = this.shouldCullMove(move, types, moves, {}, counter, movePool, teamDetails);
|
||||
|
||||
// This move doesn't satisfy our setup requirements:
|
||||
if (counter.setupType === 'Physical' && move.category === 'Special' && !counter.get('Physical')) {
|
||||
cull = true;
|
||||
}
|
||||
|
||||
|
||||
// Reject Status, non-STAB, or low basepower moves
|
||||
const moveIsRejectable = (
|
||||
(move.category !== 'Status' || !move.flags.heal) &&
|
||||
// These moves cannot be rejected in favor of a forced move
|
||||
!['batonpass', 'sleeptalk', 'spikes', 'sunnyday'].includes(move.id) &&
|
||||
(move.category === 'Status' || !types.has(move.type) || (move.basePower && move.basePower < 40))
|
||||
);
|
||||
|
||||
if (!cull && !isSetup && moveIsRejectable && (counter.setupType || !move.stallingMove)) {
|
||||
// There may be more important moves that this Pokemon needs
|
||||
if (
|
||||
// Pokemon should usually have at least one STAB move
|
||||
(
|
||||
!counter.get('stab') &&
|
||||
!counter.get('damage') &&
|
||||
!types.has('Ghost') &&
|
||||
counter.get('physicalpool') + counter.get('specialpool') > 0
|
||||
) || (movePool.includes('megahorn') || (movePool.includes('softboiled') && moves.has('present'))) ||
|
||||
// Rest + Sleep Talk should be selected together
|
||||
((moves.has('rest') && movePool.includes('sleeptalk')) || (moves.has('sleeptalk') && movePool.includes('rest'))) ||
|
||||
// Sunny Day + Solar Beam should be selected together
|
||||
(moves.has('sunnyday') && movePool.includes('solarbeam') ||
|
||||
(moves.has('solarbeam') && movePool.includes('sunnyday'))) ||
|
||||
['milkdrink', 'recover', 'spore'].some(m => movePool.includes(m))
|
||||
) {
|
||||
cull = true;
|
||||
} else {
|
||||
// Pokemon should have moves that benefit their typing
|
||||
for (const type of types) {
|
||||
if (this.moveEnforcementCheckers[type]?.(movePool, moves, new Set(), types, counter, species, teamDetails)) cull = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove rejected moves from the move list
|
||||
if (
|
||||
cull &&
|
||||
(movePool.length - availableHP || availableHP && (move.id === 'hiddenpower' || !hasHiddenPower))
|
||||
) {
|
||||
if (move.category !== 'Status' && !move.damage && (move.id !== 'hiddenpower' || !availableHP)) {
|
||||
rejectedPool.push(moveid);
|
||||
}
|
||||
moves.delete(moveid);
|
||||
if (moveid.startsWith('hiddenpower')) hasHiddenPower = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cull && rejectedPool.length) {
|
||||
moves.delete(moveid);
|
||||
if (moveid.startsWith('hiddenpower')) hasHiddenPower = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (moves.size < this.maxMoveCount && (movePool.length || rejectedPool.length));
|
||||
|
||||
// Adjust IVs for Hidden Power
|
||||
for (const setMoveid of moves) {
|
||||
if (!setMoveid.startsWith('hiddenpower')) continue;
|
||||
const hpType = setMoveid.substr(11, setMoveid.length);
|
||||
|
||||
const hpIVs: {[k: string]: Partial<typeof ivs>} = {
|
||||
dragon: {def: 28},
|
||||
ice: {def: 26},
|
||||
psychic: {def: 24},
|
||||
electric: {atk: 28},
|
||||
grass: {atk: 28, def: 28},
|
||||
water: {atk: 28, def: 26},
|
||||
fire: {atk: 28, def: 24},
|
||||
steel: {atk: 26},
|
||||
ghost: {atk: 26, def: 28},
|
||||
bug: {atk: 26, def: 26},
|
||||
rock: {atk: 26, def: 24},
|
||||
ground: {atk: 24},
|
||||
poison: {atk: 24, def: 28},
|
||||
flying: {atk: 24, def: 26},
|
||||
fighting: {atk: 24, def: 24},
|
||||
};
|
||||
if (hpIVs[hpType]) {
|
||||
ivs = {...ivs, ...hpIVs[hpType]};
|
||||
}
|
||||
|
||||
if (ivs.atk === 28 || ivs.atk === 24) ivs.hp = 14;
|
||||
if (ivs.def === 28 || ivs.def === 24) ivs.hp -= 8;
|
||||
}
|
||||
|
||||
const levelScale: {[k: string]: number} = {
|
||||
NU: 73,
|
||||
NUBL: 71,
|
||||
UU: 69,
|
||||
UUBL: 67,
|
||||
OU: 65,
|
||||
Uber: 61,
|
||||
};
|
||||
|
||||
const level = this.adjustLevel || data.level || levelScale[species.tier] || 80;
|
||||
|
||||
return {
|
||||
name: species.name,
|
||||
species: species.name,
|
||||
moves: Array.from(moves),
|
||||
ability: 'No Ability',
|
||||
evs: {hp: 255, atk: 255, def: 255, spa: 255, spd: 255, spe: 255},
|
||||
ivs,
|
||||
item: this.getItem('None', types, moves, counter, species),
|
||||
level,
|
||||
// No shiny chance because Gen 2 shinies have bad IVs
|
||||
shiny: false,
|
||||
gender: species.gender ? species.gender : 'M',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default RandomGen2Teams;
|
||||
|
|
@ -1,6 +1,4 @@
|
|||
import type { Learnset } from "../../../sim/dex-species";
|
||||
|
||||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
export const Rulesets: {[k: string]: ModdedFormatData} = {
|
||||
obtainablemoves: {
|
||||
inherit: true,
|
||||
banlist: [
|
||||
|
|
@ -28,10 +26,7 @@ export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable
|
|||
standard: {
|
||||
effectType: 'ValidatorRule',
|
||||
name: 'Standard',
|
||||
ruleset: [
|
||||
'Standard AG',
|
||||
'Sleep Clause Mod', 'Freeze Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Items Clause', 'Evasion Moves Clause',
|
||||
],
|
||||
ruleset: ['Obtainable', 'Sleep Clause Mod', 'Freeze Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Items Clause', 'Evasion Moves Clause', 'Endless battle Clause', 'HP Percentage Mod', 'Cancel Mod'],
|
||||
banlist: [
|
||||
'Hypnosis + Mean Look',
|
||||
'Hypnosis + Spider Web',
|
||||
|
|
@ -45,65 +40,68 @@ export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable
|
|||
'Spore + Spider Web',
|
||||
],
|
||||
},
|
||||
nc2000movelegality: {
|
||||
nintendocup2000movelegality: {
|
||||
effectType: 'ValidatorRule',
|
||||
name: 'NC 2000 Move Legality',
|
||||
name: 'Nintendo Cup 2000 Move Legality',
|
||||
desc: "Prevents Pok\u00e9mon from having moves that would only be obtainable in Pok\u00e9mon Crystal.",
|
||||
onValidateSet(set) {
|
||||
const illegalCombos: { [speciesid: string]: { [moveid: string]: 'E' | 'L' | 'S' } } = {
|
||||
arbok: { crunch: 'E' },
|
||||
sandslash: { metalclaw: 'E' },
|
||||
golduck: { crosschop: 'E' },
|
||||
marowak: { swordsdance: 'E' },
|
||||
electabuzz: { crosschop: 'E' },
|
||||
magmar: { crosschop: 'E' },
|
||||
jolteon: { batonpass: 'L' },
|
||||
vaporeon: { batonpass: 'L' },
|
||||
flareon: { batonpass: 'L' },
|
||||
espeon: { batonpass: 'L' },
|
||||
umbreon: { batonpass: 'L' },
|
||||
dragonite: { extremespeed: 'S' },
|
||||
meganium: { swordsdance: 'E' },
|
||||
typhlosion: { submission: 'E' },
|
||||
ariados: { agility: 'L' },
|
||||
yanma: { wingattack: 'L' },
|
||||
murkrow: { skyattack: 'E' },
|
||||
qwilfish: { spikes: 'L' },
|
||||
sneasel: { metalclaw: 'L' },
|
||||
ursaring: { metalclaw: 'E' },
|
||||
piloswine: { amnesia: 'L' },
|
||||
skarmory: { skyattack: 'E' },
|
||||
donphan: { watergun: 'E' },
|
||||
suicune: { aurorabeam: 'L' },
|
||||
dugtrio: { triattack: 'L' },
|
||||
magneton: { triattack: 'L' },
|
||||
cloyster: { spikes: 'L' },
|
||||
const illegalCombos: {[speciesid: string]: {[moveid: string]: 'E' | 'L' | 'S'}} = {
|
||||
arbok: {crunch: 'E'},
|
||||
sandslash: {metalclaw: 'E'},
|
||||
golduck: {crosschop: 'E'},
|
||||
marowak: {swordsdance: 'E'},
|
||||
electabuzz: {crosschop: 'E'},
|
||||
magmar: {crosschop: 'E'},
|
||||
jolteon: {batonpass: 'L'},
|
||||
vaporeon: {batonpass: 'L'},
|
||||
flareon: {batonpass: 'L'},
|
||||
espeon: {batonpass: 'L'},
|
||||
umbreon: {batonpass: 'L'},
|
||||
dragonite: {extremespeed: 'S'},
|
||||
meganium: {swordsdance: 'E'},
|
||||
typhlosion: {submission: 'E'},
|
||||
ariados: {agility: 'L'},
|
||||
yanma: {wingattack: 'L'},
|
||||
murkrow: {skyattack: 'E'},
|
||||
qwilfish: {spikes: 'L'},
|
||||
sneasel: {metalclaw: 'L'},
|
||||
ursaring: {metalclaw: 'E'},
|
||||
piloswine: {amnesia: 'L'},
|
||||
skarmory: {skyattack: 'E'},
|
||||
donphan: {watergun: 'E'},
|
||||
suicune: {aurorabeam: 'L'},
|
||||
dugtrio: {triattack: 'L'},
|
||||
magneton: {triattack: 'L'},
|
||||
cloyster: {spikes: 'L'},
|
||||
};
|
||||
|
||||
const moveSources: NonNullable<Learnset['learnset']> = Object.fromEntries(
|
||||
set.moves.map(move => [this.toID(move), []])
|
||||
);
|
||||
|
||||
const species = this.dex.species.get(set.species);
|
||||
for (const { learnset } of this.dex.species.getFullLearnset(species.id)) {
|
||||
for (const moveid in moveSources) {
|
||||
moveSources[moveid].push(...(learnset[moveid] || []));
|
||||
}
|
||||
}
|
||||
|
||||
const notUsableAsTM = ['icebeam', 'flamethrower', 'thunderbolt'];
|
||||
const species = this.dex.species.get(set.species || set.name);
|
||||
const learnsetData = {...(this.dex.data.Learnsets[species.id]?.learnset || {})};
|
||||
const legalityList = illegalCombos[species.id];
|
||||
const problems = [];
|
||||
let prevo = species.prevo;
|
||||
while (prevo) {
|
||||
const prevoSpecies = this.dex.species.get(prevo);
|
||||
const prevoLsetData = this.dex.data.Learnsets[prevoSpecies.id]?.learnset || {};
|
||||
for (const moveid in prevoLsetData) {
|
||||
if (!(moveid in learnsetData)) {
|
||||
learnsetData[moveid] = prevoLsetData[moveid];
|
||||
} else {
|
||||
learnsetData[moveid].push(...prevoLsetData[moveid]);
|
||||
}
|
||||
}
|
||||
prevo = prevoSpecies.prevo;
|
||||
}
|
||||
for (const moveid of set.moves.map(this.toID)) {
|
||||
// Diglett Magnemite Shellder
|
||||
if (!moveSources[moveid]) continue;
|
||||
if (!learnsetData[moveid]) continue;
|
||||
if (legalityList) {
|
||||
const list = moveSources[moveid].filter(x => !x.includes(legalityList[moveid]));
|
||||
const list = learnsetData[moveid].filter(x => !x.includes(legalityList[moveid]));
|
||||
if (!list.length) {
|
||||
switch (legalityList[moveid]) {
|
||||
case 'L':
|
||||
// Converted to a set to remove duplicate entries
|
||||
const levels = new Set(moveSources[moveid].filter(x => x.includes(legalityList[moveid])).map(x => x.slice(2)));
|
||||
const levels = new Set(learnsetData[moveid].filter(x => x.includes(legalityList[moveid])).map(x => x.slice(2)));
|
||||
problems.push(
|
||||
`${species.name} can't learn ${this.dex.moves.get(moveid).name}.`,
|
||||
`(It learns ${this.dex.moves.get(moveid).name} in Pok\u00e9mon Crystal at the following levels: ${[...levels].join(', ')})`
|
||||
|
|
@ -125,7 +123,7 @@ export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable
|
|||
}
|
||||
}
|
||||
for (const id of notUsableAsTM) {
|
||||
if (moveid === id && moveSources[id] && !moveSources[id].filter(x => !x.includes('2T')).length) {
|
||||
if (moveid === id && learnsetData[id] && !learnsetData[id].filter(x => !x.includes('2T')).length) {
|
||||
problems.push(`${species.name} can't learn ${this.dex.moves.get(id).name}.`);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
pokemon: {
|
||||
inherit: true,
|
||||
getStat(statName, unboosted, unmodified, fastReturn) {
|
||||
// @ts-expect-error type checking prevents 'hp' from being passed, but we're paranoid
|
||||
// @ts-ignore - type checking prevents 'hp' from being passed, but we're paranoid
|
||||
if (statName === 'hp') throw new Error("Please read `maxhp` directly");
|
||||
|
||||
// base stat
|
||||
|
|
@ -89,10 +89,10 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
},
|
||||
actions: {
|
||||
inherit: true,
|
||||
runMove(moveOrMoveName, pokemon, targetLoc, options) {
|
||||
runMove(moveOrMoveName, pokemon, targetLoc, sourceEffect) {
|
||||
let move = this.dex.getActiveMove(moveOrMoveName);
|
||||
let target = this.battle.getTarget(pokemon, move, targetLoc);
|
||||
if (!options?.sourceEffect && move.id !== 'struggle') {
|
||||
if (!sourceEffect && move.id !== 'struggle') {
|
||||
const changedMove = this.battle.runEvent('OverrideAction', pokemon, target, move);
|
||||
if (changedMove && changedMove !== true) {
|
||||
move = this.dex.getActiveMove(changedMove);
|
||||
|
|
@ -107,7 +107,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
// THIS IS PURELY A SANITY CHECK
|
||||
// DO NOT TAKE ADVANTAGE OF THIS TO PREVENT A POKEMON FROM MOVING;
|
||||
// USE this.battle.queue.cancelMove INSTEAD
|
||||
this.battle.debug(`${pokemon.fullname} INCONSISTENT STATE, ALREADY MOVED: ${pokemon.moveThisTurn}`);
|
||||
this.battle.debug('' + pokemon.fullname + ' INCONSISTENT STATE, ALREADY MOVED: ' + pokemon.moveThisTurn);
|
||||
this.battle.clearActiveMove(true);
|
||||
return;
|
||||
}
|
||||
|
|
@ -135,7 +135,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
}
|
||||
pokemon.moveUsed(move);
|
||||
this.battle.actions.useMove(move, pokemon, { target, sourceEffect: options?.sourceEffect });
|
||||
this.battle.actions.useMove(move, pokemon, target, sourceEffect);
|
||||
this.battle.singleEvent('AfterMove', move, null, pokemon, target, move);
|
||||
if (!move.selfSwitch && pokemon.side.foe.active[0].hp) this.battle.runEvent('AfterMoveSelf', pokemon, target, move);
|
||||
},
|
||||
|
|
@ -187,7 +187,10 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
move.ignoreImmunity = (move.category === 'Status');
|
||||
}
|
||||
|
||||
if (!target.runImmunity(move, true)) {
|
||||
if (
|
||||
(!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) &&
|
||||
!target.runImmunity(move.type, true)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -203,11 +206,6 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (move.ohko && pokemon.level < target.level) {
|
||||
this.battle.add('-immune', target, '[ohko]');
|
||||
return false;
|
||||
}
|
||||
|
||||
let accuracy = move.accuracy;
|
||||
if (move.alwaysHit) {
|
||||
accuracy = true;
|
||||
|
|
@ -218,8 +216,13 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
if (accuracy !== true) {
|
||||
accuracy = Math.floor(accuracy * 255 / 100);
|
||||
if (move.ohko) {
|
||||
accuracy += (pokemon.level - target.level) * 2;
|
||||
accuracy = Math.min(accuracy, 255);
|
||||
if (pokemon.level >= target.level) {
|
||||
accuracy += (pokemon.level - target.level) * 2;
|
||||
accuracy = Math.min(accuracy, 255);
|
||||
} else {
|
||||
this.battle.add('-immune', target, '[ohko]');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!move.ignoreAccuracy) {
|
||||
if (pokemon.boosts.accuracy > 0) {
|
||||
|
|
@ -293,11 +296,13 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
if (move.ohko) this.battle.add('-ohko');
|
||||
|
||||
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
|
||||
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
|
||||
if (!move.negateSecondary) {
|
||||
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
|
||||
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
|
||||
}
|
||||
|
||||
if (move.recoil && move.totalDamage) {
|
||||
this.battle.damage(this.calcRecoilDamage(move.totalDamage, move, pokemon), pokemon, target, 'recoil');
|
||||
this.battle.damage(this.calcRecoilDamage(move.totalDamage, move), pokemon, target, 'recoil');
|
||||
}
|
||||
return damage;
|
||||
},
|
||||
|
|
@ -492,8 +497,10 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
|
||||
// Let's test for immunities.
|
||||
if (!target.runImmunity(move, true)) {
|
||||
return false;
|
||||
if (!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) {
|
||||
if (!target.runImmunity(move.type, true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Is it an OHKO move?
|
||||
|
|
@ -538,11 +545,11 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
// Checking for the move's Critical Hit ratio
|
||||
let critRatio = this.battle.runEvent('ModifyCritRatio', source, target, move, move.critRatio || 0);
|
||||
critRatio = this.battle.clampIntRange(critRatio, 0, 5);
|
||||
const critMult = [0, 17, 32, 64, 85, 128];
|
||||
const critMult = [0, 16, 8, 4, 3, 2];
|
||||
let isCrit = move.willCrit || false;
|
||||
if (typeof move.willCrit === 'undefined') {
|
||||
if (critRatio) {
|
||||
isCrit = this.battle.random(256) < critMult[critRatio];
|
||||
isCrit = this.battle.randomChance(1, critMult[critRatio]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -619,7 +626,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
|
||||
if (move.id === 'present') {
|
||||
const typeIndexes: { [k: string]: number } = {
|
||||
const typeIndexes: {[k: string]: number} = {
|
||||
Normal: 0, Fighting: 1, Flying: 2, Poison: 3, Ground: 4, Rock: 5, Bug: 7, Ghost: 8, Steel: 9,
|
||||
Fire: 20, Water: 21, Grass: 22, Electric: 23, Psychic: 24, Ice: 25, Dragon: 26, Dark: 27,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const TypeChart: import('../../../sim/dex-data').ModdedTypeDataTable = {
|
||||
export const TypeChart: {[k: string]: ModdedTypeData} = {
|
||||
fire: {
|
||||
inherit: true,
|
||||
damageTaken: {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
* a volatile along with them to keep track of if their respective stat changes should be factored
|
||||
* in during stat calculations or not.
|
||||
*/
|
||||
export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDataTable = {
|
||||
export const Conditions: {[k: string]: ModdedConditionData} = {
|
||||
brn: {
|
||||
name: 'brn',
|
||||
effectType: 'Status',
|
||||
|
|
@ -46,7 +46,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
effectType: 'Status',
|
||||
onStart(target, source, sourceEffect) {
|
||||
if (sourceEffect && sourceEffect.effectType === 'Move') {
|
||||
this.add('-status', target, 'slp', `[from] move: ${sourceEffect.name}`);
|
||||
this.add('-status', target, 'slp', '[from] move: ' + sourceEffect.name);
|
||||
} else {
|
||||
this.add('-status', target, 'slp');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// Gen 2 Stadium fixes Dragon Fang and Dragon Scale having the wrong effects.
|
||||
export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
||||
export const Items: {[k: string]: ModdedItemData} = {
|
||||
dragonfang: {
|
||||
inherit: true,
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
|
|
@ -10,6 +10,6 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
dragonscale: {
|
||||
inherit: true,
|
||||
onModifyDamage: undefined, // no inherit
|
||||
onModifyDamage() {},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
||||
export const Moves: {[k: string]: ModdedMoveData} = {
|
||||
// Belly Drum no longer boosts attack by 2 stages if under 50% health.
|
||||
bellydrum: {
|
||||
inherit: true,
|
||||
|
|
@ -25,7 +25,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
}
|
||||
boosts = target.boosts.atk - originalStage;
|
||||
target.boosts.atk = originalStage;
|
||||
this.boost({ atk: boosts });
|
||||
this.boost({atk: boosts});
|
||||
},
|
||||
},
|
||||
destinybond: {
|
||||
|
|
|
|||
|
|
@ -1,17 +1,8 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
standardag: {
|
||||
inherit: true,
|
||||
ruleset: [
|
||||
'Obtainable', 'Team Preview', 'Exact HP Mod', 'Cancel Mod', 'Beat Up Nicknames Mod',
|
||||
],
|
||||
},
|
||||
export const Rulesets: {[k: string]: ModdedFormatData} = {
|
||||
standard: {
|
||||
effectType: 'ValidatorRule',
|
||||
name: 'Standard',
|
||||
ruleset: [
|
||||
'Standard AG',
|
||||
'Stadium Sleep Clause', 'Freeze Clause Mod', 'Self-KO Clause', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'Stadium Items Clause',
|
||||
],
|
||||
ruleset: ['Obtainable', 'Team Preview', 'Stadium Sleep Clause', 'Freeze Clause Mod', 'Self-KO Clause', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'Exact HP Mod', 'Cancel Mod', 'Stadium Items Clause'],
|
||||
},
|
||||
selfkoclause: {
|
||||
effectType: 'Rule',
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
pokemon: {
|
||||
inherit: true,
|
||||
getStat(statName, unboosted, unmodified, fastReturn) {
|
||||
// @ts-expect-error type checking prevents 'hp' from being passed, but we're paranoid
|
||||
// @ts-ignore - type checking prevents 'hp' from being passed, but we're paranoid
|
||||
if (statName === 'hp') throw new Error("Please read `maxhp` directly");
|
||||
|
||||
// base stat
|
||||
|
|
@ -122,7 +122,10 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
move.ignoreImmunity = (move.category === 'Status');
|
||||
}
|
||||
|
||||
if (!target.runImmunity(move, true)) {
|
||||
if (
|
||||
(!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) &&
|
||||
!target.runImmunity(move.type, true)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -228,13 +231,15 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
if (move.ohko) this.battle.add('-ohko');
|
||||
|
||||
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
|
||||
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
|
||||
if (!move.negateSecondary) {
|
||||
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
|
||||
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
|
||||
}
|
||||
// Implementing Recoil mechanics from Stadium 2.
|
||||
// If a pokemon caused the other to faint with a recoil move and only one pokemon remains on both sides,
|
||||
// recoil damage will not be taken.
|
||||
if (move.recoil && move.totalDamage && (pokemon.side.pokemonLeft > 1 || target.side.pokemonLeft > 1 || target.hp)) {
|
||||
this.battle.damage(this.calcRecoilDamage(move.totalDamage, move, pokemon), pokemon, target, 'recoil');
|
||||
this.battle.damage(this.calcRecoilDamage(move.totalDamage, move), pokemon, target, 'recoil');
|
||||
}
|
||||
return damage;
|
||||
},
|
||||
|
|
@ -253,8 +258,10 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
|
||||
// Let's test for immunities.
|
||||
if (!target.runImmunity(move, true)) {
|
||||
return false;
|
||||
if (!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) {
|
||||
if (!target.runImmunity(move.type, true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Is it an OHKO move?
|
||||
|
|
@ -471,7 +478,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
if (typeof effect === 'string') effect = this.dex.conditions.get(effect);
|
||||
if (!target?.hp) return 0;
|
||||
let success = null;
|
||||
boost = this.runEvent('TryBoost', target, source, effect, { ...boost });
|
||||
boost = this.runEvent('TryBoost', target, source, effect, {...boost});
|
||||
let i: BoostID;
|
||||
for (i in boost) {
|
||||
const currentBoost: SparseBoostsTable = {};
|
||||
|
|
@ -540,7 +547,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
this.queue.clear();
|
||||
// Fainting clears accumulated Bide damage
|
||||
for (const pokemon of this.getAllActive()) {
|
||||
if (pokemon.volatiles['bide']?.damage) {
|
||||
if (pokemon.volatiles['bide'] && pokemon.volatiles['bide'].damage) {
|
||||
pokemon.volatiles['bide'].damage = 0;
|
||||
this.hint("Desync Clause Mod activated!");
|
||||
this.hint("In Gen 1, Bide's accumulated damage is reset to 0 when a Pokemon faints.");
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTable = {
|
||||
export const Abilities: {[k: string]: ModdedAbilityData} = {
|
||||
cutecharm: {
|
||||
inherit: true,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
|
|
@ -51,19 +51,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
}
|
||||
},
|
||||
},
|
||||
forecast: {
|
||||
inherit: true,
|
||||
flags: {},
|
||||
},
|
||||
hustle: {
|
||||
inherit: true,
|
||||
onSourceModifyAccuracy(accuracy, target, source, move) {
|
||||
const physicalTypes = ['Normal', 'Fighting', 'Flying', 'Poison', 'Ground', 'Rock', 'Bug', 'Ghost', 'Steel'];
|
||||
if (physicalTypes.includes(move.type) && typeof accuracy === 'number') {
|
||||
return this.chainModify([3277, 4096]);
|
||||
}
|
||||
},
|
||||
},
|
||||
intimidate: {
|
||||
inherit: true,
|
||||
onStart(pokemon) {
|
||||
|
|
@ -85,38 +72,22 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
if (target.volatiles['substitute']) {
|
||||
this.add('-immune', target);
|
||||
} else {
|
||||
this.boost({ atk: -1 }, target, pokemon, null, true);
|
||||
this.boost({atk: -1}, target, pokemon, null, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
lightningrod: {
|
||||
inherit: true,
|
||||
onAnyRedirectTarget: undefined, // no inherit
|
||||
onFoeRedirectTarget(target, source, source2, move) {
|
||||
// don't count Hidden Power as Electric-type
|
||||
if (this.dex.moves.get(move.id).type !== 'Electric') return;
|
||||
if (move.type !== 'Electric') return;
|
||||
if (this.validTarget(this.effectState.target, source, move.target)) {
|
||||
return this.effectState.target;
|
||||
}
|
||||
},
|
||||
},
|
||||
magnetpull: {
|
||||
inherit: true,
|
||||
onFoeTrapPokemon: undefined, // no inherit
|
||||
onFoeMaybeTrapPokemon: undefined, // no inherit
|
||||
onAnyTrapPokemon(pokemon) {
|
||||
if (pokemon.hasType('Steel') && pokemon.isAdjacent(this.effectState.target)) {
|
||||
pokemon.tryTrap(true);
|
||||
}
|
||||
},
|
||||
onAnyMaybeTrapPokemon(pokemon, source) {
|
||||
if (!source) source = this.effectState.target;
|
||||
if (!source || !pokemon.isAdjacent(source)) return;
|
||||
if (!pokemon.knownType || pokemon.hasType('Steel')) {
|
||||
pokemon.maybeTrapped = true;
|
||||
}
|
||||
},
|
||||
isBreakable: true,
|
||||
name: "Lightning Rod",
|
||||
rating: 0,
|
||||
num: 32,
|
||||
},
|
||||
minus: {
|
||||
inherit: true,
|
||||
|
|
@ -156,7 +127,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
},
|
||||
raindish: {
|
||||
inherit: true,
|
||||
onWeather: undefined, // no inherit
|
||||
onWeather() {},
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 3,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -191,18 +162,23 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
},
|
||||
trace: {
|
||||
inherit: true,
|
||||
onUpdate: undefined, // no inherit
|
||||
onStart(pokemon) {
|
||||
onUpdate(pokemon) {
|
||||
if (!pokemon.isStarted) return;
|
||||
const target = pokemon.side.randomFoe();
|
||||
if (!target || target.fainted) return;
|
||||
const ability = target.getAbility();
|
||||
pokemon.setAbility(ability, target);
|
||||
const bannedAbilities = ['forecast', 'multitype', 'trace'];
|
||||
if (bannedAbilities.includes(target.ability)) {
|
||||
return;
|
||||
}
|
||||
if (pokemon.setAbility(ability)) {
|
||||
this.add('-ability', pokemon, ability, '[from] ability: Trace', '[of] ' + target);
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
},
|
||||
truant: {
|
||||
inherit: true,
|
||||
onStart: undefined, // no inherit
|
||||
onStart() {},
|
||||
onSwitchIn(pokemon) {
|
||||
pokemon.truantTurn = this.turn !== 0;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDataTable = {
|
||||
export const Conditions: {[k: string]: ModdedConditionData} = {
|
||||
slp: {
|
||||
name: 'slp',
|
||||
effectType: 'Status',
|
||||
onStart(target, source, sourceEffect) {
|
||||
if (sourceEffect && sourceEffect.effectType === 'Move') {
|
||||
this.add('-status', target, 'slp', `[from] move: ${sourceEffect.name}`);
|
||||
this.add('-status', target, 'slp', '[from] move: ' + sourceEffect.name);
|
||||
} else {
|
||||
this.add('-status', target, 'slp');
|
||||
}
|
||||
|
|
@ -51,6 +51,6 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
},
|
||||
sandstorm: {
|
||||
inherit: true,
|
||||
onModifySpD: undefined, // no inherit
|
||||
onModifySpD() {},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormatsDataTable = {
|
||||
export const FormatsData: {[k: string]: ModdedSpeciesFormatsData} = {
|
||||
bulbasaur: {
|
||||
tier: "LC",
|
||||
},
|
||||
ivysaur: {
|
||||
tier: "ZU",
|
||||
tier: "NFE",
|
||||
},
|
||||
venusaur: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -12,7 +12,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
charmeleon: {
|
||||
tier: "PU",
|
||||
tier: "NFE",
|
||||
},
|
||||
charizard: {
|
||||
tier: "OU",
|
||||
|
|
@ -21,7 +21,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
wartortle: {
|
||||
tier: "PU",
|
||||
tier: "NFE",
|
||||
},
|
||||
blastoise: {
|
||||
tier: "UU",
|
||||
|
|
@ -33,7 +33,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
butterfree: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
weedle: {
|
||||
tier: "LC",
|
||||
|
|
@ -42,7 +42,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
beedrill: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
pidgey: {
|
||||
tier: "LC",
|
||||
|
|
@ -63,7 +63,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
fearow: {
|
||||
tier: "RUBL",
|
||||
tier: "UU",
|
||||
},
|
||||
ekans: {
|
||||
tier: "LC",
|
||||
|
|
@ -78,7 +78,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NU",
|
||||
},
|
||||
raichu: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
sandshrew: {
|
||||
tier: "LC",
|
||||
|
|
@ -111,13 +111,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
clefable: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
vulpix: {
|
||||
tier: "LC",
|
||||
},
|
||||
ninetales: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
igglybuff: {
|
||||
tier: "LC",
|
||||
|
|
@ -141,7 +141,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
gloom: {
|
||||
tier: "ZU",
|
||||
tier: "NFE",
|
||||
},
|
||||
vileplume: {
|
||||
tier: "UU",
|
||||
|
|
@ -153,7 +153,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
parasect: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
venonat: {
|
||||
tier: "LC",
|
||||
|
|
@ -171,7 +171,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
persian: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
psyduck: {
|
||||
tier: "LC",
|
||||
|
|
@ -183,7 +183,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
primeape: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
growlithe: {
|
||||
tier: "LC",
|
||||
|
|
@ -195,16 +195,16 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
poliwhirl: {
|
||||
tier: "ZUBL",
|
||||
tier: "NFE",
|
||||
},
|
||||
poliwrath: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
politoed: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
abra: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
kadabra: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -228,10 +228,10 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
victreebel: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
tentacool: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
tentacruel: {
|
||||
tier: "UU",
|
||||
|
|
@ -240,16 +240,16 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
graveler: {
|
||||
tier: "PU",
|
||||
tier: "NFE",
|
||||
},
|
||||
golem: {
|
||||
tier: "UU",
|
||||
},
|
||||
ponyta: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
rapidash: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
slowpoke: {
|
||||
tier: "LC",
|
||||
|
|
@ -261,16 +261,16 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
magnemite: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
magneton: {
|
||||
tier: "OU",
|
||||
},
|
||||
farfetchd: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
doduo: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
dodrio: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -294,7 +294,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "OU",
|
||||
},
|
||||
gastly: {
|
||||
tier: "PU",
|
||||
tier: "LC",
|
||||
},
|
||||
haunter: {
|
||||
tier: "NU",
|
||||
|
|
@ -309,10 +309,10 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UUBL",
|
||||
},
|
||||
drowzee: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
hypno: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
krabby: {
|
||||
tier: "LC",
|
||||
|
|
@ -321,7 +321,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "PU",
|
||||
},
|
||||
voltorb: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
electrode: {
|
||||
tier: "UU",
|
||||
|
|
@ -333,7 +333,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UUBL",
|
||||
},
|
||||
cubone: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
marowak: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -354,13 +354,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "PU",
|
||||
},
|
||||
koffing: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
weezing: {
|
||||
tier: "UUBL",
|
||||
},
|
||||
rhyhorn: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
rhydon: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -381,7 +381,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
seadra: {
|
||||
tier: "PU",
|
||||
tier: "NFE",
|
||||
},
|
||||
kingdra: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -390,7 +390,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
seaking: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
staryu: {
|
||||
tier: "LC",
|
||||
|
|
@ -399,7 +399,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "OU",
|
||||
},
|
||||
mrmime: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
scyther: {
|
||||
tier: "UU",
|
||||
|
|
@ -414,7 +414,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UUBL",
|
||||
},
|
||||
elekid: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
electabuzz: {
|
||||
tier: "UU",
|
||||
|
|
@ -423,7 +423,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
magmar: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
pinsir: {
|
||||
tier: "UU",
|
||||
|
|
@ -438,10 +438,10 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "OU",
|
||||
},
|
||||
lapras: {
|
||||
tier: "UU",
|
||||
tier: "UUBL",
|
||||
},
|
||||
ditto: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
eevee: {
|
||||
tier: "LC",
|
||||
|
|
@ -462,13 +462,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UUBL",
|
||||
},
|
||||
porygon: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
porygon2: {
|
||||
tier: "UUBL",
|
||||
},
|
||||
omanyte: {
|
||||
tier: "PU",
|
||||
tier: "LC",
|
||||
},
|
||||
omastar: {
|
||||
tier: "UU",
|
||||
|
|
@ -477,7 +477,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
kabutops: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
aerodactyl: {
|
||||
tier: "OU",
|
||||
|
|
@ -498,7 +498,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
dragonair: {
|
||||
tier: "PU",
|
||||
tier: "NFE",
|
||||
},
|
||||
dragonite: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -516,13 +516,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
meganium: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
cyndaquil: {
|
||||
tier: "LC",
|
||||
},
|
||||
quilava: {
|
||||
tier: "ZU",
|
||||
tier: "NFE",
|
||||
},
|
||||
typhlosion: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -546,22 +546,22 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
noctowl: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
ledyba: {
|
||||
tier: "LC",
|
||||
},
|
||||
ledian: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
spinarak: {
|
||||
tier: "LC",
|
||||
},
|
||||
ariados: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
chinchou: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
lanturn: {
|
||||
tier: "UU",
|
||||
|
|
@ -576,13 +576,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
xatu: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
mareep: {
|
||||
tier: "LC",
|
||||
},
|
||||
flaaffy: {
|
||||
tier: "ZU",
|
||||
tier: "NFE",
|
||||
},
|
||||
ampharos: {
|
||||
tier: "UU",
|
||||
|
|
@ -594,7 +594,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
azumarill: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
sudowoodo: {
|
||||
tier: "NU",
|
||||
|
|
@ -606,19 +606,19 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
jumpluff: {
|
||||
tier: "RUBL",
|
||||
tier: "UUBL",
|
||||
},
|
||||
aipom: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
sunkern: {
|
||||
tier: "LC",
|
||||
},
|
||||
sunflora: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
yanma: {
|
||||
tier: "ZUBL",
|
||||
tier: "PU",
|
||||
},
|
||||
wooper: {
|
||||
tier: "LC",
|
||||
|
|
@ -633,7 +633,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
unown: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
wynaut: {
|
||||
tier: "Uber",
|
||||
|
|
@ -645,7 +645,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
pineco: {
|
||||
tier: "PU",
|
||||
tier: "LC",
|
||||
},
|
||||
forretress: {
|
||||
tier: "OU",
|
||||
|
|
@ -672,7 +672,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "OU",
|
||||
},
|
||||
sneasel: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
teddiursa: {
|
||||
tier: "LC",
|
||||
|
|
@ -690,10 +690,10 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
piloswine: {
|
||||
tier: "PUBL",
|
||||
tier: "PU",
|
||||
},
|
||||
corsola: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
remoraid: {
|
||||
tier: "LC",
|
||||
|
|
@ -702,16 +702,16 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NU",
|
||||
},
|
||||
delibird: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
mantine: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
skarmory: {
|
||||
tier: "OU",
|
||||
},
|
||||
houndour: {
|
||||
tier: "PU",
|
||||
tier: "LC",
|
||||
},
|
||||
houndoom: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -723,7 +723,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UUBL",
|
||||
},
|
||||
stantler: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
smeargle: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -762,7 +762,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
grovyle: {
|
||||
tier: "ZU",
|
||||
tier: "NFE",
|
||||
},
|
||||
sceptile: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -771,7 +771,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
combusken: {
|
||||
tier: "PU",
|
||||
tier: "NFE",
|
||||
},
|
||||
blaziken: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -780,7 +780,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
marshtomp: {
|
||||
tier: "PU",
|
||||
tier: "NFE",
|
||||
},
|
||||
swampert: {
|
||||
tier: "OU",
|
||||
|
|
@ -789,13 +789,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
mightyena: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
zigzagoon: {
|
||||
tier: "NFE",
|
||||
tier: "LC",
|
||||
},
|
||||
linoone: {
|
||||
tier: "UUBL",
|
||||
tier: "UU",
|
||||
},
|
||||
wurmple: {
|
||||
tier: "LC",
|
||||
|
|
@ -804,13 +804,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
beautifly: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
cascoon: {
|
||||
tier: "NFE",
|
||||
},
|
||||
dustox: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
lotad: {
|
||||
tier: "LC",
|
||||
|
|
@ -828,7 +828,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
shiftry: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
taillow: {
|
||||
tier: "LC",
|
||||
|
|
@ -855,7 +855,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
masquerain: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
shroomish: {
|
||||
tier: "LC",
|
||||
|
|
@ -876,7 +876,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
ninjask: {
|
||||
tier: "RUBL",
|
||||
tier: "UU",
|
||||
},
|
||||
shedinja: {
|
||||
tier: "PU",
|
||||
|
|
@ -888,7 +888,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
exploud: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
makuhita: {
|
||||
tier: "LC",
|
||||
|
|
@ -897,13 +897,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UUBL",
|
||||
},
|
||||
nosepass: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
skitty: {
|
||||
tier: "LC",
|
||||
},
|
||||
delcatty: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
sableye: {
|
||||
tier: "NU",
|
||||
|
|
@ -915,22 +915,22 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
lairon: {
|
||||
tier: "ZUBL",
|
||||
tier: "NFE",
|
||||
},
|
||||
aggron: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
meditite: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
medicham: {
|
||||
tier: "OU",
|
||||
tier: "UUBL",
|
||||
},
|
||||
electrike: {
|
||||
tier: "LC",
|
||||
},
|
||||
manectric: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
plusle: {
|
||||
tier: "NU",
|
||||
|
|
@ -939,10 +939,10 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "PU",
|
||||
},
|
||||
volbeat: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
illumise: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
roselia: {
|
||||
tier: "NU",
|
||||
|
|
@ -957,7 +957,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
sharpedo: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
wailmer: {
|
||||
tier: "LC",
|
||||
|
|
@ -969,7 +969,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
camerupt: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
torkoal: {
|
||||
tier: "NU",
|
||||
|
|
@ -981,13 +981,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
spinda: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
trapinch: {
|
||||
tier: "PU",
|
||||
tier: "LC",
|
||||
},
|
||||
vibrava: {
|
||||
tier: "PU",
|
||||
tier: "NFE",
|
||||
},
|
||||
flygon: {
|
||||
tier: "OU",
|
||||
|
|
@ -1035,13 +1035,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "OU",
|
||||
},
|
||||
lileep: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
cradily: {
|
||||
tier: "UU",
|
||||
},
|
||||
anorith: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
armaldo: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -1053,13 +1053,16 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "OU",
|
||||
},
|
||||
castform: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
castformsunny: {
|
||||
tier: "PU",
|
||||
},
|
||||
castformrainy: {
|
||||
tier: "PU",
|
||||
},
|
||||
castformsnowy: {
|
||||
tier: "PU",
|
||||
},
|
||||
kecleon: {
|
||||
tier: "NU",
|
||||
|
|
@ -1068,40 +1071,40 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
banette: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
duskull: {
|
||||
tier: "PU",
|
||||
tier: "LC",
|
||||
},
|
||||
dusclops: {
|
||||
tier: "UUBL",
|
||||
},
|
||||
tropius: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
chimecho: {
|
||||
tier: "NU",
|
||||
},
|
||||
absol: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
},
|
||||
snorunt: {
|
||||
tier: "LC",
|
||||
},
|
||||
glalie: {
|
||||
tier: "NUBL",
|
||||
tier: "NU",
|
||||
},
|
||||
spheal: {
|
||||
tier: "LC",
|
||||
},
|
||||
sealeo: {
|
||||
tier: "PU",
|
||||
tier: "NFE",
|
||||
},
|
||||
walrein: {
|
||||
tier: "UU",
|
||||
},
|
||||
clamperl: {
|
||||
tier: "PU",
|
||||
tier: "LC",
|
||||
},
|
||||
huntail: {
|
||||
tier: "NU",
|
||||
|
|
@ -1113,13 +1116,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NU",
|
||||
},
|
||||
luvdisc: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
bagon: {
|
||||
tier: "LC",
|
||||
},
|
||||
shelgon: {
|
||||
tier: "ZUBL",
|
||||
tier: "NFE",
|
||||
},
|
||||
salamence: {
|
||||
tier: "OU",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
||||
export const Items: {[k: string]: ModdedItemData} = {
|
||||
aguavberry: {
|
||||
inherit: true,
|
||||
onUpdate: undefined, // no inherit
|
||||
onUpdate() {},
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -12,7 +12,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
apicotberry: {
|
||||
inherit: true,
|
||||
onUpdate: undefined, // no inherit
|
||||
onUpdate() {},
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -23,12 +23,12 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
berryjuice: {
|
||||
inherit: true,
|
||||
onUpdate: undefined, // no inherit
|
||||
onUpdate() {},
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
if (pokemon.hp <= pokemon.maxhp / 2) {
|
||||
if (this.runEvent('TryHeal', pokemon, null, this.effect, 20) && pokemon.useItem()) {
|
||||
if (this.runEvent('TryHeal', pokemon) && pokemon.useItem()) {
|
||||
this.heal(20);
|
||||
}
|
||||
}
|
||||
|
|
@ -37,7 +37,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
blackbelt: {
|
||||
inherit: true,
|
||||
onBasePower: undefined, // no inherit
|
||||
onBasePower() {},
|
||||
onModifyAtkPriority: 1,
|
||||
onModifyAtk(atk, user, target, move) {
|
||||
if (move?.type === 'Fighting') {
|
||||
|
|
@ -47,7 +47,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
blackglasses: {
|
||||
inherit: true,
|
||||
onBasePower: undefined, // no inherit
|
||||
onBasePower() {},
|
||||
onModifySpAPriority: 1,
|
||||
onModifySpA(spa, user, target, move) {
|
||||
if (move?.type === 'Dark') {
|
||||
|
|
@ -57,7 +57,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
charcoal: {
|
||||
inherit: true,
|
||||
onBasePower: undefined, // no inherit
|
||||
onBasePower() {},
|
||||
onModifySpAPriority: 1,
|
||||
onModifySpA(spa, user, target, move) {
|
||||
if (move?.type === 'Fire') {
|
||||
|
|
@ -67,7 +67,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
dragonfang: {
|
||||
inherit: true,
|
||||
onBasePower: undefined, // no inherit
|
||||
onBasePower() {},
|
||||
onModifySpAPriority: 1,
|
||||
onModifySpA(spa, user, target, move) {
|
||||
if (move?.type === 'Dragon') {
|
||||
|
|
@ -82,7 +82,6 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
num: 208,
|
||||
gen: 3,
|
||||
isNonstandard: "Unobtainable",
|
||||
// No competitive use
|
||||
},
|
||||
fastball: {
|
||||
inherit: true,
|
||||
|
|
@ -90,7 +89,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
figyberry: {
|
||||
inherit: true,
|
||||
onUpdate: undefined, // no inherit
|
||||
onUpdate() {},
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -101,7 +100,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
ganlonberry: {
|
||||
inherit: true,
|
||||
onUpdate: undefined, // no inherit
|
||||
onUpdate() {},
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -112,7 +111,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
hardstone: {
|
||||
inherit: true,
|
||||
onBasePower: undefined, // no inherit
|
||||
onBasePower() {},
|
||||
onModifyAtkPriority: 1,
|
||||
onModifyAtk(atk, user, target, move) {
|
||||
if (move?.type === 'Rock') {
|
||||
|
|
@ -126,7 +125,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
iapapaberry: {
|
||||
inherit: true,
|
||||
onUpdate: undefined, // no inherit
|
||||
onUpdate() {},
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -139,8 +138,8 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
inherit: true,
|
||||
onModifyMove(move) {
|
||||
const affectedByKingsRock = [
|
||||
'aerialace', 'aeroblast', 'aircutter', 'armthrust', 'barrage', 'beatup', 'bide', 'bind', 'blastburn', 'bonerush', 'bonemerang', 'bounce', 'brickbreak', 'bulletseed', 'clamp', 'cometpunch', 'crabhammer', 'crosschop', 'cut', 'dig', 'dive', 'doublekick', 'doubleslap', 'doubleedge', 'dragonbreath', 'dragonclaw', 'dragonrage', 'drillpeck', 'earthquake', 'eggbomb', 'endeavor', 'eruption', 'explosion', 'extremespeed', 'falseswipe', 'feintattack', 'firespin', 'flail', 'fly', 'frenzyplant', 'frustration', 'furyattack', 'furycutter', 'furyswipes', 'gust', 'hiddenpower', 'highjumpkick', 'hornattack', 'hydrocannon', 'hydropump', 'hyperbeam', 'iceball', 'iciclespear', 'jumpkick', 'karatechop', 'leafblade', 'lowkick', 'machpunch', 'magicalleaf', 'magnitude', 'megakick', 'megapunch', 'megahorn', 'meteormash', 'mudshot', 'muddywater', 'nightshade', 'outrage', 'overheat', 'payday', 'peck', 'petaldance', 'pinmissile', 'poisontail', 'pound', 'psychoboost', 'psywave', 'quickattack', 'rage', 'rapidspin', 'razorleaf', 'razorwind', 'return', 'revenge', 'reversal', 'rockblast', 'rockthrow', 'rollingkick', 'rollout', 'sandtomb', 'scratch', 'seismictoss', 'selfdestruct', 'shadowpunch', 'shockwave', 'signalbeam', 'silverwind', 'skullbash', 'skyattack', 'skyuppercut', 'slam', 'slash', 'snore', 'solarbeam', 'sonicboom', 'spikecannon', 'spitup', 'steelwing', 'strength', 'struggle', 'submission', 'surf', 'swift', 'tackle', 'takedown', 'thrash', 'triplekick', 'twister', 'uproar', 'visegrip', 'vinewhip', 'vitalthrow', 'volttackle', 'watergun', 'waterpulse', 'waterfall', 'weatherball', 'whirlpool', 'wingattack', 'wrap',
|
||||
]; // Tickle also has the move flag, but can never flinch because King's Rock requires damage to trigger
|
||||
'aerialace', 'aeroblast', 'aircutter', 'armthrust', 'barrage', 'beatup', 'bide', 'bind', 'blastburn', 'bonerush', 'bonemerang', 'bounce', 'brickbreak', 'bulletseed', 'clamp', 'cometpunch', 'crabhammer', 'crosschop', 'cut', 'dig', 'dive', 'doublekick', 'doubleslap', 'doubleedge', 'dragonbreath', 'dragonclaw', 'dragonrage', 'drillpeck', 'earthquake', 'eggbomb', 'endeavor', 'eruption', 'explosion', 'extremespeed', 'falseswipe', 'feintattack', 'firespin', 'flail', 'fly', 'frenzyplant', 'frustration', 'furyattack', 'furycutter', 'furyswipes', 'gust', 'hiddenpower', 'highjumpkick', 'hornattack', 'hydrocannon', 'hydropump', 'hyperbeam', 'iceball', 'iciclespear', 'jumpkick', 'karatechop', 'leafblade', 'lowkick', 'machpunch', 'magicalleaf', 'magnitude', 'megakick', 'megapunch', 'megahorn', 'meteormash', 'mudshot', 'muddywater', 'nightshade', 'outrage', 'overheat', 'payday', 'peck', 'petaldance', 'pinmissile', 'poisontail', 'pound', 'psychoboost', 'psywave', 'quickattack', 'rage', 'rapidspin', 'razorleaf', 'razorwind', 'return', 'revenge', 'reversal', 'rockblast', 'rockthrow', 'rollingkick', 'rollout', 'sandtomb', 'scratch', 'seismictoss', 'selfdestruct', 'shadowpunch', 'shockwave', 'signalbeam', 'silverwind', 'skullbash', 'skyattack', 'skyuppercut', 'slam', 'slash', 'snore', 'solarbeam', 'sonicboom', 'spikecannon', 'spitup', 'steelwing', 'strength', 'struggle', 'submission', 'surf', 'swift', 'tackle', 'takedown', 'thrash', 'tickle', 'triplekick', 'twister', 'uproar', 'visegrip', 'vinewhip', 'vitalthrow', 'volttackle', 'watergun', 'waterpulse', 'waterfall', 'weatherball', 'whirlpool', 'wingattack', 'wrap',
|
||||
];
|
||||
if (affectedByKingsRock.includes(move.id)) {
|
||||
if (!move.secondaries) move.secondaries = [];
|
||||
move.secondaries.push({
|
||||
|
|
@ -152,7 +151,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
lansatberry: {
|
||||
inherit: true,
|
||||
onUpdate: undefined, // no inherit
|
||||
onUpdate() {},
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -175,7 +174,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
liechiberry: {
|
||||
inherit: true,
|
||||
onUpdate: undefined, // no inherit
|
||||
onUpdate() {},
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -191,7 +190,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
return this.chainModify(2);
|
||||
}
|
||||
},
|
||||
onBasePower: undefined, // no inherit
|
||||
onBasePower() {},
|
||||
},
|
||||
loveball: {
|
||||
inherit: true,
|
||||
|
|
@ -203,7 +202,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
magnet: {
|
||||
inherit: true,
|
||||
onBasePower: undefined, // no inherit
|
||||
onBasePower() {},
|
||||
onModifySpAPriority: 1,
|
||||
onModifySpA(spa, user, target, move) {
|
||||
if (move?.type === 'Electric') {
|
||||
|
|
@ -213,7 +212,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
magoberry: {
|
||||
inherit: true,
|
||||
onUpdate: undefined, // no inherit
|
||||
onUpdate() {},
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -224,7 +223,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
metalcoat: {
|
||||
inherit: true,
|
||||
onBasePower: undefined, // no inherit
|
||||
onBasePower() {},
|
||||
onModifyAtkPriority: 1,
|
||||
onModifyAtk(atk, user, target, move) {
|
||||
if (move?.type === 'Steel') {
|
||||
|
|
@ -234,7 +233,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
miracleseed: {
|
||||
inherit: true,
|
||||
onBasePower: undefined, // no inherit
|
||||
onBasePower() {},
|
||||
onModifySpAPriority: 1,
|
||||
onModifySpA(spa, user, target, move) {
|
||||
if (move?.type === 'Grass') {
|
||||
|
|
@ -248,7 +247,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
mysticwater: {
|
||||
inherit: true,
|
||||
onBasePower: undefined, // no inherit
|
||||
onBasePower() {},
|
||||
onModifySpAPriority: 1,
|
||||
onModifySpA(spa, user, target, move) {
|
||||
if (move?.type === 'Water') {
|
||||
|
|
@ -258,7 +257,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
nevermeltice: {
|
||||
inherit: true,
|
||||
onBasePower: undefined, // no inherit
|
||||
onBasePower() {},
|
||||
onModifySpAPriority: 1,
|
||||
onModifySpA(spa, user, target, move) {
|
||||
if (move?.type === 'Ice') {
|
||||
|
|
@ -268,7 +267,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
oranberry: {
|
||||
inherit: true,
|
||||
onUpdate: undefined, // no inherit
|
||||
onUpdate() {},
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -279,7 +278,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
petayaberry: {
|
||||
inherit: true,
|
||||
onUpdate: undefined, // no inherit
|
||||
onUpdate() {},
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -290,7 +289,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
poisonbarb: {
|
||||
inherit: true,
|
||||
onBasePower: undefined, // no inherit
|
||||
onBasePower() {},
|
||||
onModifyAtkPriority: 1,
|
||||
onModifyAtk(atk, user, target, move) {
|
||||
if (move?.type === 'Poison') {
|
||||
|
|
@ -300,12 +299,12 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
quickclaw: {
|
||||
inherit: true,
|
||||
onFractionalPriority: undefined, // no inherit
|
||||
onFractionalPriority() {},
|
||||
// implemented in Pokemon#getActionSpeed()
|
||||
},
|
||||
salacberry: {
|
||||
inherit: true,
|
||||
onUpdate: undefined, // no inherit
|
||||
onUpdate() {},
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -316,7 +315,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
seaincense: {
|
||||
inherit: true,
|
||||
onBasePower: undefined, // no inherit
|
||||
onBasePower() {},
|
||||
onModifySpAPriority: 1,
|
||||
onModifySpA(spa, user, target, move) {
|
||||
if (move?.type === 'Water') {
|
||||
|
|
@ -326,7 +325,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
sharpbeak: {
|
||||
inherit: true,
|
||||
onBasePower: undefined, // no inherit
|
||||
onBasePower() {},
|
||||
onModifyAtkPriority: 1,
|
||||
onModifyAtk(atk, user, target, move) {
|
||||
if (move?.type === 'Flying') {
|
||||
|
|
@ -336,7 +335,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
silkscarf: {
|
||||
inherit: true,
|
||||
onBasePower: undefined, // no inherit
|
||||
onBasePower() {},
|
||||
onModifyAtkPriority: 1,
|
||||
onModifyAtk(atk, user, target, move) {
|
||||
if (move?.type === 'Normal') {
|
||||
|
|
@ -346,7 +345,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
silverpowder: {
|
||||
inherit: true,
|
||||
onBasePower: undefined, // no inherit
|
||||
onBasePower() {},
|
||||
onModifyAtkPriority: 1,
|
||||
onModifyAtk(atk, user, target, move) {
|
||||
if (move?.type === 'Bug') {
|
||||
|
|
@ -356,7 +355,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
sitrusberry: {
|
||||
inherit: true,
|
||||
onUpdate: undefined, // no inherit
|
||||
onUpdate() {},
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -370,7 +369,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
softsand: {
|
||||
inherit: true,
|
||||
onBasePower: undefined, // no inherit
|
||||
onBasePower() {},
|
||||
onModifyAtkPriority: 1,
|
||||
onModifyAtk(atk, user, target, move) {
|
||||
if (move?.type === 'Ground') {
|
||||
|
|
@ -380,7 +379,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
spelltag: {
|
||||
inherit: true,
|
||||
onBasePower: undefined, // no inherit
|
||||
onBasePower() {},
|
||||
onModifyAtkPriority: 1,
|
||||
onModifyAtk(atk, user, target, move) {
|
||||
if (move?.type === 'Ghost') {
|
||||
|
|
@ -394,7 +393,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
starfberry: {
|
||||
inherit: true,
|
||||
onUpdate: undefined, // no inherit
|
||||
onUpdate() {},
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -405,7 +404,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
twistedspoon: {
|
||||
inherit: true,
|
||||
onBasePower: undefined, // no inherit
|
||||
onBasePower() {},
|
||||
onModifySpAPriority: 1,
|
||||
onModifySpA(spa, user, target, move) {
|
||||
if (move?.type === 'Psychic') {
|
||||
|
|
@ -415,7 +414,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
wikiberry: {
|
||||
inherit: true,
|
||||
onUpdate: undefined, // no inherit
|
||||
onUpdate() {},
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
* Gen 3 moves
|
||||
*/
|
||||
|
||||
export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
||||
export const Moves: {[k: string]: ModdedMoveData} = {
|
||||
absorb: {
|
||||
inherit: true,
|
||||
pp: 20,
|
||||
|
|
@ -18,15 +18,14 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
ancientpower: {
|
||||
inherit: true,
|
||||
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
|
||||
},
|
||||
assist: {
|
||||
inherit: true,
|
||||
flags: { metronome: 1, noassist: 1, nosleeptalk: 1 },
|
||||
flags: {contact: 1, protect: 1, mirror: 1},
|
||||
},
|
||||
astonish: {
|
||||
inherit: true,
|
||||
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1, minimize: 1 },
|
||||
basePowerCallback(pokemon, target) {
|
||||
if (target.volatiles['minimize']) return 60;
|
||||
return 30;
|
||||
},
|
||||
},
|
||||
beatup: {
|
||||
inherit: true,
|
||||
|
|
@ -41,16 +40,15 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
duration: 1,
|
||||
onModifySpAPriority: -101,
|
||||
onModifySpA(atk, pokemon, defender, move) {
|
||||
if (!this.ruleTable.has('beatupnicknamesmod')) {
|
||||
this.add('-activate', pokemon, 'move: Beat Up', '[of] ' + move.allies![0].name);
|
||||
}
|
||||
// https://www.smogon.com/forums/posts/8992145/
|
||||
// this.add('-activate', pokemon, 'move: Beat Up', '[of] ' + move.allies![0].name);
|
||||
this.event.modifier = 1;
|
||||
return this.dex.species.get(move.allies!.shift()!.set.species).baseStats.atk;
|
||||
return move.allies!.shift()!.species.baseStats.atk;
|
||||
},
|
||||
onFoeModifySpDPriority: -101,
|
||||
onFoeModifySpD(def, pokemon) {
|
||||
this.event.modifier = 1;
|
||||
return this.dex.species.get(pokemon.set.species).baseStats.def;
|
||||
return pokemon.species.baseStats.def;
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -59,8 +57,18 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
accuracy: 100,
|
||||
priority: 0,
|
||||
condition: {
|
||||
inherit: true,
|
||||
onAfterSetStatus: undefined, // no inherit
|
||||
duration: 3,
|
||||
onLockMove: 'bide',
|
||||
onStart(pokemon) {
|
||||
this.effectState.totalDamage = 0;
|
||||
this.add('-start', pokemon, 'move: Bide');
|
||||
},
|
||||
onDamagePriority: -101,
|
||||
onDamage(damage, target, source, move) {
|
||||
if (!move || move.effectType !== 'Move' || !source) return;
|
||||
this.effectState.totalDamage += damage;
|
||||
this.effectState.lastDamageSource = source;
|
||||
},
|
||||
onBeforeMove(pokemon, target, move) {
|
||||
if (this.effectState.duration === 1) {
|
||||
this.add('-end', pokemon, 'move: Bide');
|
||||
|
|
@ -88,7 +96,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
damage: this.effectState.totalDamage * 2,
|
||||
category: "Physical",
|
||||
priority: 0,
|
||||
flags: { contact: 1, protect: 1 },
|
||||
flags: {contact: 1, protect: 1},
|
||||
effectType: 'Move',
|
||||
type: 'Normal',
|
||||
} as unknown as ActiveMove;
|
||||
|
|
@ -98,11 +106,17 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
}
|
||||
this.add('-activate', pokemon, 'move: Bide');
|
||||
},
|
||||
onMoveAborted(pokemon) {
|
||||
pokemon.removeVolatile('bide');
|
||||
},
|
||||
onEnd(pokemon) {
|
||||
this.add('-end', pokemon, 'move: Bide', '[silent]');
|
||||
},
|
||||
},
|
||||
},
|
||||
blizzard: {
|
||||
inherit: true,
|
||||
onModifyMove: undefined, // no inherit
|
||||
onModifyMove() { },
|
||||
},
|
||||
brickbreak: {
|
||||
inherit: true,
|
||||
|
|
@ -115,7 +129,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
charge: {
|
||||
inherit: true,
|
||||
boosts: undefined, // no inherit
|
||||
boosts: null,
|
||||
},
|
||||
conversion: {
|
||||
inherit: true,
|
||||
|
|
@ -136,39 +150,20 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
this.add('-start', target, 'typechange', type);
|
||||
},
|
||||
},
|
||||
conversion2: {
|
||||
inherit: true,
|
||||
onHit(target, source) {
|
||||
if (!target.lastMoveUsed) {
|
||||
return false;
|
||||
}
|
||||
const possibleTypes = [];
|
||||
const lastMoveUsed = target.lastMoveUsed;
|
||||
const attackType = lastMoveUsed.id === 'struggle' ? 'Normal' : lastMoveUsed.type;
|
||||
for (const typeName of this.dex.types.names()) {
|
||||
const typeCheck = this.dex.types.get(typeName).damageTaken[attackType];
|
||||
if (typeCheck === 2 || typeCheck === 3) {
|
||||
possibleTypes.push(typeName);
|
||||
}
|
||||
}
|
||||
if (!possibleTypes.length) {
|
||||
return false;
|
||||
}
|
||||
const randomType = this.sample(possibleTypes);
|
||||
|
||||
if (!source.setType(randomType)) return false;
|
||||
this.add('-start', source, 'typechange', randomType);
|
||||
},
|
||||
},
|
||||
counter: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
duration: 1,
|
||||
noCopy: true,
|
||||
onStart(target, source, move) {
|
||||
this.effectState.slot = null;
|
||||
this.effectState.damage = 0;
|
||||
},
|
||||
onRedirectTargetPriority: -1,
|
||||
onRedirectTarget(target, source, source2) {
|
||||
if (source !== this.effectState.target || !this.effectState.slot) return;
|
||||
return this.getAtSlot(this.effectState.slot);
|
||||
},
|
||||
onDamagingHit: undefined, // no inherit
|
||||
onDamagePriority: -101,
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (
|
||||
|
|
@ -183,7 +178,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
covet: {
|
||||
inherit: true,
|
||||
flags: { protect: 1, mirror: 1, noassist: 1 },
|
||||
flags: {protect: 1, mirror: 1, noassist: 1},
|
||||
},
|
||||
crunch: {
|
||||
inherit: true,
|
||||
|
|
@ -201,14 +196,49 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
disable: {
|
||||
inherit: true,
|
||||
accuracy: 55,
|
||||
flags: { protect: 1, mirror: 1, bypasssub: 1, metronome: 1 },
|
||||
flags: {protect: 1, mirror: 1, bypasssub: 1},
|
||||
volatileStatus: 'disable',
|
||||
condition: {
|
||||
inherit: true,
|
||||
durationCallback() {
|
||||
return this.random(2, 6);
|
||||
},
|
||||
"onResidualOrder": undefined, // no inherit
|
||||
"onResidualSubOrder": undefined, // no inherit
|
||||
noCopy: true,
|
||||
onStart(pokemon) {
|
||||
if (!this.queue.willMove(pokemon)) {
|
||||
this.effectState.duration++;
|
||||
}
|
||||
if (!pokemon.lastMove) {
|
||||
return false;
|
||||
}
|
||||
for (const moveSlot of pokemon.moveSlots) {
|
||||
if (moveSlot.id === pokemon.lastMove.id) {
|
||||
if (!moveSlot.pp) {
|
||||
return false;
|
||||
} else {
|
||||
this.add('-start', pokemon, 'Disable', moveSlot.move);
|
||||
this.effectState.move = pokemon.lastMove.id;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
onEnd(pokemon) {
|
||||
this.add('-end', pokemon, 'move: Disable');
|
||||
},
|
||||
onBeforeMove(attacker, defender, move) {
|
||||
if (move.id === this.effectState.move) {
|
||||
this.add('cant', attacker, 'Disable', move);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onDisableMove(pokemon) {
|
||||
for (const moveSlot of pokemon.moveSlots) {
|
||||
if (moveSlot.id === this.effectState.move) {
|
||||
pokemon.disableMove(moveSlot.id);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
dive: {
|
||||
|
|
@ -223,7 +253,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
name: "Doom Desire",
|
||||
basePower: 120,
|
||||
category: "Physical",
|
||||
flags: { metronome: 1, futuremove: 1 },
|
||||
flags: {},
|
||||
willCrit: false,
|
||||
type: '???',
|
||||
} as unknown as ActiveMove;
|
||||
|
|
@ -231,15 +261,15 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
Object.assign(target.side.slotConditions[target.position]['futuremove'], {
|
||||
duration: 3,
|
||||
move: 'doomdesire',
|
||||
source,
|
||||
source: source,
|
||||
moveData: {
|
||||
id: 'doomdesire',
|
||||
name: "Doom Desire",
|
||||
accuracy: 85,
|
||||
basePower: 0,
|
||||
damage,
|
||||
damage: damage,
|
||||
category: "Physical",
|
||||
flags: { metronome: 1, futuremove: 1 },
|
||||
flags: {futuremove: 1},
|
||||
effectType: 'Move',
|
||||
type: '???',
|
||||
},
|
||||
|
|
@ -252,45 +282,64 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
volatileStatus: 'encore',
|
||||
condition: {
|
||||
inherit: true,
|
||||
durationCallback() {
|
||||
return this.random(3, 7);
|
||||
},
|
||||
onStart(target, source) {
|
||||
const moveIndex = target.lastMove ? target.moves.indexOf(target.lastMove.id) : -1;
|
||||
if (
|
||||
!target.lastMove || target.lastMove.flags['failencore'] ||
|
||||
!target.moveSlots[moveIndex] || target.moveSlots[moveIndex].pp <= 0
|
||||
) {
|
||||
// it failed
|
||||
return false;
|
||||
}
|
||||
this.effectState.move = target.lastMove.id;
|
||||
this.add('-start', target, 'Encore');
|
||||
},
|
||||
onOverrideAction(pokemon) {
|
||||
return this.effectState.move;
|
||||
},
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 14,
|
||||
onResidual(target) {
|
||||
if (
|
||||
target.moves.includes(this.effectState.move) &&
|
||||
target.moveSlots[target.moves.indexOf(this.effectState.move)].pp <= 0
|
||||
) {
|
||||
// early termination if you run out of PP
|
||||
target.removeVolatile('encore');
|
||||
}
|
||||
},
|
||||
onEnd(target) {
|
||||
this.add('-end', target, 'Encore');
|
||||
},
|
||||
onDisableMove(pokemon) {
|
||||
if (!this.effectState.move || !pokemon.hasMove(this.effectState.move)) {
|
||||
return;
|
||||
}
|
||||
for (const moveSlot of pokemon.moveSlots) {
|
||||
if (moveSlot.id !== this.effectState.move) {
|
||||
pokemon.disableMove(moveSlot.id);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
extrasensory: {
|
||||
inherit: true,
|
||||
flags: { protect: 1, mirror: 1, metronome: 1, minimize: 1 },
|
||||
basePowerCallback(pokemon, target) {
|
||||
if (target.volatiles['minimize']) return 160;
|
||||
return 80;
|
||||
},
|
||||
},
|
||||
fakeout: {
|
||||
inherit: true,
|
||||
flags: { protect: 1, mirror: 1, metronome: 1 },
|
||||
flags: {protect: 1, mirror: 1},
|
||||
},
|
||||
feintattack: {
|
||||
inherit: true,
|
||||
flags: { protect: 1, mirror: 1, metronome: 1 },
|
||||
},
|
||||
flail: {
|
||||
inherit: true,
|
||||
basePowerCallback(pokemon) {
|
||||
const ratio = Math.max(Math.floor(pokemon.hp * 48 / pokemon.maxhp), 1);
|
||||
let bp;
|
||||
if (ratio < 2) {
|
||||
bp = 200;
|
||||
} else if (ratio < 5) {
|
||||
bp = 150;
|
||||
} else if (ratio < 10) {
|
||||
bp = 100;
|
||||
} else if (ratio < 17) {
|
||||
bp = 80;
|
||||
} else if (ratio < 33) {
|
||||
bp = 40;
|
||||
} else {
|
||||
bp = 20;
|
||||
}
|
||||
this.debug(`BP: ${bp}`);
|
||||
return bp;
|
||||
},
|
||||
flags: {protect: 1, mirror: 1},
|
||||
},
|
||||
flash: {
|
||||
inherit: true,
|
||||
|
|
@ -302,14 +351,15 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
followme: {
|
||||
inherit: true,
|
||||
volatileStatus: undefined, // no inherit
|
||||
volatileStatus: undefined,
|
||||
slotCondition: 'followme',
|
||||
condition: {
|
||||
inherit: true,
|
||||
duration: 1,
|
||||
onStart(target, source, effect) {
|
||||
this.add('-singleturn', target, 'move: Follow Me');
|
||||
this.effectState.slot = target.getSlot();
|
||||
},
|
||||
onFoeRedirectTargetPriority: 1,
|
||||
onFoeRedirectTarget(target, source, source2, move) {
|
||||
const userSlot = this.getAtSlot(this.effectState.slot);
|
||||
if (this.validTarget(userSlot, source, move.target)) {
|
||||
|
|
@ -336,15 +386,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
ignoreImmunity: false,
|
||||
},
|
||||
haze: {
|
||||
inherit: true,
|
||||
onHitField() {
|
||||
this.add('-clearallboost');
|
||||
for (const pokemon of this.getAllActive()) {
|
||||
pokemon.clearBoosts();
|
||||
}
|
||||
},
|
||||
},
|
||||
hiddenpower: {
|
||||
inherit: true,
|
||||
category: "Physical",
|
||||
|
|
@ -402,17 +443,22 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
mimic: {
|
||||
inherit: true,
|
||||
flags: { protect: 1, bypasssub: 1, allyanim: 1, failencore: 1, noassist: 1, failmimic: 1 },
|
||||
flags: {protect: 1, bypasssub: 1, allyanim: 1, failencore: 1, noassist: 1, failmimic: 1},
|
||||
},
|
||||
mirrorcoat: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
duration: 1,
|
||||
noCopy: true,
|
||||
onStart(target, source, move) {
|
||||
this.effectState.slot = null;
|
||||
this.effectState.damage = 0;
|
||||
},
|
||||
onRedirectTargetPriority: -1,
|
||||
onRedirectTarget(target, source, source2) {
|
||||
if (source !== this.effectState.target || !this.effectState.slot) return;
|
||||
return this.getAtSlot(this.effectState.slot);
|
||||
},
|
||||
onDamagingHit: undefined, // no inherit
|
||||
onDamagePriority: -101,
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (
|
||||
|
|
@ -427,8 +473,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
mirrormove: {
|
||||
inherit: true,
|
||||
flags: { metronome: 1, failencore: 1, nosleeptalk: 1, noassist: 1 },
|
||||
onTryHit: undefined, // no inherit
|
||||
onTryHit() { },
|
||||
onHit(pokemon) {
|
||||
const noMirror = [
|
||||
'assist', 'curse', 'doomdesire', 'focuspunch', 'futuresight', 'magiccoat', 'metronome', 'mimic', 'mirrormove', 'naturepower', 'psychup', 'roleplay', 'sketch', 'sleeptalk', 'spikes', 'spitup', 'taunt', 'teeterdance', 'transform',
|
||||
|
|
@ -453,7 +498,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
needlearm: {
|
||||
inherit: true,
|
||||
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1, minimize: 1 },
|
||||
basePowerCallback(pokemon, target) {
|
||||
if (target.volatiles['minimize']) return 120;
|
||||
return 60;
|
||||
},
|
||||
},
|
||||
nightmare: {
|
||||
inherit: true,
|
||||
|
|
@ -469,59 +517,23 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
overheat: {
|
||||
inherit: true,
|
||||
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
|
||||
flags: {contact: 1, protect: 1, mirror: 1},
|
||||
},
|
||||
petaldance: {
|
||||
inherit: true,
|
||||
basePower: 70,
|
||||
},
|
||||
pursuit: {
|
||||
inherit: true,
|
||||
beforeTurnCallback(pokemon, target) {
|
||||
if (['frz', 'slp'].includes(pokemon.status) ||
|
||||
(pokemon.hasAbility('truant') && pokemon.truantTurn)) return;
|
||||
if (pokemon.isAlly(target)) return;
|
||||
target.addVolatile('pursuit');
|
||||
const data = target.volatiles['pursuit'];
|
||||
if (!data.sources) {
|
||||
data.sources = [];
|
||||
}
|
||||
data.sources.push(pokemon);
|
||||
},
|
||||
},
|
||||
recover: {
|
||||
inherit: true,
|
||||
pp: 20,
|
||||
},
|
||||
reversal: {
|
||||
inherit: true,
|
||||
basePowerCallback(pokemon) {
|
||||
const ratio = Math.max(Math.floor(pokemon.hp * 48 / pokemon.maxhp), 1);
|
||||
let bp;
|
||||
if (ratio < 2) {
|
||||
bp = 200;
|
||||
} else if (ratio < 5) {
|
||||
bp = 150;
|
||||
} else if (ratio < 10) {
|
||||
bp = 100;
|
||||
} else if (ratio < 17) {
|
||||
bp = 80;
|
||||
} else if (ratio < 33) {
|
||||
bp = 40;
|
||||
} else {
|
||||
bp = 20;
|
||||
}
|
||||
this.debug(`BP: ${bp}`);
|
||||
return bp;
|
||||
},
|
||||
},
|
||||
rocksmash: {
|
||||
inherit: true,
|
||||
basePower: 20,
|
||||
},
|
||||
sketch: {
|
||||
inherit: true,
|
||||
flags: { bypasssub: 1, failencore: 1, noassist: 1, failmimic: 1, nosketch: 1 },
|
||||
flags: {bypasssub: 1, failencore: 1, noassist: 1, failmimic: 1},
|
||||
},
|
||||
sleeptalk: {
|
||||
inherit: true,
|
||||
|
|
@ -532,7 +544,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
const pp = moveSlot.pp;
|
||||
const move = this.dex.moves.get(moveid);
|
||||
if (moveid && !move.flags['nosleeptalk'] && !move.flags['charge']) {
|
||||
moves.push({ move: moveid, pp });
|
||||
moves.push({move: moveid, pp: pp});
|
||||
}
|
||||
}
|
||||
if (!moves.length) {
|
||||
|
|
@ -579,7 +591,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
struggle: {
|
||||
inherit: true,
|
||||
flags: { contact: 1, protect: 1, noassist: 1, failencore: 1, failmimic: 1, nosketch: 1 },
|
||||
flags: {contact: 1, protect: 1, noassist: 1, failencore: 1, failmimic: 1},
|
||||
accuracy: 100,
|
||||
recoil: [1, 4],
|
||||
struggleRecoil: false,
|
||||
|
|
@ -590,31 +602,74 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
taunt: {
|
||||
inherit: true,
|
||||
flags: { protect: 1, bypasssub: 1, metronome: 1 },
|
||||
flags: {protect: 1, bypasssub: 1},
|
||||
condition: {
|
||||
inherit: true,
|
||||
duration: 2,
|
||||
durationCallback: undefined, // no inherit
|
||||
onStart(target) {
|
||||
this.add('-start', target, 'move: Taunt');
|
||||
},
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 15,
|
||||
onEnd(target) {
|
||||
this.add('-end', target, 'move: Taunt', '[silent]');
|
||||
},
|
||||
onBeforeMovePriority: undefined, // no inherit
|
||||
onDisableMove(pokemon) {
|
||||
for (const moveSlot of pokemon.moveSlots) {
|
||||
if (this.dex.moves.get(moveSlot.move).category === 'Status') {
|
||||
pokemon.disableMove(moveSlot.id);
|
||||
}
|
||||
}
|
||||
},
|
||||
onBeforeMove(attacker, defender, move) {
|
||||
if (move.category === 'Status') {
|
||||
this.add('cant', attacker, 'move: Taunt', move);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
teeterdance: {
|
||||
inherit: true,
|
||||
flags: { protect: 1, metronome: 1 },
|
||||
flags: {protect: 1},
|
||||
},
|
||||
tickle: {
|
||||
inherit: true,
|
||||
flags: { protect: 1, reflectable: 1, mirror: 1, bypasssub: 1, metronome: 1 },
|
||||
flags: {protect: 1, reflectable: 1, mirror: 1, bypasssub: 1},
|
||||
},
|
||||
uproar: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
durationCallback() {
|
||||
return this.random(2, 6);
|
||||
onStart(target) {
|
||||
this.add('-start', target, 'Uproar');
|
||||
// 2-5 turns
|
||||
this.effectState.duration = this.random(2, 6);
|
||||
},
|
||||
onResidual(target) {
|
||||
if (target.volatiles['throatchop']) {
|
||||
target.removeVolatile('uproar');
|
||||
return;
|
||||
}
|
||||
if (target.lastMove && target.lastMove.id === 'struggle') {
|
||||
// don't lock
|
||||
delete target.volatiles['uproar'];
|
||||
}
|
||||
this.add('-start', target, 'Uproar', '[upkeep]');
|
||||
},
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 11,
|
||||
onEnd(target) {
|
||||
this.add('-end', target, 'Uproar');
|
||||
},
|
||||
onLockMove: 'uproar',
|
||||
onAnySetStatus(status, pokemon) {
|
||||
if (status.id === 'slp') {
|
||||
if (pokemon === this.effectState.target) {
|
||||
this.add('-fail', pokemon, 'slp', '[from] Uproar', '[msg]');
|
||||
} else {
|
||||
this.add('-fail', pokemon, 'slp', '[from] Uproar');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -624,11 +679,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
volttackle: {
|
||||
inherit: true,
|
||||
secondary: undefined, // no inherit
|
||||
secondary: null,
|
||||
},
|
||||
waterfall: {
|
||||
inherit: true,
|
||||
secondary: undefined, // no inherit
|
||||
secondary: null,
|
||||
},
|
||||
weatherball: {
|
||||
inherit: true,
|
||||
|
|
|
|||
882
data/mods/gen3/random-data.json
Normal file
882
data/mods/gen3/random-data.json
Normal file
|
|
@ -0,0 +1,882 @@
|
|||
{
|
||||
"venusaur": {
|
||||
"level": 82,
|
||||
"moves": ["curse", "earthquake", "hiddenpowerrock", "leechseed", "sleeppowder", "sludgebomb", "swordsdance", "synthesis"]
|
||||
},
|
||||
"charizard": {
|
||||
"level": 80,
|
||||
"moves": ["bellydrum", "dragondance", "earthquake", "fireblast", "hiddenpowerflying", "substitute"]
|
||||
},
|
||||
"blastoise": {
|
||||
"level": 84,
|
||||
"moves": ["earthquake", "icebeam", "mirrorcoat", "rest", "roar", "sleeptalk", "surf", "toxic"]
|
||||
},
|
||||
"butterfree": {
|
||||
"level": 91,
|
||||
"moves": ["gigadrain", "hiddenpowerfire", "morningsun", "psychic", "sleeppowder", "stunspore", "toxic"]
|
||||
},
|
||||
"beedrill": {
|
||||
"level": 90,
|
||||
"moves": ["brickbreak", "doubleedge", "endure", "hiddenpowerbug", "sludgebomb", "swordsdance"]
|
||||
},
|
||||
"pidgeot": {
|
||||
"level": 88,
|
||||
"moves": ["aerialace", "hiddenpowerground", "quickattack", "return", "substitute", "toxic"]
|
||||
},
|
||||
"raticate": {
|
||||
"level": 88,
|
||||
"moves": ["endeavor", "hiddenpowerground", "quickattack", "return", "reversal", "shadowball", "substitute"]
|
||||
},
|
||||
"fearow": {
|
||||
"level": 84,
|
||||
"moves": ["agility", "batonpass", "drillpeck", "hiddenpowerground", "quickattack", "return", "substitute"]
|
||||
},
|
||||
"arbok": {
|
||||
"level": 90,
|
||||
"moves": ["doubleedge", "earthquake", "hiddenpowerfire", "rest", "rockslide", "sleeptalk", "sludgebomb"]
|
||||
},
|
||||
"pikachu": {
|
||||
"level": 88,
|
||||
"moves": ["hiddenpowerice", "substitute", "surf", "thunderbolt"]
|
||||
},
|
||||
"raichu": {
|
||||
"level": 84,
|
||||
"moves": ["encore", "focuspunch", "hiddenpowergrass", "hiddenpowerice", "substitute", "surf", "thunderbolt", "thunderwave"]
|
||||
},
|
||||
"sandslash": {
|
||||
"level": 84,
|
||||
"moves": ["earthquake", "hiddenpowerbug", "rapidspin", "rockslide", "swordsdance", "toxic"]
|
||||
},
|
||||
"nidoqueen": {
|
||||
"level": 84,
|
||||
"moves": ["earthquake", "fireblast", "icebeam", "shadowball", "sludgebomb", "superpower"]
|
||||
},
|
||||
"nidoking": {
|
||||
"level": 84,
|
||||
"moves": ["earthquake", "fireblast", "icebeam", "megahorn", "sludgebomb", "substitute", "thunderbolt"]
|
||||
},
|
||||
"clefable": {
|
||||
"level": 84,
|
||||
"moves": ["calmmind", "counter", "icebeam", "return", "shadowball", "softboiled", "thunderbolt", "thunderwave"]
|
||||
},
|
||||
"ninetales": {
|
||||
"level": 83,
|
||||
"moves": ["fireblast", "flamethrower", "hiddenpowergrass", "hypnosis", "substitute", "toxic", "willowisp"]
|
||||
},
|
||||
"wigglytuff": {
|
||||
"level": 90,
|
||||
"moves": ["fireblast", "icebeam", "protect", "return", "thunderbolt", "toxic", "wish"]
|
||||
},
|
||||
"vileplume": {
|
||||
"level": 85,
|
||||
"moves": ["aromatherapy", "hiddenpowerfire", "sleeppowder", "sludgebomb", "solarbeam", "sunnyday", "synthesis"]
|
||||
},
|
||||
"parasect": {
|
||||
"level": 91,
|
||||
"moves": ["aromatherapy", "gigadrain", "hiddenpowerbug", "return", "spore", "stunspore", "swordsdance"]
|
||||
},
|
||||
"venomoth": {
|
||||
"level": 88,
|
||||
"moves": ["batonpass", "hiddenpowerground", "signalbeam", "sleeppowder", "sludgebomb", "substitute"]
|
||||
},
|
||||
"dugtrio": {
|
||||
"level": 81,
|
||||
"moves": ["aerialace", "earthquake", "hiddenpowerbug", "rockslide", "substitute"]
|
||||
},
|
||||
"persian": {
|
||||
"level": 84,
|
||||
"moves": ["fakeout", "hiddenpowerground", "hypnosis", "irontail", "return", "shadowball", "substitute"]
|
||||
},
|
||||
"golduck": {
|
||||
"level": 83,
|
||||
"moves": ["calmmind", "hiddenpowergrass", "hydropump", "hypnosis", "icebeam", "substitute", "surf"]
|
||||
},
|
||||
"primeape": {
|
||||
"level": 85,
|
||||
"moves": ["bulkup", "crosschop", "earthquake", "hiddenpowerghost", "rockslide", "substitute"]
|
||||
},
|
||||
"arcanine": {
|
||||
"level": 83,
|
||||
"moves": ["extremespeed", "fireblast", "flamethrower", "hiddenpowergrass", "rest", "sleeptalk", "toxic"]
|
||||
},
|
||||
"poliwrath": {
|
||||
"level": 84,
|
||||
"moves": ["brickbreak", "bulkup", "hiddenpowerghost", "hydropump", "hypnosis", "icebeam", "substitute"]
|
||||
},
|
||||
"alakazam": {
|
||||
"level": 81,
|
||||
"moves": ["calmmind", "encore", "firepunch", "icepunch", "psychic", "recover", "substitute"]
|
||||
},
|
||||
"machamp": {
|
||||
"level": 83,
|
||||
"moves": ["bulkup", "crosschop", "earthquake", "hiddenpowerghost", "rest", "rockslide", "sleeptalk"]
|
||||
},
|
||||
"victreebel": {
|
||||
"level": 84,
|
||||
"moves": ["hiddenpowerfire", "sleeppowder", "sludgebomb", "solarbeam", "sunnyday"]
|
||||
},
|
||||
"tentacruel": {
|
||||
"level": 83,
|
||||
"moves": ["gigadrain", "haze", "hydropump", "icebeam", "rapidspin", "surf", "toxic"]
|
||||
},
|
||||
"golem": {
|
||||
"level": 84,
|
||||
"moves": ["doubleedge", "earthquake", "explosion", "hiddenpowerbug", "rockslide", "toxic"]
|
||||
},
|
||||
"rapidash": {
|
||||
"level": 84,
|
||||
"moves": ["fireblast", "hiddenpowergrass", "hiddenpowerrock", "substitute", "toxic"]
|
||||
},
|
||||
"slowbro": {
|
||||
"level": 82,
|
||||
"moves": ["calmmind", "fireblast", "icebeam", "psychic", "rest", "sleeptalk", "surf", "thunderwave"]
|
||||
},
|
||||
"magneton": {
|
||||
"level": 81,
|
||||
"moves": ["hiddenpowergrass", "hiddenpowerice", "rest", "sleeptalk", "thunderbolt", "toxic"]
|
||||
},
|
||||
"farfetchd": {
|
||||
"level": 91,
|
||||
"moves": ["agility", "batonpass", "hiddenpowerflying", "return", "swordsdance"]
|
||||
},
|
||||
"dodrio": {
|
||||
"level": 82,
|
||||
"moves": ["drillpeck", "flail", "hiddenpowerground", "quickattack", "return", "substitute"]
|
||||
},
|
||||
"dewgong": {
|
||||
"level": 88,
|
||||
"moves": ["encore", "hiddenpowergrass", "icebeam", "rest", "sleeptalk", "surf", "toxic"]
|
||||
},
|
||||
"muk": {
|
||||
"level": 84,
|
||||
"moves": ["brickbreak", "curse", "explosion", "fireblast", "hiddenpowerghost", "rest", "sludgebomb"]
|
||||
},
|
||||
"cloyster": {
|
||||
"level": 80,
|
||||
"moves": ["explosion", "icebeam", "rapidspin", "spikes", "surf", "toxic"]
|
||||
},
|
||||
"gengar": {
|
||||
"level": 79,
|
||||
"moves": ["destinybond", "explosion", "firepunch", "hypnosis", "icepunch", "substitute", "thunderbolt", "willowisp"]
|
||||
},
|
||||
"hypno": {
|
||||
"level": 84,
|
||||
"moves": ["batonpass", "calmmind", "firepunch", "hypnosis", "protect", "psychic", "toxic", "wish"]
|
||||
},
|
||||
"kingler": {
|
||||
"level": 90,
|
||||
"moves": ["doubleedge", "hiddenpowerghost", "hiddenpowerground", "surf", "swordsdance"]
|
||||
},
|
||||
"electrode": {
|
||||
"level": 84,
|
||||
"moves": ["explosion", "hiddenpowergrass", "hiddenpowerice", "substitute", "thunderbolt", "thunderwave", "toxic"]
|
||||
},
|
||||
"exeggutor": {
|
||||
"level": 82,
|
||||
"moves": ["explosion", "gigadrain", "hiddenpowerfire", "hiddenpowerice", "leechseed", "psychic", "sleeppowder", "solarbeam", "sunnyday"]
|
||||
},
|
||||
"marowak": {
|
||||
"level": 82,
|
||||
"moves": ["bonemerang", "doubleedge", "earthquake", "rockslide", "swordsdance"]
|
||||
},
|
||||
"hitmonlee": {
|
||||
"level": 85,
|
||||
"moves": ["bulkup", "earthquake", "hiddenpowerghost", "highjumpkick", "machpunch", "rockslide", "substitute"]
|
||||
},
|
||||
"hitmonchan": {
|
||||
"level": 88,
|
||||
"moves": ["bulkup", "earthquake", "hiddenpowerghost", "machpunch", "rapidspin", "skyuppercut", "toxic"]
|
||||
},
|
||||
"lickitung": {
|
||||
"level": 90,
|
||||
"moves": ["counter", "healbell", "protect", "return", "seismictoss", "toxic", "wish"]
|
||||
},
|
||||
"weezing": {
|
||||
"level": 82,
|
||||
"moves": ["explosion", "fireblast", "haze", "painsplit", "sludgebomb", "toxic", "willowisp"]
|
||||
},
|
||||
"rhydon": {
|
||||
"level": 83,
|
||||
"moves": ["doubleedge", "earthquake", "megahorn", "rockslide", "substitute", "swordsdance"]
|
||||
},
|
||||
"tangela": {
|
||||
"level": 90,
|
||||
"moves": ["hiddenpowergrass", "leechseed", "morningsun", "sleeppowder", "stunspore"]
|
||||
},
|
||||
"kangaskhan": {
|
||||
"level": 84,
|
||||
"moves": ["earthquake", "fakeout", "focuspunch", "rest", "return", "shadowball", "substitute", "toxic"]
|
||||
},
|
||||
"seaking": {
|
||||
"level": 90,
|
||||
"moves": ["hiddenpowergrass", "hydropump", "icebeam", "megahorn", "raindance"]
|
||||
},
|
||||
"starmie": {
|
||||
"level": 79,
|
||||
"moves": ["hydropump", "icebeam", "psychic", "recover", "surf", "thunderbolt"]
|
||||
},
|
||||
"mrmime": {
|
||||
"level": 84,
|
||||
"moves": ["barrier", "batonpass", "calmmind", "encore", "firepunch", "hypnosis", "psychic", "substitute", "thunderbolt"]
|
||||
},
|
||||
"scyther": {
|
||||
"level": 84,
|
||||
"moves": ["aerialace", "batonpass", "hiddenpowerground", "hiddenpowerrock", "quickattack", "silverwind", "swordsdance"]
|
||||
},
|
||||
"jynx": {
|
||||
"level": 82,
|
||||
"moves": ["calmmind", "hiddenpowerfire", "icebeam", "lovelykiss", "psychic", "substitute"]
|
||||
},
|
||||
"electabuzz": {
|
||||
"level": 84,
|
||||
"moves": ["crosschop", "firepunch", "focuspunch", "hiddenpowergrass", "icepunch", "substitute", "thunderbolt"]
|
||||
},
|
||||
"magmar": {
|
||||
"level": 84,
|
||||
"moves": ["crosschop", "fireblast", "flamethrower", "hiddenpowergrass", "psychic", "substitute", "thunderpunch"]
|
||||
},
|
||||
"pinsir": {
|
||||
"level": 83,
|
||||
"moves": ["earthquake", "hiddenpowerbug", "return", "rockslide", "swordsdance"]
|
||||
},
|
||||
"tauros": {
|
||||
"level": 79,
|
||||
"moves": ["doubleedge", "earthquake", "hiddenpowerghost", "hiddenpowerrock", "return"]
|
||||
},
|
||||
"gyarados": {
|
||||
"level": 79,
|
||||
"moves": ["doubleedge", "dragondance", "earthquake", "hiddenpowerflying", "hydropump", "taunt"]
|
||||
},
|
||||
"lapras": {
|
||||
"level": 82,
|
||||
"moves": ["healbell", "icebeam", "rest", "sleeptalk", "surf", "thunderbolt", "toxic"]
|
||||
},
|
||||
"ditto": {
|
||||
"level": 100,
|
||||
"moves": ["transform"]
|
||||
},
|
||||
"vaporeon": {
|
||||
"level": 82,
|
||||
"moves": ["icebeam", "protect", "surf", "toxic", "wish"]
|
||||
},
|
||||
"jolteon": {
|
||||
"level": 80,
|
||||
"moves": ["batonpass", "hiddenpowerice", "substitute", "thunderbolt", "toxic", "wish"]
|
||||
},
|
||||
"flareon": {
|
||||
"level": 88,
|
||||
"moves": ["doubleedge", "fireblast", "hiddenpowergrass", "protect", "shadowball", "toxic", "wish"]
|
||||
},
|
||||
"omastar": {
|
||||
"level": 84,
|
||||
"moves": ["hiddenpowergrass", "hydropump", "icebeam", "raindance", "spikes", "surf"]
|
||||
},
|
||||
"kabutops": {
|
||||
"level": 84,
|
||||
"moves": ["brickbreak", "doubleedge", "hiddenpowerground", "rockslide", "surf", "swordsdance"]
|
||||
},
|
||||
"aerodactyl": {
|
||||
"level": 79,
|
||||
"moves": ["doubleedge", "earthquake", "hiddenpowerflying", "rockslide", "substitute"]
|
||||
},
|
||||
"snorlax": {
|
||||
"level": 77,
|
||||
"moves": ["bodyslam", "curse", "earthquake", "rest", "return", "selfdestruct", "shadowball", "sleeptalk"]
|
||||
},
|
||||
"articuno": {
|
||||
"level": 82,
|
||||
"moves": ["healbell", "hiddenpowerfire", "icebeam", "protect", "rest", "roar", "sleeptalk", "toxic"]
|
||||
},
|
||||
"zapdos": {
|
||||
"level": 78,
|
||||
"moves": ["agility", "batonpass", "hiddenpowerice", "substitute", "thunderbolt", "thunderwave", "toxic"]
|
||||
},
|
||||
"moltres": {
|
||||
"level": 80,
|
||||
"moves": ["fireblast", "flamethrower", "hiddenpowergrass", "morningsun", "substitute", "toxic", "willowisp"]
|
||||
},
|
||||
"dragonite": {
|
||||
"level": 81,
|
||||
"moves": ["doubleedge", "dragondance", "earthquake", "flamethrower", "healbell", "hiddenpowerflying", "icebeam", "substitute"]
|
||||
},
|
||||
"mewtwo": {
|
||||
"level": 73,
|
||||
"moves": ["calmmind", "flamethrower", "icebeam", "psychic", "recover", "substitute", "thunderbolt"]
|
||||
},
|
||||
"mew": {
|
||||
"level": 76,
|
||||
"moves": ["calmmind", "explosion", "flamethrower", "icebeam", "psychic", "softboiled", "thunderbolt", "thunderwave", "transform"]
|
||||
},
|
||||
"meganium": {
|
||||
"level": 84,
|
||||
"moves": ["bodyslam", "hiddenpowergrass", "leechseed", "synthesis", "toxic"]
|
||||
},
|
||||
"typhlosion": {
|
||||
"level": 82,
|
||||
"moves": ["fireblast", "flamethrower", "focuspunch", "hiddenpowergrass", "hiddenpowerice", "substitute", "thunderpunch"]
|
||||
},
|
||||
"feraligatr": {
|
||||
"level": 84,
|
||||
"moves": ["earthquake", "hiddenpowerflying", "hydropump", "rockslide", "swordsdance"]
|
||||
},
|
||||
"furret": {
|
||||
"level": 90,
|
||||
"moves": ["doubleedge", "quickattack", "return", "reversal", "shadowball", "substitute", "trick"]
|
||||
},
|
||||
"noctowl": {
|
||||
"level": 90,
|
||||
"moves": ["hypnosis", "psychic", "reflect", "toxic", "whirlwind"]
|
||||
},
|
||||
"ledian": {
|
||||
"level": 92,
|
||||
"moves": ["agility", "batonpass", "lightscreen", "reflect", "silverwind", "swordsdance", "toxic"]
|
||||
},
|
||||
"ariados": {
|
||||
"level": 90,
|
||||
"moves": ["agility", "batonpass", "signalbeam", "sludgebomb", "spiderweb", "toxic"]
|
||||
},
|
||||
"crobat": {
|
||||
"level": 82,
|
||||
"moves": ["aerialace", "haze", "hiddenpowerground", "shadowball", "sludgebomb", "taunt", "toxic"]
|
||||
},
|
||||
"lanturn": {
|
||||
"level": 84,
|
||||
"moves": ["confuseray", "icebeam", "rest", "sleeptalk", "surf", "thunderbolt", "thunderwave", "toxic"]
|
||||
},
|
||||
"togetic": {
|
||||
"level": 90,
|
||||
"moves": ["charm", "encore", "flamethrower", "seismictoss", "softboiled", "thunderwave", "toxic"]
|
||||
},
|
||||
"xatu": {
|
||||
"level": 84,
|
||||
"moves": ["batonpass", "calmmind", "hiddenpowerfire", "psychic", "reflect", "wish"]
|
||||
},
|
||||
"ampharos": {
|
||||
"level": 84,
|
||||
"moves": ["firepunch", "healbell", "hiddenpowergrass", "hiddenpowerice", "thunderbolt", "toxic"]
|
||||
},
|
||||
"bellossom": {
|
||||
"level": 88,
|
||||
"moves": ["hiddenpowergrass", "leechseed", "moonlight", "sleeppowder", "sludgebomb", "stunspore"]
|
||||
},
|
||||
"azumarill": {
|
||||
"level": 85,
|
||||
"moves": ["brickbreak", "encore", "hiddenpowerghost", "hydropump", "return"]
|
||||
},
|
||||
"sudowoodo": {
|
||||
"level": 89,
|
||||
"moves": ["brickbreak", "doubleedge", "earthquake", "explosion", "rockslide", "toxic"]
|
||||
},
|
||||
"politoed": {
|
||||
"level": 84,
|
||||
"moves": ["hiddenpowergrass", "hypnosis", "icebeam", "rest", "surf", "toxic"]
|
||||
},
|
||||
"jumpluff": {
|
||||
"level": 83,
|
||||
"moves": ["encore", "hiddenpowerflying", "leechseed", "sleeppowder", "substitute", "toxic"]
|
||||
},
|
||||
"aipom": {
|
||||
"level": 90,
|
||||
"moves": ["batonpass", "doubleedge", "focuspunch", "shadowball", "substitute", "thunderwave"]
|
||||
},
|
||||
"sunflora": {
|
||||
"level": 91,
|
||||
"moves": ["hiddenpowerfire", "leechseed", "razorleaf", "synthesis", "toxic"]
|
||||
},
|
||||
"yanma": {
|
||||
"level": 90,
|
||||
"moves": ["hiddenpowerflying", "hypnosis", "reversal", "shadowball", "substitute"]
|
||||
},
|
||||
"quagsire": {
|
||||
"level": 84,
|
||||
"moves": ["counter", "curse", "earthquake", "hiddenpowerrock", "icebeam", "rest", "surf", "toxic"]
|
||||
},
|
||||
"espeon": {
|
||||
"level": 81,
|
||||
"moves": ["batonpass", "calmmind", "hiddenpowerfire", "morningsun", "psychic", "reflect"]
|
||||
},
|
||||
"umbreon": {
|
||||
"level": 82,
|
||||
"moves": ["batonpass", "hiddenpowerdark", "protect", "toxic", "wish"]
|
||||
},
|
||||
"murkrow": {
|
||||
"level": 89,
|
||||
"moves": ["doubleedge", "drillpeck", "hiddenpowerfighting", "hiddenpowerground", "meanlook", "perishsong", "protect", "shadowball", "substitute"]
|
||||
},
|
||||
"slowking": {
|
||||
"level": 84,
|
||||
"moves": ["calmmind", "flamethrower", "icebeam", "psychic", "rest", "sleeptalk", "surf", "thunderwave"]
|
||||
},
|
||||
"misdreavus": {
|
||||
"level": 84,
|
||||
"moves": ["calmmind", "hiddenpowerice", "meanlook", "perishsong", "protect", "substitute", "thunderbolt", "toxic"]
|
||||
},
|
||||
"unown": {
|
||||
"level": 100,
|
||||
"moves": ["hiddenpowerpsychic"]
|
||||
},
|
||||
"wobbuffet": {
|
||||
"level": 77,
|
||||
"moves": ["counter", "destinybond", "encore", "mirrorcoat"]
|
||||
},
|
||||
"girafarig": {
|
||||
"level": 84,
|
||||
"moves": ["agility", "batonpass", "calmmind", "psychic", "substitute", "thunderbolt", "thunderwave", "wish"]
|
||||
},
|
||||
"forretress": {
|
||||
"level": 80,
|
||||
"moves": ["earthquake", "explosion", "hiddenpowerbug", "rapidspin", "spikes", "toxic"]
|
||||
},
|
||||
"dunsparce": {
|
||||
"level": 88,
|
||||
"moves": ["bodyslam", "curse", "headbutt", "rest", "rockslide", "shadowball", "thunderwave"]
|
||||
},
|
||||
"gligar": {
|
||||
"level": 84,
|
||||
"moves": ["earthquake", "hiddenpowerflying", "irontail", "quickattack", "rockslide", "substitute", "swordsdance"]
|
||||
},
|
||||
"steelix": {
|
||||
"level": 82,
|
||||
"moves": ["doubleedge", "earthquake", "explosion", "hiddenpowerrock", "irontail", "rest", "roar", "toxic"]
|
||||
},
|
||||
"granbull": {
|
||||
"level": 84,
|
||||
"moves": ["bulkup", "earthquake", "healbell", "overheat", "rest", "return", "shadowball", "thunderwave"]
|
||||
},
|
||||
"qwilfish": {
|
||||
"level": 84,
|
||||
"moves": ["destinybond", "hydropump", "selfdestruct", "shadowball", "sludgebomb", "spikes", "swordsdance"]
|
||||
},
|
||||
"scizor": {
|
||||
"level": 82,
|
||||
"moves": ["agility", "batonpass", "hiddenpowerground", "hiddenpowerrock", "morningsun", "silverwind", "steelwing", "swordsdance"]
|
||||
},
|
||||
"shuckle": {
|
||||
"level": 91,
|
||||
"moves": ["encore", "rest", "toxic", "wrap"]
|
||||
},
|
||||
"heracross": {
|
||||
"level": 80,
|
||||
"moves": ["brickbreak", "focuspunch", "megahorn", "rest", "rockslide", "sleeptalk", "substitute", "swordsdance"]
|
||||
},
|
||||
"sneasel": {
|
||||
"level": 84,
|
||||
"moves": ["brickbreak", "doubleedge", "hiddenpowerflying", "shadowball", "substitute", "swordsdance"]
|
||||
},
|
||||
"ursaring": {
|
||||
"level": 82,
|
||||
"moves": ["earthquake", "focuspunch", "hiddenpowerghost", "return", "swordsdance"]
|
||||
},
|
||||
"magcargo": {
|
||||
"level": 90,
|
||||
"moves": ["fireblast", "hiddenpowergrass", "rest", "sleeptalk", "toxic", "yawn"]
|
||||
},
|
||||
"piloswine": {
|
||||
"level": 90,
|
||||
"moves": ["doubleedge", "earthquake", "icebeam", "protect", "rockslide", "toxic"]
|
||||
},
|
||||
"corsola": {
|
||||
"level": 91,
|
||||
"moves": ["calmmind", "icebeam", "recover", "surf", "toxic"]
|
||||
},
|
||||
"octillery": {
|
||||
"level": 88,
|
||||
"moves": ["fireblast", "hiddenpowergrass", "icebeam", "rockblast", "surf", "thunderwave"]
|
||||
},
|
||||
"delibird": {
|
||||
"level": 91,
|
||||
"moves": ["aerialace", "focuspunch", "hiddenpowerground", "icebeam", "quickattack"]
|
||||
},
|
||||
"mantine": {
|
||||
"level": 84,
|
||||
"moves": ["haze", "hiddenpowergrass", "icebeam", "raindance", "rest", "sleeptalk", "surf", "toxic"]
|
||||
},
|
||||
"skarmory": {
|
||||
"level": 80,
|
||||
"moves": ["drillpeck", "hiddenpowerground", "protect", "rest", "sleeptalk", "spikes", "toxic", "whirlwind"]
|
||||
},
|
||||
"houndoom": {
|
||||
"level": 82,
|
||||
"moves": ["crunch", "fireblast", "flamethrower", "hiddenpowergrass", "pursuit", "willowisp"]
|
||||
},
|
||||
"kingdra": {
|
||||
"level": 82,
|
||||
"moves": ["hiddenpowergrass", "hydropump", "icebeam", "raindance", "substitute", "surf"]
|
||||
},
|
||||
"donphan": {
|
||||
"level": 82,
|
||||
"moves": ["earthquake", "rapidspin", "rest", "rockslide", "sleeptalk", "toxic"]
|
||||
},
|
||||
"porygon2": {
|
||||
"level": 82,
|
||||
"moves": ["icebeam", "recover", "return", "thunderbolt", "thunderwave", "toxic"]
|
||||
},
|
||||
"stantler": {
|
||||
"level": 84,
|
||||
"moves": ["earthquake", "hypnosis", "return", "shadowball", "thunderbolt"]
|
||||
},
|
||||
"smeargle": {
|
||||
"level": 84,
|
||||
"moves": ["encore", "explosion", "spikes", "spore"]
|
||||
},
|
||||
"hitmontop": {
|
||||
"level": 84,
|
||||
"moves": ["bulkup", "earthquake", "hiddenpowerghost", "highjumpkick", "machpunch", "rockslide", "toxic"]
|
||||
},
|
||||
"miltank": {
|
||||
"level": 81,
|
||||
"moves": ["bodyslam", "curse", "earthquake", "healbell", "milkdrink", "toxic"]
|
||||
},
|
||||
"blissey": {
|
||||
"level": 80,
|
||||
"moves": ["aromatherapy", "calmmind", "icebeam", "seismictoss", "softboiled", "thunderbolt", "thunderwave", "toxic"]
|
||||
},
|
||||
"raikou": {
|
||||
"level": 79,
|
||||
"moves": ["calmmind", "crunch", "hiddenpowergrass", "hiddenpowerice", "rest", "sleeptalk", "substitute", "thunderbolt"]
|
||||
},
|
||||
"entei": {
|
||||
"level": 82,
|
||||
"moves": ["bodyslam", "calmmind", "fireblast", "flamethrower", "hiddenpowergrass", "hiddenpowerice", "solarbeam", "substitute", "sunnyday"]
|
||||
},
|
||||
"suicune": {
|
||||
"level": 77,
|
||||
"moves": ["calmmind", "icebeam", "rest", "sleeptalk", "substitute", "surf", "toxic"]
|
||||
},
|
||||
"tyranitar": {
|
||||
"level": 79,
|
||||
"moves": ["dragondance", "earthquake", "fireblast", "focuspunch", "hiddenpowerbug", "icebeam", "pursuit", "rockslide", "substitute"]
|
||||
},
|
||||
"lugia": {
|
||||
"level": 73,
|
||||
"moves": ["aeroblast", "calmmind", "earthquake", "icebeam", "recover", "substitute", "thunderbolt", "toxic"]
|
||||
},
|
||||
"hooh": {
|
||||
"level": 74,
|
||||
"moves": ["calmmind", "earthquake", "recover", "sacredfire", "substitute", "thunderbolt", "toxic"]
|
||||
},
|
||||
"celebi": {
|
||||
"level": 79,
|
||||
"moves": ["batonpass", "calmmind", "healbell", "hiddenpowergrass", "leechseed", "psychic", "recover"]
|
||||
},
|
||||
"sceptile": {
|
||||
"level": 82,
|
||||
"moves": ["focuspunch", "hiddenpowerice", "leafblade", "leechseed", "substitute", "thunderpunch"]
|
||||
},
|
||||
"blaziken": {
|
||||
"level": 82,
|
||||
"moves": ["endure", "fireblast", "hiddenpowerice", "reversal", "rockslide", "skyuppercut", "swordsdance", "thunderpunch"]
|
||||
},
|
||||
"swampert": {
|
||||
"level": 80,
|
||||
"moves": ["earthquake", "hydropump", "icebeam", "protect", "rest", "rockslide", "sleeptalk", "surf", "toxic"]
|
||||
},
|
||||
"mightyena": {
|
||||
"level": 90,
|
||||
"moves": ["crunch", "doubleedge", "healbell", "hiddenpowerfighting", "protect", "shadowball", "toxic"]
|
||||
},
|
||||
"linoone": {
|
||||
"level": 84,
|
||||
"moves": ["bellydrum", "extremespeed", "flail", "hiddenpowerground", "shadowball", "substitute"]
|
||||
},
|
||||
"beautifly": {
|
||||
"level": 91,
|
||||
"moves": ["hiddenpowerbug", "hiddenpowerflying", "morningsun", "stunspore", "substitute", "toxic"]
|
||||
},
|
||||
"dustox": {
|
||||
"level": 91,
|
||||
"moves": ["hiddenpowerground", "lightscreen", "moonlight", "sludgebomb", "toxic", "whirlwind"]
|
||||
},
|
||||
"ludicolo": {
|
||||
"level": 82,
|
||||
"moves": ["hiddenpowergrass", "icebeam", "leechseed", "raindance", "substitute", "surf"]
|
||||
},
|
||||
"shiftry": {
|
||||
"level": 85,
|
||||
"moves": ["brickbreak", "explosion", "shadowball", "swordsdance"]
|
||||
},
|
||||
"swellow": {
|
||||
"level": 82,
|
||||
"moves": ["aerialace", "doubleedge", "hiddenpowerfighting", "hiddenpowerground", "quickattack", "return"]
|
||||
},
|
||||
"pelipper": {
|
||||
"level": 88,
|
||||
"moves": ["icebeam", "protect", "rest", "sleeptalk", "surf", "toxic"]
|
||||
},
|
||||
"gardevoir": {
|
||||
"level": 82,
|
||||
"moves": ["calmmind", "firepunch", "hypnosis", "psychic", "substitute", "thunderbolt", "willowisp"]
|
||||
},
|
||||
"masquerain": {
|
||||
"level": 90,
|
||||
"moves": ["hydropump", "icebeam", "stunspore", "substitute", "toxic"]
|
||||
},
|
||||
"breloom": {
|
||||
"level": 81,
|
||||
"moves": ["focuspunch", "hiddenpowerghost", "hiddenpowerrock", "leechseed", "machpunch", "skyuppercut", "spore", "substitute", "swordsdance"]
|
||||
},
|
||||
"vigoroth": {
|
||||
"level": 87,
|
||||
"moves": ["brickbreak", "bulkup", "earthquake", "return", "shadowball", "slackoff"]
|
||||
},
|
||||
"slaking": {
|
||||
"level": 81,
|
||||
"moves": ["doubleedge", "earthquake", "focuspunch", "return", "shadowball"]
|
||||
},
|
||||
"ninjask": {
|
||||
"level": 84,
|
||||
"moves": ["aerialace", "batonpass", "hiddenpowerrock", "protect", "silverwind", "substitute", "swordsdance"]
|
||||
},
|
||||
"shedinja": {
|
||||
"level": 90,
|
||||
"moves": ["agility", "batonpass", "hiddenpowerground", "shadowball", "silverwind", "toxic"]
|
||||
},
|
||||
"exploud": {
|
||||
"level": 84,
|
||||
"moves": ["earthquake", "flamethrower", "icebeam", "overheat", "return", "shadowball", "substitute"]
|
||||
},
|
||||
"hariyama": {
|
||||
"level": 82,
|
||||
"moves": ["bulkup", "crosschop", "fakeout", "hiddenpowerghost", "rest", "rockslide", "sleeptalk"]
|
||||
},
|
||||
"nosepass": {
|
||||
"level": 91,
|
||||
"moves": ["earthquake", "explosion", "rockslide", "thunderwave", "toxic"]
|
||||
},
|
||||
"delcatty": {
|
||||
"level": 91,
|
||||
"moves": ["batonpass", "doubleedge", "healbell", "thunderwave", "wish"]
|
||||
},
|
||||
"sableye": {
|
||||
"level": 89,
|
||||
"moves": ["knockoff", "recover", "seismictoss", "shadowball", "toxic"]
|
||||
},
|
||||
"mawile": {
|
||||
"level": 91,
|
||||
"moves": ["batonpass", "brickbreak", "focuspunch", "hiddenpowersteel", "rockslide", "substitute", "swordsdance", "toxic"]
|
||||
},
|
||||
"aggron": {
|
||||
"level": 84,
|
||||
"moves": ["doubleedge", "earthquake", "focuspunch", "irontail", "rockslide", "substitute", "thunderwave", "toxic"]
|
||||
},
|
||||
"medicham": {
|
||||
"level": 82,
|
||||
"moves": ["brickbreak", "bulkup", "recover", "rockslide", "shadowball", "substitute"]
|
||||
},
|
||||
"manectric": {
|
||||
"level": 84,
|
||||
"moves": ["crunch", "hiddenpowergrass", "hiddenpowerice", "substitute", "thunderbolt", "thunderwave"]
|
||||
},
|
||||
"plusle": {
|
||||
"level": 88,
|
||||
"moves": ["agility", "batonpass", "encore", "hiddenpowergrass", "substitute", "thunderbolt", "toxic"]
|
||||
},
|
||||
"minun": {
|
||||
"level": 90,
|
||||
"moves": ["batonpass", "encore", "hiddenpowerice", "lightscreen", "substitute", "thunderbolt", "wish"]
|
||||
},
|
||||
"volbeat": {
|
||||
"level": 91,
|
||||
"moves": ["batonpass", "icepunch", "tailglow", "thunderbolt"]
|
||||
},
|
||||
"illumise": {
|
||||
"level": 90,
|
||||
"moves": ["batonpass", "encore", "icepunch", "substitute", "thunderwave", "wish"]
|
||||
},
|
||||
"roselia": {
|
||||
"level": 90,
|
||||
"moves": ["aromatherapy", "gigadrain", "hiddenpowerfire", "spikes", "stunspore", "synthesis"]
|
||||
},
|
||||
"swalot": {
|
||||
"level": 90,
|
||||
"moves": ["encore", "explosion", "hiddenpowerground", "icebeam", "sludgebomb", "toxic", "yawn"]
|
||||
},
|
||||
"sharpedo": {
|
||||
"level": 84,
|
||||
"moves": ["crunch", "earthquake", "endure", "hiddenpowerflying", "hydropump", "icebeam", "return"]
|
||||
},
|
||||
"wailord": {
|
||||
"level": 88,
|
||||
"moves": ["hiddenpowergrass", "icebeam", "rest", "selfdestruct", "sleeptalk", "surf", "toxic"]
|
||||
},
|
||||
"camerupt": {
|
||||
"level": 84,
|
||||
"moves": ["earthquake", "explosion", "fireblast", "rest", "rockslide", "sleeptalk", "toxic"]
|
||||
},
|
||||
"torkoal": {
|
||||
"level": 88,
|
||||
"moves": ["explosion", "fireblast", "flamethrower", "hiddenpowergrass", "rest", "toxic", "yawn"]
|
||||
},
|
||||
"grumpig": {
|
||||
"level": 84,
|
||||
"moves": ["calmmind", "firepunch", "icywind", "psychic", "substitute", "taunt"]
|
||||
},
|
||||
"spinda": {
|
||||
"level": 91,
|
||||
"moves": ["bodyslam", "encore", "focuspunch", "shadowball", "substitute", "teeterdance", "toxic"]
|
||||
},
|
||||
"flygon": {
|
||||
"level": 80,
|
||||
"moves": ["dragonclaw", "earthquake", "fireblast", "hiddenpowerbug", "rockslide", "substitute", "toxic"]
|
||||
},
|
||||
"cacturne": {
|
||||
"level": 89,
|
||||
"moves": ["focuspunch", "hiddenpowerdark", "leechseed", "needlearm", "spikes", "substitute", "thunderpunch"]
|
||||
},
|
||||
"altaria": {
|
||||
"level": 84,
|
||||
"moves": ["dragonclaw", "dragondance", "earthquake", "fireblast", "flamethrower", "haze", "hiddenpowerflying", "rest", "toxic"]
|
||||
},
|
||||
"zangoose": {
|
||||
"level": 82,
|
||||
"moves": ["brickbreak", "quickattack", "return", "shadowball", "swordsdance"]
|
||||
},
|
||||
"seviper": {
|
||||
"level": 90,
|
||||
"moves": ["crunch", "doubleedge", "earthquake", "flamethrower", "hiddenpowergrass", "sludgebomb"]
|
||||
},
|
||||
"lunatone": {
|
||||
"level": 84,
|
||||
"moves": ["batonpass", "calmmind", "explosion", "hypnosis", "icebeam", "psychic"]
|
||||
},
|
||||
"solrock": {
|
||||
"level": 84,
|
||||
"moves": ["earthquake", "explosion", "overheat", "reflect", "rockslide", "shadowball"]
|
||||
},
|
||||
"whiscash": {
|
||||
"level": 87,
|
||||
"moves": ["earthquake", "hiddenpowerbug", "icebeam", "rest", "rockslide", "sleeptalk", "spark", "surf", "toxic"]
|
||||
},
|
||||
"crawdaunt": {
|
||||
"level": 88,
|
||||
"moves": ["brickbreak", "crunch", "doubleedge", "hiddenpowerghost", "icebeam", "surf"]
|
||||
},
|
||||
"claydol": {
|
||||
"level": 80,
|
||||
"moves": ["earthquake", "explosion", "icebeam", "psychic", "rapidspin", "toxic"]
|
||||
},
|
||||
"cradily": {
|
||||
"level": 84,
|
||||
"moves": ["barrier", "earthquake", "hiddenpowergrass", "mirrorcoat", "recover", "rockslide", "toxic"]
|
||||
},
|
||||
"armaldo": {
|
||||
"level": 82,
|
||||
"moves": ["doubleedge", "earthquake", "hiddenpowerbug", "rockslide", "swordsdance"]
|
||||
},
|
||||
"milotic": {
|
||||
"level": 79,
|
||||
"moves": ["icebeam", "mirrorcoat", "recover", "surf", "toxic"]
|
||||
},
|
||||
"castform": {
|
||||
"level": 90,
|
||||
"moves": ["flamethrower", "icebeam", "substitute", "thunderbolt", "thunderwave"]
|
||||
},
|
||||
"kecleon": {
|
||||
"level": 88,
|
||||
"moves": ["brickbreak", "return", "shadowball", "thunderwave", "trick"]
|
||||
},
|
||||
"banette": {
|
||||
"level": 84,
|
||||
"moves": ["destinybond", "endure", "hiddenpowerfighting", "knockoff", "shadowball", "willowisp"]
|
||||
},
|
||||
"dusclops": {
|
||||
"level": 84,
|
||||
"moves": ["focuspunch", "icebeam", "painsplit", "rest", "shadowball", "sleeptalk", "substitute", "willowisp"]
|
||||
},
|
||||
"tropius": {
|
||||
"level": 90,
|
||||
"moves": ["hiddenpowerfire", "solarbeam", "sunnyday", "synthesis"]
|
||||
},
|
||||
"chimecho": {
|
||||
"level": 88,
|
||||
"moves": ["calmmind", "healbell", "hiddenpowerfire", "lightscreen", "psychic", "reflect", "toxic", "yawn"]
|
||||
},
|
||||
"absol": {
|
||||
"level": 85,
|
||||
"moves": ["batonpass", "hiddenpowerfighting", "quickattack", "shadowball", "swordsdance"]
|
||||
},
|
||||
"glalie": {
|
||||
"level": 87,
|
||||
"moves": ["earthquake", "explosion", "icebeam", "spikes", "toxic"]
|
||||
},
|
||||
"walrein": {
|
||||
"level": 84,
|
||||
"moves": ["encore", "hiddenpowergrass", "icebeam", "rest", "sleeptalk", "surf", "toxic"]
|
||||
},
|
||||
"huntail": {
|
||||
"level": 88,
|
||||
"moves": ["doubleedge", "hiddenpowergrass", "hydropump", "icebeam", "raindance", "surf"]
|
||||
},
|
||||
"gorebyss": {
|
||||
"level": 84,
|
||||
"moves": ["hiddenpowerelectric", "hiddenpowergrass", "hydropump", "icebeam", "raindance", "surf"]
|
||||
},
|
||||
"relicanth": {
|
||||
"level": 88,
|
||||
"moves": ["doubleedge", "earthquake", "hiddenpowerflying", "rest", "rockslide", "sleeptalk", "toxic"]
|
||||
},
|
||||
"luvdisc": {
|
||||
"level": 92,
|
||||
"moves": ["icebeam", "protect", "substitute", "surf", "sweetkiss", "toxic"]
|
||||
},
|
||||
"salamence": {
|
||||
"level": 78,
|
||||
"moves": ["brickbreak", "dragondance", "earthquake", "fireblast", "hiddenpowerflying", "rockslide"]
|
||||
},
|
||||
"metagross": {
|
||||
"level": 79,
|
||||
"moves": ["agility", "earthquake", "explosion", "meteormash", "psychic", "rockslide"]
|
||||
},
|
||||
"regirock": {
|
||||
"level": 82,
|
||||
"moves": ["curse", "earthquake", "explosion", "rest", "rockslide", "superpower", "thunderwave"]
|
||||
},
|
||||
"regice": {
|
||||
"level": 82,
|
||||
"moves": ["explosion", "icebeam", "rest", "sleeptalk", "thunderbolt", "thunderwave", "toxic"]
|
||||
},
|
||||
"registeel": {
|
||||
"level": 82,
|
||||
"moves": ["rest", "seismictoss", "sleeptalk", "toxic"]
|
||||
},
|
||||
"latias": {
|
||||
"level": 76,
|
||||
"moves": ["calmmind", "dragonclaw", "hiddenpowerfire", "recover", "refresh", "toxic"]
|
||||
},
|
||||
"latios": {
|
||||
"level": 75,
|
||||
"moves": ["calmmind", "dragonclaw", "hiddenpowerfire", "psychic", "recover", "thunderbolt"]
|
||||
},
|
||||
"kyogre": {
|
||||
"level": 73,
|
||||
"moves": ["calmmind", "icebeam", "rest", "sleeptalk", "surf", "thunder"]
|
||||
},
|
||||
"groudon": {
|
||||
"level": 73,
|
||||
"moves": ["earthquake", "hiddenpowerbug", "overheat", "rockslide", "substitute", "swordsdance", "thunderwave"]
|
||||
},
|
||||
"rayquaza": {
|
||||
"level": 74,
|
||||
"moves": ["dragondance", "earthquake", "extremespeed", "hiddenpowerflying", "overheat", "rockslide"]
|
||||
},
|
||||
"jirachi": {
|
||||
"level": 77,
|
||||
"moves": ["bodyslam", "calmmind", "firepunch", "icepunch", "protect", "psychic", "substitute", "thunderbolt", "wish"]
|
||||
},
|
||||
"deoxys": {
|
||||
"level": 76,
|
||||
"moves": ["extremespeed", "firepunch", "icebeam", "psychoboost", "shadowball", "superpower"]
|
||||
},
|
||||
"deoxysattack": {
|
||||
"level": 76,
|
||||
"moves": ["extremespeed", "firepunch", "psychoboost", "shadowball", "superpower"]
|
||||
},
|
||||
"deoxysdefense": {
|
||||
"level": 76,
|
||||
"moves": ["nightshade", "recover", "spikes", "taunt", "toxic"]
|
||||
},
|
||||
"deoxysspeed": {
|
||||
"level": 76,
|
||||
"moves": ["calmmind", "icebeam", "psychic", "recover", "spikes", "taunt", "toxic"]
|
||||
}
|
||||
}
|
||||
695
data/mods/gen3/random-teams.ts
Normal file
695
data/mods/gen3/random-teams.ts
Normal file
|
|
@ -0,0 +1,695 @@
|
|||
import RandomGen4Teams from '../gen4/random-teams';
|
||||
import {Utils} from '../../../lib';
|
||||
import {PRNG, PRNGSeed} from '../../../sim/prng';
|
||||
import type {MoveCounter, OldRandomBattleSpecies} from '../gen8/random-teams';
|
||||
|
||||
export class RandomGen3Teams extends RandomGen4Teams {
|
||||
battleHasDitto: boolean;
|
||||
battleHasWobbuffet: boolean;
|
||||
|
||||
randomData: {[species: string]: OldRandomBattleSpecies} = require('./random-data.json');
|
||||
|
||||
constructor(format: string | Format, prng: PRNG | PRNGSeed | null) {
|
||||
super(format, prng);
|
||||
this.battleHasDitto = false;
|
||||
this.battleHasWobbuffet = false;
|
||||
this.moveEnforcementCheckers = {
|
||||
Bug: (movePool, moves, abilities, types, counter, species) => (
|
||||
movePool.includes('megahorn') || (!species.types[1] && movePool.includes('hiddenpowerbug'))
|
||||
),
|
||||
Electric: (movePool, moves, abilities, types, counter) => !counter.get('Electric'),
|
||||
Fighting: (movePool, moves, abilities, types, counter) => !counter.get('Fighting'),
|
||||
Fire: (movePool, moves, abilities, types, counter) => !counter.get('Fire'),
|
||||
Ground: (movePool, moves, abilities, types, counter) => !counter.get('Ground'),
|
||||
Normal: (movePool, moves, abilities, types, counter, species) => {
|
||||
if (species.id === 'blissey' && movePool.includes('softboiled')) return true;
|
||||
return !counter.get('Normal') && counter.setupType === 'Physical';
|
||||
},
|
||||
Psychic: (movePool, moves, abilities, types, counter, species) => (
|
||||
types.has('Psychic') &&
|
||||
(movePool.includes('psychic') || movePool.includes('psychoboost')) &&
|
||||
species.baseStats.spa >= 100
|
||||
),
|
||||
Rock: (movePool, moves, abilities, types, counter, species) => !counter.get('Rock') && species.baseStats.atk >= 100,
|
||||
Water: (movePool, moves, abilities, types, counter, species) => (
|
||||
!counter.get('Water') && counter.setupType !== 'Physical' && species.baseStats.spa >= 60
|
||||
),
|
||||
// If the Pokémon has this move, the other move will be forced
|
||||
protect: movePool => movePool.includes('wish'),
|
||||
sunnyday: movePool => movePool.includes('solarbeam'),
|
||||
sleeptalk: movePool => movePool.includes('rest'),
|
||||
};
|
||||
}
|
||||
|
||||
shouldCullMove(
|
||||
move: Move,
|
||||
types: Set<string>,
|
||||
moves: Set<string>,
|
||||
abilities: Set<string>,
|
||||
counter: MoveCounter,
|
||||
movePool: string[],
|
||||
teamDetails: RandomTeamsTypes.TeamDetails,
|
||||
species: Species,
|
||||
): {cull: boolean, isSetup?: boolean} {
|
||||
const restTalk = moves.has('rest') && moves.has('sleeptalk');
|
||||
|
||||
switch (move.id) {
|
||||
// Set up once and only if we have the moves for it
|
||||
case 'bulkup': case 'curse': case 'dragondance': case 'swordsdance':
|
||||
return {
|
||||
cull: (
|
||||
(counter.setupType !== 'Physical' || counter.get('physicalsetup') > 1) ||
|
||||
(counter.get('Physical') + counter.get('physicalpool') < 2 && !moves.has('batonpass') && !restTalk)
|
||||
),
|
||||
isSetup: true,
|
||||
};
|
||||
case 'calmmind':
|
||||
return {
|
||||
cull: (
|
||||
counter.setupType !== 'Special' ||
|
||||
(counter.get('Special') + counter.get('specialpool') < 2 && !moves.has('batonpass') &&
|
||||
!moves.has('refresh') && !restTalk)
|
||||
),
|
||||
isSetup: true,
|
||||
};
|
||||
case 'agility':
|
||||
return {
|
||||
cull: (counter.damagingMoves.size < 2 && !moves.has('batonpass')) || moves.has('substitute') || restTalk,
|
||||
isSetup: !counter.setupType,
|
||||
};
|
||||
|
||||
// Not very useful without their supporting moves
|
||||
case 'amnesia': case 'sleeptalk':
|
||||
if (moves.has('roar') || moves.has('whirlwind')) return {cull: true};
|
||||
if (!moves.has('rest')) return {cull: true};
|
||||
if (movePool.length > 1) {
|
||||
const rest = movePool.indexOf('rest');
|
||||
if (rest >= 0) this.fastPop(movePool, rest);
|
||||
}
|
||||
break;
|
||||
case 'barrier':
|
||||
return {cull: !moves.has('calmmind') && !moves.has('batonpass') && !moves.has('mirrorcoat')};
|
||||
case 'batonpass':
|
||||
return {cull: (
|
||||
(!counter.setupType && !counter.get('speedsetup')) &&
|
||||
['meanlook', 'spiderweb', 'substitute', 'wish'].every(m => !moves.has(m))
|
||||
)};
|
||||
case 'endeavor': case 'flail': case 'reversal':
|
||||
return {cull: restTalk || (!moves.has('endure') && !moves.has('substitute'))};
|
||||
case 'endure':
|
||||
return {cull: movePool.includes('destinybond')};
|
||||
case 'extremespeed': case 'raindance': case 'sunnyday':
|
||||
return {cull: counter.damagingMoves.size < 2 || moves.has('rest')};
|
||||
case 'focuspunch':
|
||||
return {cull: (
|
||||
(counter.damagingMoves.size < 2 || moves.has('rest') || counter.setupType && !moves.has('spore')) ||
|
||||
(!moves.has('substitute') && (counter.get('Physical') < 4 || moves.has('fakeout'))) ||
|
||||
// Breloom likes to have coverage
|
||||
(species.id === 'breloom' && (moves.has('machpunch') || moves.has('skyuppercut')))
|
||||
)};
|
||||
case 'moonlight':
|
||||
return {cull: moves.has('wish') || moves.has('protect')};
|
||||
case 'perishsong':
|
||||
return {cull: !moves.has('meanlook') && !moves.has('spiderweb')};
|
||||
case 'protect':
|
||||
return {cull: !abilities.has('Speed Boost') && ['perishsong', 'toxic', 'wish'].every(m => !moves.has(m))};
|
||||
case 'refresh':
|
||||
return {cull: !counter.setupType};
|
||||
case 'rest':
|
||||
return {cull: (
|
||||
movePool.includes('sleeptalk') ||
|
||||
(!moves.has('sleeptalk') && (!!counter.get('recovery') || movePool.includes('curse')))
|
||||
)};
|
||||
case 'solarbeam':
|
||||
if (movePool.length > 1) {
|
||||
const sunnyday = movePool.indexOf('sunnyday');
|
||||
if (sunnyday >= 0) this.fastPop(movePool, sunnyday);
|
||||
}
|
||||
return {cull: !moves.has('sunnyday')};
|
||||
|
||||
// Bad after setup
|
||||
case 'aromatherapy': case 'healbell':
|
||||
return {cull: moves.has('rest') || !!teamDetails.statusCure};
|
||||
case 'confuseray':
|
||||
return {cull: !!counter.setupType || restTalk};
|
||||
case 'counter': case 'mirrorcoat':
|
||||
return {cull: !!counter.setupType || ['rest', 'substitute', 'toxic'].some(m => moves.has(m))};
|
||||
case 'destinybond':
|
||||
return {cull: !!counter.setupType || moves.has('explosion') || moves.has('selfdestruct')};
|
||||
case 'doubleedge': case 'facade': case 'fakeout': case 'waterspout':
|
||||
return {cull: (
|
||||
(!types.has(move.type) && counter.get('Status') >= 1) ||
|
||||
(move.id === 'doubleedge' && moves.has('return'))
|
||||
)};
|
||||
case 'encore': case 'painsplit': case 'recover': case 'yawn':
|
||||
return {cull: restTalk};
|
||||
case 'explosion': case 'machpunch': case 'selfdestruct':
|
||||
// Snorlax doesn't want to roll selfdestruct as its only STAB move
|
||||
const snorlaxCase = species.id === 'snorlax' && !moves.has('return') && !moves.has('bodyslam');
|
||||
return {cull: snorlaxCase || moves.has('rest') || moves.has('substitute') || !!counter.get('recovery')};
|
||||
case 'haze':
|
||||
return {cull: !!counter.setupType || moves.has('raindance') || restTalk};
|
||||
case 'icywind': case 'pursuit': case 'superpower': case 'transform':
|
||||
return {cull: !!counter.setupType || moves.has('rest')};
|
||||
case 'leechseed':
|
||||
return {cull: !!counter.setupType || moves.has('explosion')};
|
||||
case 'stunspore':
|
||||
return {cull: moves.has('sunnyday') || moves.has('toxic')};
|
||||
case 'lightscreen':
|
||||
return {cull: !!counter.setupType || !!counter.get('speedsetup')};
|
||||
case 'meanlook': case 'spiderweb':
|
||||
return {cull: !!counter.get('speedsetup') || (!moves.has('batonpass') && !moves.has('perishsong'))};
|
||||
case 'morningsun':
|
||||
return {cull: counter.get('speedsetup') >= 1};
|
||||
case 'quickattack':
|
||||
return {cull: (
|
||||
!!counter.get('speedsetup') ||
|
||||
moves.has('substitute') ||
|
||||
(!types.has('Normal') && !!counter.get('Status'))
|
||||
)};
|
||||
case 'rapidspin':
|
||||
return {cull: !!counter.setupType || moves.has('rest') || !!teamDetails.rapidSpin};
|
||||
case 'reflect':
|
||||
return {cull: !!counter.setupType || !!counter.get('speedsetup')};
|
||||
case 'roar': case 'whirlwind':
|
||||
return {cull: moves.has('sleeptalk') || moves.has('rest')};
|
||||
case 'seismictoss':
|
||||
return {cull: !!counter.setupType || moves.has('thunderbolt')};
|
||||
case 'spikes':
|
||||
return {cull: !!counter.setupType || moves.has('substitute') || restTalk || !!teamDetails.spikes};
|
||||
case 'substitute':
|
||||
const restOrDD = moves.has('rest') || (moves.has('dragondance') && !moves.has('bellydrum'));
|
||||
// This cull condition otherwise causes mono-solarbeam Entei
|
||||
return {cull: restOrDD || (species.id !== 'entei' && !moves.has('batonpass') && movePool.includes('calmmind'))};
|
||||
case 'thunderwave':
|
||||
return {cull: !!counter.setupType || moves.has('bodyslam') ||
|
||||
moves.has('substitute') && movePool.includes('toxic') || restTalk};
|
||||
case 'toxic':
|
||||
return {cull: (
|
||||
!!counter.setupType ||
|
||||
!!counter.get('speedsetup') ||
|
||||
['endure', 'focuspunch', 'raindance', 'yawn', 'hypnosis'].some(m => moves.has(m))
|
||||
)};
|
||||
case 'trick':
|
||||
return {cull: counter.get('Status') > 1};
|
||||
case 'willowisp':
|
||||
return {cull: !!counter.setupType || moves.has('hypnosis') || moves.has('toxic')};
|
||||
|
||||
// Bit redundant to have both
|
||||
case 'bodyslam':
|
||||
return {cull: moves.has('return') && !!counter.get('Status')};
|
||||
case 'headbutt':
|
||||
return {cull: !moves.has('bodyslam') && !moves.has('thunderwave')};
|
||||
case 'return':
|
||||
return {cull: (
|
||||
moves.has('endure') ||
|
||||
(moves.has('substitute') && moves.has('flail')) ||
|
||||
(moves.has('bodyslam') && !counter.get('Status'))
|
||||
)};
|
||||
case 'fireblast':
|
||||
return {cull: moves.has('flamethrower') && !!counter.get('Status')};
|
||||
case 'flamethrower':
|
||||
return {cull: moves.has('fireblast') && !counter.get('Status')};
|
||||
case 'overheat':
|
||||
return {cull: moves.has('flamethrower') || moves.has('substitute')};
|
||||
case 'hydropump':
|
||||
return {cull: moves.has('surf') && !!counter.get('Status')};
|
||||
case 'surf':
|
||||
return {cull: moves.has('hydropump') && !counter.get('Status')};
|
||||
case 'gigadrain':
|
||||
return {cull: moves.has('morningsun') || moves.has('toxic')};
|
||||
case 'hiddenpower':
|
||||
const stabCondition = types.has(move.type) && counter.get(move.type) > 1 && (
|
||||
(moves.has('substitute') && !counter.setupType && !moves.has('toxic')) ||
|
||||
// This otherwise causes STABless meganium
|
||||
(species.id !== 'meganium' && moves.has('toxic') && !moves.has('substitute')) ||
|
||||
restTalk
|
||||
);
|
||||
return {cull: stabCondition || (move.type === 'Grass' && moves.has('sunnyday') && moves.has('solarbeam'))};
|
||||
case 'brickbreak': case 'crosschop': case 'skyuppercut':
|
||||
return {cull: moves.has('substitute') && (moves.has('focuspunch') || movePool.includes('focuspunch'))};
|
||||
case 'earthquake':
|
||||
return {cull: moves.has('bonemerang')};
|
||||
}
|
||||
|
||||
return {cull: false};
|
||||
}
|
||||
|
||||
|
||||
getItem(
|
||||
ability: string,
|
||||
types: Set<string>,
|
||||
moves: Set<string>,
|
||||
counter: MoveCounter,
|
||||
species: Species
|
||||
) {
|
||||
// First, the high-priority items
|
||||
if (species.name === 'Ditto') return this.sample(['Metal Powder', 'Quick Claw']);
|
||||
if (species.name === 'Farfetch\u2019d') return 'Stick';
|
||||
if (species.name === 'Marowak') return 'Thick Club';
|
||||
if (species.name === 'Pikachu') return 'Light Ball';
|
||||
if (species.name === 'Shedinja') return 'Lum Berry';
|
||||
if (species.name === 'Unown') return 'Twisted Spoon';
|
||||
|
||||
if (moves.has('trick')) return 'Choice Band';
|
||||
if (moves.has('rest') && !moves.has('sleeptalk') && !['Early Bird', 'Natural Cure', 'Shed Skin'].includes(ability)) {
|
||||
return 'Chesto Berry';
|
||||
}
|
||||
|
||||
// Medium priority items
|
||||
if (moves.has('dragondance') && ability !== 'Natural Cure') return 'Lum Berry';
|
||||
if ((moves.has('bellydrum') && counter.get('Physical') - counter.get('priority') > 1) || (
|
||||
((moves.has('swordsdance') && counter.get('Status') < 2) || (moves.has('bulkup') && moves.has('substitute'))) &&
|
||||
!counter.get('priority') &&
|
||||
species.baseStats.spe >= 60 && species.baseStats.spe <= 95
|
||||
)) {
|
||||
return 'Salac Berry';
|
||||
}
|
||||
if (moves.has('endure') || (
|
||||
moves.has('substitute') &&
|
||||
['bellydrum', 'endeavor', 'flail', 'reversal'].some(m => moves.has(m))
|
||||
)) {
|
||||
return (
|
||||
species.baseStats.spe <= 100 && ability !== 'Speed Boost' && !counter.get('speedsetup') && !moves.has('focuspunch')
|
||||
) ? 'Salac Berry' : 'Liechi Berry';
|
||||
}
|
||||
if (moves.has('substitute') && counter.get('Physical') >= 3 && species.baseStats.spe >= 120) return 'Liechi Berry';
|
||||
if ((moves.has('substitute') || moves.has('raindance')) && counter.get('Special') >= 3) return 'Petaya Berry';
|
||||
if (counter.get('Physical') >= 4 && !moves.has('fakeout')) return 'Choice Band';
|
||||
if (counter.get('Physical') >= 3 && !moves.has('rapidspin') && (
|
||||
['fireblast', 'icebeam', 'overheat'].some(m => moves.has(m)) ||
|
||||
Array.from(moves).some(m => {
|
||||
const moveData = this.dex.moves.get(m);
|
||||
return moveData.category === 'Special' && types.has(moveData.type);
|
||||
})
|
||||
)) {
|
||||
return 'Choice Band';
|
||||
}
|
||||
if (moves.has('psychoboost')) return 'White Herb';
|
||||
|
||||
// Default to Leftovers
|
||||
return 'Leftovers';
|
||||
}
|
||||
|
||||
shouldCullAbility(
|
||||
ability: string,
|
||||
types: Set<string>,
|
||||
moves: Set<string>,
|
||||
abilities: Set<string>,
|
||||
counter: MoveCounter,
|
||||
movePool: string[],
|
||||
teamDetails: RandomTeamsTypes.TeamDetails,
|
||||
species: Species,
|
||||
) {
|
||||
switch (ability) {
|
||||
case 'Chlorophyll':
|
||||
return !moves.has('sunnyday') && !teamDetails['sun'];
|
||||
case 'Compound Eyes':
|
||||
return !counter.get('inaccurate');
|
||||
case 'Hustle':
|
||||
return counter.get('Physical') < 2;
|
||||
case 'Lightning Rod':
|
||||
return species.types.includes('Ground');
|
||||
case 'Overgrow':
|
||||
return !counter.get('Grass');
|
||||
case 'Rock Head':
|
||||
return !counter.get('recoil');
|
||||
case 'Sand Veil':
|
||||
return !teamDetails['sand'];
|
||||
case 'Serene Grace':
|
||||
return species.id === 'blissey';
|
||||
case 'Soundproof': case 'Sturdy':
|
||||
// Electrode prefers Static, and Sturdy is bad.
|
||||
return true;
|
||||
case 'Swift Swim':
|
||||
return !moves.has('raindance') && !teamDetails['rain'];
|
||||
case 'Swarm':
|
||||
return !counter.get('Bug');
|
||||
case 'Torrent':
|
||||
return !counter.get('Water');
|
||||
case 'Water Absorb':
|
||||
return abilities.has('Swift Swim');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
randomSet(species: string | Species, teamDetails: RandomTeamsTypes.TeamDetails = {}): RandomTeamsTypes.RandomSet {
|
||||
species = this.dex.species.get(species);
|
||||
let forme = species.name;
|
||||
|
||||
const data = this.randomData[species.id];
|
||||
|
||||
if (typeof species.battleOnly === 'string') forme = species.battleOnly;
|
||||
|
||||
const movePool = (data.moves || Object.keys(this.dex.species.getLearnset(species.id)!)).slice();
|
||||
const rejectedPool = [];
|
||||
const moves = new Set<string>();
|
||||
let ability = '';
|
||||
const evs = {hp: 85, atk: 85, def: 85, spa: 85, spd: 85, spe: 85};
|
||||
const ivs = {hp: 31, atk: 31, def: 31, spa: 31, spd: 31, spe: 31};
|
||||
let availableHP = 0;
|
||||
for (const setMoveid of movePool) {
|
||||
if (setMoveid.startsWith('hiddenpower')) availableHP++;
|
||||
}
|
||||
|
||||
const types = new Set(species.types);
|
||||
|
||||
const abilities = new Set(Object.values(species.abilities));
|
||||
|
||||
let counter: MoveCounter;
|
||||
// We use a special variable to track Hidden Power
|
||||
// so that we can check for all Hidden Powers at once
|
||||
let hasHiddenPower = false;
|
||||
|
||||
do {
|
||||
// Choose next 4 moves from learnset/viable moves and add them to moves list:
|
||||
while (moves.size < this.maxMoveCount && movePool.length) {
|
||||
const moveid = this.sampleNoReplace(movePool);
|
||||
if (moveid.startsWith('hiddenpower')) {
|
||||
availableHP--;
|
||||
if (hasHiddenPower) continue;
|
||||
hasHiddenPower = true;
|
||||
}
|
||||
moves.add(moveid);
|
||||
}
|
||||
|
||||
while (moves.size < this.maxMoveCount && rejectedPool.length) {
|
||||
const moveid = this.sampleNoReplace(rejectedPool);
|
||||
if (moveid.startsWith('hiddenpower')) {
|
||||
if (hasHiddenPower) continue;
|
||||
hasHiddenPower = true;
|
||||
}
|
||||
moves.add(moveid);
|
||||
}
|
||||
|
||||
counter = this.queryMoves(moves, species.types, abilities, movePool);
|
||||
|
||||
// Iterate through the moves again, this time to cull them:
|
||||
for (const moveid of moves) {
|
||||
const move = this.dex.moves.get(moveid);
|
||||
|
||||
let {cull, isSetup} = this.shouldCullMove(move, types, moves, abilities, counter, movePool, teamDetails, species);
|
||||
|
||||
// This move doesn't satisfy our setup requirements:
|
||||
if (
|
||||
(counter.setupType === 'Physical' && move.category === 'Special' && !types.has(move.type) && move.type !== 'Fire') ||
|
||||
(counter.setupType === 'Special' && move.category === 'Physical' && moveid !== 'superpower')
|
||||
) {
|
||||
cull = true;
|
||||
}
|
||||
const moveIsRejectable = (
|
||||
!move.weather &&
|
||||
(move.category !== 'Status' || !move.flags.heal) &&
|
||||
(counter.setupType || !move.stallingMove) &&
|
||||
// These moves cannot be rejected in favor of a forced move
|
||||
!['batonpass', 'sleeptalk', 'solarbeam', 'substitute', 'sunnyday'].includes(moveid) &&
|
||||
(move.category === 'Status' || !types.has(move.type) || (move.basePower && move.basePower < 40 && !move.multihit))
|
||||
);
|
||||
// Pokemon should usually have at least one STAB move
|
||||
const requiresStab = (
|
||||
!counter.get('stab') &&
|
||||
!moves.has('seismictoss') && !moves.has('nightshade') &&
|
||||
species.id !== 'castform' && species.id !== 'umbreon' &&
|
||||
// If a Flying-type has Psychic, it doesn't need STAB
|
||||
!(moves.has('psychic') && types.has('Flying')) &&
|
||||
!(types.has('Ghost') && species.baseStats.spa > species.baseStats.atk) &&
|
||||
!(
|
||||
// With Calm Mind, Lugia and pure Normal-types are fine without STAB
|
||||
counter.setupType === 'Special' && (
|
||||
species.id === 'lugia' ||
|
||||
(types.has('Normal') && species.types.length < 2)
|
||||
)
|
||||
) &&
|
||||
!(
|
||||
// With Swords Dance, Dark-types and pure Water-types are fine without STAB
|
||||
counter.setupType === 'Physical' &&
|
||||
((types.has('Water') && species.types.length < 2) || types.has('Dark'))
|
||||
) &&
|
||||
counter.get('physicalpool') + counter.get('specialpool') > 0
|
||||
);
|
||||
|
||||
const runEnforcementChecker = (checkerName: string) => {
|
||||
if (!this.moveEnforcementCheckers[checkerName]) return false;
|
||||
return this.moveEnforcementCheckers[checkerName](
|
||||
movePool, moves, abilities, types, counter, species as Species, teamDetails
|
||||
);
|
||||
};
|
||||
|
||||
if (!cull && !isSetup && moveIsRejectable) {
|
||||
// There may be more important moves that this Pokemon needs
|
||||
if (
|
||||
requiresStab ||
|
||||
(counter.setupType && counter.get(counter.setupType) < 2 && !moves.has('refresh')) ||
|
||||
(moves.has('substitute') && movePool.includes('morningsun')) ||
|
||||
['meteormash', 'spore', 'recover'].some(m => movePool.includes(m))
|
||||
) {
|
||||
cull = true;
|
||||
} else {
|
||||
// Pokemon should have moves that benefit their typing and their other moves
|
||||
for (const type of types) {
|
||||
if (runEnforcementChecker(type)) {
|
||||
cull = true;
|
||||
}
|
||||
}
|
||||
for (const m of moves) {
|
||||
if (runEnforcementChecker(m)) cull = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sleep Talk shouldn't be selected without Rest
|
||||
if (moveid === 'rest' && cull) {
|
||||
const sleeptalk = movePool.indexOf('sleeptalk');
|
||||
if (sleeptalk >= 0) {
|
||||
if (movePool.length < 2) {
|
||||
cull = false;
|
||||
} else {
|
||||
this.fastPop(movePool, sleeptalk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove rejected moves from the move list
|
||||
const moveIsHP = moveid.startsWith('hiddenpower');
|
||||
if (
|
||||
cull &&
|
||||
(movePool.length - availableHP || availableHP && (moveIsHP || !hasHiddenPower))
|
||||
) {
|
||||
if (move.category !== 'Status' && !move.damage && (!moveIsHP || !availableHP)) {
|
||||
rejectedPool.push(moveid);
|
||||
}
|
||||
if (moveIsHP) hasHiddenPower = false;
|
||||
moves.delete(moveid);
|
||||
break;
|
||||
}
|
||||
if (cull && rejectedPool.length) {
|
||||
if (moveIsHP) hasHiddenPower = false;
|
||||
moves.delete(moveid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (moves.size < this.maxMoveCount && (movePool.length || rejectedPool.length));
|
||||
|
||||
if (hasHiddenPower) {
|
||||
let hpType;
|
||||
for (const move of moves) {
|
||||
if (move.startsWith('hiddenpower')) hpType = move.substr(11);
|
||||
}
|
||||
if (!hpType) throw new Error(`hasHiddenPower is true, but no Hidden Power move was found.`);
|
||||
const HPivs = this.dex.types.get(hpType).HPivs;
|
||||
let iv: StatID;
|
||||
for (iv in HPivs) {
|
||||
ivs[iv] = HPivs[iv]!;
|
||||
}
|
||||
}
|
||||
|
||||
const abilityData = Array.from(abilities).map(a => this.dex.abilities.get(a)).filter(a => a.gen === 3);
|
||||
Utils.sortBy(abilityData, abil => -abil.rating);
|
||||
let ability0 = abilityData[0];
|
||||
let ability1 = abilityData[1];
|
||||
if (abilityData[1]) {
|
||||
if (ability0.rating <= ability1.rating && this.randomChance(1, 2)) {
|
||||
[ability0, ability1] = [ability1, ability0];
|
||||
} else if (ability0.rating - 0.6 <= ability1.rating && this.randomChance(2, 3)) {
|
||||
[ability0, ability1] = [ability1, ability0];
|
||||
}
|
||||
ability = ability0.name;
|
||||
|
||||
while (this.shouldCullAbility(ability, types, moves, abilities, counter, movePool, teamDetails, species)) {
|
||||
if (ability === ability0.name && ability1.rating > 1) {
|
||||
ability = ability1.name;
|
||||
} else {
|
||||
// Default to the highest rated ability if all are rejected
|
||||
ability = abilityData[0].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ability = abilityData[0].name;
|
||||
}
|
||||
|
||||
const item = this.getItem(ability, types, moves, counter, species);
|
||||
const level = this.adjustLevel || data.level || (species.nfe ? 90 : 80);
|
||||
|
||||
// Prepare optimal HP
|
||||
let hp = Math.floor(Math.floor(2 * species.baseStats.hp + ivs.hp + Math.floor(evs.hp / 4) + 100) * level / 100 + 10);
|
||||
if (moves.has('substitute') && ['endeavor', 'flail', 'reversal'].some(m => moves.has(m))) {
|
||||
// Endeavor/Flail/Reversal users should be able to use four Substitutes
|
||||
if (hp % 4 === 0) evs.hp -= 4;
|
||||
} else if (moves.has('substitute') && (item === 'Salac Berry' || item === 'Petaya Berry' || item === 'Liechi Berry')) {
|
||||
// Other pinch berry holders should have berries activate after three Substitutes
|
||||
while (hp % 4 > 0) {
|
||||
evs.hp -= 4;
|
||||
hp = Math.floor(Math.floor(2 * species.baseStats.hp + ivs.hp + Math.floor(evs.hp / 4) + 100) * level / 100 + 10);
|
||||
}
|
||||
}
|
||||
|
||||
// Minimize confusion damage
|
||||
if (!counter.get('Physical') && !moves.has('transform')) {
|
||||
evs.atk = 0;
|
||||
ivs.atk = hasHiddenPower ? ivs.atk - 28 : 0;
|
||||
}
|
||||
|
||||
return {
|
||||
name: species.baseSpecies,
|
||||
species: forme,
|
||||
gender: species.gender,
|
||||
moves: Array.from(moves),
|
||||
ability: ability,
|
||||
evs: evs,
|
||||
ivs: ivs,
|
||||
item: item,
|
||||
level,
|
||||
shiny: this.randomChance(1, 1024),
|
||||
};
|
||||
}
|
||||
|
||||
randomTeam() {
|
||||
this.enforceNoDirectCustomBanlistChanges();
|
||||
|
||||
const seed = this.prng.seed;
|
||||
const ruleTable = this.dex.formats.getRuleTable(this.format);
|
||||
const pokemon: RandomTeamsTypes.RandomSet[] = [];
|
||||
|
||||
// For Monotype
|
||||
const isMonotype = !!this.forceMonotype || ruleTable.has('sametypeclause');
|
||||
const typePool = this.dex.types.names();
|
||||
const type = this.forceMonotype || this.sample(typePool);
|
||||
|
||||
const baseFormes: {[k: string]: number} = {};
|
||||
const tierCount: {[k: string]: number} = {};
|
||||
const typeCount: {[k: string]: number} = {};
|
||||
const typeComboCount: {[k: string]: number} = {};
|
||||
const typeWeaknesses: {[k: string]: number} = {};
|
||||
const teamDetails: RandomTeamsTypes.TeamDetails = {};
|
||||
|
||||
const pokemonPool = this.getPokemonPool(type, pokemon, isMonotype);
|
||||
|
||||
while (pokemonPool.length && pokemon.length < this.maxTeamSize) {
|
||||
const species = this.dex.species.get(this.sampleNoReplace(pokemonPool));
|
||||
if (!species.exists || !this.randomData[species.id]?.moves) continue;
|
||||
// Limit to one of each species (Species Clause)
|
||||
if (baseFormes[species.baseSpecies]) continue;
|
||||
|
||||
// Limit to one Wobbuffet per battle (not just per team)
|
||||
if (species.name === 'Wobbuffet' && this.battleHasWobbuffet) continue;
|
||||
// Limit to one Ditto per battle in Gen 2
|
||||
if (this.dex.gen < 3 && species.name === 'Ditto' && this.battleHasDitto) continue;
|
||||
|
||||
const tier = species.tier;
|
||||
const types = species.types;
|
||||
const typeCombo = types.slice().sort().join();
|
||||
|
||||
if (!isMonotype && !this.forceMonotype) {
|
||||
// Dynamically scale limits for different team sizes. The default and minimum value is 1.
|
||||
const limitFactor = Math.round(this.maxTeamSize / 6) || 1;
|
||||
|
||||
// Limit two Pokemon per tier
|
||||
if (tierCount[tier] >= 2 * limitFactor) continue;
|
||||
|
||||
// Limit two of any type
|
||||
let skip = false;
|
||||
for (const typeName of types) {
|
||||
if (typeCount[typeName] >= 2 * limitFactor) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (skip) continue;
|
||||
|
||||
// Limit three weak to any type
|
||||
for (const typeName of this.dex.types.names()) {
|
||||
// it's weak to the type
|
||||
if (this.dex.getEffectiveness(typeName, species) > 0) {
|
||||
if (!typeWeaknesses[typeName]) typeWeaknesses[typeName] = 0;
|
||||
if (typeWeaknesses[typeName] >= 3 * limitFactor) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (skip) continue;
|
||||
|
||||
// Limit one of any type combination
|
||||
if (!this.forceMonotype && typeComboCount[typeCombo] >= 1 * limitFactor) continue;
|
||||
}
|
||||
|
||||
// Okay, the set passes, add it to our team
|
||||
const set = this.randomSet(species, teamDetails);
|
||||
pokemon.push(set);
|
||||
|
||||
// Now that our Pokemon has passed all checks, we can increment our counters
|
||||
baseFormes[species.baseSpecies] = 1;
|
||||
|
||||
// Increment tier counter
|
||||
if (tierCount[tier]) {
|
||||
tierCount[tier]++;
|
||||
} else {
|
||||
tierCount[tier] = 1;
|
||||
}
|
||||
|
||||
// Increment type counters
|
||||
for (const typeName of types) {
|
||||
if (typeName in typeCount) {
|
||||
typeCount[typeName]++;
|
||||
} else {
|
||||
typeCount[typeName] = 1;
|
||||
}
|
||||
}
|
||||
if (typeCombo in typeComboCount) {
|
||||
typeComboCount[typeCombo]++;
|
||||
} else {
|
||||
typeComboCount[typeCombo] = 1;
|
||||
}
|
||||
|
||||
// Increment weakness counter
|
||||
for (const typeName of this.dex.types.names()) {
|
||||
// it's weak to the type
|
||||
if (this.dex.getEffectiveness(typeName, species) > 0) {
|
||||
typeWeaknesses[typeName]++;
|
||||
}
|
||||
}
|
||||
|
||||
// Updateeam details
|
||||
if (set.ability === 'Drizzle' || set.moves.includes('raindance')) teamDetails.rain = 1;
|
||||
if (set.ability === 'Sand Stream') teamDetails.sand = 1;
|
||||
if (set.moves.includes('spikes')) teamDetails.spikes = 1;
|
||||
if (set.moves.includes('rapidspin')) teamDetails.rapidSpin = 1;
|
||||
if (set.moves.includes('aromatherapy') || set.moves.includes('healbell')) teamDetails.statusCure = 1;
|
||||
|
||||
// In Gen 3, Shadow Tag users can prevent each other from switching out, possibly causing and endless battle or at least causing a long stall war
|
||||
// To prevent this, we prevent more than one Wobbuffet in a single battle.
|
||||
if (set.ability === 'Shadow Tag') this.battleHasWobbuffet = true;
|
||||
if (species.id === 'ditto') this.battleHasDitto = true;
|
||||
}
|
||||
|
||||
if (pokemon.length < this.maxTeamSize && !isMonotype && !this.forceMonotype && pokemon.length < 12) {
|
||||
throw new Error(`Could not build a random team for ${this.format} (seed=${seed})`);
|
||||
}
|
||||
|
||||
return pokemon;
|
||||
}
|
||||
}
|
||||
|
||||
export default RandomGen3Teams;
|
||||
|
|
@ -1,24 +1,8 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
export const Rulesets: {[k: string]: ModdedFormatData} = {
|
||||
standard: {
|
||||
effectType: 'ValidatorRule',
|
||||
name: 'Standard',
|
||||
desc: "The standard ruleset for all official Smogon singles tiers (Ubers, OU, etc.)",
|
||||
ruleset: [
|
||||
'Standard AG',
|
||||
'Sleep Clause Mod', 'Switch Priority Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Items Clause', 'Evasion Moves Clause',
|
||||
],
|
||||
},
|
||||
standarddraft: {
|
||||
effectType: 'ValidatorRule',
|
||||
name: 'Standard Draft',
|
||||
desc: "The custom Draft League ruleset",
|
||||
ruleset: [
|
||||
'Obtainable', 'Nickname Clause', 'Beat Up Nicknames Mod', '+Unreleased', 'Sleep Clause Mod', 'OHKO Clause', 'Evasion Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod',
|
||||
'One Boost Passer Clause', 'Freeze Clause Mod', 'Accuracy Moves Clause', 'Baton Pass Trap Clause',
|
||||
],
|
||||
banlist: [
|
||||
'Uber', 'Smeargle + Ingrain', 'Swagger', 'Focus Band', 'King\'s Rock', 'Quick Claw', 'Baton Pass + Ancient Power', 'Baton Pass + Silver Wind',
|
||||
],
|
||||
// timer: {starting: 60 * 60, grace: 0, addPerTurn: 10, maxPerTurn: 100, timeoutAutoChoose: true},
|
||||
desc: "The standard ruleset for all offical Smogon singles tiers (Ubers, OU, etc.)",
|
||||
ruleset: ['Obtainable', 'Sleep Clause Mod', 'Switch Priority Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Items Clause', 'Evasion Moves Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod'],
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,9 +17,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
inherit: true,
|
||||
getActionSpeed() {
|
||||
let speed = this.getStat('spe', false, false);
|
||||
const trickRoomCheck = this.battle.ruleTable.has('twisteddimensionmod') ?
|
||||
!this.battle.field.getPseudoWeather('trickroom') : this.battle.field.getPseudoWeather('trickroom');
|
||||
if (trickRoomCheck) {
|
||||
if (this.battle.field.getPseudoWeather('trickroom')) {
|
||||
speed = -speed;
|
||||
}
|
||||
if (this.battle.quickClawRoll && this.hasItem('quickclaw')) {
|
||||
|
|
@ -49,8 +47,8 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
// In Generation 3, the spread move modifier is 0.5x instead of 0.75x. Moves that hit both foes
|
||||
// and the user's ally, like Earthquake and Explosion, don't get affected by spread modifiers
|
||||
if (move.spreadHit && move.target === 'allAdjacentFoes') {
|
||||
const spreadModifier = 0.5;
|
||||
this.battle.debug(`Spread modifier: ${spreadModifier}`);
|
||||
const spreadModifier = move.spreadModifier || 0.5;
|
||||
this.battle.debug('Spread modifier: ' + spreadModifier);
|
||||
baseDamage = this.battle.modify(baseDamage, spreadModifier);
|
||||
}
|
||||
|
||||
|
|
@ -72,17 +70,12 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
baseDamage = Math.floor(this.battle.runEvent('ModifyDamagePhase2', pokemon, target, move, baseDamage));
|
||||
|
||||
// STAB
|
||||
// The "???" type never gets STAB
|
||||
// Not even if you Roost in Gen 4 and somehow manage to use
|
||||
// Struggle in the same turn.
|
||||
// (On second thought, it might be easier to get a MissingNo.)
|
||||
if (type !== '???') {
|
||||
let stab: number | [number, number] = 1;
|
||||
if (move.forceSTAB || pokemon.hasType(type)) {
|
||||
stab = 1.5;
|
||||
}
|
||||
stab = this.battle.runEvent('ModifySTAB', pokemon, target, move, stab);
|
||||
baseDamage = this.battle.modify(baseDamage, stab);
|
||||
if (move.forceSTAB || type !== '???' && pokemon.hasType(type)) {
|
||||
// The "???" type never gets STAB
|
||||
// Not even if you Roost in Gen 4 and somehow manage to use
|
||||
// Struggle in the same turn.
|
||||
// (On second thought, it might be easier to get a MissingNo.)
|
||||
baseDamage = this.battle.modify(baseDamage, move.stab || 1.5);
|
||||
}
|
||||
// types
|
||||
let typeMod = target.runEffectiveness(move);
|
||||
|
|
@ -117,9 +110,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
|
||||
return Math.floor(baseDamage);
|
||||
},
|
||||
useMoveInner(moveOrMoveName, pokemon, options) {
|
||||
let sourceEffect = options?.sourceEffect;
|
||||
let target = options?.target;
|
||||
useMoveInner(moveOrMoveName, pokemon, target, sourceEffect, zMove) {
|
||||
if (!sourceEffect && this.battle.effect.id) sourceEffect = this.battle.effect;
|
||||
if (sourceEffect && sourceEffect.id === 'instruct') sourceEffect = null;
|
||||
|
||||
|
|
@ -162,8 +153,8 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
|
||||
let movename = move.name;
|
||||
if (move.id === 'hiddenpower') movename = 'Hidden Power';
|
||||
if (sourceEffect) attrs += `|[from] ${this.dex.conditions.get(sourceEffect).name}`;
|
||||
this.battle.addMove('move', pokemon, movename, `${target}${attrs}`);
|
||||
if (sourceEffect) attrs += `|[from]${this.dex.conditions.get(sourceEffect)}`;
|
||||
this.battle.addMove('move', pokemon, movename, target + attrs);
|
||||
|
||||
if (!target) {
|
||||
this.battle.attrLastMove('[notarget]');
|
||||
|
|
@ -171,7 +162,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
return false;
|
||||
}
|
||||
|
||||
const { targets, pressureTargets } = pokemon.getMoveTargets(move, target);
|
||||
const {targets, pressureTargets} = pokemon.getMoveTargets(move, target);
|
||||
|
||||
if (!sourceEffect || sourceEffect.id === 'pursuit') {
|
||||
let extraPP = 0;
|
||||
|
|
@ -256,7 +247,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!(move.hasSheerForce && pokemon.hasAbility('sheerforce'))) {
|
||||
if (!move.negateSecondary && !(move.hasSheerForce && pokemon.hasAbility('sheerforce'))) {
|
||||
this.battle.singleEvent('AfterMoveSecondarySelf', move, null, pokemon, target, move);
|
||||
this.battle.runEvent('AfterMoveSecondarySelf', pokemon, target, move);
|
||||
}
|
||||
|
|
@ -308,7 +299,10 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
move.ignoreImmunity = (move.category === 'Status');
|
||||
}
|
||||
|
||||
if (!target.runImmunity(move)) {
|
||||
if (
|
||||
(!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) &&
|
||||
!target.runImmunity(move.type)
|
||||
) {
|
||||
naturalImmunity = true;
|
||||
} else {
|
||||
hitResult = this.battle.singleEvent('TryImmunity', move, {}, target, pokemon, move);
|
||||
|
|
@ -325,7 +319,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
let boost: number;
|
||||
if (accuracy !== true) {
|
||||
if (!move.ignoreAccuracy) {
|
||||
boosts = this.battle.runEvent('ModifyBoost', pokemon, null, null, { ...pokemon.boosts });
|
||||
boosts = this.battle.runEvent('ModifyBoost', pokemon, null, null, {...pokemon.boosts});
|
||||
boost = this.battle.clampIntRange(boosts['accuracy'], -6, 6);
|
||||
if (boost > 0) {
|
||||
accuracy *= boostTable[boost];
|
||||
|
|
@ -334,7 +328,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
}
|
||||
if (!move.ignoreEvasion) {
|
||||
boosts = this.battle.runEvent('ModifyBoost', target, null, null, { ...target.boosts });
|
||||
boosts = this.battle.runEvent('ModifyBoost', target, null, null, {...target.boosts});
|
||||
boost = this.battle.clampIntRange(boosts['evasion'], -6, 6);
|
||||
if (boost > 0) {
|
||||
accuracy /= boostTable[boost];
|
||||
|
|
@ -414,7 +408,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
accuracy = move.accuracy;
|
||||
if (accuracy !== true) {
|
||||
if (!move.ignoreAccuracy) {
|
||||
boosts = this.battle.runEvent('ModifyBoost', pokemon, null, null, { ...pokemon.boosts });
|
||||
boosts = this.battle.runEvent('ModifyBoost', pokemon, null, null, {...pokemon.boosts});
|
||||
boost = this.battle.clampIntRange(boosts['accuracy'], -6, 6);
|
||||
if (boost > 0) {
|
||||
accuracy *= boostTable[boost];
|
||||
|
|
@ -423,7 +417,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
}
|
||||
if (!move.ignoreEvasion) {
|
||||
boosts = this.battle.runEvent('ModifyBoost', target, null, null, { ...target.boosts });
|
||||
boosts = this.battle.runEvent('ModifyBoost', target, null, null, {...target.boosts});
|
||||
boost = this.battle.clampIntRange(boosts['evasion'], -6, 6);
|
||||
if (boost > 0) {
|
||||
accuracy /= boostTable[boost];
|
||||
|
|
@ -457,7 +451,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
|
||||
if (move.recoil && move.totalDamage) {
|
||||
this.battle.damage(this.calcRecoilDamage(move.totalDamage, move, pokemon), pokemon, target, 'recoil');
|
||||
this.battle.damage(this.calcRecoilDamage(move.totalDamage, move), pokemon, target, 'recoil');
|
||||
}
|
||||
|
||||
if (target && pokemon !== target) target.gotAttacked(move, damage, pokemon);
|
||||
|
|
@ -468,7 +462,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
|
||||
this.battle.eachEvent('Update');
|
||||
|
||||
if (target) {
|
||||
if (target && !move.negateSecondary) {
|
||||
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
|
||||
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
/**
|
||||
* Gen 3 colosseum modifications (perish song should fail if it effects all remaining pokemon)
|
||||
*/
|
||||
export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
||||
perishsong: {
|
||||
inherit: true,
|
||||
onTryMove(attacker, defender, move) {
|
||||
if (attacker.side.pokemonLeft === 1) {
|
||||
this.add('-fail', attacker, 'move: Perish Song');
|
||||
this.hint("Self KO Clause: The last pokemon on a team cannot use moves that force fainting");
|
||||
return false;
|
||||
}
|
||||
},
|
||||
},
|
||||
destinybond: {
|
||||
inherit: true,
|
||||
onTryMove(attacker, defender, move) {
|
||||
if (attacker.side.pokemonLeft === 1) {
|
||||
this.add('-fail', attacker, 'move: Perish Song');
|
||||
this.hint("Self KO Clause: The last pokemon on a team cannot use moves that force fainting");
|
||||
return false;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
export const Scripts: ModdedBattleScriptsData = {
|
||||
inherit: 'gen3',
|
||||
gen: 3,
|
||||
|
||||
checkWin(faintData?: Battle['faintQueue'][0]) {
|
||||
if (this.sides.every(side => !side.pokemonLeft)) {
|
||||
let isSelfKo = false;
|
||||
if (faintData?.effect) {
|
||||
isSelfKo = isSelfKo || this.dex.moves.getByID(faintData?.effect?.id).selfdestruct !== undefined;
|
||||
isSelfKo = isSelfKo || this.dex.moves.getByID(faintData?.effect?.id).recoil !== undefined;
|
||||
}
|
||||
if (isSelfKo) {
|
||||
this.win(faintData ? faintData.target.side : null);
|
||||
return true;
|
||||
} else {
|
||||
this.win(undefined);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (const side of this.sides) {
|
||||
if (!side.foePokemonLeft()) {
|
||||
this.win(side);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,58 +0,0 @@
|
|||
export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
||||
apicotberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
berryjuice: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
fastball: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
ganlonberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
heavyball: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
lansatberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
levelball: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
loveball: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
lureball: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
moonball: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
petayaberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
salacberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
sportball: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
starfberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,3 +0,0 @@
|
|||
export const Scripts: ModdedBattleScriptsData = {
|
||||
inherit: 'gen3',
|
||||
};
|
||||
|
|
@ -1,17 +1,15 @@
|
|||
export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTable = {
|
||||
export const Abilities: {[k: string]: ModdedAbilityData} = {
|
||||
airlock: {
|
||||
inherit: true,
|
||||
onSwitchIn: undefined, // no inherit
|
||||
onStart(pokemon) {
|
||||
pokemon.abilityState.ending = false;
|
||||
},
|
||||
onSwitchIn() {},
|
||||
onStart() {},
|
||||
},
|
||||
angerpoint: {
|
||||
inherit: true,
|
||||
onAfterSubDamage(damage, target, source, move) {
|
||||
if (!target.hp) return;
|
||||
if (move && move.effectType === 'Move' && target.getMoveHitData(move).crit) {
|
||||
target.setBoost({ atk: 6 });
|
||||
target.setBoost({atk: 6});
|
||||
this.add('-setboost', target, 'atk', 12, '[from] ability: Anger Point');
|
||||
}
|
||||
},
|
||||
|
|
@ -23,9 +21,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
onResidualSubOrder: 10,
|
||||
},
|
||||
blaze: {
|
||||
inherit: true,
|
||||
onModifyAtk: undefined, // no inherit
|
||||
onModifySpA: undefined, // no inherit
|
||||
onBasePowerPriority: 2,
|
||||
onBasePower(basePower, attacker, defender, move) {
|
||||
if (move.type === 'Fire' && attacker.hp <= attacker.maxhp / 3) {
|
||||
|
|
@ -33,13 +28,14 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
return this.chainModify(1.5);
|
||||
}
|
||||
},
|
||||
name: "Blaze",
|
||||
rating: 2,
|
||||
num: 66,
|
||||
},
|
||||
cloudnine: {
|
||||
inherit: true,
|
||||
onSwitchIn: undefined, // no inherit
|
||||
onStart(pokemon) {
|
||||
pokemon.abilityState.ending = false;
|
||||
},
|
||||
onSwitchIn() {},
|
||||
onStart() {},
|
||||
},
|
||||
colorchange: {
|
||||
inherit: true,
|
||||
|
|
@ -51,14 +47,14 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
this.add('-start', target, 'typechange', type, '[from] ability: Color Change');
|
||||
}
|
||||
},
|
||||
onAfterMoveSecondary: undefined, // no inherit
|
||||
onAfterMoveSecondary() {},
|
||||
},
|
||||
compoundeyes: {
|
||||
onSourceModifyAccuracyPriority: 9,
|
||||
onSourceModifyAccuracy(accuracy) {
|
||||
if (typeof accuracy !== 'number') return;
|
||||
this.debug('compoundeyes - enhancing accuracy');
|
||||
return this.chainModify(1.3);
|
||||
return accuracy * 1.3;
|
||||
},
|
||||
inherit: true,
|
||||
},
|
||||
|
|
@ -72,23 +68,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
}
|
||||
},
|
||||
},
|
||||
download: {
|
||||
inherit: true,
|
||||
onStart(pokemon) {
|
||||
let totaldef = 0;
|
||||
let totalspd = 0;
|
||||
for (const target of pokemon.foes()) {
|
||||
if (target.volatiles.substitute) continue;
|
||||
totaldef += target.getStat('def', false, true);
|
||||
totalspd += target.getStat('spd', false, true);
|
||||
}
|
||||
if (totaldef && totaldef >= totalspd) {
|
||||
this.boost({ spa: 1 });
|
||||
} else if (totalspd) {
|
||||
this.boost({ atk: 1 });
|
||||
}
|
||||
},
|
||||
},
|
||||
effectspore: {
|
||||
inherit: true,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
|
|
@ -128,15 +107,19 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
}
|
||||
},
|
||||
condition: {
|
||||
inherit: true,
|
||||
onModifyAtk: undefined, // no inherit
|
||||
onModifySpA: undefined, // no inherit
|
||||
noCopy: true, // doesn't get copied by Baton Pass
|
||||
onStart(target) {
|
||||
this.add('-start', target, 'ability: Flash Fire');
|
||||
},
|
||||
onModifyDamagePhase1(atk, attacker, defender, move) {
|
||||
if (move.type === 'Fire') {
|
||||
this.debug('Flash Fire boost');
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
},
|
||||
onEnd(target) {
|
||||
this.add('-end', target, 'ability: Flash Fire', '[silent]');
|
||||
},
|
||||
},
|
||||
},
|
||||
flowergift: {
|
||||
|
|
@ -151,11 +134,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
return this.chainModify(1.5);
|
||||
}
|
||||
},
|
||||
flags: { breakable: 1 },
|
||||
},
|
||||
forecast: {
|
||||
inherit: true,
|
||||
flags: { notrace: 1 },
|
||||
},
|
||||
forewarn: {
|
||||
inherit: true,
|
||||
|
|
@ -185,9 +163,10 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
frisk: {
|
||||
inherit: true,
|
||||
onStart(pokemon) {
|
||||
const target = pokemon.side.randomFoe();
|
||||
if (target?.item) {
|
||||
this.add('-item', '', target.getItem().name, '[from] ability: Frisk', `[of] ${pokemon}`);
|
||||
for (const target of pokemon.foes()) {
|
||||
if (target.item && !target.itemState.knockedOff) {
|
||||
this.add('-item', target, target.getItem().name, '[from] ability: Frisk', '[of] ' + pokemon, '[identify]');
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
@ -196,19 +175,20 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
onSourceModifyAccuracyPriority: 7,
|
||||
onSourceModifyAccuracy(accuracy, target, source, move) {
|
||||
if (move.category === 'Physical' && typeof accuracy === 'number') {
|
||||
return this.chainModify(0.8);
|
||||
return accuracy * 0.8;
|
||||
}
|
||||
},
|
||||
},
|
||||
hydration: {
|
||||
inherit: true,
|
||||
onResidual: undefined, // no inherit
|
||||
onWeather(target, source, effect) {
|
||||
if (effect.id === 'raindance' && target.status) {
|
||||
this.add('-activate', target, 'ability: Hydration');
|
||||
target.cureStatus();
|
||||
}
|
||||
},
|
||||
name: "Hydration",
|
||||
rating: 1.5,
|
||||
num: 93,
|
||||
},
|
||||
insomnia: {
|
||||
inherit: true,
|
||||
|
|
@ -233,7 +213,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
} else if (target.volatiles['substitutebroken']?.move === 'uturn') {
|
||||
this.hint("In Gen 4, if U-turn breaks Substitute the incoming Intimidate does nothing.");
|
||||
} else {
|
||||
this.boost({ atk: -1 }, target, pokemon, null, true);
|
||||
this.boost({atk: -1}, target, pokemon, null, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -242,7 +222,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
inherit: true,
|
||||
onSetStatus(status, target, source, effect) {
|
||||
if (effect && effect.id === 'rest') {
|
||||
// do nothing
|
||||
return;
|
||||
} else if (this.field.isWeather('sunnyday')) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -250,13 +230,13 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
},
|
||||
lightningrod: {
|
||||
inherit: true,
|
||||
onTryHit: undefined, // no inherit
|
||||
onTryHit() {},
|
||||
rating: 0,
|
||||
},
|
||||
liquidooze: {
|
||||
inherit: true,
|
||||
onSourceTryHeal(damage, target, source, effect) {
|
||||
this.debug(`Heal is occurring: ${target} <- ${source} :: ${effect.id}`);
|
||||
this.debug("Heal is occurring: " + target + " <- " + source + " :: " + effect.id);
|
||||
const canOoze = ['drain', 'leechseed'];
|
||||
if (canOoze.includes(effect.id) && this.activeMove?.id !== 'dreameater') {
|
||||
this.damage(damage, null, null, null, true);
|
||||
|
|
@ -265,28 +245,35 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
},
|
||||
},
|
||||
magicguard: {
|
||||
inherit: true,
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (effect.effectType !== 'Move') {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onSetStatus(status, target, source, effect) {
|
||||
if (effect && effect.id === 'toxicspikes') {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
name: "Magic Guard",
|
||||
rating: 4.5,
|
||||
num: 98,
|
||||
},
|
||||
minus: {
|
||||
inherit: true,
|
||||
onModifySpAPriority: undefined, // no inherit
|
||||
onModifySpA(spa, pokemon) {
|
||||
for (const allyActive of pokemon.allies()) {
|
||||
if (allyActive.hasAbility('plus')) {
|
||||
return this.chainModify(1.5);
|
||||
for (const ally of pokemon.allies()) {
|
||||
if (ally.ability === 'plus') {
|
||||
return spa * 1.5;
|
||||
}
|
||||
}
|
||||
},
|
||||
name: "Minus",
|
||||
rating: 0,
|
||||
num: 58,
|
||||
},
|
||||
naturalcure: {
|
||||
inherit: true,
|
||||
onCheckShow: undefined, // no inherit
|
||||
onCheckShow(pokemon) {},
|
||||
onSwitchOut(pokemon) {
|
||||
if (!pokemon.status || pokemon.status === 'fnt') return;
|
||||
|
||||
|
|
@ -306,9 +293,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
},
|
||||
},
|
||||
overgrow: {
|
||||
inherit: true,
|
||||
onModifyAtk: undefined, // no inherit
|
||||
onModifySpA: undefined, // no inherit
|
||||
onBasePowerPriority: 2,
|
||||
onBasePower(basePower, attacker, defender, move) {
|
||||
if (move.type === 'Grass' && attacker.hp <= attacker.maxhp / 3) {
|
||||
|
|
@ -316,23 +300,26 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
return this.chainModify(1.5);
|
||||
}
|
||||
},
|
||||
name: "Overgrow",
|
||||
rating: 2,
|
||||
num: 65,
|
||||
},
|
||||
pickup: {
|
||||
inherit: true,
|
||||
onResidual: undefined, // no inherit
|
||||
name: "Pickup",
|
||||
rating: 0,
|
||||
// No competitive use
|
||||
num: 53,
|
||||
},
|
||||
plus: {
|
||||
inherit: true,
|
||||
onModifySpAPriority: undefined, // no inherit
|
||||
onModifySpA(spa, pokemon) {
|
||||
for (const allyActive of pokemon.allies()) {
|
||||
if (allyActive.hasAbility('minus')) {
|
||||
return this.chainModify(1.5);
|
||||
for (const ally of pokemon.allies()) {
|
||||
if (ally.ability === 'minus') {
|
||||
return spa * 1.5;
|
||||
}
|
||||
}
|
||||
},
|
||||
name: "Plus",
|
||||
rating: 0,
|
||||
num: 57,
|
||||
},
|
||||
poisonpoint: {
|
||||
inherit: true,
|
||||
|
|
@ -345,12 +332,16 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
},
|
||||
},
|
||||
pressure: {
|
||||
inherit: true,
|
||||
onStart(pokemon) {
|
||||
this.add('-ability', pokemon, 'Pressure');
|
||||
},
|
||||
onDeductPP(target, source) {
|
||||
if (target === source) return;
|
||||
return 1;
|
||||
},
|
||||
name: "Pressure",
|
||||
rating: 1.5,
|
||||
num: 46,
|
||||
},
|
||||
roughskin: {
|
||||
inherit: true,
|
||||
|
|
@ -367,14 +358,14 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
if (typeof accuracy !== 'number') return;
|
||||
if (this.field.isWeather('sandstorm')) {
|
||||
this.debug('Sand Veil - decreasing accuracy');
|
||||
return this.chainModify(0.8);
|
||||
return accuracy * 0.8;
|
||||
}
|
||||
},
|
||||
},
|
||||
serenegrace: {
|
||||
inherit: true,
|
||||
onModifyMove(move) {
|
||||
if (move.secondaries && move.id !== 'chatter') {
|
||||
if (move.secondaries) {
|
||||
this.debug('doubling secondary chance');
|
||||
for (const secondary of move.secondaries) {
|
||||
if (secondary.chance) secondary.chance *= 2;
|
||||
|
|
@ -388,14 +379,16 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
onResidualSubOrder: 3,
|
||||
},
|
||||
simple: {
|
||||
inherit: true,
|
||||
onChangeBoost: undefined, // no inherit
|
||||
onModifyBoost(boosts) {
|
||||
let key: BoostID;
|
||||
for (key in boosts) {
|
||||
boosts[key]! *= 2;
|
||||
}
|
||||
},
|
||||
isBreakable: true,
|
||||
name: "Simple",
|
||||
rating: 4,
|
||||
num: 86,
|
||||
},
|
||||
snowcloak: {
|
||||
inherit: true,
|
||||
|
|
@ -404,7 +397,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
if (typeof accuracy !== 'number') return;
|
||||
if (this.field.isWeather('hail')) {
|
||||
this.debug('Snow Cloak - decreasing accuracy');
|
||||
return this.chainModify(0.8);
|
||||
return accuracy * 0.8;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
@ -424,10 +417,9 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
},
|
||||
},
|
||||
stench: {
|
||||
inherit: true,
|
||||
onModifyMove: undefined, // no inherit
|
||||
name: "Stench",
|
||||
rating: 0,
|
||||
// No competitive use
|
||||
num: 1,
|
||||
},
|
||||
stickyhold: {
|
||||
inherit: true,
|
||||
|
|
@ -440,18 +432,15 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
},
|
||||
stormdrain: {
|
||||
inherit: true,
|
||||
onTryHit: undefined, // no inherit
|
||||
onTryHit() {},
|
||||
rating: 0,
|
||||
},
|
||||
sturdy: {
|
||||
inherit: true,
|
||||
onDamage: undefined, // no inherit
|
||||
onDamage() {},
|
||||
rating: 0,
|
||||
},
|
||||
swarm: {
|
||||
inherit: true,
|
||||
onModifyAtk: undefined, // no inherit
|
||||
onModifySpA: undefined, // no inherit
|
||||
onBasePowerPriority: 2,
|
||||
onBasePower(basePower, attacker, defender, move) {
|
||||
if (move.type === 'Bug' && attacker.hp <= attacker.maxhp / 3) {
|
||||
|
|
@ -459,6 +448,9 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
return this.chainModify(1.5);
|
||||
}
|
||||
},
|
||||
name: "Swarm",
|
||||
rating: 2,
|
||||
num: 68,
|
||||
},
|
||||
synchronize: {
|
||||
inherit: true,
|
||||
|
|
@ -478,25 +470,23 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
if (typeof accuracy !== 'number') return;
|
||||
if (target?.volatiles['confusion']) {
|
||||
this.debug('Tangled Feet - decreasing accuracy');
|
||||
return this.chainModify(0.5);
|
||||
return accuracy * 0.5;
|
||||
}
|
||||
},
|
||||
},
|
||||
thickfat: {
|
||||
inherit: true,
|
||||
onSourceModifyAtk: undefined, // no inherit
|
||||
onSourceModifySpA: undefined, // no inherit
|
||||
onSourceBasePowerPriority: 1,
|
||||
onSourceBasePower(basePower, attacker, defender, move) {
|
||||
if (move.type === 'Ice' || move.type === 'Fire') {
|
||||
return this.chainModify(0.5);
|
||||
}
|
||||
},
|
||||
isBreakable: true,
|
||||
name: "Thick Fat",
|
||||
rating: 3.5,
|
||||
num: 47,
|
||||
},
|
||||
torrent: {
|
||||
inherit: true,
|
||||
onModifyAtk: undefined, // no inherit
|
||||
onModifySpA: undefined, // no inherit
|
||||
onBasePowerPriority: 2,
|
||||
onBasePower(basePower, attacker, defender, move) {
|
||||
if (move.type === 'Water' && attacker.hp <= attacker.maxhp / 3) {
|
||||
|
|
@ -504,11 +494,14 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
return this.chainModify(1.5);
|
||||
}
|
||||
},
|
||||
name: "Torrent",
|
||||
rating: 2,
|
||||
num: 67,
|
||||
},
|
||||
trace: {
|
||||
inherit: true,
|
||||
onUpdate(pokemon) {
|
||||
if (!this.effectState.seek) return;
|
||||
if (!pokemon.isStarted) return;
|
||||
const target = pokemon.side.randomFoe();
|
||||
if (!target || target.fainted) return;
|
||||
const ability = target.getAbility();
|
||||
|
|
@ -516,9 +509,20 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
if (bannedAbilities.includes(target.ability)) {
|
||||
return;
|
||||
}
|
||||
pokemon.setAbility(ability, target);
|
||||
if (pokemon.setAbility(ability)) {
|
||||
this.add('-ability', pokemon, ability, '[from] ability: Trace', '[of] ' + target);
|
||||
}
|
||||
},
|
||||
},
|
||||
unburden: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
onModifySpe(spe, pokemon) {
|
||||
if ((!pokemon.item || pokemon.itemState.knockedOff) && !pokemon.ignoringAbility()) {
|
||||
return this.chainModify(2);
|
||||
}
|
||||
},
|
||||
},
|
||||
flags: { notrace: 1 },
|
||||
},
|
||||
vitalspirit: {
|
||||
inherit: true,
|
||||
|
|
@ -528,19 +532,15 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
inherit: true,
|
||||
onTryHit(target, source, move) {
|
||||
if (move.id === 'firefang') {
|
||||
this.hint("In Gen 4, Fire Fang is always able to hit through Wonder Guard.", true, target.side);
|
||||
this.hint("In Gen 4, Fire Fang is always able to hit through Wonder Guard.");
|
||||
return;
|
||||
}
|
||||
if (target === source || move.category === 'Status' || move.type === '???') return;
|
||||
if (target === source || move.category === 'Status' || move.type === '???' || move.id === 'struggle') return;
|
||||
this.debug('Wonder Guard immunity: ' + move.id);
|
||||
if (target.runEffectiveness(move) <= 0 || !target.runImmunity(move)) {
|
||||
if (target.runEffectiveness(move) <= 0) {
|
||||
this.add('-immune', target, '[from] ability: Wonder Guard');
|
||||
return null;
|
||||
}
|
||||
},
|
||||
},
|
||||
rebound: {
|
||||
inherit: true,
|
||||
onTryHitSide: undefined, // no inherit
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDataTable = {
|
||||
export const Conditions: {[k: string]: ModdedConditionData} = {
|
||||
brn: {
|
||||
inherit: true,
|
||||
onResidualOrder: 10,
|
||||
|
|
@ -24,7 +24,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
effectType: 'Status',
|
||||
onStart(target, source, sourceEffect) {
|
||||
if (sourceEffect && sourceEffect.effectType === 'Move') {
|
||||
this.add('-status', target, 'slp', `[from] move: ${sourceEffect.name}`);
|
||||
this.add('-status', target, 'slp', '[from] move: ' + sourceEffect.name);
|
||||
} else {
|
||||
this.add('-status', target, 'slp');
|
||||
}
|
||||
|
|
@ -116,10 +116,6 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 9,
|
||||
},
|
||||
lockedmove: {
|
||||
inherit: true,
|
||||
onAfterMove: undefined, // no inherit
|
||||
},
|
||||
choicelock: {
|
||||
inherit: true,
|
||||
onStart(pokemon) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormatsDataTable = {
|
||||
export const FormatsData: {[k: string]: ModdedSpeciesFormatsData} = {
|
||||
bulbasaur: {
|
||||
tier: "LC",
|
||||
},
|
||||
|
|
@ -222,7 +222,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NU",
|
||||
},
|
||||
machamp: {
|
||||
tier: "Uber",
|
||||
tier: "OU",
|
||||
},
|
||||
bellsprout: {
|
||||
tier: "LC",
|
||||
|
|
@ -736,7 +736,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NU",
|
||||
},
|
||||
weavile: {
|
||||
tier: "(OU)",
|
||||
tier: "OU",
|
||||
},
|
||||
teddiursa: {
|
||||
tier: "LC",
|
||||
|
|
@ -1137,12 +1137,9 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
castform: {
|
||||
tier: "NU",
|
||||
},
|
||||
castformsunny: {
|
||||
},
|
||||
castformrainy: {
|
||||
},
|
||||
castformsnowy: {
|
||||
},
|
||||
castformsunny: {},
|
||||
castformrainy: {},
|
||||
castformsnowy: {},
|
||||
kecleon: {
|
||||
tier: "NU",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
||||
export const Items: {[k: string]: ModdedItemData} = {
|
||||
adamantorb: {
|
||||
inherit: true,
|
||||
onBasePower(basePower, user, target, move) {
|
||||
|
|
@ -32,24 +32,24 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
choiceband: {
|
||||
inherit: true,
|
||||
onStart: undefined, // no inherit
|
||||
onModifyMove: undefined, // no inherit
|
||||
onStart() {},
|
||||
onModifyMove() {},
|
||||
onAfterMove(pokemon) {
|
||||
pokemon.addVolatile('choicelock');
|
||||
},
|
||||
},
|
||||
choicescarf: {
|
||||
inherit: true,
|
||||
onStart: undefined, // no inherit
|
||||
onModifyMove: undefined, // no inherit
|
||||
onStart() {},
|
||||
onModifyMove() {},
|
||||
onAfterMove(pokemon) {
|
||||
pokemon.addVolatile('choicelock');
|
||||
},
|
||||
},
|
||||
choicespecs: {
|
||||
inherit: true,
|
||||
onStart: undefined, // no inherit
|
||||
onModifyMove: undefined, // no inherit
|
||||
onStart() {},
|
||||
onModifyMove() {},
|
||||
onAfterMove(pokemon) {
|
||||
pokemon.addVolatile('choicelock');
|
||||
},
|
||||
|
|
@ -72,7 +72,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
custapberry: {
|
||||
inherit: true,
|
||||
onFractionalPriority: undefined, // no inherit
|
||||
onFractionalPriority() {},
|
||||
onBeforeTurn(pokemon) {
|
||||
if (pokemon.hp <= pokemon.maxhp / 4 || (pokemon.hp <= pokemon.maxhp / 2 && pokemon.ability === 'gluttony')) {
|
||||
const action = this.queue.willMove(pokemon);
|
||||
|
|
@ -89,7 +89,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
onCustap(pokemon) {
|
||||
const action = this.queue.willMove(pokemon);
|
||||
this.debug(`custap action: ${action?.moveid}`);
|
||||
this.debug('custap action: ' + action);
|
||||
if (action && pokemon.eatItem()) {
|
||||
this.queue.cancelAction(pokemon);
|
||||
this.add('-message', "Custap Berry activated.");
|
||||
|
|
@ -113,38 +113,18 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
}
|
||||
},
|
||||
},
|
||||
dracoplate: {
|
||||
inherit: true,
|
||||
onTakeItem: true,
|
||||
},
|
||||
dreadplate: {
|
||||
inherit: true,
|
||||
onTakeItem: true,
|
||||
},
|
||||
earthplate: {
|
||||
inherit: true,
|
||||
onTakeItem: true,
|
||||
},
|
||||
fastball: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
},
|
||||
fistplate: {
|
||||
inherit: true,
|
||||
onTakeItem: true,
|
||||
},
|
||||
flameorb: {
|
||||
inherit: true,
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 20,
|
||||
},
|
||||
flameplate: {
|
||||
inherit: true,
|
||||
onTakeItem: true,
|
||||
},
|
||||
focussash: {
|
||||
inherit: true,
|
||||
onDamage: undefined, // no inherit
|
||||
onDamage() { },
|
||||
onTryHit(target, source, move) {
|
||||
if (target !== source && target.hp === target.maxhp) {
|
||||
target.addVolatile('focussash');
|
||||
|
|
@ -176,21 +156,9 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
inherit: true,
|
||||
isNonstandard: null,
|
||||
},
|
||||
icicleplate: {
|
||||
inherit: true,
|
||||
onTakeItem: true,
|
||||
},
|
||||
insectplate: {
|
||||
inherit: true,
|
||||
onTakeItem: true,
|
||||
},
|
||||
ironball: {
|
||||
inherit: true,
|
||||
onEffectiveness: undefined, // no inherit
|
||||
},
|
||||
ironplate: {
|
||||
inherit: true,
|
||||
onTakeItem: true,
|
||||
onEffectiveness() {},
|
||||
},
|
||||
kingsrock: {
|
||||
inherit: true,
|
||||
|
|
@ -227,8 +195,8 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
lifeorb: {
|
||||
inherit: true,
|
||||
onModifyDamage: undefined, // no inherit
|
||||
onAfterMoveSecondarySelf: undefined, // no inherit
|
||||
onModifyDamage() {},
|
||||
onAfterMoveSecondarySelf() {},
|
||||
onBasePower(basePower, user, target) {
|
||||
if (!target.volatiles['substitute']) {
|
||||
user.addVolatile('lifeorb');
|
||||
|
|
@ -241,7 +209,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
condition: {
|
||||
duration: 1,
|
||||
onAfterMoveSecondarySelf(source, target, move) {
|
||||
if (move && move.effectType === 'Move' && source?.volatiles['lifeorb']) {
|
||||
if (move && move.effectType === 'Move' && source && source.volatiles['lifeorb']) {
|
||||
this.damage(source.baseMaxhp / 10, source, source, this.dex.items.get('lifeorb'));
|
||||
source.removeVolatile('lifeorb');
|
||||
}
|
||||
|
|
@ -250,8 +218,8 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
lightball: {
|
||||
inherit: true,
|
||||
onModifyAtk: undefined, // no inherit
|
||||
onModifySpA: undefined, // no inherit
|
||||
onModifyAtk() {},
|
||||
onModifySpA() {},
|
||||
onBasePower(basePower, pokemon) {
|
||||
if (pokemon.species.name === 'Pikachu') {
|
||||
return this.chainModify(2);
|
||||
|
|
@ -282,10 +250,6 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
}
|
||||
},
|
||||
},
|
||||
meadowplate: {
|
||||
inherit: true,
|
||||
onTakeItem: true,
|
||||
},
|
||||
mentalherb: {
|
||||
inherit: true,
|
||||
fling: {
|
||||
|
|
@ -306,7 +270,11 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
metronome: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
onStart(pokemon) {
|
||||
this.effectState.numConsecutive = 0;
|
||||
this.effectState.lastMove = '';
|
||||
},
|
||||
onTryMovePriority: -2,
|
||||
onTryMove(pokemon, target, move) {
|
||||
if (!pokemon.hasItem('metronome')) {
|
||||
pokemon.removeVolatile('metronome');
|
||||
|
|
@ -319,7 +287,6 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
}
|
||||
this.effectState.lastMove = move.id;
|
||||
},
|
||||
onModifyDamage: undefined, // no inherit
|
||||
onModifyDamagePhase2(damage, source, target, move) {
|
||||
return damage * (1 + (this.effectState.numConsecutive / 10));
|
||||
},
|
||||
|
|
@ -328,7 +295,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
micleberry: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
duration: 2,
|
||||
onSourceModifyAccuracyPriority: 3,
|
||||
onSourceModifyAccuracy(accuracy, target, source) {
|
||||
this.add('-enditem', source, 'Micle Berry');
|
||||
|
|
@ -339,10 +306,6 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
},
|
||||
},
|
||||
mindplate: {
|
||||
inherit: true,
|
||||
onTakeItem: true,
|
||||
},
|
||||
moonball: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
|
|
@ -362,18 +325,6 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
}
|
||||
},
|
||||
},
|
||||
skyplate: {
|
||||
inherit: true,
|
||||
onTakeItem: true,
|
||||
},
|
||||
splashplate: {
|
||||
inherit: true,
|
||||
onTakeItem: true,
|
||||
},
|
||||
spookyplate: {
|
||||
inherit: true,
|
||||
onTakeItem: true,
|
||||
},
|
||||
sportball: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
|
|
@ -391,10 +342,6 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 20,
|
||||
},
|
||||
stoneplate: {
|
||||
inherit: true,
|
||||
onTakeItem: true,
|
||||
},
|
||||
thickclub: {
|
||||
inherit: true,
|
||||
onModifyAtk(atk, pokemon) {
|
||||
|
|
@ -408,10 +355,6 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 20,
|
||||
},
|
||||
toxicplate: {
|
||||
inherit: true,
|
||||
onTakeItem: true,
|
||||
},
|
||||
widelens: {
|
||||
inherit: true,
|
||||
onSourceModifyAccuracyPriority: 4,
|
||||
|
|
@ -421,10 +364,6 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
}
|
||||
},
|
||||
},
|
||||
zapplate: {
|
||||
inherit: true,
|
||||
onTakeItem: true,
|
||||
},
|
||||
zoomlens: {
|
||||
inherit: true,
|
||||
onSourceModifyAccuracyPriority: 4,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,4 +1,4 @@
|
|||
export const Pokedex: import('../../../sim/dex-species').ModdedSpeciesDataTable = {
|
||||
export const Pokedex: {[k: string]: ModdedSpeciesData} = {
|
||||
milotic: {
|
||||
inherit: true,
|
||||
evoType: 'levelExtra',
|
||||
|
|
|
|||
1190
data/mods/gen4/random-data.json
Normal file
1190
data/mods/gen4/random-data.json
Normal file
File diff suppressed because it is too large
Load Diff
873
data/mods/gen4/random-teams.ts
Normal file
873
data/mods/gen4/random-teams.ts
Normal file
|
|
@ -0,0 +1,873 @@
|
|||
import RandomGen5Teams from '../gen5/random-teams';
|
||||
import {Utils} from '../../../lib';
|
||||
import {toID} from '../../../sim/dex';
|
||||
import {PRNG} from '../../../sim';
|
||||
import type {MoveCounter, OldRandomBattleSpecies} from '../gen8/random-teams';
|
||||
|
||||
|
||||
// These moves can be used even if we aren't setting up to use them:
|
||||
const SetupException = ['dracometeor', 'overheat'];
|
||||
|
||||
// Give recovery moves priority over certain other defensive status moves
|
||||
const recoveryMoves = [
|
||||
'healorder', 'milkdrink', 'moonlight', 'morningsun', 'painsplit', 'recover', 'rest', 'roost',
|
||||
'slackoff', 'softboiled', 'synthesis', 'wish',
|
||||
];
|
||||
const defensiveStatusMoves = ['aromatherapy', 'haze', 'healbell', 'roar', 'whirlwind', 'willowisp', 'yawn'];
|
||||
export class RandomGen4Teams extends RandomGen5Teams {
|
||||
randomData: {[species: string]: OldRandomBattleSpecies} = require('./random-data.json');
|
||||
|
||||
constructor(format: string | Format, prng: PRNG | PRNGSeed | null) {
|
||||
super(format, prng);
|
||||
this.moveEnforcementCheckers = {
|
||||
Bug: (movePool, moves, abilities, types, counter) => (
|
||||
(movePool.includes('bugbuzz') || movePool.includes('megahorn'))
|
||||
),
|
||||
Dark: (movePool, moves, abilities, types, counter) => (
|
||||
!counter.get('damage') &&
|
||||
(!counter.get('Dark') || (counter.get('Dark') < 2 && moves.has('pursuit') && movePool.includes('suckerpunch')))),
|
||||
Dragon: (movePool, moves, abilities, types, counter) => !counter.get('Dragon'),
|
||||
Electric: (movePool, moves, abilities, types, counter) => !counter.get('Electric'),
|
||||
Fighting: (movePool, moves, abilities, types, counter) => (
|
||||
!counter.get('Fighting') &&
|
||||
(!!counter.setupType || !counter.get('Status') || movePool.includes('closecombat') || movePool.includes('highjumpkick'))
|
||||
),
|
||||
Fire: (movePool, moves, abilities, types, counter) => !counter.get('Fire'),
|
||||
Flying: (movePool, moves, abilities, types, counter) => !counter.get('Flying') && (
|
||||
(counter.setupType !== 'Special' && movePool.includes('bravebird')) ||
|
||||
(abilities.has('Serene Grace') && movePool.includes('airslash'))
|
||||
),
|
||||
Grass: (movePool, moves, abilities, types, counter) => (
|
||||
!counter.get('Grass') &&
|
||||
['leafblade', 'leafstorm', 'seedflare', 'woodhammer'].some(m => movePool.includes(m))
|
||||
),
|
||||
Ground: (movePool, moves, abilities, types, counter) => !counter.get('Ground'),
|
||||
Ice: (movePool, moves, abilities, types, counter) => (
|
||||
!counter.get('Ice') && (!types.has('Water') || !counter.get('Water'))
|
||||
),
|
||||
Rock: (movePool, moves, abilities, types, counter) => (
|
||||
!counter.get('Rock') && (movePool.includes('headsmash') || movePool.includes('stoneedge'))
|
||||
),
|
||||
Steel: (movePool, moves, abilities, types, counter) => !counter.get('Steel') && movePool.includes('meteormash'),
|
||||
Water: (movePool, moves, abilities, types, counter) => (
|
||||
!counter.get('Water') && (moves.has('raindance') || !types.has('Ice') || !counter.get('Ice'))
|
||||
),
|
||||
Adaptability: (movePool, moves, abilities, types, counter, species) => (
|
||||
!counter.setupType &&
|
||||
species.types.length > 1 &&
|
||||
(!counter.get(species.types[0]) || !counter.get(species.types[1]))
|
||||
),
|
||||
Guts: (movePool, moves, abilities, types) => types.has('Normal') && movePool.includes('facade'),
|
||||
'Slow Start': movePool => movePool.includes('substitute'),
|
||||
protect: movePool => movePool.includes('wish'),
|
||||
wish: movePool => movePool.includes('protect'),
|
||||
};
|
||||
}
|
||||
shouldCullMove(
|
||||
move: Move,
|
||||
types: Set<string>,
|
||||
moves: Set<string>,
|
||||
abilities: Set<string>,
|
||||
counter: MoveCounter,
|
||||
movePool: string[],
|
||||
teamDetails: RandomTeamsTypes.TeamDetails,
|
||||
species: Species,
|
||||
isLead: boolean,
|
||||
): {cull: boolean, isSetup?: boolean} {
|
||||
const restTalk = moves.has('rest') && moves.has('sleeptalk');
|
||||
|
||||
switch (move.id) {
|
||||
// Not very useful without their supporting moves
|
||||
case 'batonpass':
|
||||
return {cull: !counter.setupType && !counter.get('speedsetup') && !moves.has('substitute')};
|
||||
case 'eruption': case 'waterspout':
|
||||
return {cull: counter.get('Physical') + counter.get('Special') < 4};
|
||||
case 'focuspunch':
|
||||
return {cull: !moves.has('substitute') || counter.damagingMoves.size < 2 || moves.has('hammerarm')};
|
||||
case 'lightscreen':
|
||||
if (movePool.length > 1) {
|
||||
const screen = movePool.indexOf('reflect');
|
||||
if (screen >= 0) {
|
||||
this.fastPop(movePool, screen);
|
||||
return {cull: true};
|
||||
}
|
||||
}
|
||||
return {cull: false};
|
||||
case 'raindance':
|
||||
return {cull: abilities.has('Hydration') ? !moves.has('rest') : counter.get('Physical') + counter.get('Special') < 2};
|
||||
case 'reflect':
|
||||
if (movePool.length > 1) {
|
||||
const screen = movePool.indexOf('lightscreen');
|
||||
if (screen >= 0) {
|
||||
this.fastPop(movePool, screen);
|
||||
return {cull: true};
|
||||
}
|
||||
}
|
||||
return {cull: false};
|
||||
case 'refresh':
|
||||
return {cull: !(moves.has('calmmind') && (moves.has('recover') || moves.has('roost')))};
|
||||
case 'rest':
|
||||
return {cull: movePool.includes('sleeptalk') || (abilities.has('Hydration') && !moves.has('raindance')) ||
|
||||
moves.has('reflect') && moves.has('lightscreen')};
|
||||
case 'sleeptalk':
|
||||
if (movePool.length > 1) {
|
||||
const rest = movePool.indexOf('rest');
|
||||
if (rest >= 0) this.fastPop(movePool, rest);
|
||||
}
|
||||
return {cull: !moves.has('rest')};
|
||||
case 'sunnyday':
|
||||
return {cull: !moves.has('solarbeam')};
|
||||
case 'weatherball':
|
||||
return {cull: !moves.has('raindance') && !moves.has('sunnyday')};
|
||||
|
||||
// Set up once and only if we have the moves for it
|
||||
case 'bellydrum': case 'bulkup': case 'curse': case 'dragondance': case 'swordsdance':
|
||||
const notEnoughPhysicalMoves = (
|
||||
counter.get('Physical') + counter.get('physicalpool') < 2 &&
|
||||
!moves.has('batonpass') &&
|
||||
(!moves.has('rest') || !moves.has('sleeptalk'))
|
||||
);
|
||||
const badPhysicalMoveset = counter.setupType !== 'Physical' || counter.get('physicalsetup') > 1;
|
||||
return {cull: moves.has('sunnyday') || notEnoughPhysicalMoves || badPhysicalMoveset, isSetup: true};
|
||||
case 'calmmind': case 'nastyplot': case 'tailglow':
|
||||
const notEnoughSpecialMoves = (
|
||||
counter.get('Special') + counter.get('specialpool') < 2 &&
|
||||
!moves.has('batonpass') &&
|
||||
(!moves.has('rest') || !moves.has('sleeptalk'))
|
||||
);
|
||||
const badSpecialMoveset = counter.setupType !== 'Special' || counter.get('specialsetup') > 1;
|
||||
return {cull: notEnoughSpecialMoves || badSpecialMoveset, isSetup: true};
|
||||
case 'agility': case 'rockpolish':
|
||||
return {cull: restTalk || (counter.damagingMoves.size < 2 && !moves.has('batonpass')), isSetup: !counter.setupType};
|
||||
|
||||
// Bad after setup
|
||||
case 'destinybond':
|
||||
return {cull: !!counter.setupType || moves.has('explosion')};
|
||||
case 'explosion': case 'selfdestruct':
|
||||
return {cull: (
|
||||
counter.setupType === 'Special' ||
|
||||
Array.from(moves).some(id => recoveryMoves.includes(id) || defensiveStatusMoves.includes(id)) ||
|
||||
['batonpass', 'protect', 'substitute'].some(m => moves.has(m))
|
||||
)};
|
||||
case 'foresight': case 'roar': case 'whirlwind':
|
||||
return {cull: !!counter.setupType && !abilities.has('Speed Boost')};
|
||||
case 'healingwish': case 'lunardance':
|
||||
return {cull: !!counter.setupType || moves.has('rest') || moves.has('substitute')};
|
||||
case 'protect':
|
||||
return {cull: (
|
||||
['rest', 'softboiled'].some(m => moves.has(m)) ||
|
||||
!['Guts', 'Quick Feet', 'Speed Boost'].some(abil => abilities.has(abil)) &&
|
||||
!['toxic', 'wish'].some(m => moves.has(m))
|
||||
)};
|
||||
case 'wish':
|
||||
return {cull: (
|
||||
!['batonpass', 'ironhead', 'moonlight', 'protect', 'softboiled', 'uturn'].some(m => moves.has(m)) &&
|
||||
!movePool.includes('protect')
|
||||
)};
|
||||
case 'moonlight':
|
||||
return {cull: (moves.has('wish') && (moves.has('protect') || movePool.includes('protect')))};
|
||||
case 'rapidspin':
|
||||
return {cull: !!teamDetails.rapidSpin || (!!counter.setupType && counter.get('Physical') + counter.get('Special') < 2)};
|
||||
case 'fakeout':
|
||||
return {cull: !!counter.setupType || !!counter.get('speedsetup') || moves.has('substitute')};
|
||||
case 'spikes':
|
||||
return {cull: !!counter.setupType || !!counter.get('speedsetup') || moves.has('substitute')};
|
||||
case 'stealthrock':
|
||||
return {cull: (
|
||||
!!counter.setupType ||
|
||||
!!counter.get('speedsetup') ||
|
||||
moves.has('rest') || moves.has('substitute') ||
|
||||
!!teamDetails.stealthRock
|
||||
)};
|
||||
case 'switcheroo': case 'trick':
|
||||
return {cull: (
|
||||
counter.get('Physical') + counter.get('Special') < 3 ||
|
||||
!!counter.setupType ||
|
||||
['fakeout', 'lightscreen', 'reflect', 'suckerpunch', 'trickroom'].some(m => moves.has(m))
|
||||
)};
|
||||
case 'toxic': case 'toxicspikes':
|
||||
return {cull: (
|
||||
!!counter.setupType || !!counter.get('speedsetup') || !!teamDetails.toxicSpikes || moves.has('willowisp')
|
||||
)};
|
||||
case 'trickroom':
|
||||
return {cull: (
|
||||
!!counter.setupType ||
|
||||
!!counter.get('speedsetup') ||
|
||||
counter.damagingMoves.size < 2 ||
|
||||
moves.has('lightscreen') || moves.has('reflect') ||
|
||||
restTalk
|
||||
)};
|
||||
case 'uturn':
|
||||
return {cull: (
|
||||
(abilities.has('Speed Boost') && moves.has('protect')) ||
|
||||
!!counter.setupType ||
|
||||
!!counter.get('speedsetup') ||
|
||||
moves.has('batonpass') || moves.has('substitute')
|
||||
)};
|
||||
|
||||
// Bit redundant to have both
|
||||
// Attacks:
|
||||
case 'bodyslam': case 'slash':
|
||||
return {cull: moves.has('facade') || moves.has('return')};
|
||||
case 'bugbite':
|
||||
return {cull: moves.has('uturn')};
|
||||
case 'doubleedge':
|
||||
return {cull: ['bodyslam', 'facade', 'return'].some(m => moves.has(m))};
|
||||
case 'endeavor':
|
||||
return {cull: !isLead};
|
||||
case 'facade':
|
||||
return {cull: moves.has('substitute')};
|
||||
case 'headbutt':
|
||||
return {cull: !moves.has('bodyslam') && !moves.has('thunderwave')};
|
||||
case 'swift':
|
||||
return {cull: counter.setupType !== 'Special'};
|
||||
case 'quickattack':
|
||||
return {cull: moves.has('thunderwave')};
|
||||
case 'firepunch': case 'flamethrower':
|
||||
return {cull: moves.has('fireblast') || moves.has('overheat') && !counter.setupType};
|
||||
case 'flareblitz':
|
||||
return {cull: moves.has('superpower') && !!counter.get('speedsetup')};
|
||||
case 'lavaplume': case 'fireblast':
|
||||
if (move.id === 'fireblast' && moves.has('lavaplume') && !counter.get('speedsetup')) return {cull: true};
|
||||
if (move.id === 'lavaplume' && moves.has('fireblast') && counter.get('speedsetup')) return {cull: true};
|
||||
if (moves.has('flareblitz') && counter.setupType !== 'Special' &&
|
||||
(!moves.has('superpower') || !counter.get('speedsetup'))) return {cull: true};
|
||||
break;
|
||||
case 'overheat':
|
||||
return {cull: counter.setupType === 'Special' || ['batonpass', 'fireblast', 'flareblitz'].some(m => moves.has(m))};
|
||||
case 'aquajet':
|
||||
return {cull: moves.has('dragondance') || (moves.has('waterfall') && counter.get('Physical') < 3)};
|
||||
case 'hydropump':
|
||||
return {cull: moves.has('surf')};
|
||||
case 'waterfall':
|
||||
return {cull: (
|
||||
moves.has('aquatail') ||
|
||||
(counter.setupType !== 'Physical' && (moves.has('hydropump') || moves.has('surf')))
|
||||
)};
|
||||
case 'chargebeam':
|
||||
return {cull: moves.has('thunderbolt') && counter.get('Special') < 3};
|
||||
case 'discharge':
|
||||
return {cull: moves.has('thunderbolt') || moves.has('shadowball')};
|
||||
case 'energyball':
|
||||
return {cull: (
|
||||
moves.has('woodhammer') ||
|
||||
(moves.has('sunnyday') && moves.has('solarbeam')) ||
|
||||
(moves.has('leafstorm') && counter.get('Physical') + counter.get('Special') < 4)
|
||||
)};
|
||||
case 'grassknot': case 'leafblade': case 'seedbomb':
|
||||
return {cull: moves.has('woodhammer') || (moves.has('sunnyday') && moves.has('solarbeam'))};
|
||||
case 'leafstorm':
|
||||
return {cull: (
|
||||
!!counter.setupType ||
|
||||
moves.has('batonpass') ||
|
||||
moves.has('powerwhip') ||
|
||||
moves.has('leafblade') ||
|
||||
(moves.has('sunnyday') && moves.has('solarbeam'))
|
||||
)};
|
||||
case 'solarbeam':
|
||||
return {cull: counter.setupType === 'Physical' || !moves.has('sunnyday')};
|
||||
case 'icepunch':
|
||||
return {cull: !counter.setupType && moves.has('icebeam')};
|
||||
case 'aurasphere': case 'drainpunch': case 'focusblast':
|
||||
return {cull: moves.has('closecombat') && counter.setupType !== 'Special'};
|
||||
case 'brickbreak': case 'closecombat': case 'crosschop': case 'lowkick':
|
||||
return {cull: moves.has('substitute') && moves.has('focuspunch')};
|
||||
case 'machpunch':
|
||||
return {cull: (counter.damagingMoves.size <= counter.get('Fighting'))};
|
||||
case 'seismictoss':
|
||||
return {cull: moves.has('nightshade') || counter.get('Physical') + counter.get('Special') >= 1};
|
||||
case 'superpower':
|
||||
return {cull: moves.has('dragondance') || !!counter.get('speedsetup') && !types.has('Fighting')};
|
||||
case 'gunkshot':
|
||||
return {cull: moves.has('poisonjab')};
|
||||
case 'earthpower':
|
||||
return {cull: moves.has('earthquake')};
|
||||
case 'airslash':
|
||||
return {cull: !counter.setupType && moves.has('bravebird')};
|
||||
case 'zenheadbutt':
|
||||
return {cull: moves.has('psychocut')};
|
||||
case 'rockblast': case 'rockslide':
|
||||
return {cull: moves.has('stoneedge')};
|
||||
case 'shadowclaw': case 'shadowsneak':
|
||||
return {cull: moves.has('suckerpunch') && !types.has('Ghost')};
|
||||
case 'dracometeor':
|
||||
return {cull: moves.has('calmmind') || restTalk || (!!counter.setupType && counter.get('stab') < 2)};
|
||||
case 'dragonclaw':
|
||||
return {cull: moves.has('outrage')};
|
||||
case 'dragonpulse':
|
||||
return {cull: moves.has('dracometeor') || moves.has('outrage')};
|
||||
case 'crunch': case 'nightslash':
|
||||
return {cull: moves.has('suckerpunch') && !types.has('Dark')};
|
||||
case 'pursuit':
|
||||
return {cull: !!counter.setupType || moves.has('payback')};
|
||||
case 'flashcannon':
|
||||
return {cull: (moves.has('ironhead') || movePool.includes('ironhead')) && counter.setupType !== 'Special'};
|
||||
|
||||
// Status:
|
||||
case 'encore':
|
||||
return {cull: ['roar', 'taunt', 'whirlwind'].some(m => moves.has(m)) || restTalk};
|
||||
case 'haze': case 'taunt':
|
||||
return {cull: restTalk};
|
||||
case 'healbell':
|
||||
// Ampharos doesn't want both
|
||||
return {cull: moves.has('reflect') && moves.has('lightscreen')};
|
||||
case 'leechseed': case 'painsplit':
|
||||
return {cull: !!counter.setupType || !!counter.get('speedsetup') || moves.has('rest')};
|
||||
case 'recover': case 'slackoff':
|
||||
return {cull: restTalk};
|
||||
case 'stunspore':
|
||||
return {cull: (
|
||||
!!counter.setupType ||
|
||||
moves.has('toxic') ||
|
||||
movePool.includes('sleeppowder') ||
|
||||
movePool.includes('spore')
|
||||
)};
|
||||
case 'substitute':
|
||||
return {cull: ['lightscreen', 'pursuit', 'rapidspin', 'reflect', 'rest', 'taunt'].some(m => moves.has(m))};
|
||||
case 'thunderwave':
|
||||
return {cull: (
|
||||
!!counter.setupType ||
|
||||
moves.has('toxic') ||
|
||||
moves.has('trickroom') ||
|
||||
(moves.has('bodyslam') && abilities.has('Serene Grace'))
|
||||
)};
|
||||
case 'yawn':
|
||||
return {cull: moves.has('thunderwave') || moves.has('toxic')};
|
||||
}
|
||||
return {cull: false};
|
||||
}
|
||||
|
||||
shouldCullAbility(
|
||||
ability: string,
|
||||
types: Set<string>,
|
||||
moves: Set<string>,
|
||||
abilities: Set<string>,
|
||||
counter: MoveCounter,
|
||||
movePool: string[],
|
||||
teamDetails: RandomTeamsTypes.TeamDetails,
|
||||
species: Species,
|
||||
) {
|
||||
switch (ability) {
|
||||
case 'Anger Point': case 'Ice Body': case 'Steadfast': case 'Unaware':
|
||||
return true;
|
||||
case 'Blaze':
|
||||
return !counter.get('Fire');
|
||||
case 'Chlorophyll':
|
||||
return !moves.has('sunnyday') && !teamDetails.sun;
|
||||
case 'Compound Eyes': case 'No Guard':
|
||||
return !counter.get('inaccurate');
|
||||
case 'Early Bird':
|
||||
return !moves.has('rest');
|
||||
case 'Gluttony':
|
||||
return !moves.has('bellydrum');
|
||||
case 'Hustle':
|
||||
return counter.get('Physical') < 2;
|
||||
case 'Mold Breaker':
|
||||
return !moves.has('earthquake');
|
||||
case 'Overgrow':
|
||||
return !counter.get('Grass');
|
||||
case 'Reckless': case 'Rock Head':
|
||||
return !counter.get('recoil');
|
||||
case 'Sand Veil':
|
||||
return !teamDetails.sand;
|
||||
case 'Serene Grace':
|
||||
return !counter.get('serenegrace') || species.id === 'blissey';
|
||||
case 'Simple':
|
||||
return !counter.setupType && !moves.has('cosmicpower');
|
||||
case 'Skill Link':
|
||||
return !counter.get('skilllink');
|
||||
case 'Snow Cloak':
|
||||
return !teamDetails.hail;
|
||||
case 'Solar Power':
|
||||
return !counter.get('Special') || !moves.has('sunnyday') && !teamDetails.sun;
|
||||
case 'Speed Boost':
|
||||
return moves.has('uturn');
|
||||
case 'Swift Swim':
|
||||
return !moves.has('raindance') && !teamDetails.rain;
|
||||
case 'Swarm':
|
||||
return !counter.get('Bug');
|
||||
case 'Synchronize':
|
||||
return counter.get('Status') < 2;
|
||||
case 'Technician':
|
||||
return !counter.get('technician') || moves.has('toxic');
|
||||
case 'Thick Fat':
|
||||
return (moves.has('facade') || moves.has('fakeout')) && abilities.has('Guts');
|
||||
case 'Tinted Lens':
|
||||
return moves.has('protect');
|
||||
case 'Torrent':
|
||||
return !counter.get('Water');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
getHighPriorityItem(
|
||||
ability: string,
|
||||
types: Set<string>,
|
||||
moves: Set<string>,
|
||||
counter: MoveCounter,
|
||||
teamDetails: RandomTeamsTypes.TeamDetails,
|
||||
species: Species,
|
||||
isLead: boolean,
|
||||
): string | undefined {
|
||||
if (species.requiredItem) return species.requiredItem;
|
||||
if (species.requiredItems) return this.sample(species.requiredItems);
|
||||
if (species.name === 'Ditto') return this.sample(['Salac Berry', 'Sitrus Berry']);
|
||||
if (species.name === 'Farfetch\u2019d' && counter.get('Physical') < 4) return 'Stick';
|
||||
if (species.name === 'Marowak') return 'Thick Club';
|
||||
if (species.name === 'Pikachu') return 'Light Ball';
|
||||
if (species.name === 'Shedinja' || species.name === 'Smeargle') return 'Focus Sash';
|
||||
if (species.name === 'Unown') return 'Choice Specs';
|
||||
if (species.name === 'Wobbuffet') {
|
||||
return moves.has('destinybond') ? 'Custap Berry' : this.sample(['Leftovers', 'Sitrus Berry']);
|
||||
}
|
||||
|
||||
if (moves.has('switcheroo') || moves.has('trick')) {
|
||||
if (
|
||||
species.baseStats.spe >= 60 && species.baseStats.spe <= 108 &&
|
||||
!counter.get('priority') &&
|
||||
this.randomChance(2, 3)
|
||||
) {
|
||||
return 'Choice Scarf';
|
||||
} else {
|
||||
return (counter.get('Physical') > counter.get('Special')) ? 'Choice Band' : 'Choice Specs';
|
||||
}
|
||||
}
|
||||
if (moves.has('bellydrum')) return 'Sitrus Berry';
|
||||
if (ability === 'Magic Guard' || ability === 'Speed Boost' && counter.get('Status') < 2) return 'Life Orb';
|
||||
if (ability === 'Poison Heal' || ability === 'Toxic Boost') return 'Toxic Orb';
|
||||
|
||||
if (moves.has('rest') && !moves.has('sleeptalk') && ability !== 'Natural Cure' && ability !== 'Shed Skin') {
|
||||
return (moves.has('raindance') && ability === 'Hydration') ? 'Damp Rock' : 'Chesto Berry';
|
||||
}
|
||||
if (moves.has('raindance') && ability === 'Swift Swim' && counter.get('Status') < 2) return 'Life Orb';
|
||||
if (moves.has('sunnyday')) return (ability === 'Chlorophyll' && counter.get('Status') < 2) ? 'Life Orb' : 'Heat Rock';
|
||||
if (moves.has('lightscreen') && moves.has('reflect')) return 'Light Clay';
|
||||
if ((ability === 'Guts' || ability === 'Quick Feet') && moves.has('facade')) return 'Toxic Orb';
|
||||
if (ability === 'Unburden') return 'Sitrus Berry';
|
||||
if (species.baseStats.hp + species.baseStats.def + species.baseStats.spd <= 150) {
|
||||
return isLead ? 'Focus Sash' : 'Life Orb';
|
||||
}
|
||||
if (moves.has('endeavor')) return 'Focus Sash';
|
||||
}
|
||||
|
||||
getMediumPriorityItem(
|
||||
ability: string,
|
||||
moves: Set<string>,
|
||||
counter: MoveCounter,
|
||||
species: Species,
|
||||
isDoubles: boolean,
|
||||
isLead: boolean
|
||||
): string | undefined {
|
||||
if (
|
||||
ability === 'Slow Start' ||
|
||||
['curse', 'leechseed', 'protect', 'roar', 'sleeptalk', 'whirlwind'].some(m => moves.has(m)) ||
|
||||
(ability === 'Serene Grace' && ['bodyslam', 'headbutt', 'ironhead'].some(m => moves.has(m)))
|
||||
) {
|
||||
return 'Leftovers';
|
||||
}
|
||||
|
||||
if (counter.get('Physical') >= 4 && !moves.has('fakeout') && !moves.has('rapidspin') && !moves.has('suckerpunch')) {
|
||||
return (
|
||||
species.baseStats.spe >= 60 && species.baseStats.spe <= 108 &&
|
||||
!counter.get('priority') && !moves.has('bodyslam') && this.randomChance(2, 3)
|
||||
) ? 'Choice Scarf' : 'Choice Band';
|
||||
}
|
||||
|
||||
if (
|
||||
(counter.get('Special') >= 4 || (
|
||||
counter.get('Special') >= 3 &&
|
||||
['batonpass', 'uturn', 'waterspout', 'selfdestruct'].some(m => moves.has(m))
|
||||
)) &&
|
||||
!moves.has('chargebeam')
|
||||
) {
|
||||
return (
|
||||
species.baseStats.spe >= 60 && species.baseStats.spe <= 108 &&
|
||||
ability !== 'Speed Boost' && !counter.get('priority') && this.randomChance(2, 3)
|
||||
) ? 'Choice Scarf' : 'Choice Specs';
|
||||
}
|
||||
|
||||
if (moves.has('outrage') && counter.setupType) return 'Lum Berry';
|
||||
if (moves.has('substitute')) {
|
||||
return (counter.damagingMoves.size < 2 ||
|
||||
!counter.get('drain') &&
|
||||
(counter.damagingMoves.size < 3 || species.baseStats.hp >= 60 || species.baseStats.def + species.baseStats.spd >= 180)
|
||||
) ? 'Leftovers' : 'Life Orb';
|
||||
}
|
||||
if (ability === 'Guts') return 'Toxic Orb';
|
||||
if (
|
||||
isLead &&
|
||||
!counter.get('recoil') &&
|
||||
!Array.from(moves).some(id => !!recoveryMoves.includes(id)) &&
|
||||
species.baseStats.hp + species.baseStats.def + species.baseStats.spd < 225
|
||||
) {
|
||||
return 'Focus Sash';
|
||||
}
|
||||
if (counter.get('Dark') >= 3) return 'Black Glasses';
|
||||
if (counter.damagingMoves.size >= 4) {
|
||||
return (
|
||||
counter.get('Normal') || counter.get('Dragon') > 1 || moves.has('chargebeam') || moves.has('suckerpunch')
|
||||
) ? 'Life Orb' : 'Expert Belt';
|
||||
}
|
||||
if (counter.damagingMoves.size >= 3 && !moves.has('superfang') && !moves.has('metalburst')) {
|
||||
const totalBulk = species.baseStats.hp + species.baseStats.def + species.baseStats.spd;
|
||||
return (
|
||||
counter.get('speedsetup') || counter.get('priority') ||
|
||||
moves.has('dragondance') || moves.has('trickroom') ||
|
||||
totalBulk < 235 ||
|
||||
(species.baseStats.spe >= 70 && (totalBulk < 260 || (!!counter.get('recovery') && totalBulk < 285)))
|
||||
) ? 'Life Orb' : 'Leftovers';
|
||||
}
|
||||
}
|
||||
|
||||
getLowPriorityItem(
|
||||
ability: string,
|
||||
types: Set<string>,
|
||||
moves: Set<string>,
|
||||
abilities: Set<string>,
|
||||
counter: MoveCounter,
|
||||
teamDetails: RandomTeamsTypes.TeamDetails,
|
||||
species: Species,
|
||||
) {
|
||||
if (types.has('Poison')) return 'Black Sludge';
|
||||
if (this.dex.getEffectiveness('Rock', species) >= 1 || moves.has('roar')) return 'Leftovers';
|
||||
if (counter.get('Status') <= 1 && ['metalburst', 'rapidspin', 'superfang'].every(m => !moves.has(m))) return 'Life Orb';
|
||||
return 'Leftovers';
|
||||
}
|
||||
|
||||
randomSet(
|
||||
species: string | Species,
|
||||
teamDetails: RandomTeamsTypes.TeamDetails = {},
|
||||
isLead = false
|
||||
): RandomTeamsTypes.RandomSet {
|
||||
species = this.dex.species.get(species);
|
||||
let forme = species.name;
|
||||
|
||||
if (typeof species.battleOnly === 'string') forme = species.battleOnly;
|
||||
|
||||
if (species.cosmeticFormes) {
|
||||
forme = this.sample([species.name].concat(species.cosmeticFormes));
|
||||
}
|
||||
|
||||
const data = this.randomData[species.id];
|
||||
const movePool = (data.moves || Object.keys(this.dex.species.getLearnset(species.id)!)).slice();
|
||||
const rejectedPool: string[] = [];
|
||||
const moves = new Set<string>();
|
||||
let ability = '';
|
||||
let item: string | undefined;
|
||||
const evs = {hp: 85, atk: 85, def: 85, spa: 85, spd: 85, spe: 85};
|
||||
const ivs: SparseStatsTable = {hp: 31, atk: 31, def: 31, spa: 31, spd: 31, spe: 31};
|
||||
|
||||
const types = new Set(species.types);
|
||||
|
||||
const abilities = new Set(Object.values(species.abilities));
|
||||
|
||||
let availableHP = 0;
|
||||
for (const setMoveid of movePool) {
|
||||
if (setMoveid.startsWith('hiddenpower')) availableHP++;
|
||||
}
|
||||
|
||||
let counter: MoveCounter;
|
||||
let hasHiddenPower = false;
|
||||
|
||||
do {
|
||||
// Choose next 4 moves from learnset/viable moves and add them to moves list:
|
||||
while (moves.size < this.maxMoveCount && movePool.length) {
|
||||
const moveid = this.sampleNoReplace(movePool);
|
||||
if (moveid.startsWith('hiddenpower')) {
|
||||
availableHP--;
|
||||
if (hasHiddenPower) continue;
|
||||
hasHiddenPower = true;
|
||||
}
|
||||
moves.add(moveid);
|
||||
}
|
||||
|
||||
while (moves.size < this.maxMoveCount && rejectedPool.length) {
|
||||
const moveid = this.sampleNoReplace(rejectedPool);
|
||||
if (moveid.startsWith('hiddenpower')) {
|
||||
if (hasHiddenPower) continue;
|
||||
hasHiddenPower = true;
|
||||
}
|
||||
moves.add(moveid);
|
||||
}
|
||||
|
||||
counter = this.queryMoves(moves, species.types, abilities, movePool);
|
||||
if (types.has('Dark') && moves.has('suckerpunch') && species.types.length === 1) {
|
||||
counter.add('stab');
|
||||
}
|
||||
|
||||
// Iterate through the moves again, this time to cull them:
|
||||
for (const moveid of moves) {
|
||||
const move = this.dex.moves.get(moveid);
|
||||
|
||||
let {cull, isSetup} = this.shouldCullMove(
|
||||
move, types, moves, abilities, counter,
|
||||
movePool, teamDetails, species, isLead
|
||||
);
|
||||
|
||||
// Increased/decreased priority moves are unneeded with moves that boost only speed
|
||||
if (move.priority !== 0 && !!counter.get('speedsetup')) cull = true;
|
||||
|
||||
// This move doesn't satisfy our setup requirements:
|
||||
if (
|
||||
(move.category === 'Physical' && counter.setupType === 'Special') ||
|
||||
(move.category === 'Special' && counter.setupType === 'Physical')
|
||||
) {
|
||||
// Reject STABs last in case the setup type changes later on
|
||||
if (
|
||||
!SetupException.includes(moveid) &&
|
||||
(!types.has(move.type) || counter.get('stab') > 1 || counter.get(move.category) < 2)
|
||||
) {
|
||||
cull = true;
|
||||
}
|
||||
}
|
||||
if (
|
||||
counter.setupType && !isSetup && move.category !== counter.setupType &&
|
||||
counter.get(counter.setupType) < 2 && !moves.has('batonpass')
|
||||
) {
|
||||
// Mono-attacking with setup and RestTalk or recovery + status healing is allowed
|
||||
if (
|
||||
moveid !== 'rest' && moveid !== 'sleeptalk' &&
|
||||
!(recoveryMoves.includes(moveid) && (moves.has('healbell') || moves.has('refresh'))) &&
|
||||
!((moveid === 'healbell' || moveid === 'refresh') && Array.from(moves).some(id => recoveryMoves.includes(id))) && (
|
||||
// Reject Status moves only if there is nothing else to reject
|
||||
move.category !== 'Status' || (
|
||||
counter.get(counter.setupType) + counter.get('Status') > 3 &&
|
||||
counter.get('physicalsetup') + counter.get('specialsetup') < 2
|
||||
)
|
||||
)
|
||||
) {
|
||||
cull = true;
|
||||
}
|
||||
}
|
||||
if (
|
||||
moveid === 'hiddenpower' &&
|
||||
counter.setupType === 'Special' &&
|
||||
species.types.length > 1 &&
|
||||
counter.get('Special') <= 2 &&
|
||||
!types.has(move.type) &&
|
||||
!counter.get('Physical') &&
|
||||
counter.get('specialpool') &&
|
||||
(!(types.has('Ghost') && move.type === 'Fighting' || types.has('Electric') && move.type === 'Ice'))
|
||||
) {
|
||||
// Hidden Power isn't good enough
|
||||
cull = true;
|
||||
}
|
||||
|
||||
// Reject defensive status moves if a reliable recovery move is available but not selected.
|
||||
// Toxic is only defensive if used with another status move other than Protect (Toxic + 3 attacks and Toxic + Protect are ok).
|
||||
if (
|
||||
!Array.from(moves).some(id => recoveryMoves.includes(id)) &&
|
||||
movePool.some(id => recoveryMoves.includes(id)) && (
|
||||
defensiveStatusMoves.includes(moveid) ||
|
||||
(moveid === 'toxic' && ((counter.get('Status') > 1 && !moves.has('protect')) || counter.get('Status') > 2))
|
||||
)
|
||||
) {
|
||||
cull = true;
|
||||
}
|
||||
|
||||
const runEnforcementChecker = (checkerName: string) => {
|
||||
if (!this.moveEnforcementCheckers[checkerName]) return false;
|
||||
return this.moveEnforcementCheckers[checkerName](
|
||||
movePool, moves, abilities, types, counter, species as Species, teamDetails
|
||||
);
|
||||
};
|
||||
|
||||
const moveIsRejectable = (
|
||||
!move.weather &&
|
||||
!move.damage &&
|
||||
(move.category !== 'Status' || !move.flags.heal) &&
|
||||
(move.category === 'Status' || !types.has(move.type) || (move.basePower && move.basePower < 40 && !move.multihit)) &&
|
||||
// These moves cannot be rejected in favor of a forced move
|
||||
!['judgment', 'lightscreen', 'reflect', 'sleeptalk'].includes(moveid) &&
|
||||
// Setup-supported moves should only be rejected under specific circumstances
|
||||
(counter.get('physicalsetup') + counter.get('specialsetup') < 2 && (
|
||||
!counter.setupType || counter.setupType === 'Mixed' ||
|
||||
(move.category !== counter.setupType && move.category !== 'Status') ||
|
||||
counter.get(counter.setupType) + counter.get('Status') > 3
|
||||
))
|
||||
);
|
||||
|
||||
if (!cull && !isSetup && moveIsRejectable) {
|
||||
// There may be more important moves that this Pokemon needs
|
||||
const canRollForcedMoves = (
|
||||
// These moves should always be rolled
|
||||
movePool.includes('spore') || (!Array.from(moves).some(id => recoveryMoves.includes(id)) && (
|
||||
movePool.includes('softboiled') && !moves.has('explosion') ||
|
||||
(species.baseSpecies === 'Arceus' && movePool.includes('recover'))
|
||||
))
|
||||
);
|
||||
// Pokemon should usually have at least one STAB move
|
||||
const requiresStab = (
|
||||
!counter.get('stab') && !counter.get('damage') && (
|
||||
species.types.length > 1 ||
|
||||
(species.types[0] !== 'Normal' && species.types[0] !== 'Psychic') ||
|
||||
!moves.has('icebeam') ||
|
||||
species.baseStats.spa >= species.baseStats.spd
|
||||
)
|
||||
);
|
||||
if (
|
||||
canRollForcedMoves ||
|
||||
requiresStab ||
|
||||
(species.requiredMove && movePool.includes(toID(species.requiredMove))) ||
|
||||
(counter.get('defensesetup') && !counter.get('recovery') && !moves.has('rest'))
|
||||
) {
|
||||
cull = true;
|
||||
} else {
|
||||
// Pokemon should have moves that benefit their typing or ability
|
||||
for (const type of types) {
|
||||
if (runEnforcementChecker(type)) cull = true;
|
||||
}
|
||||
for (const abil of abilities) {
|
||||
if (runEnforcementChecker(abil)) cull = true;
|
||||
}
|
||||
for (const m of moves) {
|
||||
if (runEnforcementChecker(m)) cull = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sleep Talk shouldn't be selected without Rest
|
||||
if (moveid === 'rest' && cull) {
|
||||
const sleeptalk = movePool.indexOf('sleeptalk');
|
||||
if (sleeptalk >= 0) {
|
||||
if (movePool.length < 2) {
|
||||
cull = false;
|
||||
} else {
|
||||
this.fastPop(movePool, sleeptalk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove rejected moves from the move list
|
||||
if (cull && (
|
||||
movePool.length - availableHP || availableHP && (moveid.startsWith('hiddenpower') || !hasHiddenPower)
|
||||
)) {
|
||||
if (move.category !== 'Status' && (!moveid.startsWith('hiddenpower') || !availableHP)) rejectedPool.push(moveid);
|
||||
moves.delete(moveid);
|
||||
if (moveid.startsWith('hiddenpower')) hasHiddenPower = false;
|
||||
break;
|
||||
}
|
||||
if (cull && rejectedPool.length) {
|
||||
moves.delete(moveid);
|
||||
if (moveid.startsWith('hiddenpower')) hasHiddenPower = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (moves.size < this.maxMoveCount && (movePool.length || rejectedPool.length));
|
||||
|
||||
if (hasHiddenPower) {
|
||||
let hpType;
|
||||
for (const move of moves) {
|
||||
if (move.startsWith('hiddenpower')) {
|
||||
hpType = move.substr(11);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hpType) throw new Error(`hasHiddenPower is true, but no Hidden Power move was found.`);
|
||||
const HPivs = this.dex.types.get(hpType).HPivs;
|
||||
let iv: StatID;
|
||||
for (iv in HPivs) {
|
||||
ivs[iv] = HPivs[iv]!;
|
||||
}
|
||||
}
|
||||
|
||||
const abilityData = Array.from(abilities).map(a => this.dex.abilities.get(a));
|
||||
Utils.sortBy(abilityData, abil => -abil.rating);
|
||||
|
||||
let ability0 = abilityData[0];
|
||||
let ability1 = abilityData[1];
|
||||
if (abilityData[1]) {
|
||||
if (ability0.rating <= ability1.rating && this.randomChance(1, 2)) {
|
||||
[ability0, ability1] = [ability1, ability0];
|
||||
} else if (ability0.rating - 0.6 <= ability1.rating && this.randomChance(2, 3)) {
|
||||
[ability0, ability1] = [ability1, ability0];
|
||||
}
|
||||
ability = ability0.name;
|
||||
|
||||
while (this.shouldCullAbility(ability, types, moves, abilities, counter, movePool, teamDetails, species)) {
|
||||
if (ability === ability0.name && ability1.rating >= 1) {
|
||||
ability = ability1.name;
|
||||
} else {
|
||||
// Default to the highest rated ability if all are rejected
|
||||
ability = abilityData[0].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (abilities.has('Hydration') && moves.has('raindance') && moves.has('rest')) {
|
||||
ability = 'Hydration';
|
||||
} else if (abilities.has('Swift Swim') && moves.has('raindance')) {
|
||||
ability = 'Swift Swim';
|
||||
} else if (abilities.has('Technician') && moves.has('machpunch') && types.has('Fighting') && counter.get('stab') < 2) {
|
||||
ability = 'Technician';
|
||||
}
|
||||
} else {
|
||||
ability = ability0.name;
|
||||
}
|
||||
|
||||
item = this.getHighPriorityItem(ability, types, moves, counter, teamDetails, species, isLead);
|
||||
if (item === undefined) item = this.getMediumPriorityItem(ability, moves, counter, species, false, isLead);
|
||||
if (item === undefined) {
|
||||
item = this.getLowPriorityItem(ability, types, moves, abilities, counter, teamDetails, species);
|
||||
}
|
||||
|
||||
// For Trick / Switcheroo
|
||||
if (item === 'Leftovers' && types.has('Poison')) {
|
||||
item = 'Black Sludge';
|
||||
}
|
||||
|
||||
const level = this.adjustLevel || data.level || (species.nfe ? 90 : 80);
|
||||
|
||||
// Prepare optimal HP
|
||||
let hp = Math.floor(
|
||||
Math.floor(
|
||||
2 * species.baseStats.hp + (ivs.hp || 31) + Math.floor(evs.hp / 4) + 100
|
||||
) * level / 100 + 10
|
||||
);
|
||||
if (moves.has('substitute') && item === 'Sitrus Berry') {
|
||||
// Two Substitutes should activate Sitrus Berry
|
||||
while (hp % 4 > 0) {
|
||||
evs.hp -= 4;
|
||||
hp = Math.floor(
|
||||
Math.floor(
|
||||
2 * species.baseStats.hp + (ivs.hp || 31) + Math.floor(evs.hp / 4) + 100
|
||||
) * level / 100 + 10
|
||||
);
|
||||
}
|
||||
} else if (moves.has('bellydrum') && item === 'Sitrus Berry') {
|
||||
// Belly Drum should activate Sitrus Berry
|
||||
if (hp % 2 > 0) evs.hp -= 4;
|
||||
} else {
|
||||
// Maximize number of Stealth Rock switch-ins
|
||||
const srWeakness = this.dex.getEffectiveness('Rock', species);
|
||||
if (srWeakness > 0 && hp % (4 / srWeakness) === 0) evs.hp -= 4;
|
||||
}
|
||||
|
||||
// Minimize confusion damage
|
||||
if (!counter.get('Physical') && !moves.has('transform')) {
|
||||
evs.atk = 0;
|
||||
ivs.atk = hasHiddenPower ? (ivs.atk || 31) - 28 : 0;
|
||||
}
|
||||
|
||||
if (['gyroball', 'metalburst', 'trickroom'].some(m => moves.has(m))) {
|
||||
evs.spe = 0;
|
||||
ivs.spe = hasHiddenPower ? (ivs.spe || 31) - 28 : 0;
|
||||
}
|
||||
|
||||
return {
|
||||
name: species.baseSpecies,
|
||||
species: forme,
|
||||
gender: species.gender,
|
||||
shiny: this.randomChance(1, 1024),
|
||||
moves: Array.from(moves),
|
||||
ability,
|
||||
evs,
|
||||
ivs,
|
||||
item,
|
||||
level,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default RandomGen4Teams;
|
||||
|
|
@ -1,20 +1,11 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
standardag: {
|
||||
inherit: true,
|
||||
ruleset: [
|
||||
'Obtainable', 'HP Percentage Mod', 'Cancel Mod', 'Beat Up Nicknames Mod', 'Endless Battle Clause',
|
||||
],
|
||||
},
|
||||
export const Rulesets: {[k: string]: ModdedFormatData} = {
|
||||
standard: {
|
||||
inherit: true,
|
||||
ruleset: [
|
||||
'Standard AG',
|
||||
'Sleep Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Items Clause', 'Evasion Moves Clause',
|
||||
],
|
||||
ruleset: ['Obtainable', 'Sleep Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Items Clause', 'Evasion Moves Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod'],
|
||||
},
|
||||
flatrules: {
|
||||
inherit: true,
|
||||
ruleset: ['Obtainable', 'Species Clause', 'Nickname Clause', 'Beat Up Nicknames Mod', 'Item Clause = 1', 'Adjust Level Down = 50', 'Picked Team Size = Auto', 'Cancel Mod'],
|
||||
ruleset: ['Obtainable', 'Species Clause', 'Nickname Clause', 'Item Clause', 'Adjust Level Down = 50', 'Cancel Mod'],
|
||||
},
|
||||
teampreview: {
|
||||
inherit: true,
|
||||
|
|
@ -22,9 +13,8 @@ export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable
|
|||
this.add('clearpoke');
|
||||
for (const pokemon of this.getAllPokemon()) {
|
||||
const details = pokemon.details.replace(', shiny', '')
|
||||
.replace(/(Arceus|Genesect|Gourgeist|Pumpkaboo|Xerneas|Silvally|Urshifu|Dudunsparce)(-[a-zA-Z?-]+)?/g, '$1-*')
|
||||
.replace(/(Zacian|Zamazenta)(?!-Crowned)/g, '$1-*') // Hacked-in Crowned formes will be revealed
|
||||
.replace(/(Greninja)(?!-Ash)/g, '$1-*'); // Hacked-in Greninja-Ash will be revealed
|
||||
.replace(/(Arceus|Gourgeist|Pumpkaboo|Xerneas|Silvally|Urshifu|Dudunsparce)(-[a-zA-Z?-]+)?/g, '$1-*')
|
||||
.replace(/(Zacian|Zamazenta)(?!-Crowned)/g, '$1-*'); // Hacked-in Crowned formes will be revealed
|
||||
this.add('poke', pokemon.side.id, details, pokemon.item ? 'item' : '');
|
||||
}
|
||||
this.makeRequest('teampreview');
|
||||
|
|
|
|||
|
|
@ -4,33 +4,6 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
|
||||
actions: {
|
||||
inherit: true,
|
||||
runSwitch(pokemon) {
|
||||
this.battle.runEvent('EntryHazard', pokemon);
|
||||
|
||||
this.battle.runEvent('SwitchIn', pokemon);
|
||||
|
||||
if (this.battle.gen <= 2) {
|
||||
// pokemon.lastMove is reset for all Pokemon on the field after a switch. This affects Mirror Move.
|
||||
for (const poke of this.battle.getAllActive()) poke.lastMove = null;
|
||||
if (this.battle.gen === 1) pokemon.side.lastSelectedMoveSlot = 0;
|
||||
if (!pokemon.side.faintedThisTurn && pokemon.draggedIn !== this.battle.turn) {
|
||||
this.battle.runEvent('AfterSwitchInSelf', pokemon);
|
||||
}
|
||||
}
|
||||
if (!pokemon.hp) return false;
|
||||
pokemon.isStarted = true;
|
||||
if (!pokemon.fainted) {
|
||||
this.battle.singleEvent('Start', pokemon.getAbility(), pokemon.abilityState, pokemon);
|
||||
this.battle.singleEvent('Start', pokemon.getItem(), pokemon.itemState, pokemon);
|
||||
}
|
||||
if (this.battle.gen === 4) {
|
||||
for (const foeActive of pokemon.foes()) {
|
||||
foeActive.removeVolatile('substitutebroken');
|
||||
}
|
||||
}
|
||||
pokemon.draggedIn = null;
|
||||
return true;
|
||||
},
|
||||
modifyDamage(baseDamage, pokemon, target, move, suppressMessages = false) {
|
||||
// DPP divides modifiers into several mathematically important stages
|
||||
// The modifiers run earlier than other generations are called with ModifyDamagePhase1 and ModifyDamagePhase2
|
||||
|
|
@ -49,13 +22,17 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
// Double battle multi-hit
|
||||
if (move.spreadHit) {
|
||||
const spreadModifier = move.spreadModifier || (this.battle.gameType === 'freeforall' ? 0.5 : 0.75);
|
||||
this.battle.debug(`Spread modifier: ${spreadModifier}`);
|
||||
this.battle.debug('Spread modifier: ' + spreadModifier);
|
||||
baseDamage = this.battle.modify(baseDamage, spreadModifier);
|
||||
}
|
||||
|
||||
// Weather
|
||||
baseDamage = this.battle.runEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
|
||||
|
||||
if (this.battle.gen === 3 && move.category === 'Physical' && !Math.floor(baseDamage)) {
|
||||
baseDamage = 1;
|
||||
}
|
||||
|
||||
baseDamage += 2;
|
||||
|
||||
const isCrit = target.getMoveHitData(move).crit;
|
||||
|
|
@ -70,17 +47,12 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
baseDamage = this.battle.randomizer(baseDamage);
|
||||
|
||||
// STAB
|
||||
// The "???" type never gets STAB
|
||||
// Not even if you Roost in Gen 4 and somehow manage to use
|
||||
// Struggle in the same turn.
|
||||
// (On second thought, it might be easier to get a MissingNo.)
|
||||
if (type !== '???') {
|
||||
let stab: number | [number, number] = 1;
|
||||
if (move.forceSTAB || pokemon.hasType(type)) {
|
||||
stab = 1.5;
|
||||
}
|
||||
stab = this.battle.runEvent('ModifySTAB', pokemon, target, move, stab);
|
||||
baseDamage = this.battle.modify(baseDamage, stab);
|
||||
if (move.forceSTAB || type !== '???' && pokemon.hasType(type)) {
|
||||
// The "???" type never gets STAB
|
||||
// Not even if you Roost in Gen 4 and somehow manage to use
|
||||
// Struggle in the same turn.
|
||||
// (On second thought, it might be easier to get a MissingNo.)
|
||||
baseDamage = this.battle.modify(baseDamage, move.stab || 1.5);
|
||||
}
|
||||
// types
|
||||
let typeMod = target.runEffectiveness(move);
|
||||
|
|
@ -144,7 +116,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
let boost!: number;
|
||||
if (accuracy !== true) {
|
||||
if (!move.ignoreAccuracy) {
|
||||
boosts = this.battle.runEvent('ModifyBoost', pokemon, null, null, { ...pokemon.boosts });
|
||||
boosts = this.battle.runEvent('ModifyBoost', pokemon, null, null, {...pokemon.boosts});
|
||||
boost = this.battle.clampIntRange(boosts['accuracy'], -6, 6);
|
||||
if (boost > 0) {
|
||||
accuracy *= boostTable[boost];
|
||||
|
|
@ -153,7 +125,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
}
|
||||
if (!move.ignoreEvasion) {
|
||||
boosts = this.battle.runEvent('ModifyBoost', target, null, null, { ...target.boosts });
|
||||
boosts = this.battle.runEvent('ModifyBoost', target, null, null, {...target.boosts});
|
||||
boost = this.battle.clampIntRange(boosts['evasion'], -6, 6);
|
||||
if (boost > 0) {
|
||||
accuracy /= boostTable[boost];
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormatsDataTable = {
|
||||
export const FormatsData: {[k: string]: ModdedSpeciesFormatsData} = {
|
||||
pichuspikyeared: {
|
||||
isNonstandard: "Future",
|
||||
tier: "Illegal",
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user