Update to ESLint 9 (#10926)

ESLint has a whole new config format, so I figure it's a good time to
make the config system saner.

- First, we no longer have separate eslint-no-types configs. Lint
  performance shouldn't be enough of a problem to justify the
  relevant maintenance complexity.

- Second, our base config should work out-of-the-box now. `npx eslint`
  will work as expected, without any CLI flags. You should still use
  `npm run lint` which adds the `--cached` flag for performance.

- Third, whatever updates I did fixed style linting, which apparently
  has been bugged for quite some time, considering all the obvious
  mixed-tabs-and-spaces issues I found in the upgrade.

Also here are some changes to our style rules. In particular:

- Curly brackets (for objects etc) now have spaces inside them. Sorry
  for the huge change. ESLint doesn't support our old style, and most
  projects use Prettier style, so we might as well match them in this way.
  See https://github.com/eslint-stylistic/eslint-stylistic/issues/415

- String + number concatenation is no longer allowed. We now
  consistently use template strings for this.
This commit is contained in:
Guangcong Luo 2025-02-25 20:03:46 -08:00 committed by GitHub
parent 44a9e287fc
commit 78439b4a02
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
637 changed files with 21544 additions and 21441 deletions

View File

@ -1,359 +0,0 @@
{
"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
['"`\/]
*/

View File

@ -1,51 +0,0 @@
{
"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"
}
}
]
}

View File

@ -17,7 +17,7 @@ jobs:
strategy:
matrix:
node-version: [16.x]
node-version: [18.x]
steps:
- uses: actions/checkout@v3

View File

@ -1,10 +1,6 @@
{
"editor.insertSpaces": false,
"editor.formatOnSave": false,
"typescript.tsdk": "node_modules/typescript/lib",
"javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": false,
"typescript.format.semicolons": "insert",
"eslint.options": {
"configFile": ".eslintrc.json"
}
"typescript.format.semicolons": "insert"
}

6
build
View File

@ -2,10 +2,10 @@
"use strict";
try {
// technically this was introduced in Node 15, but we'll ask for the most recent LTS with it to be safe
Promise.any([null]);
// technically this was introduced in Node 17, but we'll ask for the most recent LTS with it to be safe
structuredClone({});
} catch (e) {
console.log("We require Node.js version 16 or later; you're using " + process.version);
console.log("We require Node.js version 18 or later; you're using " + process.version);
process.exit(1);
}

View File

@ -531,7 +531,7 @@ export const Formats: import('../sim/dex-formats').FormatList = [
],
battle: {
endTurn() {
// @ts-ignore Hack
// @ts-expect-error Hack
for (const pokemon of this.getAllActive(false, true)) {
// turn counter hasn't been incremented yet
if (this.turn & 1 && pokemon.position === (this.turn & 2 ? 0 : 1) && pokemon.hp && pokemon.allies().length) {
@ -1007,8 +1007,8 @@ export const Formats: import('../sim/dex-formats').FormatList = [
Object.assign(t.side.slotConditions[t.position]['futuremove'], {
duration: 3,
move: moveData.id,
source: source,
moveData: moveData,
source,
moveData,
});
this.add('-message', `${source.name} foresaw an attack!`);
return this.NOT_FAIL;
@ -1075,10 +1075,12 @@ export const Formats: import('../sim/dex-formats').FormatList = [
move.secondaries?.some(secondary => secondary.boosts?.accuracy && secondary.boosts?.accuracy < 0);
const flinchMove = move.secondaries?.some(secondary => secondary.volatileStatus === 'flinch');
const freezeMove = move.secondaries?.some(secondary => secondary.status === 'frz') || move.id === 'triattack';
if (this.ruleTable.isRestricted(`move:${move.id}`) ||
if (
this.ruleTable.isRestricted(`move:${move.id}`) ||
((accuracyLoweringMove || move.ohko || move.multihit || move.id === 'beatup' || move.flags['charge'] ||
move.priority > 0 || move.damageCallback || flinchMove || freezeMove) &&
!this.ruleTable.has(`+move:${move.id}`))) {
!this.ruleTable.has(`+move:${move.id}`))
) {
problems.push(`The move ${move.name} can't be used as an item.`);
}
return problems.length ? problems : null;
@ -1542,7 +1544,7 @@ export const Formats: import('../sim/dex-formats').FormatList = [
delete pokemon.m.innate;
}
const ally = pokemon.side.active.find(mon => mon && mon !== pokemon && !mon.fainted);
if (ally && ally.m.innate) {
if (ally?.m.innate) {
ally.removeVolatile(ally.m.innate);
delete ally.m.innate;
}
@ -1553,7 +1555,7 @@ export const Formats: import('../sim/dex-formats').FormatList = [
delete pokemon.m.innate;
}
const ally = pokemon.side.active.find(mon => mon && mon !== pokemon && !mon.fainted);
if (ally && ally.m.innate) {
if (ally?.m.innate) {
ally.removeVolatile(ally.m.innate);
delete ally.m.innate;
}
@ -1688,11 +1690,11 @@ export const Formats: import('../sim/dex-formats').FormatList = [
set.moves.splice(i, 1);
}
}
const allowedPokemoves = this.ruleTable.valueRules.get('allowedpokemoves') || 1;
if (pokemoves > Number(allowedPokemoves)) {
const allowedPokemoves = Number(this.ruleTable.valueRules.get('allowedpokemoves') || '1');
if (pokemoves > allowedPokemoves) {
problems.push(
`${set.species} has ${pokemoves} Pokemoves.`,
`(Pok\u00e9mon can only have ${allowedPokemoves} Pokemove${allowedPokemoves + '' === '1' ? '' : 's'} each.)`
`(Pok\u00e9mon can only have ${allowedPokemoves} Pokemove${allowedPokemoves === 1 ? '' : 's'} each.)`
);
}
if (this.validateSet(set, teamHas)) {
@ -1890,7 +1892,7 @@ export const Formats: import('../sim/dex-formats').FormatList = [
if (move.spreadHit) {
// multi-target modifier (doubles only)
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);
} else if (move.multihitType === 'parentalbond' && move.hit > 1) {
// Parental Bond modifier
@ -2575,7 +2577,7 @@ export const Formats: import('../sim/dex-formats').FormatList = [
// that a pokemon is on a team through the onStart even triggering
// at the start of a match, users with pokemon names will need their
// statuses to end in "user".
name = name + 'user';
name = `${name}user`;
}
// Add the mon's status effect to it as a volatile.
const status = this.dex.conditions.get(name);

View File

@ -227,7 +227,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
const armorTailHolder = this.effectState.target;
if ((source.isAlly(armorTailHolder) || move.target === 'all') && move.priority > 0.1) {
this.attrLastMove('[still]');
this.add('cant', armorTailHolder, 'ability: Armor Tail', move, '[of] ' + target);
this.add('cant', armorTailHolder, 'ability: Armor Tail', move, `[of] ${target}`);
return false;
}
},
@ -241,7 +241,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
if (['attract', 'disable', 'encore', 'healblock', 'taunt', 'torment'].includes(status.id)) {
if (effect.effectType === 'Move') {
const effectHolder = this.effectState.target;
this.add('-block', target, 'ability: Aroma Veil', '[of] ' + effectHolder);
this.add('-block', target, 'ability: Aroma Veil', `[of] ${effectHolder}`);
}
return null;
}
@ -442,7 +442,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
if (boost.def && boost.def < 0) {
delete boost.def;
if (!(effect as ActiveMove).secondaries && effect.id !== 'octolock') {
this.add("-fail", target, "unboost", "Defense", "[from] ability: Big Pecks", "[of] " + target);
this.add("-fail", target, "unboost", "Defense", "[from] ability: Big Pecks", `[of] ${target}`);
}
}
},
@ -526,7 +526,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
}
}
if (showMsg && !(effect as ActiveMove).secondaries && effect.id !== 'octolock') {
this.add("-fail", target, "unboost", "[from] ability: Clear Body", "[of] " + target);
this.add("-fail", target, "unboost", "[from] ability: Clear Body", `[of] ${target}`);
}
},
flags: { breakable: 1 },
@ -622,7 +622,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
// Cancel all actions this turn for pokemon if applicable
this.queue.cancelAction(pokemon);
// Add volatiles to both pokemon
this.add('-activate', pokemon, 'ability: Commander', '[of] ' + ally);
this.add('-activate', pokemon, 'ability: Commander', `[of] ${ally}`);
pokemon.addVolatile('commanding');
ally.addVolatile('commanded', pokemon);
// Continued in conditions.ts in the volatiles
@ -771,7 +771,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
onStart(pokemon) {
for (const ally of pokemon.adjacentAllies()) {
ally.clearBoosts();
this.add('-clearboost', ally, '[from] ability: Curious Medicine', '[of] ' + pokemon);
this.add('-clearboost', ally, '[from] ability: Curious Medicine', `[of] ${pokemon}`);
}
},
flags: {},
@ -810,7 +810,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
onAnyTryMove(target, source, effect) {
if (['explosion', 'mindblown', 'mistyexplosion', 'selfdestruct'].includes(effect.id)) {
this.attrLastMove('[still]');
this.add('cant', this.effectState.target, 'ability: Damp', effect, '[of] ' + target);
this.add('cant', this.effectState.target, 'ability: Damp', effect, `[of] ${target}`);
return false;
}
},
@ -869,7 +869,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
const dazzlingHolder = this.effectState.target;
if ((source.isAlly(dazzlingHolder) || move.target === 'all') && move.priority > 0.1) {
this.attrLastMove('[still]');
this.add('cant', dazzlingHolder, 'ability: Dazzling', move, '[of] ' + target);
this.add('cant', dazzlingHolder, 'ability: Dazzling', move, `[of] ${target}`);
return false;
}
},
@ -1370,7 +1370,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
}
if (showMsg && !(effect as ActiveMove).secondaries) {
const effectHolder = this.effectState.target;
this.add('-block', target, 'ability: Flower Veil', '[of] ' + effectHolder);
this.add('-block', target, 'ability: Flower Veil', `[of] ${effectHolder}`);
}
},
onAllySetStatus(status, target, source, effect) {
@ -1378,7 +1378,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
this.debug('interrupting setStatus with Flower Veil');
if (effect.name === 'Synchronize' || (effect.effectType === 'Move' && !effect.secondaries)) {
const effectHolder = this.effectState.target;
this.add('-block', target, 'ability: Flower Veil', '[of] ' + effectHolder);
this.add('-block', target, 'ability: Flower Veil', `[of] ${effectHolder}`);
}
return null;
}
@ -1387,7 +1387,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
if (target.hasType('Grass') && status.id === 'yawn') {
this.debug('Flower Veil blocking yawn');
const effectHolder = this.effectState.target;
this.add('-block', target, 'ability: Flower Veil', '[of] ' + effectHolder);
this.add('-block', target, 'ability: Flower Veil', `[of] ${effectHolder}`);
return null;
}
},
@ -1464,7 +1464,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
}
if (!warnMoves.length) return;
const [warnMoveName, warnTarget] = this.sample(warnMoves);
this.add('-activate', pokemon, 'ability: Forewarn', warnMoveName, '[of] ' + warnTarget);
this.add('-activate', pokemon, 'ability: Forewarn', warnMoveName, `[of] ${warnTarget}`);
},
flags: {},
name: "Forewarn",
@ -1487,7 +1487,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
onStart(pokemon) {
for (const target of pokemon.foes()) {
if (target.item) {
this.add('-item', target, target.getItem().name, '[from] ability: Frisk', '[of] ' + pokemon);
this.add('-item', target, target.getItem().name, '[from] ability: Frisk', `[of] ${pokemon}`);
}
}
},
@ -1508,7 +1508,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
}
}
if (showMsg && !(effect as ActiveMove).secondaries && effect.id !== 'octolock') {
this.add("-fail", target, "unboost", "[from] ability: Full Metal Body", "[of] " + target);
this.add("-fail", target, "unboost", "[from] ability: Full Metal Body", `[of] ${target}`);
}
},
flags: {},
@ -1884,7 +1884,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
if (boost.atk && boost.atk < 0) {
delete boost.atk;
if (!(effect as ActiveMove).secondaries) {
this.add("-fail", target, "unboost", "Attack", "[from] ability: Hyper Cutter", "[of] " + target);
this.add("-fail", target, "unboost", "Attack", "[from] ability: Hyper Cutter", `[of] ${target}`);
}
}
},
@ -1981,7 +1981,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
if (boost.accuracy && boost.accuracy < 0) {
delete boost.accuracy;
if (!(effect as ActiveMove).secondaries) {
this.add("-fail", target, "unboost", "accuracy", "[from] ability: Illuminate", "[of] " + target);
this.add("-fail", target, "unboost", "accuracy", "[from] ability: Illuminate", `[of] ${target}`);
}
}
},
@ -2097,7 +2097,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
onTryBoost(boost, target, source, effect) {
if (effect.name === 'Intimidate' && boost.atk) {
delete boost.atk;
this.add('-fail', target, 'unboost', 'Attack', '[from] ability: Inner Focus', '[of] ' + target);
this.add('-fail', target, 'unboost', 'Attack', '[from] ability: Inner Focus', `[of] ${target}`);
}
},
flags: { breakable: 1 },
@ -2203,7 +2203,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
if (boost.accuracy && boost.accuracy < 0) {
delete boost.accuracy;
if (!(effect as ActiveMove).secondaries) {
this.add("-fail", target, "unboost", "accuracy", "[from] ability: Keen Eye", "[of] " + target);
this.add("-fail", target, "unboost", "accuracy", "[from] ability: Keen Eye", `[of] ${target}`);
}
}
},
@ -2333,7 +2333,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
if (this.checkMoveMakesContact(move, source, target, !source.isAlly(target))) {
const oldAbility = source.setAbility('lingeringaroma', target);
if (oldAbility) {
this.add('-activate', target, 'ability: Lingering Aroma', this.dex.abilities.get(oldAbility).name, '[of] ' + source);
this.add('-activate', target, 'ability: Lingering Aroma', this.dex.abilities.get(oldAbility).name, `[of] ${source}`);
}
}
},
@ -2344,7 +2344,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
},
liquidooze: {
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', 'strengthsap'];
if (canOoze.includes(effect.id)) {
this.damage(damage);
@ -2430,7 +2430,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
target.item = yourItem.id; // bypass setItem so we don't break choicelock or anything
return;
}
this.add('-item', source, yourItem, '[from] ability: Magician', '[of] ' + target);
this.add('-item', source, yourItem, '[from] ability: Magician', `[of] ${target}`);
}
},
flags: {},
@ -2548,7 +2548,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
if (boost.accuracy && boost.accuracy < 0) {
delete boost.accuracy;
if (!(effect as ActiveMove).secondaries) {
this.add("-fail", target, "unboost", "accuracy", "[from] ability: Mind's Eye", "[of] " + target);
this.add("-fail", target, "unboost", "accuracy", "[from] ability: Mind's Eye", `[of] ${target}`);
}
}
},
@ -2711,7 +2711,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
if (this.checkMoveMakesContact(move, source, target, !source.isAlly(target))) {
const oldAbility = source.setAbility('mummy', target);
if (oldAbility) {
this.add('-activate', target, 'ability: Mummy', this.dex.abilities.get(oldAbility).name, '[of] ' + source);
this.add('-activate', target, 'ability: Mummy', this.dex.abilities.get(oldAbility).name, `[of] ${source}`);
}
}
},
@ -2794,7 +2794,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
// It's not possible to know what pokemon were cured
// Unlike a -hint, this is real information that battlers need, so we use a -message
this.add('-message', "(" + cureList.length + " of " + pokemon.side.name + "'s pokemon " + (cureList.length === 1 ? "was" : "were") + " cured by Natural Cure.)");
this.add('-message', `(${cureList.length} of ${pokemon.side.name}'s pokemon ${cureList.length === 1 ? "was" : "were"} cured by Natural Cure.)`);
for (const pkmn of cureList) {
pkmn.showCure = false;
@ -2959,7 +2959,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
onTryBoost(boost, target, source, effect) {
if (effect.name === 'Intimidate' && boost.atk) {
delete boost.atk;
this.add('-fail', target, 'unboost', 'Attack', '[from] ability: Oblivious', '[of] ' + target);
this.add('-fail', target, 'unboost', 'Attack', '[from] ability: Oblivious', `[of] ${target}`);
}
},
flags: { breakable: 1 },
@ -2975,7 +2975,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
let i: BoostID;
for (i in boost) {
if (boost[i]! > 0) {
boostPlus[i] = (boostPlus[i] || 0) + boost[i];
boostPlus[i] = (boostPlus[i] || 0) + boost[i]!;
}
}
},
@ -3078,7 +3078,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
onTryBoost(boost, target, source, effect) {
if (effect.name === 'Intimidate' && boost.atk) {
delete boost.atk;
this.add('-fail', target, 'unboost', 'Attack', '[from] ability: Own Tempo', '[of] ' + target);
this.add('-fail', target, 'unboost', 'Attack', '[from] ability: Own Tempo', `[of] ${target}`);
}
},
flags: { breakable: 1 },
@ -3134,7 +3134,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
if (!['psn', 'tox'].includes(status.id)) return;
if ((effect as Move)?.status) {
const effectHolder = this.effectState.target;
this.add('-block', target, 'ability: Pastel Veil', '[of] ' + effectHolder);
this.add('-block', target, 'ability: Pastel Veil', `[of] ${effectHolder}`);
}
return false;
},
@ -3169,8 +3169,8 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
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);
this.add('-enditem', source, yourItem, '[silent]', '[from] ability: Pickpocket', `[of] ${source}`);
this.add('-item', target, yourItem, '[from] ability: Pickpocket', `[of] ${source}`);
}
},
flags: {},
@ -3313,7 +3313,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
const ability = target.getAbility();
if (ability.flags['noreceiver'] || ability.id === 'noability') return;
if (this.effectState.target.setAbility(ability)) {
this.add('-ability', this.effectState.target, ability, '[from] ability: Power of Alchemy', '[of] ' + target);
this.add('-ability', this.effectState.target, ability, '[from] ability: Power of Alchemy', `[of] ${target}`);
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1 },
@ -3635,7 +3635,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
const dazzlingHolder = this.effectState.target;
if ((source.isAlly(dazzlingHolder) || move.target === 'all') && move.priority > 0.1) {
this.attrLastMove('[still]');
this.add('cant', dazzlingHolder, 'ability: Queenly Majesty', move, '[of] ' + target);
this.add('cant', dazzlingHolder, 'ability: Queenly Majesty', move, `[of] ${target}`);
return false;
}
},
@ -3702,7 +3702,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
const ability = target.getAbility();
if (ability.flags['noreceiver'] || ability.id === 'noability') return;
if (this.effectState.target.setAbility(ability)) {
this.add('-ability', this.effectState.target, ability, '[from] ability: Receiver', '[of] ' + target);
this.add('-ability', this.effectState.target, ability, '[from] ability: Receiver', `[of] ${target}`);
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1 },
@ -4002,7 +4002,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
onTryBoost(boost, target, source, effect) {
if (effect.name === 'Intimidate' && boost.atk) {
delete boost.atk;
this.add('-fail', target, 'unboost', 'Attack', '[from] ability: Scrappy', '[of] ' + target);
this.add('-fail', target, 'unboost', 'Attack', '[from] ability: Scrappy', `[of] ${target}`);
}
},
flags: {},
@ -4692,7 +4692,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
if (status.id === 'slp') {
this.debug('Sweet Veil interrupts sleep');
const effectHolder = this.effectState.target;
this.add('-block', target, 'ability: Sweet Veil', '[of] ' + effectHolder);
this.add('-block', target, 'ability: Sweet Veil', `[of] ${effectHolder}`);
return null;
}
},
@ -4700,7 +4700,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
if (status.id === 'yawn') {
this.debug('Sweet Veil blocking yawn');
const effectHolder = this.effectState.target;
this.add('-block', target, 'ability: Sweet Veil', '[of] ' + effectHolder);
this.add('-block', target, 'ability: Sweet Veil', `[of] ${effectHolder}`);
return null;
}
},
@ -4733,7 +4733,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
source.item = myItem.id;
return;
}
this.add('-activate', source, 'ability: Symbiosis', myItem, '[of] ' + pokemon);
this.add('-activate', source, 'ability: Symbiosis', myItem, `[of] ${pokemon}`);
},
flags: {},
name: "Symbiosis",
@ -4821,7 +4821,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
onBasePowerPriority: 30,
onBasePower(basePower, attacker, defender, move) {
const basePowerAfterMultiplier = this.modify(basePower, this.event.modifier);
this.debug('Base Power: ' + basePowerAfterMultiplier);
this.debug(`Base Power: ${basePowerAfterMultiplier}`);
if (basePowerAfterMultiplier <= 60) {
this.debug('Technician boost');
return this.chainModify(1.5);
@ -5062,7 +5062,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
const target = this.sample(possibleTargets);
const ability = target.getAbility();
if (pokemon.setAbility(ability)) {
this.add('-ability', pokemon, ability, '[from] ability: Trace', '[of] ' + target);
this.add('-ability', pokemon, ability, '[from] ability: Trace', `[of] ${target}`);
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1 },
@ -5282,9 +5282,9 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
const sourceAbility = source.setAbility('wanderingspirit', target);
if (!sourceAbility) return;
if (target.isAlly(source)) {
this.add('-activate', target, 'Skill Swap', '', '', '[of] ' + source);
this.add('-activate', target, 'Skill Swap', '', '', `[of] ${source}`);
} else {
this.add('-activate', target, 'ability: Wandering Spirit', this.dex.abilities.get(sourceAbility).name, 'Wandering Spirit', '[of] ' + source);
this.add('-activate', target, 'ability: Wandering Spirit', this.dex.abilities.get(sourceAbility).name, 'Wandering Spirit', `[of] ${source}`);
}
target.setAbility(sourceAbility);
}
@ -5416,7 +5416,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
}
}
if (showMsg && !(effect as ActiveMove).secondaries && effect.id !== 'octolock') {
this.add("-fail", target, "unboost", "[from] ability: White Smoke", "[of] " + target);
this.add("-fail", target, "unboost", "[from] ability: White Smoke", `[of] ${target}`);
}
},
flags: { breakable: 1 },

View File

@ -34,7 +34,7 @@
*/
import { Dex, PRNG, SQL } from '../sim';
import {EventMethods} from '../sim/dex-conditions';
import type { EventMethods } from '../sim/dex-conditions';
import {
ABILITY_MOVE_BONUSES,
ABILITY_MOVE_TYPE_BONUSES,
@ -493,7 +493,7 @@ export default class TeamGenerator {
weight *= 32;
// these moves can also lessen the effectiveness of the user's team's own hazards
weight *= Math.pow(0.8, Object.values(teamStats.hazardSetters).reduce((total, num) => total + num, 0));
weight *= 0.8 ** Object.values(teamStats.hazardSetters).reduce((total, num) => total + num, 0);
}
// boosts
@ -639,8 +639,8 @@ export default class TeamGenerator {
if (move.category === 'Special') powerEstimate *= Math.max(0.5, 1 + specialSetup) / Math.max(0.5, 1 + physicalSetup);
const abilityBonus = (
((ABILITY_MOVE_BONUSES[this.dex.toID(ability)] || {})[move.id] || 1) *
((ABILITY_MOVE_TYPE_BONUSES[this.dex.toID(ability)] || {})[moveType] || 1)
(ABILITY_MOVE_BONUSES[this.dex.toID(ability)]?.[move.id] || 1) *
(ABILITY_MOVE_TYPE_BONUSES[this.dex.toID(ability)]?.[moveType] || 1)
);
let weight = powerEstimate * abilityBonus;
@ -664,7 +664,7 @@ export default class TeamGenerator {
if (move.flags.contact) {
if (ability === 'Tough Claws') weight *= 1.3;
if (ability === 'Unseen Fist') weight *= 1.1;
if (ability === 'Poison Touch') weight *= TeamGenerator.statusWeight('psn', 1 - Math.pow(0.7, numberOfHits));
if (ability === 'Poison Touch') weight *= TeamGenerator.statusWeight('psn', 1 - (0.7 ** numberOfHits));
}
if (move.flags.bite && ability === 'Strong Jaw') weight *= 1.5;
// 5% boost for ability to break subs
@ -697,7 +697,7 @@ export default class TeamGenerator {
}
}
}
if (ability === 'Toxic Chain') weight *= TeamGenerator.statusWeight('tox', 1 - Math.pow(0.7, numberOfHits));
if (ability === 'Toxic Chain') weight *= TeamGenerator.statusWeight('tox', 1 - (0.7 ** numberOfHits));
// Special effect if something special happened earlier in the turn
// More useful on slower Pokemon
@ -734,7 +734,7 @@ export default class TeamGenerator {
// these two hazard removers don't clear hazards on the opponent's field, but can be blocked by type immunities
if (['rapidspin', 'mortalspin'].includes(move.id)) {
weight *= 1 + 20 * Math.pow(0.25, teamStats.hazardRemovers);
weight *= 1 + 20 * (0.25 ** teamStats.hazardRemovers);
}
// these moves have a hard-coded 16x bonus

View File

@ -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,7 +22,7 @@ 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');
}
@ -49,9 +49,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 +85,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');
}
@ -106,7 +106,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();
}
},
@ -126,7 +126,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');
}
@ -144,7 +144,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');
}
@ -167,7 +167,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
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);
this.add('-start', target, 'confusion', '[from] ability: ' + sourceEffect.name, `[of] ${source}`);
} else {
this.add('-start', target, 'confusion');
}
@ -228,7 +228,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,
@ -444,7 +444,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;
@ -493,7 +493,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');
}
@ -528,7 +528,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() {
@ -567,7 +567,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');
}
@ -606,7 +606,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;
@ -642,7 +642,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');
}
@ -672,7 +672,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');
}
@ -708,7 +708,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', 'Snowscape', '[from] ability: ' + effect.name, '[of] ' + source);
this.add('-weather', 'Snowscape', '[from] ability: ' + effect.name, `[of] ${source}`);
} else {
this.add('-weather', 'Snowscape');
}
@ -734,7 +734,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() {
@ -880,7 +880,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
duration: 2,
onBasePower(relayVar, source, target, move) {
let bp = Math.max(1, move.basePower);
bp *= Math.pow(2, source.volatiles['rolloutstorage'].contactHitCount);
bp *= 2 ** source.volatiles['rolloutstorage'].contactHitCount;
if (source.volatiles['defensecurl']) {
bp *= 2;
}

View File

@ -922,7 +922,7 @@ export const Items: import('../sim/dex-items').ItemDataTable = {
},
onStart(pokemon) {
if (pokemon.volatiles['choicelock']) {
this.debug('removing choicelock: ' + pokemon.volatiles['choicelock']);
this.debug('removing choicelock');
}
pokemon.removeVolatile('choicelock');
},
@ -946,7 +946,7 @@ export const Items: import('../sim/dex-items').ItemDataTable = {
},
onStart(pokemon) {
if (pokemon.volatiles['choicelock']) {
this.debug('removing choicelock: ' + pokemon.volatiles['choicelock']);
this.debug('removing choicelock');
}
pokemon.removeVolatile('choicelock');
},
@ -969,7 +969,7 @@ export const Items: import('../sim/dex-items').ItemDataTable = {
},
onStart(pokemon) {
if (pokemon.volatiles['choicelock']) {
this.debug('removing choicelock: ' + pokemon.volatiles['choicelock']);
this.debug('removing choicelock');
}
pokemon.removeVolatile('choicelock');
},
@ -1037,7 +1037,7 @@ export const Items: import('../sim/dex-items').ItemDataTable = {
}
}
if (showMsg && !(effect as ActiveMove).secondaries && effect.id !== 'octolock') {
this.add('-fail', target, 'unboost', '[from] item: Clear Amulet', '[of] ' + target);
this.add('-fail', target, 'unboost', '[from] item: Clear Amulet', `[of] ${target}`);
}
},
num: 1882,
@ -1304,7 +1304,7 @@ export const Items: import('../sim/dex-items').ItemDataTable = {
},
onAttractPriority: -100,
onAttract(target, source) {
this.debug('attract intercepted: ' + target + ' from ' + source);
this.debug(`attract intercepted: ${target} from ${source}`);
if (!source || source === target) return;
if (!source.volatiles['attract']) source.addVolatile('attract', target);
},
@ -3809,7 +3809,7 @@ export const Items: import('../sim/dex-items').ItemDataTable = {
let i: BoostID;
for (i in boost) {
if (boost[i]! > 0) {
boostPlus[i] = (boostPlus[i] || 0) + boost[i];
boostPlus[i] = (boostPlus[i] || 0) + boost[i]!;
this.effectState.ready = true;
}
}

View File

@ -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,7 +155,6 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
pokemon.removeVolatile('lockedmove');
return false;
}
return;
},
},
flinch: {

View File

@ -175,7 +175,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: {
@ -876,8 +876,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);
@ -899,7 +899,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
// Add here counter damage
const lastAttackedBy = target.getLastAttackedBy();
if (!lastAttackedBy) {
target.attackedBy.push({source: source, move: move.id, damage: uncappedDamage, slot: source.getSlot(), thisTurn: true});
target.attackedBy.push({ source, move: move.id, damage: uncappedDamage, slot: source.getSlot(), thisTurn: true });
} else {
lastAttackedBy.move = move.id;
lastAttackedBy.damage = uncappedDamage;

View File

@ -26,7 +26,7 @@ export const Scripts: ModdedBattleScriptsData = {
pokemon: {
inherit: true,
getStat(statName, unmodified) {
// @ts-ignore - type checking prevents 'hp' from being passed, but we're paranoid
// @ts-expect-error 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];
@ -160,8 +160,8 @@ export const Scripts: ModdedBattleScriptsData = {
let lockedMove = this.battle.runEvent('LockMove', pokemon);
if (lockedMove === true) lockedMove = false;
if (
(!lockedMove &&
(!pokemon.volatiles['partialtrappinglock'] || pokemon.volatiles['partialtrappinglock'].locked !== target))
!lockedMove &&
(!pokemon.volatiles['partialtrappinglock'] || pokemon.volatiles['partialtrappinglock'].locked !== target)
) {
pokemon.deductPP(move, null, target);
} else {
@ -293,8 +293,8 @@ export const Scripts: ModdedBattleScriptsData = {
return false;
}
if (sourceEffect) attrs += '|[from]' + this.battle.dex.conditions.get(sourceEffect);
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;
@ -394,7 +394,7 @@ export const Scripts: ModdedBattleScriptsData = {
}
// If a sleep inducing move is used while the user is recharging, the accuracy is true.
if (move.status === 'slp' && target && target.volatiles['mustrecharge']) {
if (move.status === 'slp' && target?.volatiles['mustrecharge']) {
accuracy = true;
}

View File

@ -65,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: source, move: move.id, damage: uncappedDamage, thisTurn: true, slot: source.getSlot()});
target.attackedBy.push({ source, move: move.id, damage: uncappedDamage, thisTurn: true, slot: source.getSlot() });
} else {
lastAttackedBy.move = move.id;
lastAttackedBy.damage = uncappedDamage;

View File

@ -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');
}
@ -108,7 +108,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
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)) {

View File

@ -270,7 +270,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
// Add here counter damage
const lastAttackedBy = target.getLastAttackedBy();
if (!lastAttackedBy) {
target.attackedBy.push({source: source, move: move.id, damage: damage, slot: source.getSlot(), thisTurn: true});
target.attackedBy.push({ source, move: move.id, damage, slot: source.getSlot(), thisTurn: true });
} else {
lastAttackedBy.move = move.id;
lastAttackedBy.damage = damage;

View File

@ -81,7 +81,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);
@ -199,8 +199,8 @@ export const Scripts: ModdedBattleScriptsData = {
return false;
}
if (sourceEffect) attrs += '|[from]' + this.battle.dex.conditions.get(sourceEffect);
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;
@ -609,26 +609,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 = critChance >> 2;
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 = critChance << 2;
critChance <<= 2;
// Then we add 160.
critChance += 160;
} else {
// If it is not active, we left shift it by 1.
critChance = critChance << 1;
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 = critChance << 2;
critChance <<= 2;
} else if (move.critRatio === 1) {
// Normal hit ratio, we divide the crit chance by 2 and floor the result again.
critChance = critChance >> 1;
critChance >>= 1;
}
// Now we make sure it's a number between 1 and 255.

View File

@ -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');
}
@ -223,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() {

View File

@ -140,7 +140,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
condition: {
onStart(pokemon, source) {
this.add('-start', pokemon, 'Curse', '[of] ' + source);
this.add('-start', pokemon, 'Curse', `[of] ${source}`);
},
onAfterMoveSelf(pokemon) {
this.damage(pokemon.baseMaxhp / 4);
@ -548,7 +548,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
onResidualOrder: 4,
onResidual(pokemon) {
const duration = pokemon.volatiles['perishsong'].duration;
this.add('-start', pokemon, 'perish' + duration);
this.add('-start', pokemon, `perish${duration}`);
},
},
},
@ -909,7 +909,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}`);
},
},
},

View File

@ -8,7 +8,7 @@ export const Scripts: ModdedBattleScriptsData = {
pokemon: {
inherit: true,
getStat(statName, unboosted, unmodified, fastReturn) {
// @ts-ignore - type checking prevents 'hp' from being passed, but we're paranoid
// @ts-expect-error type checking prevents 'hp' from being passed, but we're paranoid
if (statName === 'hp') throw new Error("Please read `maxhp` directly");
// base stat
@ -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;
}

View File

@ -4,7 +4,7 @@ export const Scripts: ModdedBattleScriptsData = {
pokemon: {
inherit: true,
getStat(statName, unboosted, unmodified, fastReturn) {
// @ts-ignore - type checking prevents 'hp' from being passed, but we're paranoid
// @ts-expect-error type checking prevents 'hp' from being passed, but we're paranoid
if (statName === 'hp') throw new Error("Please read `maxhp` directly");
// base stat
@ -297,7 +297,7 @@ export const Scripts: ModdedBattleScriptsData = {
if (targets.length > 1) move.spreadHit = true;
if (move.spreadHit && move.target === 'allAdjacentFoes') {
const spreadModifier = move.spreadModifier || 0.5;
this.battle.debug('Spread modifier: ' + spreadModifier);
this.battle.debug(`Spread modifier: ${spreadModifier}`);
damage = this.battle.modify(damage, spreadModifier);
}

View File

@ -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');
}

View File

@ -7,7 +7,7 @@ export const Scripts: ModdedBattleScriptsData = {
pokemon: {
inherit: true,
getStat(statName, unboosted, unmodified, fastReturn) {
// @ts-ignore - type checking prevents 'hp' from being passed, but we're paranoid
// @ts-expect-error type checking prevents 'hp' from being passed, but we're paranoid
if (statName === 'hp') throw new Error("Please read `maxhp` directly");
// base stat
@ -547,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'] && pokemon.volatiles['bide'].damage) {
if (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.");

View File

@ -182,7 +182,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
if (!target || target.fainted) return;
const ability = target.getAbility();
if (pokemon.setAbility(ability)) {
this.add('-ability', pokemon, ability, '[from] ability: Trace', '[of] ' + target);
this.add('-ability', pokemon, ability, '[from] ability: Trace', `[of] ${target}`);
}
},
flags: {},

View File

@ -4,7 +4,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');
}

View File

@ -265,13 +265,13 @@ 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 },
effectType: 'Move',
@ -363,7 +363,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
} else {
bp = 20;
}
this.debug('BP: ' + bp);
this.debug(`BP: ${bp}`);
return bp;
},
},
@ -572,7 +572,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
} else {
bp = 20;
}
this.debug('BP: ' + bp);
this.debug(`BP: ${bp}`);
return bp;
},
},
@ -593,7 +593,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: pp});
moves.push({ move: moveid, pp });
}
}
if (!moves.length) {

View File

@ -50,7 +50,7 @@ export const Scripts: ModdedBattleScriptsData = {
// and the user's ally, like Earthquake and Explosion, don't get affected by spread modifiers
if (move.spreadHit && move.target === 'allAdjacentFoes') {
const spreadModifier = move.spreadModifier || 0.5;
this.battle.debug('Spread modifier: ' + spreadModifier);
this.battle.debug(`Spread modifier: ${spreadModifier}`);
baseDamage = this.battle.modify(baseDamage, spreadModifier);
}
@ -163,7 +163,7 @@ export const Scripts: ModdedBattleScriptsData = {
let movename = move.name;
if (move.id === 'hiddenpower') movename = 'Hidden Power';
if (sourceEffect) attrs += `|[from]${this.dex.conditions.get(sourceEffect)}`;
this.battle.addMove('move', pokemon, movename, target + attrs);
this.battle.addMove('move', pokemon, movename, `${target}${attrs}`);
if (!target) {
this.battle.attrLastMove('[notarget]');

View File

@ -191,7 +191,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
onStart(pokemon) {
const target = pokemon.side.randomFoe();
if (target?.item && !target.itemState.knockedOff) {
this.add('-item', '', target.getItem().name, '[from] ability: Frisk', '[of] ' + pokemon);
this.add('-item', '', target.getItem().name, '[from] ability: Frisk', `[of] ${pokemon}`);
}
},
},
@ -247,7 +247,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
inherit: true,
onSetStatus(status, target, source, effect) {
if (effect && effect.id === 'rest') {
return;
// do nothing
} else if (this.field.isWeather('sunnyday')) {
return false;
}
@ -261,7 +261,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
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);
@ -535,7 +535,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
return;
}
if (pokemon.setAbility(ability)) {
this.add('-ability', pokemon, ability, '[from] ability: Trace', '[of] ' + target);
this.add('-ability', pokemon, ability, '[from] ability: Trace', `[of] ${target}`);
}
},
flags: { notrace: 1 },

View File

@ -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');
}

View File

@ -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);
this.debug(`custap action: ${action?.moveid}`);
if (action && pokemon.eatItem()) {
this.queue.cancelAction(pokemon);
this.add('-message', "Custap Berry activated.");
@ -241,7 +241,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
condition: {
duration: 1,
onAfterMoveSecondarySelf(source, target, move) {
if (move && move.effectType === 'Move' && source && source.volatiles['lifeorb']) {
if (move && move.effectType === 'Move' && source?.volatiles['lifeorb']) {
this.damage(source.baseMaxhp / 10, source, source, this.dex.items.get('lifeorb'));
source.removeVolatile('lifeorb');
}

View File

@ -257,7 +257,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
basePowerCallback(pokemon, target) {
const bp = Math.floor(target.hp * 120 / target.maxhp) + 1;
this.debug('BP for ' + target.hp + '/' + target.maxhp + " HP: " + bp);
this.debug(`BP for ${target.hp}/${target.maxhp} HP: ${bp}`);
return bp;
},
},
@ -269,7 +269,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
delete move.volatileStatus;
delete move.onHit;
move.self = { boosts: { atk: 1, def: 1, spe: -1 } };
move.target = move.nonGhostTarget as MoveTarget;
move.target = move.nonGhostTarget!;
} else if (target?.volatiles['substitute']) {
delete move.volatileStatus;
delete move.onHit;
@ -277,7 +277,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
condition: {
onStart(pokemon, source) {
this.add('-start', pokemon, 'Curse', '[of] ' + source);
this.add('-start', pokemon, 'Curse', `[of] ${source}`);
},
onResidualOrder: 10,
onResidualSubOrder: 8,
@ -383,13 +383,13 @@ 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: "Special",
flags: { metronome: 1, futuremove: 1 },
effectType: 'Move',
@ -535,7 +535,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
} else {
bp = 20;
}
this.debug('BP: ' + bp);
this.debug(`BP: ${bp}`);
return bp;
},
},
@ -552,7 +552,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
if (!this.singleEvent('TakeItem', item, source.itemState, source, source, move, item)) return false;
if (!item.fling) return false;
move.basePower = item.fling.basePower;
this.debug('BP: ' + move.basePower);
this.debug(`BP: ${move.basePower}`);
if (item.isBerry) {
move.onHit = function (foe) {
if (this.singleEvent('Eat', item, null, foe, null, null)) {
@ -628,13 +628,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
Object.assign(target.side.slotConditions[target.position]['futuremove'], {
duration: 3,
move: 'futuresight',
source: source,
source,
moveData: {
id: 'futuresight',
name: "Future Sight",
accuracy: 90,
basePower: 0,
damage: damage,
damage,
category: "Special",
flags: { metronome: 1, futuremove: 1 },
effectType: 'Move',
@ -880,7 +880,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
const item = target.getItem();
if (this.runEvent('TakeItem', target, source, move, item)) {
target.itemState.knockedOff = true;
this.add('-enditem', target, item.name, '[from] move: Knock Off', '[of] ' + source);
this.add('-enditem', target, item.name, '[from] move: Knock Off', `[of] ${source}`);
this.hint("In Gens 3-4, Knock Off only makes the target's item unusable; it cannot obtain a new item.", true);
}
},
@ -1255,7 +1255,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
onResidualOrder: 12,
onResidual(pokemon) {
const duration = pokemon.volatiles['perishsong'].duration;
this.add('-start', pokemon, 'perish' + duration);
this.add('-start', pokemon, `perish${duration}`);
},
},
},
@ -1335,12 +1335,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
self: {
onHit(pokemon) {
if (pokemon.removeVolatile('leechseed')) {
this.add('-end', pokemon, 'Leech Seed', '[from] move: Rapid Spin', '[of] ' + pokemon);
this.add('-end', pokemon, 'Leech Seed', '[from] move: Rapid Spin', `[of] ${pokemon}`);
}
const sideConditions = ['spikes', 'toxicspikes', 'stealthrock', 'stickyweb'];
for (const condition of sideConditions) {
if (pokemon.side.removeSideCondition(condition)) {
this.add('-sideend', pokemon.side, this.dex.conditions.get(condition).name, '[from] move: Rapid Spin', '[of] ' + pokemon);
this.add('-sideend', pokemon.side, this.dex.conditions.get(condition).name, '[from] move: Rapid Spin', `[of] ${pokemon}`);
}
}
if (pokemon.volatiles['partiallytrapped']) {
@ -1399,7 +1399,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
} else {
bp = 20;
}
this.debug('BP: ' + bp);
this.debug(`BP: ${bp}`);
return bp;
},
},
@ -1544,7 +1544,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
return;
}
snatchUser.removeVolatile('snatch');
this.add('-activate', snatchUser, 'move: Snatch', '[of] ' + source);
this.add('-activate', snatchUser, 'move: Snatch', `[of] ${source}`);
this.actions.useMove(move.id, snatchUser);
return null;
},
@ -1590,7 +1590,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
onEntryHazard(pokemon) {
if (pokemon.hasItem('heavydutyboots')) return;
const typeMod = this.clampIntRange(pokemon.runEffectiveness(this.dex.getActiveMove('stealthrock')), -6, 6);
this.damage(pokemon.maxhp * Math.pow(2, typeMod) / 8);
this.damage(pokemon.maxhp * 2 ** typeMod / 8);
},
},
},
@ -1788,10 +1788,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
onEntryHazard(pokemon) {
if (!pokemon.isGrounded()) return;
if (pokemon.hasType('Poison')) {
this.add('-sideend', pokemon.side, 'move: Toxic Spikes', '[of] ' + pokemon);
this.add('-sideend', pokemon.side, 'move: Toxic Spikes', `[of] ${pokemon}`);
pokemon.side.removeSideCondition('toxicspikes');
} else if (pokemon.volatiles['substitute'] || pokemon.hasType('Steel')) {
return;
// do nothing
} else if (this.effectState.layers >= 2) {
pokemon.trySetStatus('tox', pokemon.side.foe.active[0]);
} else {
@ -1823,9 +1823,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
onFieldStart(target, source) {
if (source?.hasAbility('persistent')) {
this.add('-fieldstart', 'move: Trick Room', '[of] ' + source, '[persistent]');
this.add('-fieldstart', 'move: Trick Room', `[of] ${source}`, '[persistent]');
} else {
this.add('-fieldstart', 'move: Trick Room', '[of] ' + source);
this.add('-fieldstart', 'move: Trick Room', `[of] ${source}`);
}
},
onFieldRestart(target, source) {
@ -1941,7 +1941,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
basePowerCallback(pokemon, target) {
const bp = Math.floor(target.hp * 120 / target.maxhp) + 1;
this.debug('BP for ' + target.hp + '/' + target.maxhp + " HP: " + bp);
this.debug(`BP for ${target.hp}/${target.maxhp} HP: ${bp}`);
return bp;
},
},
@ -1951,7 +1951,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
noCopy: true, // doesn't get copied by Baton Pass
duration: 2,
onStart(target, source) {
this.add('-start', target, 'move: Yawn', '[of] ' + source);
this.add('-start', target, 'move: Yawn', `[of] ${source}`);
},
onResidualOrder: 10,
onResidualSubOrder: 19,

View File

@ -48,7 +48,7 @@ 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);
}

View File

@ -21,7 +21,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
onStart(pokemon) {
const target = pokemon.side.randomFoe();
if (target?.item) {
this.add('-item', '', target.getItem().name, '[from] ability: Frisk', '[of] ' + pokemon);
this.add('-item', '', target.getItem().name, '[from] ability: Frisk', `[of] ${pokemon}`);
}
},
},

View File

@ -8,7 +8,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
partiallytrapped: {
inherit: true,
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') ? 8 : 16;
},
onResidual(pokemon) {
@ -34,7 +34,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
if (counter >= 256) {
return this.randomChance(1, 2 ** 32);
}
this.debug("Success chance: " + Math.round(100 / counter) + "%");
this.debug(`Success chance: ${Math.round(100 / counter)}%`);
return this.randomChance(1, counter);
},
onRestart() {

View File

@ -164,7 +164,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
const sideConditions = ['reflect', 'lightscreen', 'safeguard', 'mist', 'spikes', 'toxicspikes', 'stealthrock'];
for (const condition of sideConditions) {
if (pokemon.side.removeSideCondition(condition)) {
this.add('-sideend', pokemon.side, this.dex.conditions.get(condition).name, '[from] move: Defog', '[of] ' + pokemon);
this.add('-sideend', pokemon.side, this.dex.conditions.get(condition).name, '[from] move: Defog', `[of] ${pokemon}`);
}
}
},
@ -202,7 +202,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
basePowerCallback(pokemon, target) {
const ratio = Math.floor(pokemon.getStat('spe') / Math.max(1, target.getStat('spe')));
const bp = [40, 60, 80, 120, 150][Math.min(ratio, 4)];
this.debug('BP: ' + bp);
this.debug(`BP: ${bp}`);
return bp;
},
},
@ -277,7 +277,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
Object.assign(target.side.slotConditions[target.position]['futuremove'], {
duration: 3,
move: 'futuresight',
source: source,
source,
moveData: {
id: 'futuresight',
name: "Future Sight",
@ -335,7 +335,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
basePowerCallback(pokemon, target) {
let power = Math.floor(25 * target.getStat('spe') / Math.max(1, pokemon.getStat('spe'))) + 1;
if (power > 150) power = 150;
this.debug('BP: ' + power);
this.debug(`BP: ${power}`);
return power;
},
},
@ -368,7 +368,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
basePower: 0,
basePowerCallback(pokemon) {
const bp = pokemon.hpPower || 70;
this.debug('BP: ' + bp);
this.debug(`BP: ${bp}`);
return bp;
},
},
@ -793,7 +793,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
if (targetAbility === sourceAbility) {
return false;
}
this.add('-activate', source, 'move: Skill Swap', this.dex.abilities.get(targetAbility), this.dex.abilities.get(sourceAbility), '[of] ' + target);
this.add('-activate', source, 'move: Skill Swap', this.dex.abilities.get(targetAbility), this.dex.abilities.get(sourceAbility), `[of] ${target}`);
source.setAbility(targetAbility);
target.setAbility(sourceAbility);
},

View File

@ -32,7 +32,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
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.damage(damage, null, null, null, true);
@ -108,7 +108,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
source.item = myItem.id;
return;
}
this.add('-activate', source, 'ability: Symbiosis', myItem, '[of] ' + pokemon);
this.add('-activate', source, 'ability: Symbiosis', myItem, `[of] ${pokemon}`);
},
},
weakarmor: {

View File

@ -151,7 +151,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
onFieldStart(field, source, effect) {
if (effect?.effectType === 'Ability') {
this.add('-fieldstart', 'move: Misty Terrain', '[from] ability: ' + effect, '[of] ' + source);
this.add('-fieldstart', 'move: Misty Terrain', `[from] ability: ${effect}`, `[of] ${source}`);
} else {
this.add('-fieldstart', 'move: Misty Terrain');
}

View File

@ -134,13 +134,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
for (const targetCondition of removeTarget) {
if (target.side.removeSideCondition(targetCondition)) {
if (!removeAll.includes(targetCondition)) continue;
this.add('-sideend', target.side, this.dex.conditions.get(targetCondition).name, '[from] move: Defog', '[of] ' + source);
this.add('-sideend', target.side, this.dex.conditions.get(targetCondition).name, '[from] move: Defog', `[of] ${source}`);
success = true;
}
}
for (const sideCondition of removeAll) {
if (source.side.removeSideCondition(sideCondition)) {
this.add('-sideend', source.side, this.dex.conditions.get(sideCondition).name, '[from] move: Defog', '[of] ' + source);
this.add('-sideend', source.side, this.dex.conditions.get(sideCondition).name, '[from] move: Defog', `[of] ${source}`);
success = true;
}
}
@ -214,7 +214,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
onFieldStart(field, source, effect) {
if (effect && effect.effectType === 'Ability') {
this.add('-fieldstart', 'move: Electric Terrain', '[from] ability: ' + effect, '[of] ' + source);
this.add('-fieldstart', 'move: Electric Terrain', `[from] ability: ${effect}`, `[of] ${source}`);
} else {
this.add('-fieldstart', 'move: Electric Terrain');
}
@ -337,7 +337,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
onFieldStart(field, source, effect) {
if (effect && effect.effectType === 'Ability') {
this.add('-fieldstart', 'move: Grassy Terrain', '[from] ability: ' + effect, '[of] ' + source);
this.add('-fieldstart', 'move: Grassy Terrain', `[from] ability: ${effect}`, `[of] ${source}`);
} else {
this.add('-fieldstart', 'move: Grassy Terrain');
}
@ -813,7 +813,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
onFieldStart(field, source, effect) {
if (effect && effect.effectType === 'Ability') {
this.add('-fieldstart', 'move: Psychic Terrain', '[from] ability: ' + effect, '[of] ' + source);
this.add('-fieldstart', 'move: Psychic Terrain', `[from] ability: ${effect}`, `[of] ${source}`);
} else {
this.add('-fieldstart', 'move: Psychic Terrain');
}
@ -1072,7 +1072,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
if (myItem) source.item = myItem.id;
return false;
}
this.add('-activate', source, 'move: Trick', '[of] ' + target);
this.add('-activate', source, 'move: Trick', `[of] ${target}`);
if (myItem) {
target.setItem(myItem);
this.add('-item', target, myItem, '[from] move: Switcheroo');
@ -1172,7 +1172,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
if (myItem) source.item = myItem.id;
return false;
}
this.add('-activate', source, 'move: Trick', '[of] ' + target);
this.add('-activate', source, 'move: Trick', `[of] ${target}`);
if (myItem) {
target.setItem(myItem);
this.add('-item', target, myItem, '[from] move: Trick');

View File

@ -10,7 +10,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
if (this.checkMoveMakesContact(move, source, target, !source.isAlly(target))) {
const oldAbility = source.setAbility('mummy', target);
if (oldAbility) {
this.add('-activate', target, 'ability: Mummy', this.dex.abilities.get(oldAbility).name, '[of] ' + source);
this.add('-activate', target, 'ability: Mummy', this.dex.abilities.get(oldAbility).name, `[of] ${source}`);
}
}
} else {
@ -22,13 +22,13 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
if (abil === source.ability) {
const oldAbility = source.setAbility('mummy', target);
if (oldAbility) {
this.add('-activate', target, 'ability: Mummy', this.dex.abilities.get(oldAbility).name, '[of] ' + source);
this.add('-activate', target, 'ability: Mummy', this.dex.abilities.get(oldAbility).name, `[of] ${source}`);
}
} else {
source.removeVolatile('ability:' + abil);
source.addVolatile('ability:mummy', source);
if (abil) {
this.add('-activate', target, 'ability: Mummy', this.dex.abilities.get(abil).name, '[of] ' + source);
this.add('-activate', target, 'ability: Mummy', this.dex.abilities.get(abil).name, `[of] ${source}`);
}
}
}
@ -48,12 +48,12 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
.filter(val => !this.dex.abilities.get(val).flags['noreceiver'] && !additionalBannedAbilities.includes(val));
if (!possibleAbilities.length) return;
const ability = this.dex.abilities.get(possibleAbilities[this.random(possibleAbilities.length)]);
this.add('-ability', pokemon, ability, '[from] ability: Power of Alchemy', '[of] ' + ally);
this.add('-ability', pokemon, ability, '[from] ability: Power of Alchemy', `[of] ${ally}`);
if (isAbility) {
pokemon.setAbility(ability);
} else {
pokemon.removeVolatile("ability:powerofalchemy");
pokemon.addVolatile("ability:" + ability, pokemon);
pokemon.addVolatile(`ability:${ability}`, pokemon);
}
},
},
@ -70,12 +70,12 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
.filter(val => !this.dex.abilities.get(val).flags['noreceiver'] && !additionalBannedAbilities.includes(val));
if (!possibleAbilities.length) return;
const ability = this.dex.abilities.get(possibleAbilities[this.random(possibleAbilities.length)]);
this.add('-ability', pokemon, ability, '[from] ability: Receiver', '[of] ' + ally);
this.add('-ability', pokemon, ability, '[from] ability: Receiver', `[of] ${ally}`);
if (isAbility) {
pokemon.setAbility(ability);
} else {
pokemon.removeVolatile("ability:receiver");
pokemon.addVolatile("ability:" + ability, pokemon);
pokemon.addVolatile(`ability:${ability}`, pokemon);
}
},
},
@ -103,12 +103,12 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
continue;
}
const ability = this.dex.abilities.get(this.sample(possibleAbilities));
this.add('-ability', pokemon, ability, '[from] ability: Trace', '[of] ' + target);
this.add('-ability', pokemon, ability, '[from] ability: Trace', `[of] ${target}`);
if (isAbility) {
pokemon.setAbility(ability);
} else {
pokemon.removeVolatile("ability:trace");
pokemon.addVolatile("ability:" + ability, pokemon);
pokemon.addVolatile(`ability:${ability}`, pokemon);
}
return;
}

View File

@ -114,7 +114,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
onModifyMove(move, source, target) {
if (!source.hasType('Ghost')) {
move.target = move.nonGhostTarget as MoveTarget;
move.target = move.nonGhostTarget!;
}
},
target: "randomNormal",

View File

@ -2,7 +2,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
pursuit: {
inherit: true,
beforeTurnCallback(pokemon, target) {
// @ts-ignore
// @ts-expect-error modded
const linkedMoves: [string, string] = pokemon.getLinkedMoves();
if (linkedMoves.length) {
if (linkedMoves[0] !== 'pursuit' && linkedMoves[1] === 'pursuit') return;
@ -21,7 +21,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
const action = this.queue.willMove(target);
if (action) {
// Mod-specific: Me First copies the first move in the link
// @ts-ignore
// @ts-expect-error modded
const move = this.dex.getActiveMove(action.linked?.[0] || action.move);
if (move.category !== 'Status' && !move.flags['failmefirst']) {
pokemon.addVolatile('mefirst');
@ -50,7 +50,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.add('-fail', source);
return null;
}
// @ts-ignore
// @ts-expect-error modded
if (!action.linked) {
if (action.move.category === 'Status' && action.move.id !== 'mefirst') {
this.attrLastMove('[still]');
@ -58,7 +58,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
return null;
}
} else {
// @ts-ignore
// @ts-expect-error modded
for (const linkedMove of action.linked) {
if (linkedMove.category !== 'Status' || linkedMove.id === 'mefirst') return;
}
@ -132,7 +132,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
) {
return false;
}
this.add('-singleturn', target, 'move: Instruct', '[of] ' + source);
this.add('-singleturn', target, 'move: Instruct', `[of] ${source}`);
this.actions.runMove(lastMove.id, target, target.lastMoveTargetLoc!);
},
},
@ -140,7 +140,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
onTryHit(target, pokemon) {
const move: Move | ActiveMove | null = target.m.lastMoveAbsolute;
if (!move || !move.flags['mirror'] || move.isZ || move.isMax) {
if (!move?.flags['mirror'] || move.isZ || move.isMax) {
return false;
}
this.actions.useMove(move.id, pokemon, { target });
@ -173,7 +173,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
return false;
} else {
if (effect.id === 'cursedbody') {
this.add('-start', pokemon, 'Disable', moveSlot.move, '[from] ability: Cursed Body', '[of] ' + source);
this.add('-start', pokemon, 'Disable', moveSlot.move, '[from] ability: Cursed Body', `[of] ${source}`);
} else {
this.add('-start', pokemon, 'Disable', moveSlot.move);
}
@ -213,7 +213,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
let lastMove: Move | ActiveMove | null = target.m.lastMoveAbsolute;
if (!lastMove || target.volatiles['dynamax']) return false;
if ((lastMove as ActiveMove).isZOrMaxPowered) lastMove = this.dex.moves.get(lastMove.baseMove);
// @ts-ignore
// @ts-expect-error modded
const linkedMoves: [string, string] = target.getLinkedMoves(true);
const moveIndex = target.moves.indexOf(lastMove.id);
if (linkedMoves.includes(lastMove.id) && this.dex.moves.get((linkedMoves[0])).flags['failencore'] &&
@ -273,7 +273,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
const index = target.moves.indexOf(lastMove.id);
if (index === -1) return; // no last move
// @ts-ignore
// @ts-expect-error modded
if (target.hasLinkedMove(lastMove.id)) {
// TODO: Check instead whether the last executed move was linked
if (target.moveSlots[0].pp <= 0 || target.moveSlots[1].pp <= 0) {

View File

@ -99,16 +99,16 @@ export const Scripts: ModdedBattleScriptsData = {
if (!action.pokemon.isActive) return false;
if (action.pokemon.fainted) return false;
// Linked moves
// @ts-ignore
// @ts-expect-error modded
if (action.linked) {
// @ts-ignore
// @ts-expect-error modded
const linkedMoves: ActiveMove[] = action.linked;
for (let i = linkedMoves.length - 1; i >= 0; i--) {
const validTarget = this.validTargetLoc(action.targetLoc, action.pokemon, linkedMoves[i].target);
const targetLoc = validTarget ? action.targetLoc : 0;
const pseudoAction: Action = {
choice: 'move', priority: action.priority, speed: action.speed, pokemon: action.pokemon,
targetLoc: targetLoc, moveid: linkedMoves[i].id, move: linkedMoves[i], mega: action.mega,
targetLoc, moveid: linkedMoves[i].id, move: linkedMoves[i], mega: action.mega,
order: action.order, fractionalPriority: action.fractionalPriority, originalTarget: action.originalTarget,
};
this.queue.unshift(pseudoAction);
@ -482,9 +482,11 @@ export const Scripts: ModdedBattleScriptsData = {
}
action.fractionalPriority = this.battle.runEvent('FractionalPriority', action.pokemon, null, action.move, 0);
const linkedMoves: [string, string] = action.pokemon.getLinkedMoves();
if (linkedMoves.length &&
if (
linkedMoves.length &&
!(action.pokemon.getItem().isChoice || action.pokemon.hasAbility('gorillatactics')) &&
!action.zmove && !action.maxMove) {
!action.zmove && !action.maxMove
) {
const decisionMove = this.battle.toID(action.move);
if (linkedMoves.includes(decisionMove)) {
action.linked = linkedMoves.map(moveid => this.battle.dex.getActiveMove(moveid));
@ -543,7 +545,7 @@ export const Scripts: ModdedBattleScriptsData = {
return ret;
},
hasLinkedMove(moveid) {
// @ts-ignore
// @ts-expect-error modded
const linkedMoves: ID[] = this.getLinkedMoves(true);
if (!linkedMoves.length) return false;
return linkedMoves.some(x => x === moveid);

View File

@ -116,7 +116,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
onTryBoost(boost, target, source, effect) {
if (effect.name === 'Intimidate' && boost.atk) {
delete boost.atk;
this.add('-fail', target, 'unboost', 'Attack', '[from] ability: Paw Prints', '[of] ' + target);
this.add('-fail', target, 'unboost', 'Attack', '[from] ability: Paw Prints', `[of] ${target}`);
}
},
onModifyMove(move) {
@ -134,7 +134,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
onBasePowerPriority: 30,
onBasePower(basePower, attacker, defender, move) {
const basePowerAfterMultiplier = this.modify(basePower, this.event.modifier);
this.debug('Base Power: ' + basePowerAfterMultiplier);
this.debug(`Base Power: ${basePowerAfterMultiplier}`);
if (basePowerAfterMultiplier <= 60) {
this.debug('Confirmed Town boost');
return this.chainModify(1.5);
@ -360,7 +360,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
}
}
if (showMsg && !(effect as ActiveMove).secondaries && effect.id !== 'octolock') {
this.add("-fail", target, "unboost", "[from] ability: Supervised Learning", "[of] " + target);
this.add("-fail", target, "unboost", "[from] ability: Supervised Learning", `[of] ${target}`);
}
},
flags: {},
@ -762,7 +762,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
for (const ally of pokemon.side.pokemon) {
if (!ally.hp || ally === pokemon) continue;
if (ally.heal(this.modify(ally.baseMaxhp, pokemon.hp > pokemon.maxhp / 4 ? 0.05 : 0.1))) {
this.add('-heal', ally, ally.getHealth, '[from] ability: Coalescence', '[of] ' + pokemon);
this.add('-heal', ally, ally.getHealth, '[from] ability: Coalescence', `[of] ${pokemon}`);
}
}
},
@ -879,8 +879,8 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
const finalGambit = {
move: move.name,
id: move.id,
pp: (move.noPPBoosts || move.isZ) ? move.pp : move.pp * 8 / 5,
maxpp: (move.noPPBoosts || move.isZ) ? move.pp : move.pp * 8 / 5,
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,
@ -1164,7 +1164,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
];
for (const sideCondition of remove) {
if (side.removeSideCondition(sideCondition)) {
this.add('-sideend', side, this.dex.conditions.get(sideCondition).name, '[from] ability: Anfield', '[of] ' + target);
this.add('-sideend', side, this.dex.conditions.get(sideCondition).name, '[from] ability: Anfield', `[of] ${target}`);
}
}
}
@ -1321,12 +1321,12 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
const displayText = ['spikes', 'toxicspikes', 'stealthrock', 'stickyweb', 'gmaxsteelsurge'];
for (const targetCondition of Object.keys(target.sideConditions)) {
if (target.removeSideCondition(targetCondition) && displayText.includes(targetCondition)) {
this.add('-sideend', target, this.dex.conditions.get(targetCondition).name, '[from] ability: Idealized World', '[of] ' + pokemon);
this.add('-sideend', target, this.dex.conditions.get(targetCondition).name, '[from] ability: Idealized World', `[of] ${pokemon}`);
}
}
for (const sideCondition of Object.keys(pokemon.side.sideConditions)) {
if (pokemon.side.removeSideCondition(sideCondition) && displayText.includes(sideCondition)) {
this.add('-sideend', pokemon.side, this.dex.conditions.get(sideCondition).name, '[from] ability: Idealized World', '[of] ' + pokemon);
this.add('-sideend', pokemon.side, this.dex.conditions.get(sideCondition).name, '[from] ability: Idealized World', `[of] ${pokemon}`);
}
}
this.field.clearTerrain();
@ -1470,7 +1470,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
];
for (const sideCondition of remove) {
if (side.removeSideCondition(sideCondition)) {
this.add('-sideend', side, this.dex.conditions.get(sideCondition).name, '[from] ability: End Round', '[of] ' + pokemon);
this.add('-sideend', side, this.dex.conditions.get(sideCondition).name, '[from] ability: End Round', `[of] ${pokemon}`);
}
}
}
@ -1505,7 +1505,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
}
}
mon.clearBoosts();
this.add('-clearboost', mon, '[from] ability: End Round', '[of] ' + pokemon);
this.add('-clearboost', mon, '[from] ability: End Round', `[of] ${pokemon}`);
}
},
flags: { cantsuppress: 1 },
@ -1697,9 +1697,9 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
const sourceAbility = source.setAbility('drifting', target);
if (!sourceAbility) return;
if (target.isAlly(source)) {
this.add('-activate', target, 'Skill Swap', '', '', '[of] ' + source);
this.add('-activate', target, 'Skill Swap', '', '', `[of] ${source}`);
} else {
this.add('-activate', target, 'ability: Drifting', this.dex.abilities.get(sourceAbility).name, 'Drifting', '[of] ' + source);
this.add('-activate', target, 'ability: Drifting', this.dex.abilities.get(sourceAbility).name, 'Drifting', `[of] ${source}`);
}
target.setAbility(sourceAbility);
}
@ -2037,7 +2037,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
const target = this.sample(possibleTargets);
const ability = target.getAbility();
if (pokemon.setAbility(ability)) {
this.add('-ability', pokemon, ability, '[from] ability: Monke See Monke Do', '[of] ' + target);
this.add('-ability', pokemon, ability, '[from] ability: Monke See Monke Do', `[of] ${target}`);
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1 },
@ -2250,7 +2250,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
shortDesc: "Every turn, raises a random stat by 1 stage if the foe has more raised stats.",
name: "Adaptive Engineering",
onResidual(source) {
if (source === undefined || source.foes() === undefined || source.foes()[0] === undefined) return;
if (source?.foes()?.[0] === undefined) return;
if (source.positiveBoosts() < source.foes()[0].positiveBoosts()) {
const stats: BoostID[] = [];
let stat: BoostID;
@ -2338,7 +2338,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
if (target.lastMove && target.lastMove.id !== 'struggle') {
if (move.id === target.lastMove.id) {
this.attrLastMove('[still]');
this.add('cant', target, 'ability: Overasked Clause', move, '[of] ' + source);
this.add('cant', target, 'ability: Overasked Clause', move, `[of] ${source}`);
return false;
}
}
@ -2406,7 +2406,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
const dazzlingHolder = this.effectState.target;
if ((source.isAlly(dazzlingHolder) || move.target === 'all') && move.priority > 0.1) {
this.attrLastMove('[still]');
this.add('cant', target, 'ability: Sand Sleuth', move, '[of] ' + source);
this.add('cant', target, 'ability: Sand Sleuth', move, `[of] ${source}`);
return false;
}
}

View File

@ -1,6 +1,6 @@
import { ssbSets } from "./random-teams";
import { changeSet, getName, enemyStaff } from './scripts';
import {ModdedConditionData} from "../../../sim/dex-conditions";
import type { ModdedConditionData } from "../../../sim/dex-conditions";
export const Conditions: { [id: IDEntry]: ModdedConditionData & { innateName?: string } } = {
/*
@ -619,7 +619,7 @@ export const Conditions: {[id: IDEntry]: ModdedConditionData & {innateName?: str
if (target.illusion) return;
if (effect.name === 'Intimidate' && boost.atk) {
delete boost.atk;
this.add('-fail', target, 'unboost', 'Attack', '[from] ability: Oblivious', '[of] ' + target);
this.add('-fail', target, 'unboost', 'Attack', '[from] ability: Oblivious', `[of] ${target}`);
}
},
},
@ -3069,7 +3069,7 @@ export const Conditions: {[id: IDEntry]: ModdedConditionData & {innateName?: str
onFieldStart(battle, source, effect) {
if (effect?.effectType === 'Ability') {
if (this.gen <= 5) this.effectState.duration = 0;
this.add('-weather', 'StormSurge', '[from] ability: ' + effect.name, '[of] ' + source);
this.add('-weather', 'StormSurge', '[from] ability: ' + effect.name, `[of] ${source}`);
} else {
this.add('-weather', 'StormSurge');
}
@ -3107,7 +3107,7 @@ export const Conditions: {[id: IDEntry]: ModdedConditionData & {innateName?: str
}
},
onFieldStart(field, source, effect) {
this.add('-weather', 'DesertedDunes', '[from] ability: ' + effect.name, '[of] ' + source);
this.add('-weather', 'DesertedDunes', '[from] ability: ' + effect.name, `[of] ${source}`);
},
onFieldResidualOrder: 1,
onFieldResidual() {
@ -3179,16 +3179,16 @@ export const Conditions: {[id: IDEntry]: ModdedConditionData & {innateName?: str
}
if (effect.name === 'Cute Charm') {
this.add('-start', pokemon, 'Attract', '[from] ability: Cute Charm', '[of] ' + source);
this.add('-start', pokemon, 'Attract', '[from] ability: Cute Charm', `[of] ${source}`);
} else if (effect.name === 'Destiny Knot') {
this.add('-start', pokemon, 'Attract', '[from] item: Destiny Knot', '[of] ' + source);
this.add('-start', pokemon, 'Attract', '[from] item: Destiny Knot', `[of] ${source}`);
} else {
this.add('-start', pokemon, 'Attract');
}
},
onUpdate(pokemon) {
if (this.effectState.source && !this.effectState.source.isActive && pokemon.volatiles['attract']) {
this.debug('Removing Attract volatile on ' + pokemon);
this.debug(`Removing Attract volatile on ${pokemon}`);
pokemon.removeVolatile('attract');
}
},

View File

@ -835,7 +835,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
} else if (chance <= 70) {
for (const condition of sideConditions) {
if (source.side.removeSideCondition(condition)) {
this.add('-sideend', source.side, this.dex.conditions.get(condition).name, '[from] move: Sigil\'s Storm', '[of] ' + source);
this.add('-sideend', source.side, this.dex.conditions.get(condition).name, '[from] move: Sigil\'s Storm', `[of] ${source}`);
}
}
} else if (chance <= 80) {
@ -2444,7 +2444,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
type: "Dark",
},
// HoeenHero
reprogram: {
accuracy: 100,
@ -2470,7 +2469,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
if (source.addVolatile('lockon', target)) {
this.add('-message', 'HoeenHero double checked their work and fixed any errors!');
this.add('-activate', source, 'move: Lock-On', '[of] ' + target);
this.add('-activate', source, 'move: Lock-On', `[of] ${target}`);
success = true;
}
if (success) {
@ -2732,7 +2731,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.addMove('-anim', target, 'Wish', target);
target.clearBoosts();
this.add('-clearboost', target);
// @ts-ignore set wants a sig but randbats sets don't have one
// @ts-expect-error set wants a sig but randbats sets don't have one
changeSet(this, target, team[0], true);
this.add(`c:|${getName((source.illusion || source).name)}|${msg}`);
},
@ -2933,7 +2932,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
for (const condition of sideConditions) {
if (source.side.removeSideCondition(condition)) {
success = true;
this.add('-sideend', source.side, this.dex.conditions.get(condition).name, '[from] move: , (ac)', '[of] ' + source);
this.add('-sideend', source.side, this.dex.conditions.get(condition).name, '[from] move: , (ac)', `[of] ${source}`);
}
}
} else if (effect < 95) {
@ -3040,9 +3039,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
onFieldStart(target, source) {
if (source?.hasAbility('persistent')) {
this.add('-fieldstart', 'move: Anfield Atmosphere', '[of] ' + source, '[persistent]');
this.add('-fieldstart', 'move: Anfield Atmosphere', `[of] ${source}`, '[persistent]');
} else {
this.add('-fieldstart', 'move: Anfield Atmosphere', '[of] ' + source);
this.add('-fieldstart', 'move: Anfield Atmosphere', `[of] ${source}`);
}
for (const pokemon of this.getAllActive()) {
if (pokemon.volatiles['confusion']) {
@ -3430,7 +3429,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
basePower: 30,
basePowerCallback(pokemon, target, move) {
const bp = move.basePower + 20 * pokemon.positiveBoosts();
this.debug('BP: ' + bp);
this.debug(`BP: ${bp}`);
return bp;
},
category: "Special",
@ -3754,7 +3753,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
const sideConditions = ['spikes', 'toxicspikes', 'stealthrock', 'stickyweb', 'gmaxsteelsurge'];
for (const condition of sideConditions) {
if (pokemon.side.removeSideCondition(condition)) {
this.add('-sideend', pokemon.side, this.dex.conditions.get(condition).name, '[from] move: Time Skip', '[of] ' + pokemon);
this.add('-sideend', pokemon.side, this.dex.conditions.get(condition).name, '[from] move: Time Skip', `[of] ${pokemon}`);
}
}
// 9 turn addition so the +1 from endTurn totals to 10 turns
@ -4596,7 +4595,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
if (player.removeSideCondition(targetCondition)) {
success = true;
if (displayText.includes(targetCondition)) {
this.add('-sideend', player, this.dex.conditions.get(targetCondition).name, '[from] move: Magic Trick', '[of] ' + source);
this.add('-sideend', player, this.dex.conditions.get(targetCondition).name, '[from] move: Magic Trick', `[of] ${source}`);
}
}
}
@ -4939,13 +4938,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
for (const targetCondition of removeTarget) {
if (targetSide.removeSideCondition(targetCondition)) {
if (!removeAll.includes(targetCondition)) continue;
this.add('-sideend', targetSide, this.dex.conditions.get(targetCondition).name, '[from] move: Treacherous Traversal', '[of] ' + source);
this.add('-sideend', targetSide, this.dex.conditions.get(targetCondition).name, '[from] move: Treacherous Traversal', `[of] ${source}`);
success = true;
}
}
for (const sideCondition of removeAll) {
if (source.side.removeSideCondition(sideCondition)) {
this.add('-sideend', source.side, this.dex.conditions.get(sideCondition).name, '[from] move: Treacherous Traversal', '[of] ' + source);
this.add('-sideend', source.side, this.dex.conditions.get(sideCondition).name, '[from] move: Treacherous Traversal', `[of] ${source}`);
success = true;
}
}
@ -5021,7 +5020,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
if (source.hp) {
const item = target.takeItem();
if (item) {
this.add('-enditem', target, item.name, '[from] move: Grass Gaming', '[of] ' + source);
this.add('-enditem', target, item.name, '[from] move: Grass Gaming', `[of] ${source}`);
}
}
},
@ -5093,12 +5092,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
onAfterHit(target, pokemon) {
if (pokemon.hp && pokemon.removeVolatile('leechseed')) {
this.add('-end', pokemon, 'Leech Seed', '[from] move: Concept Relevant', '[of] ' + pokemon);
this.add('-end', pokemon, 'Leech Seed', '[from] move: Concept Relevant', `[of] ${pokemon}`);
}
const sideConditions = ['spikes', 'toxicspikes', 'stealthrock', 'stickyweb', 'gmaxsteelsurge'];
for (const condition of sideConditions) {
if (pokemon.hp && pokemon.side.removeSideCondition(condition)) {
this.add('-sideend', pokemon.side, this.dex.conditions.get(condition).name, '[from] move: Concept Relevant', '[of] ' + pokemon);
this.add('-sideend', pokemon.side, this.dex.conditions.get(condition).name, '[from] move: Concept Relevant', `[of] ${pokemon}`);
}
}
if (pokemon.hp && pokemon.volatiles['partiallytrapped']) {
@ -5121,12 +5120,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
onAfterSubDamage(damage, target, pokemon) {
if (pokemon.hp && pokemon.removeVolatile('leechseed')) {
this.add('-end', pokemon, 'Leech Seed', '[from] move: Concept Relevant', '[of] ' + pokemon);
this.add('-end', pokemon, 'Leech Seed', '[from] move: Concept Relevant', `[of] ${pokemon}`);
}
const sideConditions = ['spikes', 'toxicspikes', 'stealthrock', 'stickyweb', 'gmaxsteelsurge'];
for (const condition of sideConditions) {
if (pokemon.hp && pokemon.side.removeSideCondition(condition)) {
this.add('-sideend', pokemon.side, this.dex.conditions.get(condition).name, '[from] move: Concept Relevant', '[of] ' + pokemon);
this.add('-sideend', pokemon.side, this.dex.conditions.get(condition).name, '[from] move: Concept Relevant', `[of] ${pokemon}`);
}
}
if (pokemon.hp && pokemon.volatiles['partiallytrapped']) {
@ -5570,13 +5569,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
for (const targetCondition of removeTarget) {
if (target.side.removeSideCondition(targetCondition)) {
if (!removeAll.includes(targetCondition)) continue;
this.add('-sideend', target.side, this.dex.conditions.get(targetCondition).name, '[from] move: Eternal Wish', '[of] ' + source);
this.add('-sideend', target.side, this.dex.conditions.get(targetCondition).name, '[from] move: Eternal Wish', `[of] ${source}`);
success = true;
}
}
for (const sideCondition of removeAll) {
if (source.side.removeSideCondition(sideCondition)) {
this.add('-sideend', source.side, this.dex.conditions.get(sideCondition).name, '[from] move: Eternal Wish', '[of] ' + source);
this.add('-sideend', source.side, this.dex.conditions.get(sideCondition).name, '[from] move: Eternal Wish', `[of] ${source}`);
success = true;
}
}
@ -5751,7 +5750,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
type: "???",
},
// UT
myboys: {
accuracy: 100,
@ -5851,13 +5849,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
for (const targetCondition of removeTarget) {
if (target.side.removeSideCondition(targetCondition)) {
if (!removeAll.includes(targetCondition)) continue;
this.add('-sideend', target.side, this.dex.conditions.get(targetCondition).name, '[from] move: Your Crippling Interest', '[of] ' + source);
this.add('-sideend', target.side, this.dex.conditions.get(targetCondition).name, '[from] move: Your Crippling Interest', `[of] ${source}`);
success = true;
}
}
for (const sideCondition of removeAll) {
if (source.side.removeSideCondition(sideCondition)) {
this.add('-sideend', source.side, this.dex.conditions.get(sideCondition).name, '[from] move: Your Crippling Interest', '[of] ' + source);
this.add('-sideend', source.side, this.dex.conditions.get(sideCondition).name, '[from] move: Your Crippling Interest', `[of] ${source}`);
success = true;
}
}
@ -6201,7 +6199,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
if (!target.hasItem('Miracle Seed')) {
const item = target.takeItem();
if (item) {
this.add('-enditem', target, item.name, '[from] move: top kek', '[of] ' + source);
this.add('-enditem', target, item.name, '[from] move: top kek', `[of] ${source}`);
target.setItem('Miracle Seed', source, move);
}
}
@ -6638,7 +6636,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
onFieldStart(field, source, effect) {
if (effect?.effectType === 'Ability') {
this.add('-fieldstart', 'move: Misty Terrain', '[from] ability: ' + effect.name, '[of] ' + source);
this.add('-fieldstart', 'move: Misty Terrain', '[from] ability: ' + effect.name, `[of] ${source}`);
} else {
this.add('-fieldstart', 'move: Misty Terrain');
}
@ -6755,7 +6753,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
onFieldStart(field, source, effect) {
if (effect?.effectType === 'Ability') {
this.add('-fieldstart', 'move: Psychic Terrain', '[from] ability: ' + effect.name, '[of] ' + source);
this.add('-fieldstart', 'move: Psychic Terrain', '[from] ability: ' + effect.name, `[of] ${source}`);
} else {
this.add('-fieldstart', 'move: Psychic Terrain');
}
@ -6777,7 +6775,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
return null;
}
if (source.hasAbility(['insomnia', 'vitalspirit'])) {
this.add('-fail', source, '[from] ability: ' + source.getAbility().name, '[of] ' + source);
this.add('-fail', source, '[from] ability: ' + source.getAbility().name, `[of] ${source}`);
return null;
}
},
@ -6940,7 +6938,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
move.basePower *= 2;
break;
}
this.debug('BP: ' + move.basePower);
this.debug(`BP: ${move.basePower}`);
},
},
wildboltstorm: {

View File

@ -243,7 +243,7 @@ export const ssbSets: SSBSets = {
'Snatch', 'Heal Order', 'Parting Shot', 'Population Bomb', 'Metronome',
],
signatureMove: 'Role System',
// eslint-disable-next-line max-len
// eslint-disable-next-line @stylistic/max-len
evs: { hp: 85, atk: 85, def: 85, spa: 85, spd: 85, spe: 85 }, nature: 'Hardy', teraType: ['Ghost', 'Poison', 'Fairy'], shiny: 1024, level: 97,
},
chaos: {
@ -370,7 +370,7 @@ export const ssbSets: SSBSets = {
species: 'Emboar', ability: 'Hogwash', item: 'Choice Band', gender: 'F',
moves: ['Flare Blitz', 'Wave Crash', 'Volt Tackle'],
signatureMove: 'Insert boar pun here',
// eslint-disable-next-line max-len
// eslint-disable-next-line @stylistic/max-len
evs: { hp: 252, atk: 252, def: 4 }, nature: 'Adamant', teraType: ['Fire', 'Water', 'Fighting', 'Electric'], shiny: 50 / 49,
},
Fame: {
@ -1018,7 +1018,7 @@ export const ssbSets: SSBSets = {
species: 'Tropius', ability: 'Primeval Harvest', item: 'Starf Berry', gender: ['M', 'M', 'F'],
moves: ['Sunny Day', 'Natural Gift', ['Bitter Blade', 'Sappy Seed', 'Stored Power', 'Counter']],
signatureMove: 'Fruitful Longbow',
// eslint-disable-next-line max-len
// eslint-disable-next-line @stylistic/max-len
evs: { hp: 184, atk: 112, def: 36, spd: 88, spe: 88 }, ivs: { spa: 29 }, nature: 'Impish', teraType: ['Dragon', 'Psychic', 'Fighting'], shiny: 20,
},
Waves: {

View File

@ -2,13 +2,13 @@ export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable
sleepclausemod: {
inherit: true,
onSetStatus(status, target, source) {
if (source && source.isAlly(target)) {
if (source?.isAlly(target)) {
return;
}
if (status.id === 'slp') {
for (const pokemon of target.side.pokemon) {
if (pokemon.hp && pokemon.status === 'slp') {
if (!pokemon.statusState.source || !pokemon.statusState.source.isAlly(pokemon)) {
if (!pokemon.statusState.source?.isAlly(pokemon)) {
if (source.hasAbility('ididitagain')) {
this.add('-ability', source, 'I Did It Again');
return;

View File

@ -1,7 +1,8 @@
import {SSBSet} from "./random-teams";
import {ChosenAction} from '../../../sim/side';
import type { SSBSet } from "./random-teams";
import type { ChosenAction } from '../../../sim/side';
import { FS } from '../../../lib';
import { toID } from '../../../sim/dex-data';
import { type SwitchAction } from "../../../sim/battle-queue";
// Similar to User.usergroups. Cannot import here due to users.ts requiring Chat
// This also acts as a cache, meaning ranks will only update when a hotpatch/restart occurs
@ -38,7 +39,7 @@ export function getName(name: string): string {
let group = usergroups[userid] || ' ';
if (name === 'Artemis') group = '@';
if (name === 'Jeopard-E' || name === 'Ice Kyubs') group = '*';
return Math.floor(Date.now() / 1000) + '|' + group + name;
return `${Math.floor(Date.now() / 1000)}|${group}${name}`;
}
export function enemyStaff(pokemon: Pokemon): string {
@ -76,7 +77,7 @@ export function changeSet(context: Battle, pokemon: Pokemon, newSet: SSBSet, cha
const oldGender = pokemon.set.gender;
if ((pokemon.set.gender !== newSet.gender) && !Array.isArray(newSet.gender)) {
pokemon.set.gender = newSet.gender;
// @ts-ignore Shut up sharp_claw wanted this
// @ts-expect-error Shut up sharp_claw wanted this
pokemon.gender = newSet.gender;
}
const oldShiny = pokemon.set.shiny;
@ -144,9 +145,8 @@ export function changeMoves(context: Battle, pokemon: Pokemon, newMoves: (string
const moveSlot = {
move: move.name,
id: move.id,
// eslint-disable-next-line max-len
pp: ((move.noPPBoosts || move.isZ) ? Math.floor(move.pp * carryOver[slot]) : Math.floor((move.pp * (8 / 5)) * carryOver[slot])),
maxpp: ((move.noPPBoosts || move.isZ) ? move.pp : move.pp * 8 / 5),
pp: Math.floor((move.noPPBoosts ? move.pp : move.pp * 8 / 5) * carryOver[slot]),
maxpp: (move.noPPBoosts ? move.pp : move.pp * 8 / 5),
target: move.target,
disabled: false,
disabledSource: '',
@ -323,7 +323,7 @@ export const Scripts: ModdedBattleScriptsData = {
this.queue.clear();
// Fainting clears accumulated Bide damage
for (const pokemon of this.getAllActive()) {
if (pokemon.volatiles['bide'] && pokemon.volatiles['bide'].damage) {
if (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.");
@ -398,8 +398,8 @@ export const Scripts: ModdedBattleScriptsData = {
pokemon.baseMoveSlots[ironHead] = {
move: move.name,
id: move.id,
pp: (move.noPPBoosts || move.isZ) ? move.pp : move.pp * 8 / 5,
maxpp: (move.noPPBoosts || move.isZ) ? move.pp : move.pp * 8 / 5,
pp: move.noPPBoosts ? move.pp : move.pp * 8 / 5,
maxpp: move.noPPBoosts ? move.pp : move.pp * 8 / 5,
target: move.target,
disabled: false,
disabledSource: '',
@ -523,28 +523,23 @@ export const Scripts: ModdedBattleScriptsData = {
this.add('-heal', action.target, action.target.getHealth, '[from] move: Revival Blessing');
action.pokemon.side.removeSlotCondition(action.pokemon, 'revivalblessing');
break;
// @ts-ignore I'm sorry but it takes a lot
// @ts-expect-error I'm sorry but it takes a lot
case 'scapegoat':
// @ts-ignore
action = action as SwitchAction;
const percent = (action.target.hp / action.target.baseMaxhp) * 100;
// @ts-ignore TODO: Client support for custom faint
// TODO: Client support for custom faint
action.target.faint();
if (percent > 66) {
this.add('message', `Your courage will be greatly rewarded.`);
// @ts-ignore
this.boost({atk: 3, spa: 3, spe: 3}, action.pokemon, action.pokemon, this.dex.moves.get('scapegoat'));
this.boost({ atk: 3, spa: 3, spe: 3 }, action.pokemon, action.pokemon, this.dex.moves.get('scapegoat') as any);
} else if (percent > 33) {
this.add('message', `Your offering was accepted.`);
// @ts-ignore
this.boost({atk: 2, spa: 2, spe: 2}, action.pokemon, action.pokemon, this.dex.moves.get('scapegoat'));
this.boost({ atk: 2, spa: 2, spe: 2 }, action.pokemon, action.pokemon, this.dex.moves.get('scapegoat') as any);
} else {
this.add('message', `Coward.`);
// @ts-ignore
this.boost({atk: 1, spa: 1, spe: 1}, action.pokemon, action.pokemon, this.dex.moves.get('scapegoat'));
this.boost({ atk: 1, spa: 1, spe: 1 }, action.pokemon, action.pokemon, this.dex.moves.get('scapegoat') as any);
}
// @ts-ignore
this.add(`c:|${getName((action.pokemon.illusion || action.pokemon).name)}|Don't worry, if this plan fails we can just blame ${action.target.name}`);
// @ts-ignore
action.pokemon.side.removeSlotCondition(action.pokemon, 'scapegoat');
break;
case 'runSwitch':
@ -633,8 +628,10 @@ export const Scripts: ModdedBattleScriptsData = {
let reviveSwitch = false; // Used to ignore the fake switch for Revival Blessing
if (switches[i] && !this.canSwitch(this.sides[i])) {
for (const pokemon of this.sides[i].active) {
if (this.sides[i].slotConditions[pokemon.position]['revivalblessing'] ||
this.sides[i].slotConditions[pokemon.position]['scapegoat']) {
if (
this.sides[i].slotConditions[pokemon.position]['revivalblessing'] ||
this.sides[i].slotConditions[pokemon.position]['scapegoat']
) {
reviveSwitch = true;
continue;
}
@ -721,7 +718,7 @@ export const Scripts: ModdedBattleScriptsData = {
if (move.spreadHit) {
// multi-target modifier (doubles only)
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);
} else if (move.multihitType === 'parentalbond' && move.hit > 1) {
// Parental Bond modifier
@ -906,7 +903,7 @@ export const Scripts: ModdedBattleScriptsData = {
}
this.battle.runEvent('BeforeSwitchIn', pokemon);
if (sourceEffect) {
this.battle.add(isDrag ? 'drag' : 'switch', pokemon, pokemon.getFullDetails, '[from] ' + sourceEffect);
this.battle.add(isDrag ? 'drag' : 'switch', pokemon, pokemon.getFullDetails, `[from] ${sourceEffect}`);
} else {
this.battle.add(isDrag ? 'drag' : 'switch', pokemon, pokemon.getFullDetails);
}
@ -1320,7 +1317,7 @@ export const Scripts: ModdedBattleScriptsData = {
attrs = '|[anim]' + movename + attrs;
movename = 'Z-' + movename;
}
this.battle.addMove('move', pokemon, movename, target + attrs);
this.battle.addMove('move', pokemon, movename, `${target}${attrs}`);
if (zMove) this.runZPower(move, pokemon);
@ -1517,7 +1514,7 @@ export const Scripts: ModdedBattleScriptsData = {
// purposes of Counter, Metal Burst, and Mirror Coat.
damage[i] = md === true || !md ? 0 : md;
// Total damage dealt is accumulated for the purposes of recoil (Parental Bond).
move.totalDamage += damage[i] as number;
move.totalDamage += damage[i];
}
if (move.mindBlownRecoil) {
const hpBeforeRecoil = pokemon.hp;
@ -1583,7 +1580,7 @@ export const Scripts: ModdedBattleScriptsData = {
this.battle.eachEvent('Update');
this.afterMoveSecondaryEvent(targetsCopy.filter(val => !!val) as Pokemon[], pokemon, move);
this.afterMoveSecondaryEvent(targetsCopy.filter(val => !!val), pokemon, move);
if (!move.negateSecondary && !(move.hasSheerForce && pokemon.hasAbility('sheerforce'))) {
for (const [i, d] of damage.entries()) {
@ -1611,11 +1608,13 @@ export const Scripts: ModdedBattleScriptsData = {
} else if (!this.battle.singleEvent('TryImmunity', move, {}, target, pokemon, move)) {
this.battle.add('-immune', target);
hitResults[i] = false;
} else if (this.battle.gen >= 7 && move.pranksterBoosted &&
} else if (
this.battle.gen >= 7 && move.pranksterBoosted &&
// Prankster Clone immunity
(pokemon.hasAbility('prankster') || pokemon.hasAbility('youkaiofthedusk') ||
pokemon.volatiles['irpachuza'] || pokemon.hasAbility('neverendingfhunt')) &&
!targets[i].isAlly(pokemon) && !this.dex.getImmunity('prankster', target)) {
!targets[i].isAlly(pokemon) && !this.dex.getImmunity('prankster', target)
) {
this.battle.debug('natural prankster immunity');
if (!target.illusion) this.battle.hint("Since gen 7, Dark is immune to Prankster moves.");
this.battle.add('-immune', target);
@ -1636,8 +1635,7 @@ export const Scripts: ModdedBattleScriptsData = {
}
const move = this.dex.getActiveMove(moveOrMoveName);
let hitResult: boolean | number | null = true;
let moveData = hitEffect as ActiveMove;
if (!moveData) moveData = move;
const moveData = hitEffect || move;
if (!moveData.flags) moveData.flags = {};
if (move.target === 'all' && !isSelf) {
hitResult = this.battle.singleEvent('TryHitField', moveData, {}, target || null, pokemon, move);
@ -1854,7 +1852,7 @@ export const Scripts: ModdedBattleScriptsData = {
case 'switch':
case 'instaswitch':
case 'revivalblessing':
// @ts-ignore custom status falls through
// @ts-expect-error custom status falls through
case 'scapegoat':
return `switch ${action.target!.position + 1}`;
case 'team':
@ -1938,7 +1936,7 @@ export const Scripts: ModdedBattleScriptsData = {
// Should always subtract, but stop at 0 to prevent errors.
this.choice.forcedSwitchesLeft = this.battle.clampIntRange(this.choice.forcedSwitchesLeft - 1, 0);
pokemon.switchFlag = false;
// @ts-ignore custom request
// @ts-expect-error custom request
this.choice.actions.push({
choice: 'scapegoat',
pokemon,

View File

@ -74,7 +74,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
target.item = yourItem.id; // bypass setItem so we don't break choicelock or anything
return;
}
this.add('-item', source, yourItem, '[from] ability: Magic Resistance', '[of] ' + target);
this.add('-item', source, yourItem, '[from] ability: Magic Resistance', `[of] ${target}`);
}
},
flags: { breakable: 1 },

View File

@ -42,7 +42,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
onSwitchIn(pokemon) {
if (pokemon.hasItem('heavydutyboots') || pokemon.hasAbility('magmaticentrance') || pokemon.hasAbility('hover')) return;
const typeMod = this.clampIntRange(pokemon.runEffectiveness(this.dex.getActiveMove('stealthrock')), -6, 6);
this.damage(pokemon.maxhp * Math.pow(2, typeMod) / 8);
this.damage(pokemon.maxhp * (2 ** typeMod) / 8);
},
},
secondary: null,

View File

@ -60,7 +60,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
inherit: true,
onSwitchIn(pokemon) {
if (pokemon.isActive && !pokemon.species.isPrimal && !pokemon.transformed) {
// @ts-ignore
// @ts-expect-error modded
const species: Species = this.actions.getMixedSpecies(pokemon.m.originalSpecies, 'Kyogre-Primal', pokemon);
if (pokemon.m.originalSpecies === 'Kyogre') {
pokemon.formeChange(species, this.effect, true);
@ -211,7 +211,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
inherit: true,
onSwitchIn(pokemon) {
if (pokemon.isActive && !pokemon.species.isPrimal && !pokemon.transformed) {
// @ts-ignore
// @ts-expect-error modded
const species: Species = this.actions.getMixedSpecies(pokemon.m.originalSpecies, 'Groudon-Primal', pokemon);
if (pokemon.m.originalSpecies === 'Groudon') {
pokemon.formeChange(species, this.effect, true);

View File

@ -130,8 +130,8 @@ export const Scripts: ModdedBattleScriptsData = {
pokemon.baseMoveSlots[ironHead] = {
move: move.name,
id: move.id,
pp: (move.noPPBoosts || move.isZ) ? move.pp : move.pp * 8 / 5,
maxpp: (move.noPPBoosts || move.isZ) ? move.pp : move.pp * 8 / 5,
pp: move.noPPBoosts ? move.pp : move.pp * 8 / 5,
maxpp: move.noPPBoosts ? move.pp : move.pp * 8 / 5,
target: move.target,
disabled: false,
disabledSource: '',

View File

@ -62,7 +62,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
const target = this.sample(possibleTargets);
const ability = target.getAbility();
this.add('-ability', pokemon, ability, '[from] ability: Trace', '[of] ' + target);
this.add('-ability', pokemon, ability, '[from] ability: Trace', `[of] ${target}`);
if (isAbility) {
pokemon.setAbility(ability);
} else {

View File

@ -134,9 +134,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
const ally = source.side.active.find(mon => mon && mon !== source && !mon.fainted);
const foeAlly = target.side.active.find(mon => mon && mon !== target && !mon.fainted);
if (target.isAlly(source)) {
this.add('-activate', source, 'move: Skill Swap', '', '', '[of] ' + target);
this.add('-activate', source, 'move: Skill Swap', '', '', `[of] ${target}`);
} else {
this.add('-activate', source, 'move: Skill Swap', targetAbility, sourceAbility, '[of] ' + target);
this.add('-activate', source, 'move: Skill Swap', targetAbility, sourceAbility, `[of] ${target}`);
}
this.singleEvent('End', sourceAbility, source.abilityState, source);
if (ally?.m.innate) {
@ -152,7 +152,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
source.ability = targetAbility.id;
source.abilityState = this.initEffectState({ id: this.toID(source.ability), target: source });
if (source.m.innate && source.m.innate.endsWith(targetAbility.id)) {
if (source.m.innate?.endsWith(targetAbility.id)) {
source.removeVolatile(source.m.innate);
delete source.m.innate;
}
@ -166,8 +166,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
target.ability = sourceAbility.id;
target.abilityState = this.initEffectState({id: this.toID(target.ability), target: target});
if (target.m.innate && target.m.innate.endsWith(sourceAbility.id)) {
target.abilityState = this.initEffectState({ id: this.toID(target.ability), target });
if (target.m.innate?.endsWith(sourceAbility.id)) {
target.removeVolatile(target.m.innate);
delete target.m.innate;
}

View File

@ -24,9 +24,9 @@ export const Scripts: ModdedBattleScriptsData = {
const volatileState = ally.volatiles[ally.m.innate];
if (volatileState) {
const volatile = this.dex.conditions.getByID(ally.m.innate as ID);
// @ts-ignore - dynamic lookup
// @ts-expect-error dynamic lookup
let callback = volatile[callbackName];
// @ts-ignore - dynamic lookup
// @ts-expect-error dynamic lookup
if (this.gen >= 5 && !volatile.onSwitchIn && !volatile.onAnySwitchIn) {
callback = volatile.onStart;
}
@ -54,7 +54,7 @@ export const Scripts: ModdedBattleScriptsData = {
handlers.shift();
const effect = handler.effect;
if ((handler.effectHolder as Pokemon).fainted || (handler.state?.pic as Pokemon)?.fainted) continue;
if (eventid === 'Residual' && handler.end && handler.state && handler.state.duration) {
if (eventid === 'Residual' && handler.end && handler.state?.duration) {
handler.state.duration--;
if (!handler.state.duration) {
const endCallArgs = handler.endCallArgs || [handler.effectHolder, effect.id];
@ -88,7 +88,7 @@ export const Scripts: ModdedBattleScriptsData = {
const ally = side.active.find(mon => mon && mon !== pokemon && !mon.fainted);
let allyMoves = ally ? this.dex.deepClone(ally.moveSlots) : [];
if (ally) {
// @ts-ignore
// @ts-expect-error modded
allyMoves = allyMoves.filter(move => !pokemon.moves.includes(move.id) && ally.m.curMoves.includes(move.id));
for (const aMove of allyMoves) {
aMove.pp = this.clampIntRange(aMove.maxpp - (pokemon.m.trackPP.get(aMove.id) || 0), 0);
@ -290,8 +290,8 @@ export const Scripts: ModdedBattleScriptsData = {
delete ally.m.innate;
}
if (this.battle.effect && this.battle.effect.effectType === 'Move' && !isFromFormeChange) {
this.battle.add('-endability', this, this.battle.dex.abilities.get(oldAbility), '[from] move: ' +
this.battle.dex.moves.get(this.battle.effect.id));
this.battle.add('-endability', this, this.battle.dex.abilities.get(oldAbility),
`[from] move: ${this.battle.dex.moves.get(this.battle.effect.id)}`);
}
this.ability = ability.id;
this.abilityState = this.battle.initEffectState({ id: ability.id, target: this });
@ -309,7 +309,7 @@ export const Scripts: ModdedBattleScriptsData = {
}
}
// Entrainment
if (this.m.innate && this.m.innate.endsWith(ability.id)) {
if (this.m.innate?.endsWith(ability.id)) {
this.removeVolatile(this.m.innate);
delete this.m.innate;
}
@ -331,10 +331,12 @@ export const Scripts: ModdedBattleScriptsData = {
},
transformInto(pokemon, effect) {
const species = pokemon.species;
if (pokemon.fainted || this.illusion || pokemon.illusion || (pokemon.volatiles['substitute'] && this.battle.gen >= 5) ||
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 || pokemon.terastallized))
) {
return false;
}

View File

@ -59,7 +59,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
function calculate(battle: Battle, source: Pokemon, pokemon: Pokemon) {
const move = battle.dex.getActiveMove('tackle');
move.type = source.getTypes()[0];
const typeMod = Math.pow(2, battle.clampIntRange(pokemon.runEffectiveness(move), -6, 6));
const typeMod = 2 ** battle.clampIntRange(pokemon.runEffectiveness(move), -6, 6);
if (!pokemon.runImmunity(move.type)) return 0;
return typeMod;
}

View File

@ -50,7 +50,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
function calculate(battle: Battle, source: Pokemon, pokemon: Pokemon) {
const move = battle.dex.getActiveMove('tackle');
move.type = source.getTypes()[0];
const typeMod = Math.pow(2, battle.clampIntRange(pokemon.runEffectiveness(move), -6, 6));
const typeMod = 2 ** battle.clampIntRange(pokemon.runEffectiveness(move), -6, 6);
if (!pokemon.runImmunity(move.type)) return 0;
return typeMod;
}

View File

@ -62,7 +62,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
function calculate(battle: Battle, source: Pokemon, pokemon: Pokemon) {
const move = battle.dex.getActiveMove('tackle');
move.type = source.getTypes()[0];
const typeMod = Math.pow(2, battle.clampIntRange(pokemon.runEffectiveness(move), -6, 6));
const typeMod = 2 ** battle.clampIntRange(pokemon.runEffectiveness(move), -6, 6);
if (!pokemon.runImmunity(move.type)) return 0;
return typeMod;
}

View File

@ -59,7 +59,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
condition: {
onStart(pokemon, source) {
this.add('-start', pokemon, 'Curse', '[of] ' + source);
this.add('-start', pokemon, 'Curse', `[of] ${source}`);
},
onResidualOrder: 12,
onResidual(pokemon) {
@ -282,10 +282,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
onSwitchIn(pokemon) {
if (!pokemon.isGrounded()) return;
if (pokemon.hasType('Poison')) {
this.add('-sideend', pokemon.side, 'move: Toxic Spikes', '[of] ' + pokemon);
this.add('-sideend', pokemon.side, 'move: Toxic Spikes', `[of] ${pokemon}`);
pokemon.side.removeSideCondition('toxicspikes');
} else if (pokemon.hasType('Steel') || pokemon.hasItem('heavydutyboots')) {
return;
// do nothing
} else if (this.effectState.layers >= 2) {
pokemon.trySetStatus('tox', this.effectState.source);
} else {
@ -299,7 +299,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
function calculate(battle: Battle, source: Pokemon, pokemon: Pokemon, moveid = 'tackle') {
const move = battle.dex.getActiveMove(moveid);
move.type = source.getTypes()[0];
const typeMod = Math.pow(2, battle.clampIntRange(pokemon.runEffectiveness(move), -6, 6));
const typeMod = 2 ** battle.clampIntRange(pokemon.runEffectiveness(move), -6, 6);
if (!pokemon.runImmunity(move.type)) return 0;
return typeMod;
}

View File

@ -108,7 +108,7 @@ export const Scripts: ModdedBattleScriptsData = {
// purposes of Counter, Metal Burst, and Mirror Coat.
damage[i] = md === true || !md ? 0 : md;
// Total damage dealt is accumulated for the purposes of recoil (Parental Bond).
move.totalDamage += damage[i] as number;
move.totalDamage += damage[i];
}
if (move.mindBlownRecoil) {
const hpBeforeRecoil = pokemon.hp;
@ -176,7 +176,7 @@ export const Scripts: ModdedBattleScriptsData = {
this.battle.eachEvent('Update');
this.afterMoveSecondaryEvent(targetsCopy.filter(val => !!val) as Pokemon[], pokemon, move);
this.afterMoveSecondaryEvent(targetsCopy.filter(val => !!val), pokemon, move);
if (!move.negateSecondary && !(move.hasSheerForce && pokemon.hasAbility('sheerforce'))) {
for (const [i, d] of damage.entries()) {
@ -207,7 +207,7 @@ export const Scripts: ModdedBattleScriptsData = {
function calculate(battle: Battle, source: Pokemon, pokemon: Pokemon, moveid = 'tackle') {
const move = battle.dex.getActiveMove(moveid);
move.type = source.getTypes()[0];
const typeMod = Math.pow(2, battle.clampIntRange(pokemon.runEffectiveness(move), -6, 6));
const typeMod = 2 ** battle.clampIntRange(pokemon.runEffectiveness(move), -6, 6);
if (!pokemon.runImmunity(move.type)) return 0;
return typeMod;
}

View File

@ -10,7 +10,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
if (this.checkMoveMakesContact(move, source, target, !source.isAlly(target))) {
const oldAbility = source.setAbility('mummy', target);
if (oldAbility) {
this.add('-activate', target, 'ability: Mummy', this.dex.abilities.get(oldAbility).name, '[of] ' + source);
this.add('-activate', target, 'ability: Mummy', this.dex.abilities.get(oldAbility).name, `[of] ${source}`);
}
}
} else {
@ -22,13 +22,13 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
if (abil === source.ability) {
const oldAbility = source.setAbility('mummy', target);
if (oldAbility) {
this.add('-activate', target, 'ability: Mummy', this.dex.abilities.get(oldAbility).name, '[of] ' + source);
this.add('-activate', target, 'ability: Mummy', this.dex.abilities.get(oldAbility).name, `[of] ${source}`);
}
} else {
source.removeVolatile('ability:' + abil);
source.addVolatile('ability:mummy', source);
if (abil) {
this.add('-activate', target, 'ability: Mummy', this.dex.abilities.get(abil).name, '[of] ' + source);
this.add('-activate', target, 'ability: Mummy', this.dex.abilities.get(abil).name, `[of] ${source}`);
}
}
}
@ -105,12 +105,12 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
.filter(val => !this.dex.abilities.get(val).flags['noreceiver'] && !additionalBannedAbilities.includes(val));
if (!possibleAbilities.length) return;
const ability = this.dex.abilities.get(possibleAbilities[this.random(possibleAbilities.length)]);
this.add('-ability', pokemon, ability, '[from] ability: Power of Alchemy', '[of] ' + ally);
this.add('-ability', pokemon, ability, '[from] ability: Power of Alchemy', `[of] ${ally}`);
if (isAbility) {
pokemon.setAbility(ability);
} else {
pokemon.removeVolatile("ability:powerofalchemy");
pokemon.addVolatile("ability:" + ability, pokemon);
pokemon.addVolatile(`ability:${ability}`, pokemon);
}
},
},
@ -127,12 +127,12 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
.filter(val => !this.dex.abilities.get(val).flags['noreceiver'] && !additionalBannedAbilities.includes(val));
if (!possibleAbilities.length) return;
const ability = this.dex.abilities.get(possibleAbilities[this.random(possibleAbilities.length)]);
this.add('-ability', pokemon, ability, '[from] ability: Receiver', '[of] ' + ally);
this.add('-ability', pokemon, ability, '[from] ability: Receiver', `[of] ${ally}`);
if (isAbility) {
pokemon.setAbility(ability);
} else {
pokemon.removeVolatile("ability:receiver");
pokemon.addVolatile("ability:" + ability, pokemon);
pokemon.addVolatile(`ability:${ability}`, pokemon);
}
},
},
@ -160,12 +160,12 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
continue;
}
const ability = this.dex.abilities.get(this.sample(possibleAbilities));
this.add('-ability', pokemon, ability, '[from] ability: Trace', '[of] ' + target);
this.add('-ability', pokemon, ability, '[from] ability: Trace', `[of] ${target}`);
if (isAbility) {
pokemon.setAbility(ability);
} else {
pokemon.removeVolatile("ability:trace");
pokemon.addVolatile("ability:" + ability, pokemon);
pokemon.addVolatile(`ability:${ability}`, pokemon);
}
return;
}
@ -182,9 +182,9 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
const sourceAbility = source.setAbility('wanderingspirit', target);
if (!sourceAbility) return;
if (target.isAlly(source)) {
this.add('-activate', target, 'Skill Swap', '', '', '[of] ' + source);
this.add('-activate', target, 'Skill Swap', '', '', `[of] ${source}`);
} else {
this.add('-activate', target, 'ability: Wandering Spirit', this.dex.abilities.get(sourceAbility).name, 'Wandering Spirit', '[of] ' + source);
this.add('-activate', target, 'ability: Wandering Spirit', this.dex.abilities.get(sourceAbility).name, 'Wandering Spirit', `[of] ${source}`);
}
target.setAbility(sourceAbility);
}
@ -202,9 +202,9 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
source.addVolatile('ability:wanderingspirit', source);
}
if (target.isAlly(source)) {
this.add('-activate', target, 'Skill Swap', '', '', '[of] ' + source);
this.add('-activate', target, 'Skill Swap', '', '', `[of] ${source}`);
} else {
this.add('-activate', target, 'ability: Wandering Spirit', this.dex.abilities.get(sourceAbility).name, 'Wandering Spirit', '[of] ' + source);
this.add('-activate', target, 'ability: Wandering Spirit', this.dex.abilities.get(sourceAbility).name, 'Wandering Spirit', `[of] ${source}`);
}
if (sourceAbility === source.ability) {
target.setAbility(sourceAbility);

View File

@ -15,12 +15,12 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
if (isAbility) {
if (pokemon.setAbility(ability)) {
this.add('-ability', pokemon, ability, '[from] ability: Trace', '[of] ' + target);
this.add('-ability', pokemon, ability, '[from] ability: Trace', `[of] ${target}`);
}
} else {
pokemon.removeVolatile('ability:trace');
pokemon.addVolatile('ability:' + ability.id, pokemon);
this.add('-ability', pokemon, ability, '[from] ability: Trace', '[of] ' + target);
this.add('-ability', pokemon, ability, '[from] ability: Trace', `[of] ${target}`);
}
},
},

View File

@ -66,12 +66,12 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
if (isAbility) {
if (pokemon.setAbility(ability)) {
this.add('-ability', pokemon, ability, '[from] ability: Trace', '[of] ' + target);
this.add('-ability', pokemon, ability, '[from] ability: Trace', `[of] ${target}`);
}
} else {
pokemon.removeVolatile('ability:trace');
pokemon.addVolatile('ability:' + ability.id, pokemon);
this.add('-ability', pokemon, ability, '[from] ability: Trace', '[of] ' + target);
this.add('-ability', pokemon, ability, '[from] ability: Trace', `[of] ${target}`);
}
},
},

View File

@ -30,7 +30,7 @@ export const Scripts: ModdedBattleScriptsData = {
const hasAnyItem = !!this.item || Object.keys(this.volatiles).some(v => v.startsWith('item:'));
// Best to declare everything early because ally might have a gem that needs proccing
if (!sourceEffect && this.battle.effect) sourceEffect = this.battle.effect;
if (!source && this.battle.event && this.battle.event.target) source = this.battle.event.target;
if (!source && this.battle.event?.target) source = this.battle.event.target;
const item = (sourceEffect?.id.startsWith('item:')) ? sourceEffect as Item : this.getItem();
if ((!this.hp && !item.isGem) || !this.isActive) return false;
if (!hasAnyItem) return false;
@ -38,7 +38,7 @@ export const Scripts: ModdedBattleScriptsData = {
if (this.battle.runEvent('UseItem', this, null, null, item)) {
switch (item.id.startsWith('item:') ? item.id.slice(5) : item.id) {
case 'redcard':
this.battle.add('-enditem', this, item.fullname, '[of] ' + source);
this.battle.add('-enditem', this, item.fullname, `[of] ${source}`);
break;
default:
if (item.isGem) {
@ -71,7 +71,7 @@ export const Scripts: ModdedBattleScriptsData = {
eatItem(force, source, sourceEffect) {
const hasAnyItem = !!this.item || Object.keys(this.volatiles).some(v => v.startsWith('item:'));
if (!sourceEffect && this.battle.effect) sourceEffect = this.battle.effect;
if (!source && this.battle.event && this.battle.event.target) source = this.battle.event.target;
if (!source && this.battle.event?.target) source = this.battle.event.target;
const item = (sourceEffect?.id.startsWith('item:')) ? sourceEffect as Item : this.getItem();
if (!hasAnyItem) return false;
if ((!this.hp && this.battle.toID(item.name) !== 'jabocaberry' && this.battle.toID(item.name) !== 'rowapberry') ||
@ -135,7 +135,7 @@ export const Scripts: ModdedBattleScriptsData = {
this.battle.singleEvent('Start', item, this.itemState, this, source, effect);
for (const ally of this.side.pokemon) {
if (!ally.m.sharedItemsUsed) continue;
ally.m.sharedItemsUsed = ally.m.sharedItemsUsed.filter((i: ID) => i !== (item as Item).id);
ally.m.sharedItemsUsed = ally.m.sharedItemsUsed.filter((i: ID) => i !== item.id);
}
}
return true;

View File

@ -209,10 +209,12 @@ export const Scripts: ModdedBattleScriptsData = {
},
transformInto(pokemon, effect) {
const species = pokemon.species;
if (pokemon.fainted || this.illusion || pokemon.illusion || (pokemon.volatiles['substitute'] && this.battle.gen >= 5) ||
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') {
(this.terastallized || pokemon.terastallized)) || this.terastallized === 'Stellar'
) {
return false;
}

View File

@ -352,7 +352,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
// 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("Ally Switch success chance: " + Math.round(100 / counter) + "%");
this.debug(`Ally Switch success chance: ${Math.round(100 / counter)}%`);
const success = this.randomChance(1, counter);
if (!success) {
delete pokemon.volatiles['allyswitch'];
@ -752,16 +752,16 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
}
if (effect.name === 'Cute Charm') {
this.add('-start', pokemon, 'Attract', '[from] ability: Cute Charm', '[of] ' + source);
this.add('-start', pokemon, 'Attract', '[from] ability: Cute Charm', `[of] ${source}`);
} else if (effect.name === 'Destiny Knot') {
this.add('-start', pokemon, 'Attract', '[from] item: Destiny Knot', '[of] ' + source);
this.add('-start', pokemon, 'Attract', '[from] item: Destiny Knot', `[of] ${source}`);
} else {
this.add('-start', pokemon, 'Attract');
}
},
onUpdate(pokemon) {
if (this.effectState.source && !this.effectState.source.isActive && pokemon.volatiles['attract']) {
this.debug('Removing Attract volatile on ' + pokemon);
this.debug(`Removing Attract volatile on ${pokemon}`);
pokemon.removeVolatile('attract');
}
},
@ -944,7 +944,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
p => p.source === target && p.damage > 0 && p.thisTurn
);
if (damagedByTarget) {
this.debug('BP doubled for getting hit by ' + target);
this.debug(`BP doubled for getting hit by ${target}`);
return move.basePower * 2;
}
return move.basePower;
@ -1196,7 +1196,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
basePowerCallback(pokemon, target, move) {
const currentSpecies = move.allies!.shift()!.species;
const bp = 5 + Math.floor(currentSpecies.baseStats.atk / 10);
this.debug('BP for ' + currentSpecies.name + ' hit: ' + bp);
this.debug(`BP for ${currentSpecies.name} hit: ${bp}`);
return bp;
},
category: "Physical",
@ -1298,7 +1298,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
source.item = myItem.id;
return false;
}
this.add('-item', target, myItem.name, '[from] move: Bestow', '[of] ' + source);
this.add('-item', target, myItem.name, '[from] move: Bestow', `[of] ${source}`);
},
secondary: null,
target: "normal",
@ -1985,7 +1985,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
onHit(target, source) {
const item = target.getItem();
if (source.hp && item.isBerry && target.takeItem(source)) {
this.add('-enditem', target, item.name, '[from] stealeat', '[move] Bug Bite', '[of] ' + source);
this.add('-enditem', target, item.name, '[from] stealeat', '[move] Bug Bite', `[of] ${source}`);
if (this.singleEvent('Eat', item, null, source, null, null)) {
this.runEvent('EatItem', source, null, null, item);
if (item.id === 'leppaberry') target.staleness = 'external';
@ -2585,7 +2585,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
if (source.hp <= (source.maxhp * 33 / 100) || source.maxhp === 1) return false;
},
onTryHit(pokemon, target, move) {
if (!this.boost(move.boosts as SparseBoostsTable)) return null;
if (!this.boost(move.boosts!)) return null;
delete move.boosts;
},
onHit(pokemon) {
@ -2780,7 +2780,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
flags: { contact: 1, protect: 1, mirror: 1, failmefirst: 1 },
onTry(source) {
const lastDamagedBy = source.getLastDamagedBy(true);
if (lastDamagedBy === undefined || !lastDamagedBy.thisTurn) return false;
if (!lastDamagedBy?.thisTurn) return false;
},
onModifyTarget(targetRelayVar, source, target, move) {
const lastDamagedBy = source.getLastDamagedBy(true);
@ -3017,7 +3017,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
onHit(target, source) {
const item = target.takeItem(source);
if (item) {
this.add('-enditem', target, item.name, '[from] move: Corrosive Gas', '[of] ' + source);
this.add('-enditem', target, item.name, '[from] move: Corrosive Gas', `[of] ${source}`);
} else {
this.add('-fail', target, 'move: Corrosive Gas');
}
@ -3223,7 +3223,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
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);
this.add('-item', source, yourItem, '[from] move: Covet', `[of] ${target}`);
},
secondary: null,
target: "normal",
@ -3356,7 +3356,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
const hp = target.hp;
const maxHP = target.maxhp;
const bp = Math.floor(Math.floor((120 * (100 * Math.floor(hp * 4096 / maxHP)) + 2048 - 1) / 4096) / 100) || 1;
this.debug('BP for ' + hp + '/' + maxHP + " HP: " + bp);
this.debug(`BP for ${hp}/${maxHP} HP: ${bp}`);
return bp;
},
category: "Physical",
@ -3383,7 +3383,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
volatileStatus: 'curse',
onModifyMove(move, source, target) {
if (!source.hasType('Ghost')) {
move.target = move.nonGhostTarget as MoveTarget;
move.target = move.nonGhostTarget!;
} else if (source.isAlly(target)) {
move.target = 'randomNormal';
}
@ -3402,7 +3402,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
},
condition: {
onStart(pokemon, source) {
this.add('-start', pokemon, 'Curse', '[of] ' + source);
this.add('-start', pokemon, 'Curse', `[of] ${source}`);
},
onResidualOrder: 12,
onResidual(pokemon) {
@ -3582,13 +3582,13 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
for (const targetCondition of removeTarget) {
if (target.side.removeSideCondition(targetCondition)) {
if (!removeAll.includes(targetCondition)) continue;
this.add('-sideend', target.side, this.dex.conditions.get(targetCondition).name, '[from] move: Defog', '[of] ' + source);
this.add('-sideend', target.side, this.dex.conditions.get(targetCondition).name, '[from] move: Defog', `[of] ${source}`);
success = true;
}
}
for (const sideCondition of removeAll) {
if (source.side.removeSideCondition(sideCondition)) {
this.add('-sideend', source.side, this.dex.conditions.get(sideCondition).name, '[from] move: Defog', '[of] ' + source);
this.add('-sideend', source.side, this.dex.conditions.get(sideCondition).name, '[from] move: Defog', `[of] ${source}`);
success = true;
}
}
@ -3790,7 +3790,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
}
}
if (effect.effectType === 'Ability') {
this.add('-start', pokemon, 'Disable', pokemon.lastMove.name, '[from] ability: ' + effect.name, '[of] ' + source);
this.add('-start', pokemon, 'Disable', pokemon.lastMove.name, '[from] ability: ' + effect.name, `[of] ${source}`);
} else {
this.add('-start', pokemon, 'Disable', pokemon.lastMove.name);
}
@ -3992,7 +3992,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
if (!target.side.addSlotCondition(target, 'futuremove')) return false;
Object.assign(target.side.slotConditions[target.position]['futuremove'], {
move: 'doomdesire',
source: source,
source,
moveData: {
id: 'doomdesire',
name: "Doom Desire",
@ -4284,7 +4284,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
basePower: 150,
basePowerCallback(pokemon, target, move) {
const bp = move.basePower * pokemon.hp / pokemon.maxhp;
this.debug('BP: ' + bp);
this.debug(`BP: ${bp}`);
return bp;
},
category: "Special",
@ -4570,7 +4570,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
if (this.field.pseudoWeather.echoedvoice) {
bp = move.basePower * this.field.pseudoWeather.echoedvoice.multiplier;
}
this.debug('BP: ' + move.basePower);
this.debug(`BP: ${move.basePower}`);
return bp;
},
category: "Special",
@ -4700,7 +4700,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
},
onFieldStart(field, source, effect) {
if (effect?.effectType === 'Ability') {
this.add('-fieldstart', 'move: Electric Terrain', '[from] ability: ' + effect.name, '[of] ' + source);
this.add('-fieldstart', 'move: Electric Terrain', '[from] ability: ' + effect.name, `[of] ${source}`);
} else {
this.add('-fieldstart', 'move: Electric Terrain');
}
@ -4758,7 +4758,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
let ratio = Math.floor(pokemon.getStat('spe') / target.getStat('spe'));
if (!isFinite(ratio)) ratio = 0;
const bp = [40, 60, 80, 120, 150][Math.min(ratio, 4)];
this.debug('BP: ' + bp);
this.debug(`BP: ${bp}`);
return bp;
},
category: "Special",
@ -5067,7 +5067,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
basePower: 150,
basePowerCallback(pokemon, target, move) {
const bp = move.basePower * pokemon.hp / pokemon.maxhp;
this.debug('BP: ' + bp);
this.debug(`BP: ${bp}`);
return bp;
},
category: "Special",
@ -5477,7 +5477,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
if (source.hp <= source.maxhp / 2 || source.maxhp === 1) return false;
},
onTryHit(pokemon, target, move) {
if (!this.boost(move.boosts as SparseBoostsTable)) return null;
if (!this.boost(move.boosts!)) return null;
delete move.boosts;
},
onHit(pokemon) {
@ -5746,7 +5746,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
} else {
bp = 20;
}
this.debug('BP: ' + bp);
this.debug(`BP: ${bp}`);
return bp;
},
category: "Physical",
@ -5950,7 +5950,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
if (!this.singleEvent('TakeItem', item, source.itemState, source, source, move, item)) return false;
if (!item.fling) return false;
move.basePower = item.fling.basePower;
this.debug('BP: ' + move.basePower);
this.debug(`BP: ${move.basePower}`);
if (item.isBerry) {
move.onHit = function (foe) {
if (this.singleEvent('Eat', item, null, foe, null, null)) {
@ -6216,7 +6216,9 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
name: "Focus Punch",
pp: 20,
priority: -3,
flags: {contact: 1, protect: 1, punch: 1, failmefirst: 1, nosleeptalk: 1, noassist: 1, failcopycat: 1, failinstruct: 1},
flags: {
contact: 1, protect: 1, punch: 1, failmefirst: 1, nosleeptalk: 1, noassist: 1, failcopycat: 1, failinstruct: 1,
},
priorityChargeCallback(pokemon) {
pokemon.addVolatile('focuspunch');
},
@ -6529,7 +6531,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
pokemon.addVolatile('furycutter');
}
const bp = this.clampIntRange(move.basePower * pokemon.volatiles['furycutter'].multiplier, 1, 160);
this.debug('BP: ' + bp);
this.debug(`BP: ${bp}`);
return bp;
},
category: "Physical",
@ -6624,7 +6626,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
if (!target.side.addSlotCondition(target, 'futuremove')) return false;
Object.assign(target.side.slotConditions[target.position]['futuremove'], {
move: 'futuresight',
source: source,
source,
moveData: {
id: 'futuresight',
name: "Future Sight",
@ -7499,7 +7501,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
const steelHazard = this.dex.getActiveMove('Stealth Rock');
steelHazard.type = 'Steel';
const typeMod = this.clampIntRange(pokemon.runEffectiveness(steelHazard), -6, 6);
this.damage(pokemon.maxhp * Math.pow(2, typeMod) / 8);
this.damage(pokemon.maxhp * (2 ** typeMod) / 8);
},
},
secondary: null,
@ -7788,13 +7790,13 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
for (const targetCondition of removeTarget) {
if (source.side.foe.removeSideCondition(targetCondition)) {
if (!removeAll.includes(targetCondition)) continue;
this.add('-sideend', source.side.foe, this.dex.conditions.get(targetCondition).name, '[from] move: G-Max Wind Rage', '[of] ' + source);
this.add('-sideend', source.side.foe, this.dex.conditions.get(targetCondition).name, '[from] move: G-Max Wind Rage', `[of] ${source}`);
success = true;
}
}
for (const sideCondition of removeAll) {
if (source.side.removeSideCondition(sideCondition)) {
this.add('-sideend', source.side, this.dex.conditions.get(sideCondition).name, '[from] move: G-Max Wind Rage', '[of] ' + source);
this.add('-sideend', source.side, this.dex.conditions.get(sideCondition).name, '[from] move: G-Max Wind Rage', `[of] ${source}`);
success = true;
}
}
@ -7827,7 +7829,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
} else {
bp = 20;
}
this.debug('BP: ' + bp);
this.debug(`BP: ${bp}`);
return bp;
},
category: "Special",
@ -7979,7 +7981,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
},
onFieldStart(field, source, effect) {
if (effect?.effectType === 'Ability') {
this.add('-fieldstart', 'move: Grassy Terrain', '[from] ability: ' + effect.name, '[of] ' + source);
this.add('-fieldstart', 'move: Grassy Terrain', '[from] ability: ' + effect.name, `[of] ${source}`);
} else {
this.add('-fieldstart', 'move: Grassy Terrain');
}
@ -8242,7 +8244,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
const newspd = Math.floor((target.storedStats.spd + source.storedStats.spd) / 2);
target.storedStats.spd = newspd;
source.storedStats.spd = newspd;
this.add('-activate', source, 'move: Guard Split', '[of] ' + target);
this.add('-activate', source, 'move: Guard Split', `[of] ${target}`);
},
secondary: null,
target: "normal",
@ -8336,7 +8338,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
let power = Math.floor(25 * target.getStat('spe') / pokemon.getStat('spe')) + 1;
if (!isFinite(power)) power = 1;
if (power > 150) power = 150;
this.debug('BP: ' + power);
this.debug(`BP: ${power}`);
return power;
},
category: "Physical",
@ -8431,7 +8433,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
const hp = target.hp;
const maxHP = target.maxhp;
const bp = Math.floor(Math.floor((100 * (100 * Math.floor(hp * 4096 / maxHP)) + 2048 - 1) / 4096) / 100) || 1;
this.debug('BP for ' + hp + '/' + maxHP + " HP: " + bp);
this.debug(`BP for ${hp}/${maxHP} HP: ${bp}`);
return bp;
},
category: "Physical",
@ -8785,7 +8787,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
} else {
bp = 40;
}
this.debug('BP: ' + bp);
this.debug(`BP: ${bp}`);
return bp;
},
category: "Physical",
@ -8843,7 +8845,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
} else {
bp = 40;
}
this.debug('BP: ' + bp);
this.debug(`BP: ${bp}`);
return bp;
},
category: "Physical",
@ -8882,11 +8884,11 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
duration: 1,
onStart(target, source) {
this.effectState.multiplier = 1.5;
this.add('-singleturn', target, 'Helping Hand', '[of] ' + source);
this.add('-singleturn', target, 'Helping Hand', `[of] ${source}`);
},
onRestart(target, source) {
this.effectState.multiplier *= 1.5;
this.add('-singleturn', target, 'Helping Hand', '[of] ' + source);
this.add('-singleturn', target, 'Helping Hand', `[of] ${source}`);
},
onBasePowerPriority: 10,
onBasePower(basePower) {
@ -9573,7 +9575,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
let bp = move.basePower;
const iceballData = pokemon.volatiles['iceball'];
if (iceballData?.hitCount) {
bp *= Math.pow(2, iceballData.contactHitCount);
bp *= 2 ** iceballData.contactHitCount;
}
if (iceballData && pokemon.status !== 'slp') {
iceballData.hitCount++;
@ -9585,7 +9587,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
if (pokemon.volatiles['defensecurl']) {
bp *= 2;
}
this.debug("BP: " + bp);
this.debug(`BP: ${bp}`);
return bp;
},
category: "Physical",
@ -10004,7 +10006,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
) {
return false;
}
this.add('-singleturn', target, 'move: Instruct', '[of] ' + source);
this.add('-singleturn', target, 'move: Instruct', `[of] ${source}`);
this.queue.prioritizeAction(this.queue.resolveAction({
choice: 'move',
pokemon: target,
@ -10337,7 +10339,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
if (source.hp) {
const item = target.takeItem();
if (item) {
this.add('-enditem', target, item.name, '[from] move: Knock Off', '[of] ' + source);
this.add('-enditem', target, item.name, '[from] move: Knock Off', `[of] ${source}`);
}
}
},
@ -10785,7 +10787,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
},
onHit(target, source) {
source.addVolatile('lockon', target);
this.add('-activate', source, 'move: Lock-On', '[of] ' + target);
this.add('-activate', source, 'move: Lock-On', `[of] ${target}`);
},
condition: {
noCopy: true, // doesn't get copied by Baton Pass
@ -10841,7 +10843,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
} else {
bp = 20;
}
this.debug('BP: ' + bp);
this.debug(`BP: ${bp}`);
return bp;
},
category: "Physical",
@ -11161,9 +11163,9 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
},
onFieldStart(target, source) {
if (source?.hasAbility('persistent')) {
this.add('-fieldstart', 'move: Magic Room', '[of] ' + source, '[persistent]');
this.add('-fieldstart', 'move: Magic Room', `[of] ${source}`, '[persistent]');
} else {
this.add('-fieldstart', 'move: Magic Room', '[of] ' + source);
this.add('-fieldstart', 'move: Magic Room', `[of] ${source}`);
}
for (const mon of this.getAllActive()) {
this.singleEvent('End', mon.getItem(), mon.itemState, mon);
@ -12082,7 +12084,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
flags: { protect: 1, mirror: 1, metronome: 1, failmefirst: 1 },
onTry(source) {
const lastDamagedBy = source.getLastDamagedBy(true);
if (lastDamagedBy === undefined || !lastDamagedBy.thisTurn) return false;
if (!lastDamagedBy?.thisTurn) return false;
},
onModifyTarget(targetRelayVar, source, target, move) {
const lastDamagedBy = source.getLastDamagedBy(true);
@ -12333,7 +12335,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
},
onHit(target, source) {
source.addVolatile('lockon', target);
this.add('-activate', source, 'move: Mind Reader', '[of] ' + target);
this.add('-activate', source, 'move: Mind Reader', `[of] ${target}`);
},
secondary: null,
target: "normal",
@ -12628,7 +12630,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
},
onFieldStart(field, source, effect) {
if (effect?.effectType === 'Ability') {
this.add('-fieldstart', 'move: Misty Terrain', '[from] ability: ' + effect.name, '[of] ' + source);
this.add('-fieldstart', 'move: Misty Terrain', '[from] ability: ' + effect.name, `[of] ${source}`);
} else {
this.add('-fieldstart', 'move: Misty Terrain');
}
@ -12765,12 +12767,12 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
onAfterHit(target, pokemon, move) {
if (!move.hasSheerForce) {
if (pokemon.hp && pokemon.removeVolatile('leechseed')) {
this.add('-end', pokemon, 'Leech Seed', '[from] move: Mortal Spin', '[of] ' + pokemon);
this.add('-end', pokemon, 'Leech Seed', '[from] move: Mortal Spin', `[of] ${pokemon}`);
}
const sideConditions = ['spikes', 'toxicspikes', 'stealthrock', 'stickyweb', 'gmaxsteelsurge'];
for (const condition of sideConditions) {
if (pokemon.hp && pokemon.side.removeSideCondition(condition)) {
this.add('-sideend', pokemon.side, this.dex.conditions.get(condition).name, '[from] move: Mortal Spin', '[of] ' + pokemon);
this.add('-sideend', pokemon.side, this.dex.conditions.get(condition).name, '[from] move: Mortal Spin', `[of] ${pokemon}`);
}
}
if (pokemon.hp && pokemon.volatiles['partiallytrapped']) {
@ -12781,12 +12783,12 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
onAfterSubDamage(damage, target, pokemon, move) {
if (!move.hasSheerForce) {
if (pokemon.hp && pokemon.removeVolatile('leechseed')) {
this.add('-end', pokemon, 'Leech Seed', '[from] move: Mortal Spin', '[of] ' + pokemon);
this.add('-end', pokemon, 'Leech Seed', '[from] move: Mortal Spin', `[of] ${pokemon}`);
}
const sideConditions = ['spikes', 'toxicspikes', 'stealthrock', 'stickyweb', 'gmaxsteelsurge'];
for (const condition of sideConditions) {
if (pokemon.hp && pokemon.side.removeSideCondition(condition)) {
this.add('-sideend', pokemon.side, this.dex.conditions.get(condition).name, '[from] move: Mortal Spin', '[of] ' + pokemon);
this.add('-sideend', pokemon.side, this.dex.conditions.get(condition).name, '[from] move: Mortal Spin', `[of] ${pokemon}`);
}
}
if (pokemon.hp && pokemon.volatiles['partiallytrapped']) {
@ -12889,7 +12891,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
condition: {
duration: 5,
onFieldStart(field, source) {
this.add('-fieldstart', 'move: Mud Sport', '[of] ' + source);
this.add('-fieldstart', 'move: Mud Sport', `[of] ${source}`);
},
onBasePowerPriority: 1,
onBasePower(basePower, attacker, defender, move) {
@ -13028,7 +13030,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
const item = pokemon.getItem();
if (!item.naturalGift) return false;
move.basePower = item.naturalGift.basePower;
this.debug('BP: ' + move.basePower);
this.debug(`BP: ${move.basePower}`);
pokemon.setItem('');
pokemon.lastItem = item.id;
pokemon.usedItemThisTurn = true;
@ -13418,7 +13420,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
volatileStatus: 'octolock',
condition: {
onStart(pokemon, source) {
this.add('-start', pokemon, 'move: Octolock', '[of] ' + source);
this.add('-start', pokemon, 'move: Octolock', `[of] ${source}`);
},
onResidualOrder: 14,
onResidual(pokemon) {
@ -13431,7 +13433,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
this.boost({ def: -1, spd: -1 }, pokemon, source, this.dex.getActiveMove('octolock'));
},
onTrapPokemon(pokemon) {
if (this.effectState.source && this.effectState.source.isActive) pokemon.tryTrap();
if (this.effectState.source?.isActive) pokemon.tryTrap();
},
},
secondary: null,
@ -13729,7 +13731,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
onResidualOrder: 24,
onResidual(pokemon) {
const duration = pokemon.volatiles['perishsong'].duration;
this.add('-start', pokemon, 'perish' + duration);
this.add('-start', pokemon, `perish${duration}`);
},
},
secondary: null,
@ -13828,7 +13830,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
basePower: 0,
basePowerCallback(pokemon) {
const bp = Math.floor((pokemon.happiness * 10) / 25) || 1;
this.debug('BP: ' + bp);
this.debug(`BP: ${bp}`);
return bp;
},
category: "Special",
@ -13924,7 +13926,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
onHit(target, source) {
const item = target.getItem();
if (source.hp && item.isBerry && target.takeItem(source)) {
this.add('-enditem', target, item.name, '[from] stealeat', '[move] Pluck', '[of] ' + source);
this.add('-enditem', target, item.name, '[from] stealeat', '[move] Pluck', `[of] ${source}`);
if (this.singleEvent('Eat', item, null, source, null, null)) {
this.runEvent('EatItem', source, null, null, item);
if (item.id === 'leppaberry') target.staleness = 'external';
@ -14265,7 +14267,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
const newspa = Math.floor((target.storedStats.spa + source.storedStats.spa) / 2);
target.storedStats.spa = newspa;
source.storedStats.spa = newspa;
this.add('-activate', source, 'move: Power Split', '[of] ' + target);
this.add('-activate', source, 'move: Power Split', `[of] ${target}`);
},
secondary: null,
target: "normal",
@ -14350,7 +14352,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
basePower: 20,
basePowerCallback(pokemon, target, move) {
const bp = move.basePower + 20 * pokemon.positiveBoosts();
this.debug('BP: ' + bp);
this.debug(`BP: ${bp}`);
return bp;
},
category: "Physical",
@ -14676,7 +14678,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
},
onFieldStart(field, source, effect) {
if (effect?.effectType === 'Ability') {
this.add('-fieldstart', 'move: Psychic Terrain', '[from] ability: ' + effect.name, '[of] ' + source);
this.add('-fieldstart', 'move: Psychic Terrain', '[from] ability: ' + effect.name, `[of] ${source}`);
} else {
this.add('-fieldstart', 'move: Psychic Terrain');
}
@ -14843,7 +14845,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
basePowerCallback(pokemon, target) {
let power = 60 + 20 * target.positiveBoosts();
if (power > 200) power = 200;
this.debug('BP: ' + power);
this.debug(`BP: ${power}`);
return power;
},
category: "Physical",
@ -15244,12 +15246,12 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
onAfterHit(target, pokemon, move) {
if (!move.hasSheerForce) {
if (pokemon.hp && pokemon.removeVolatile('leechseed')) {
this.add('-end', pokemon, 'Leech Seed', '[from] move: Rapid Spin', '[of] ' + pokemon);
this.add('-end', pokemon, 'Leech Seed', '[from] move: Rapid Spin', `[of] ${pokemon}`);
}
const sideConditions = ['spikes', 'toxicspikes', 'stealthrock', 'stickyweb', 'gmaxsteelsurge'];
for (const condition of sideConditions) {
if (pokemon.hp && pokemon.side.removeSideCondition(condition)) {
this.add('-sideend', pokemon.side, this.dex.conditions.get(condition).name, '[from] move: Rapid Spin', '[of] ' + pokemon);
this.add('-sideend', pokemon.side, this.dex.conditions.get(condition).name, '[from] move: Rapid Spin', `[of] ${pokemon}`);
}
}
if (pokemon.hp && pokemon.volatiles['partiallytrapped']) {
@ -15260,12 +15262,12 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
onAfterSubDamage(damage, target, pokemon, move) {
if (!move.hasSheerForce) {
if (pokemon.hp && pokemon.removeVolatile('leechseed')) {
this.add('-end', pokemon, 'Leech Seed', '[from] move: Rapid Spin', '[of] ' + pokemon);
this.add('-end', pokemon, 'Leech Seed', '[from] move: Rapid Spin', `[of] ${pokemon}`);
}
const sideConditions = ['spikes', 'toxicspikes', 'stealthrock', 'stickyweb', 'gmaxsteelsurge'];
for (const condition of sideConditions) {
if (pokemon.hp && pokemon.side.removeSideCondition(condition)) {
this.add('-sideend', pokemon.side, this.dex.conditions.get(condition).name, '[from] move: Rapid Spin', '[of] ' + pokemon);
this.add('-sideend', pokemon.side, this.dex.conditions.get(condition).name, '[from] move: Rapid Spin', `[of] ${pokemon}`);
}
}
if (pokemon.hp && pokemon.volatiles['partiallytrapped']) {
@ -15447,7 +15449,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
return false;
}
}
this.add('-start', source, 'typechange', '[from] move: Reflect Type', '[of] ' + target);
this.add('-start', source, 'typechange', '[from] move: Reflect Type', `[of] ${target}`);
source.setType(newBaseTypes);
source.addedType = target.addedType;
source.knownType = target.isAlly(source) && target.knownType;
@ -15525,11 +15527,11 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
}
// insomnia and vital spirit checks are separate so that the message is accurate in multi-ability mods
if (source.hasAbility('insomnia')) {
this.add('-fail', source, '[from] ability: Insomnia', '[of] ' + source);
this.add('-fail', source, '[from] ability: Insomnia', `[of] ${source}`);
return null;
}
if (source.hasAbility('vitalspirit')) {
this.add('-fail', source, '[from] ability: Vital Spirit', '[of] ' + source);
this.add('-fail', source, '[from] ability: Vital Spirit', `[of] ${source}`);
return null;
}
},
@ -15616,7 +15618,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
p => p.source === target && p.damage > 0 && p.thisTurn
);
if (damagedByTarget) {
this.debug('BP doubled for getting hit by ' + target);
this.debug(`BP doubled for getting hit by ${target}`);
return move.basePower * 2;
}
return move.basePower;
@ -15652,7 +15654,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
} else {
bp = 20;
}
this.debug('BP: ' + bp);
this.debug(`BP: ${bp}`);
return bp;
},
category: "Physical",
@ -15903,7 +15905,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
onHit(target, source) {
const oldAbility = source.setAbility(target.ability);
if (oldAbility) {
this.add('-ability', source, source.getAbility().name, '[from] move: Role Play', '[of] ' + target);
this.add('-ability', source, source.getAbility().name, '[from] move: Role Play', `[of] ${target}`);
return;
}
return oldAbility as false | null;
@ -15940,7 +15942,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
let bp = move.basePower;
const rolloutData = pokemon.volatiles['rollout'];
if (rolloutData?.hitCount) {
bp *= Math.pow(2, rolloutData.contactHitCount);
bp *= 2 ** rolloutData.contactHitCount;
}
if (rolloutData && pokemon.status !== 'slp') {
rolloutData.hitCount++;
@ -15952,7 +15954,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
if (pokemon.volatiles['defensecurl']) {
bp *= 2;
}
this.debug("BP: " + bp);
this.debug(`BP: ${bp}`);
return bp;
},
category: "Physical",
@ -17229,16 +17231,16 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
const targetAbility = target.getAbility();
const sourceAbility = source.getAbility();
if (target.isAlly(source)) {
this.add('-activate', source, 'move: Skill Swap', '', '', '[of] ' + target);
this.add('-activate', source, 'move: Skill Swap', '', '', `[of] ${target}`);
} else {
this.add('-activate', source, 'move: Skill Swap', targetAbility, sourceAbility, '[of] ' + target);
this.add('-activate', source, 'move: Skill Swap', targetAbility, sourceAbility, `[of] ${target}`);
}
this.singleEvent('End', sourceAbility, source.abilityState, source);
this.singleEvent('End', targetAbility, target.abilityState, target);
source.ability = targetAbility.id;
target.ability = sourceAbility.id;
source.abilityState = this.initEffectState({ id: this.toID(source.ability), target: source });
target.abilityState = this.initEffectState({id: this.toID(target.ability), target: target});
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);
@ -17783,7 +17785,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
return;
}
snatchUser.removeVolatile('snatch');
this.add('-activate', snatchUser, 'move: Snatch', '[of] ' + source);
this.add('-activate', snatchUser, 'move: Snatch', `[of] ${source}`);
this.actions.useMove(move.id, snatchUser);
return null;
},
@ -18103,7 +18105,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
const targetSpe = target.storedStats.spe;
target.storedStats.spe = source.storedStats.spe;
source.storedStats.spe = targetSpe;
this.add('-activate', source, 'move: Speed Swap', '[of] ' + target);
this.add('-activate', source, 'move: Speed Swap', `[of] ${target}`);
},
secondary: null,
target: "normal",
@ -18509,7 +18511,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
onSwitchIn(pokemon) {
if (pokemon.hasItem('heavydutyboots')) return;
const typeMod = this.clampIntRange(pokemon.runEffectiveness(this.dex.getActiveMove('stealthrock')), -6, 6);
this.damage(pokemon.maxhp * Math.pow(2, typeMod) / 8);
this.damage(pokemon.maxhp * (2 ** typeMod) / 8);
},
},
secondary: null,
@ -18805,7 +18807,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
basePower: 20,
basePowerCallback(pokemon, target, move) {
const bp = move.basePower + 20 * pokemon.positiveBoosts();
this.debug('BP: ' + bp);
this.debug(`BP: ${bp}`);
return bp;
},
category: "Special",
@ -19391,7 +19393,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
if (myItem) source.item = myItem.id;
return false;
}
this.add('-activate', source, 'move: Trick', '[of] ' + target);
this.add('-activate', source, 'move: Trick', `[of] ${target}`);
if (myItem) {
target.setItem(myItem);
this.add('-item', target, myItem, '[from] move: Switcheroo');
@ -20068,8 +20070,8 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
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);
this.add('-enditem', target, yourItem, '[silent]', '[from] move: Thief', `[of] ${source}`);
this.add('-item', source, yourItem, '[from] move: Thief', `[of] ${target}`);
},
secondary: null,
target: "normal",
@ -20534,10 +20536,10 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
onSwitchIn(pokemon) {
if (!pokemon.isGrounded()) return;
if (pokemon.hasType('Poison')) {
this.add('-sideend', pokemon.side, 'move: Toxic Spikes', '[of] ' + pokemon);
this.add('-sideend', pokemon.side, 'move: Toxic Spikes', `[of] ${pokemon}`);
pokemon.side.removeSideCondition('toxicspikes');
} else if (pokemon.hasType('Steel') || pokemon.hasItem('heavydutyboots')) {
return;
// do nothing
} else if (this.effectState.layers >= 2) {
pokemon.trySetStatus('tox', pokemon.side.foe.active[0]);
} else {
@ -20665,7 +20667,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
if (myItem) source.item = myItem.id;
return false;
}
this.add('-activate', source, 'move: Trick', '[of] ' + target);
this.add('-activate', source, 'move: Trick', `[of] ${target}`);
if (myItem) {
target.setItem(myItem);
this.add('-item', target, myItem, '[from] move: Trick');
@ -20735,9 +20737,9 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
},
onFieldStart(target, source) {
if (source?.hasAbility('persistent')) {
this.add('-fieldstart', 'move: Trick Room', '[of] ' + source, '[persistent]');
this.add('-fieldstart', 'move: Trick Room', `[of] ${source}`, '[persistent]');
} else {
this.add('-fieldstart', 'move: Trick Room', '[of] ' + source);
this.add('-fieldstart', 'move: Trick Room', `[of] ${source}`);
}
},
onFieldRestart(target, source) {
@ -20884,7 +20886,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
}
}
this.debug('BP: ' + bp);
this.debug(`BP: ${bp}`);
return bp;
},
category: "Special",
@ -21109,7 +21111,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
basePower: 0,
basePowerCallback(pokemon) {
const bp = Math.floor((pokemon.happiness * 10) / 25) || 1;
this.debug('BP: ' + bp);
this.debug(`BP: ${bp}`);
return bp;
},
category: "Physical",
@ -21439,7 +21441,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
condition: {
duration: 5,
onFieldStart(field, source) {
this.add('-fieldstart', 'move: Water Sport', '[of] ' + source);
this.add('-fieldstart', 'move: Water Sport', `[of] ${source}`);
},
onBasePowerPriority: 1,
onBasePower(basePower, attacker, defender, move) {
@ -21466,7 +21468,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
basePower: 150,
basePowerCallback(pokemon, target, move) {
const bp = move.basePower * pokemon.hp / pokemon.maxhp;
this.debug('BP: ' + bp);
this.debug(`BP: ${bp}`);
return bp;
},
category: "Special",
@ -21539,7 +21541,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
move.basePower *= 2;
break;
}
this.debug('BP: ' + move.basePower);
this.debug(`BP: ${move.basePower}`);
},
secondary: null,
target: "normal",
@ -21813,9 +21815,9 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
},
onFieldStart(field, source) {
if (source?.hasAbility('persistent')) {
this.add('-fieldstart', 'move: Wonder Room', '[of] ' + source, '[persistent]');
this.add('-fieldstart', 'move: Wonder Room', `[of] ${source}`, '[persistent]');
} else {
this.add('-fieldstart', 'move: Wonder Room', '[of] ' + source);
this.add('-fieldstart', 'move: Wonder Room', `[of] ${source}`);
}
},
onFieldRestart(target, source) {
@ -21929,7 +21931,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
const hp = target.hp;
const maxHP = target.maxhp;
const bp = Math.floor(Math.floor((120 * (100 * Math.floor(hp * 4096 / maxHP)) + 2048 - 1) / 4096) / 100) || 1;
this.debug('BP for ' + hp + '/' + maxHP + " HP: " + bp);
this.debug(`BP for ${hp}/${maxHP} HP: ${bp}`);
return bp;
},
category: "Special",
@ -21978,7 +21980,7 @@ export const Moves: import('../sim/dex-moves').MoveDataTable = {
noCopy: true, // doesn't get copied by Baton Pass
duration: 2,
onStart(target, source) {
this.add('-start', target, 'move: Yawn', '[of] ' + source);
this.add('-start', target, 'move: Yawn', `[of] ${source}`);
},
onResidualOrder: 23,
onEnd(target) {

View File

@ -89,8 +89,8 @@ export class RandomGen1Teams extends RandomGen2Teams {
moves: this.multipleSamplesNoReplace(pool, 4),
gender: false,
ability: 'No Ability',
evs: evs,
ivs: ivs,
evs,
ivs,
item: '',
level,
happiness: 0,

View File

@ -1,5 +1,5 @@
import RandomGen3Teams from '../gen3/teams';
import {PRNG, PRNGSeed} from '../../../sim/prng';
import type { PRNG, PRNGSeed } from '../../../sim/prng';
import type { MoveCounter } from '../gen8/teams';
// Moves that restore HP:
@ -312,7 +312,7 @@ export class RandomGen2Teams extends RandomGen3Teams {
if (['Fast Attacker', 'Setup Sweeper', 'Bulky Attacker'].includes(role)) {
if (counter.damagingMoves.size === 1) {
// Find the type of the current attacking move
const currentAttackType = counter.damagingMoves.values().next().value.type;
const currentAttackType = counter.damagingMoves.values().next().value!.type;
// Choose an attacking move that is of different type to the current single attack
const coverageMoves = [];
for (const moveid of movePool) {

View File

@ -1,5 +1,5 @@
import RandomGen4Teams from '../gen4/teams';
import {PRNG, PRNGSeed} from '../../../sim/prng';
import type { PRNG, PRNGSeed } from '../../../sim/prng';
import type { MoveCounter } from '../gen8/teams';
// Moves that restore HP:
@ -349,7 +349,7 @@ export class RandomGen3Teams extends RandomGen4Teams {
if (['Fast Attacker', 'Setup Sweeper', 'Bulky Attacker', 'Wallbreaker', 'Berry Sweeper'].includes(role)) {
if (counter.damagingMoves.size === 1) {
// Find the type of the current attacking move
const currentAttackType = counter.damagingMoves.values().next().value.type;
const currentAttackType = counter.damagingMoves.values().next().value!.type;
// Choose an attacking move that is of different type to the current single attack
const coverageMoves = [];
for (const moveid of movePool) {
@ -410,7 +410,6 @@ export class RandomGen3Teams extends RandomGen4Teams {
return false;
}
getAbility(
types: Set<string>,
moves: Set<string>,
@ -701,7 +700,7 @@ export class RandomGen3Teams extends RandomGen4Teams {
}
if (this.dex.getEffectiveness(typeName, species) > 1) {
if (!typeDoubleWeaknesses[typeName]) typeDoubleWeaknesses[typeName] = 0;
if (typeDoubleWeaknesses[typeName] >= 1 * limitFactor) {
if (typeDoubleWeaknesses[typeName] >= limitFactor) {
skip = true;
break;
}

View File

@ -1,5 +1,5 @@
import RandomGen5Teams from '../gen5/teams';
import {PRNG} from '../../../sim';
import type { PRNG } from '../../../sim';
import type { MoveCounter } from '../gen8/teams';
// Moves that restore HP:
@ -427,7 +427,7 @@ export class RandomGen4Teams extends RandomGen5Teams {
if (['Fast Attacker', 'Setup Sweeper', 'Bulky Attacker', 'Wallbreaker'].includes(role)) {
if (counter.damagingMoves.size === 1) {
// Find the type of the current attacking move
const currentAttackType = counter.damagingMoves.values().next().value.type;
const currentAttackType = counter.damagingMoves.values().next().value!.type;
// Choose an attacking move that is of different type to the current single attack
const coverageMoves = [];
for (const moveid of movePool) {
@ -490,7 +490,6 @@ export class RandomGen4Teams extends RandomGen5Teams {
return false;
}
getAbility(
types: Set<string>,
moves: Set<string>,

View File

@ -1,6 +1,6 @@
import RandomGen6Teams from '../gen6/teams';
import {PRNG} from '../../../sim';
import {MoveCounter} from '../gen8/teams';
import type { PRNG } from '../../../sim';
import type { MoveCounter } from '../gen8/teams';
import { toID } from '../../../sim/dex';
// Moves that restore HP:
@ -454,7 +454,7 @@ export class RandomGen5Teams extends RandomGen6Teams {
if (['Fast Attacker', 'Setup Sweeper', 'Bulky Attacker', 'Wallbreaker'].includes(role)) {
if (counter.damagingMoves.size === 1) {
// Find the type of the current attacking move
const currentAttackType = counter.damagingMoves.values().next().value.type;
const currentAttackType = counter.damagingMoves.values().next().value!.type;
// Choose an attacking move that is of different type to the current single attack
const coverageMoves = [];
for (const moveid of movePool) {
@ -521,7 +521,6 @@ export class RandomGen5Teams extends RandomGen6Teams {
return false;
}
getAbility(
types: Set<string>,
moves: Set<string>,
@ -905,7 +904,7 @@ export class RandomGen5Teams extends RandomGen6Teams {
}
if (this.dex.getEffectiveness(typeName, species) > 1) {
if (!typeDoubleWeaknesses[typeName]) typeDoubleWeaknesses[typeName] = 0;
if (typeDoubleWeaknesses[typeName] >= 1 * limitFactor) {
if (typeDoubleWeaknesses[typeName] >= limitFactor) {
skip = true;
break;
}

View File

@ -1,6 +1,6 @@
import {MoveCounter, TeamData} from '../gen8/teams';
import RandomGen7Teams, {BattleFactorySpecies, ZeroAttackHPIVs} from '../gen7/teams';
import {PRNG, PRNGSeed} from '../../../sim/prng';
import { type MoveCounter, type TeamData } from '../gen8/teams';
import RandomGen7Teams, { type BattleFactorySpecies, ZeroAttackHPIVs } from '../gen7/teams';
import { type PRNG, type PRNGSeed } from '../../../sim/prng';
import { toID } from '../../../sim/dex';
// Moves that restore HP:
@ -490,7 +490,7 @@ export class RandomGen6Teams extends RandomGen7Teams {
if (['Fast Attacker', 'Setup Sweeper', 'Bulky Attacker', 'Wallbreaker'].includes(role)) {
if (counter.damagingMoves.size === 1) {
// Find the type of the current attacking move
const currentAttackType = counter.damagingMoves.values().next().value.type;
const currentAttackType = counter.damagingMoves.values().next().value!.type;
// Choose an attacking move that is of different type to the current single attack
const coverageMoves = [];
for (const moveid of movePool) {
@ -561,7 +561,6 @@ export class RandomGen6Teams extends RandomGen7Teams {
return false;
}
getAbility(
types: Set<string>,
moves: Set<string>,
@ -905,7 +904,9 @@ export class RandomGen6Teams extends RandomGen7Teams {
const movesMax: { [k: string]: number } = {
rapidspin: 1, batonpass: 1, stealthrock: 1, defog: 1, spikes: 1, toxicspikes: 1,
};
const requiredMoves: {[k: string]: string} = {stealthrock: 'hazardSet', rapidspin: 'hazardClear', defog: 'hazardClear'};
const requiredMoves: { [k: string]: string } = {
stealthrock: 'hazardSet', rapidspin: 'hazardClear', defog: 'hazardClear',
};
const weatherAbilitiesRequire: { [k: string]: string } = {
hydration: 'raindance', swiftswim: 'raindance',
leafguard: 'sunnyday', solarpower: 'sunnyday', chlorophyll: 'sunnyday',
@ -975,7 +976,7 @@ export class RandomGen6Teams extends RandomGen7Teams {
evs: setData.set.evs || { hp: 84, atk: 84, def: 84, spa: 84, spd: 84, spe: 84 },
ivs: setData.set.ivs || { hp: 31, atk: 31, def: 31, spa: 31, spd: 31, spe: 31 },
nature: setData.set.nature || 'Serious',
moves: moves,
moves,
};
}
@ -998,7 +999,9 @@ export class RandomGen6Teams extends RandomGen7Teams {
weaknesses: {}, resistances: {},
};
const requiredMoveFamilies = ['hazardSet', 'hazardClear'];
const requiredMoves: {[k: string]: string} = {stealthrock: 'hazardSet', rapidspin: 'hazardClear', defog: 'hazardClear'};
const requiredMoves: { [k: string]: string } = {
stealthrock: 'hazardSet', rapidspin: 'hazardClear', defog: 'hazardClear',
};
const weatherAbilitiesSet: { [k: string]: string } = {
drizzle: 'raindance', drought: 'sunnyday', snowwarning: 'hail', sandstream: 'sandstorm',
};
@ -1047,7 +1050,7 @@ export class RandomGen6Teams extends RandomGen7Teams {
// Drought and Drizzle don't count towards the type combo limit
typeCombo = set.ability;
}
if (teamData.typeComboCount[typeCombo] >= 1 * limitFactor) continue;
if (teamData.typeComboCount[typeCombo] >= limitFactor) continue;
// Okay, the set passes, add it to our team
pokemon.push(set);

View File

@ -1,5 +1,5 @@
import {MoveCounter, TeamData, RandomGen8Teams} from '../gen8/teams';
import {PRNG, PRNGSeed} from '../../../sim/prng';
import { MoveCounter, type TeamData, RandomGen8Teams } from '../gen8/teams';
import type { PRNG, PRNGSeed } from '../../../sim/prng';
import { toID } from '../../../sim/dex';
export interface BattleFactorySpecies {
@ -679,7 +679,7 @@ export class RandomGen7Teams extends RandomGen8Teams {
if (['Fast Attacker', 'Setup Sweeper', 'Bulky Attacker', 'Wallbreaker', 'Z-Move user'].includes(role)) {
if (counter.damagingMoves.size === 1) {
// Find the type of the current attacking move
const currentAttackType = counter.damagingMoves.values().next().value.type;
const currentAttackType = counter.damagingMoves.values().next().value!.type;
// Choose an attacking move that is of different type to the current single attack
const coverageMoves = [];
for (const moveid of movePool) {
@ -752,7 +752,6 @@ export class RandomGen7Teams extends RandomGen8Teams {
return false;
}
getAbility(
types: Set<string>,
moves: Set<string>,
@ -1268,7 +1267,7 @@ export class RandomGen7Teams extends RandomGen8Teams {
}
if (this.dex.getEffectiveness(typeName, species) > 0) {
if (!typeDoubleWeaknesses[typeName]) typeDoubleWeaknesses[typeName] = 0;
if (typeDoubleWeaknesses[typeName] >= 1 * limitFactor) {
if (typeDoubleWeaknesses[typeName] >= limitFactor) {
skip = true;
break;
}
@ -1483,7 +1482,6 @@ export class RandomGen7Teams extends RandomGen8Teams {
moves.push(setData.moveVariants ? moveSlot[setData.moveVariants[i]] : this.sample(moveSlot));
}
const item = setData.item || this.sampleIfArray(setData.set.item);
const ability = setData.ability || this.sampleIfArray(setData.set.ability);
const nature = this.sampleIfArray(setData.set.nature);
@ -1537,7 +1535,7 @@ export class RandomGen7Teams extends RandomGen8Teams {
const teamData: TeamData = {
typeCount: {}, typeComboCount: {}, baseFormes: {}, megaCount: 0, zCount: 0,
has: {}, forceResult: forceResult, weaknesses: {}, resistances: {},
has: {}, forceResult, weaknesses: {}, resistances: {},
};
const requiredMoveFamilies = ['hazardSet', 'hazardClear'];
const requiredMoves: { [k: string]: string } = {
@ -1623,7 +1621,7 @@ export class RandomGen7Teams extends RandomGen8Teams {
// Drought and Drizzle don't count towards the type combo limit
typeCombo = set.ability + '';
}
if (teamData.typeComboCount[typeCombo] >= 1 * limitFactor) continue;
if (teamData.typeComboCount[typeCombo] >= limitFactor) continue;
}
// Okay, the set passes, add it to our team
@ -1866,7 +1864,7 @@ export class RandomGen7Teams extends RandomGen8Teams {
// Drought and Drizzle don't count towards the type combo limit
typeCombo = set.ability;
}
if (teamData.typeComboCount[typeCombo] >= 1 * limitFactor) continue;
if (teamData.typeComboCount[typeCombo] >= limitFactor) continue;
// Okay, the set passes, add it to our team
pokemon.push(set);

View File

@ -1,5 +1,5 @@
import type { PRNG } from '../../../sim';
import {MoveCounter, RandomGen8Teams, OldRandomBattleSpecies} from '../gen8/teams';
import { type MoveCounter, RandomGen8Teams, type OldRandomBattleSpecies } from '../gen8/teams';
export class RandomLetsGoTeams extends RandomGen8Teams {
randomData: { [species: string]: OldRandomBattleSpecies } = require('./data.json');

View File

@ -1,7 +1,7 @@
import { Dex, toID } from '../../../sim/dex';
import { Utils } from '../../../lib';
import {PRNG, PRNGSeed} from '../../../sim/prng';
import {RuleTable} from '../../../sim/dex-formats';
import { PRNG, type PRNGSeed } from '../../../sim/prng';
import { type RuleTable } from '../../../sim/dex-formats';
import { Tags } from './../../tags';
export interface TeamData {
@ -169,7 +169,7 @@ export class RandomGen8Teams {
!moves.has('calmmind') &&
['protect', 'substitute', 'spikyshield'].some(m => movePool.includes(m))
),
Bug: (movePool) => movePool.includes('megahorn'),
Bug: movePool => movePool.includes('megahorn'),
Dark: (movePool, moves, abilities, types, counter) => {
if (!counter.get('Dark')) return true;
return moves.has('suckerpunch') && (movePool.includes('knockoff') || movePool.includes('wickedblow'));
@ -250,7 +250,7 @@ export class RandomGen8Teams {
const generatorName = (
typeof this.format.team === 'string' && this.format.team.startsWith('random')
) ? this.format.team + 'Team' : '';
// @ts-ignore
// @ts-expect-error property access
return this[generatorName || 'randomTeam'](options);
}
@ -1687,7 +1687,6 @@ export class RandomGen8Teams {
return false;
}
getAbility(
types: Set<string>,
moves: Set<string>,
@ -2234,7 +2233,7 @@ export class RandomGen8Teams {
const runEnforcementChecker = (checkerName: string) => {
if (!this.moveEnforcementCheckers[checkerName]) return false;
return this.moveEnforcementCheckers[checkerName](
movePool, moves, abilities, types, counter, species as Species, teamDetails
movePool, moves, abilities, types, counter, species, teamDetails
);
};
@ -2562,7 +2561,7 @@ export class RandomGen8Teams {
}
if (this.dex.getEffectiveness(typeName, species) > 1) {
if (!typeDoubleWeaknesses[typeName]) typeDoubleWeaknesses[typeName] = 0;
if (typeDoubleWeaknesses[typeName] >= 1 * limitFactor) {
if (typeDoubleWeaknesses[typeName] >= limitFactor) {
skip = true;
break;
}
@ -2788,7 +2787,6 @@ export class RandomGen8Teams {
moves.push(setData.moveVariants ? moveSlot[setData.moveVariants[i]] : this.sample(moveSlot));
}
const item = setData.item || this.sampleIfArray(setData.set.item);
const ability = setData.ability || this.sampleIfArray(setData.set.ability);
const nature = this.sampleIfArray(setData.set.nature);
@ -2847,7 +2845,7 @@ export class RandomGen8Teams {
const teamData: TeamData = {
typeCount: {}, typeComboCount: {}, baseFormes: {},
has: {}, forceResult: forceResult, weaknesses: {}, resistances: {},
has: {}, forceResult, weaknesses: {}, resistances: {},
};
const requiredMoveFamilies = ['hazardSet', 'hazardClear'];
const requiredMoves: { [k: string]: string } = {
@ -2925,7 +2923,7 @@ export class RandomGen8Teams {
// Drought and Drizzle don't count towards the type combo limit
typeCombo = set.ability + '';
}
if (teamData.typeComboCount[typeCombo] >= 1 * limitFactor) continue;
if (teamData.typeComboCount[typeCombo] >= limitFactor) continue;
}
// Okay, the set passes, add it to our team
@ -3085,7 +3083,7 @@ export class RandomGen8Teams {
const pokemonPool = Object.keys(this.randomBSSFactorySets);
const teamData: TeamData = {
typeCount: {}, typeComboCount: {}, baseFormes: {}, has: {}, forceResult: forceResult,
typeCount: {}, typeComboCount: {}, baseFormes: {}, has: {}, forceResult,
weaknesses: {}, resistances: {},
};
const weatherAbilitiesSet: { [k: string]: string } = {
@ -3111,8 +3109,8 @@ export class RandomGen8Teams {
const shuffledSpecies = [];
for (const speciesName of pokemonPool) {
const sortObject = {
speciesName: speciesName,
score: Math.pow(this.prng.random(), 1 / this.randomBSSFactorySets[speciesName].usage),
speciesName,
score: this.prng.random() ** (1 / this.randomBSSFactorySets[speciesName].usage),
};
shuffledSpecies.push(sortObject);
}

View File

@ -1,7 +1,7 @@
// BDSP team generation logic is currently largely shared with Swsh
import {PRNG, PRNGSeed} from '../../../sim/prng';
import {MoveCounter, RandomGen8Teams, OldRandomBattleSpecies} from '../gen8/teams';
import { type PRNG, type PRNGSeed } from '../../../sim/prng';
import { type MoveCounter, RandomGen8Teams, type OldRandomBattleSpecies } from '../gen8/teams';
export class RandomBDSPTeams extends RandomGen8Teams {
randomData: { [species: string]: OldRandomBattleSpecies } = require('./data.json');

View File

@ -1,7 +1,7 @@
import { Dex, toID } from '../../../sim/dex';
import { Utils } from '../../../lib';
import {PRNG, PRNGSeed} from '../../../sim/prng';
import {RuleTable} from '../../../sim/dex-formats';
import { PRNG, type PRNGSeed } from '../../../sim/prng';
import { type RuleTable } from '../../../sim/dex-formats';
import { Tags } from './../../tags';
import { Teams } from '../../../sim/teams';
@ -255,11 +255,11 @@ export class RandomTeams {
this.prng = PRNG.get(prng);
}
getTeam(options?: PlayerOptions | null): PokemonSet[] {
getTeam(options: PlayerOptions | null = null): PokemonSet[] {
const generatorName = (
typeof this.format.team === 'string' && this.format.team.startsWith('random')
) ? this.format.team + 'Team' : '';
// @ts-ignore
// @ts-expect-error property access
return this[generatorName || 'randomTeam'](options);
}
@ -995,7 +995,7 @@ export class RandomTeams {
if (!['AV Pivot', 'Fast Support', 'Bulky Support', 'Bulky Protect', 'Doubles Support'].includes(role)) {
if (counter.damagingMoves.size === 1) {
// Find the type of the current attacking move
const currentAttackType = counter.damagingMoves.values().next().value.type;
const currentAttackType = counter.damagingMoves.values().next().value!.type;
// Choose an attacking move that is of different type to the current single attack
const coverageMoves = [];
for (const moveid of movePool) {
@ -1081,7 +1081,6 @@ export class RandomTeams {
return false;
}
getAbility(
types: string[],
moves: Set<string>,
@ -1715,7 +1714,7 @@ export class RandomTeams {
}
if (this.dex.getEffectiveness(typeName, species) > 1) {
if (!typeDoubleWeaknesses[typeName]) typeDoubleWeaknesses[typeName] = 0;
if (typeDoubleWeaknesses[typeName] >= 1 * limitFactor) {
if (typeDoubleWeaknesses[typeName] >= limitFactor) {
skip = true;
break;
}
@ -2496,7 +2495,6 @@ export class RandomTeams {
};
}
randomFactoryTeam(side: PlayerOptions, depth = 0): RandomTeamsTypes.RandomFactorySet[] {
this.enforceNoDirectCustomBanlistChanges();
@ -2525,7 +2523,7 @@ export class RandomTeams {
baseFormes: {},
has: {},
wantsTeraCount: 0,
forceResult: forceResult,
forceResult,
weaknesses: {},
resistances: {},
};
@ -2560,7 +2558,7 @@ export class RandomTeams {
for (const speciesName of pokemonPool) {
const sortObject = {
speciesName,
score: Math.pow(this.prng.random(), 1 / this.randomFactorySets[this.factoryTier][speciesName].weight),
score: this.prng.random() ** (1 / this.randomFactorySets[this.factoryTier][speciesName].weight),
};
shuffledSpecies.push(sortObject);
}
@ -2813,7 +2811,6 @@ export class RandomTeams {
};
}
randomBSSFactoryTeam(side: PlayerOptions, depth = 0): RandomTeamsTypes.RandomFactorySet[] {
this.enforceNoDirectCustomBanlistChanges();
@ -2829,7 +2826,7 @@ export class RandomTeams {
baseFormes: {},
has: {},
wantsTeraCount: 0,
forceResult: forceResult,
forceResult,
weaknesses: {},
resistances: {},
};
@ -2858,7 +2855,7 @@ export class RandomTeams {
for (const speciesName of pokemonPool) {
const sortObject = {
speciesName,
score: Math.pow(this.prng.random(), 1 / this.randomBSSFactorySets[speciesName].weight),
score: this.prng.random() ** (1 / this.randomBSSFactorySets[speciesName].weight),
};
shuffledSpecies.push(sortObject);
}

View File

@ -1,5 +1,5 @@
import {PRNG, PRNGSeed} from "../../../sim/prng";
import {RandomTeams, MoveCounter} from "../gen9/teams";
import type { PRNG, PRNGSeed } from "../../../sim/prng";
import { RandomTeams, type MoveCounter } from "../gen9/teams";
import { Utils } from '../../../lib';
// First, some lists of moves that can be used for rules throughout set generation. Taken from regular gen9.
@ -62,7 +62,6 @@ export class RandomBabyTeams extends RandomTeams {
);
}
cullMovePool(
types: string[],
moves: Set<string>,
@ -376,7 +375,7 @@ export class RandomBabyTeams extends RandomTeams {
if (!['Fast Support', 'Bulky Support'].includes(role) || species.id === 'magnemite') {
if (counter.damagingMoves.size === 1) {
// Find the type of the current attacking move
const currentAttackType = counter.damagingMoves.values().next().value.type;
const currentAttackType = counter.damagingMoves.values().next().value!.type;
// Choose an attacking move that is of different type to the current single attack
const coverageMoves = [];
for (const moveid of movePool) {
@ -593,7 +592,6 @@ export class RandomBabyTeams extends RandomTeams {
// Get level
const level = this.getLevel(species);
// Prepare optimal HP for Belly Drum and Life Orb
let hp = Math.floor(Math.floor(2 * species.baseStats.hp + ivs.hp + Math.floor(evs.hp / 4) + 100) * level / 100 + 10);
let targetHP = hp;
@ -731,7 +729,7 @@ export class RandomBabyTeams extends RandomTeams {
}
}
if (this.dex.getEffectiveness(typeName, species) > 1) {
if (typeDoubleWeaknesses.get(typeName) >= 1 * limitFactor) {
if (typeDoubleWeaknesses.get(typeName) >= limitFactor) {
skip = true;
break;
}
@ -758,7 +756,6 @@ export class RandomBabyTeams extends RandomTeams {
const set: RandomTeamsTypes.RandomSet = this.randomSet(species, teamDetails, false, false);
pokemon.push(set);
// Don't bother tracking details for the last Pokemon
if (pokemon.length === this.maxTeamSize) break;

View File

@ -1,4 +1,4 @@
import {RandomTeams, MoveCounter} from "../gen9/teams";
import { RandomTeams, type MoveCounter } from "../gen9/teams";
/** Pokemon who should never be in the lead slot */
const NO_LEAD_POKEMON = [
@ -265,7 +265,7 @@ export class RandomCAPTeams extends RandomTeams {
}
if (this.dex.getEffectiveness(typeName, species) > 1) {
if (!typeDoubleWeaknesses[typeName]) typeDoubleWeaknesses[typeName] = 0;
if (typeDoubleWeaknesses[typeName] >= 1 * limitFactor) {
if (typeDoubleWeaknesses[typeName] >= limitFactor) {
skip = true;
break;
}

View File

@ -479,7 +479,7 @@ export const Rulesets: import('../sim/dex-formats').FormatDataTable = {
name: 'PotD',
desc: "Forces the Pokemon of the Day onto every random team.",
onBegin() {
if (global.Config && global.Config.potd) {
if (global.Config?.potd) {
this.add('rule', "Pokemon of the Day: " + this.dex.species.get(Config.potd).name);
}
},
@ -1064,7 +1064,7 @@ export const Rulesets: import('../sim/dex-formats').FormatDataTable = {
for (const moveId of set.moves) {
const move = this.dex.moves.get(moveId);
if (move.id === 'flamecharge' || (move.boosts && move.boosts.spe && move.boosts.spe > 0)) {
if (move.id === 'flamecharge' || (move.boosts?.spe && move.boosts.spe > 0)) {
speedBoosted = true;
}
const nonSpeedBoostedMoves = [
@ -1082,8 +1082,8 @@ export const Rulesets: import('../sim/dex-formats').FormatDataTable = {
if (!speedBoosted) speedBoosted = move.name;
}
if (
((boosts.atk && boosts.atk > 0) || (boosts.def && boosts.def > 0) ||
(boosts.spa && boosts.spa > 0) || (boosts.spd && boosts.spd > 0))
(boosts.atk && boosts.atk > 0) || (boosts.def && boosts.def > 0) ||
(boosts.spa && boosts.spa > 0) || (boosts.spd && boosts.spd > 0)
) {
if (!nonSpeedBoosted || move.name === speedBoosted) nonSpeedBoosted = move.name;
}
@ -1312,13 +1312,13 @@ export const Rulesets: import('../sim/dex-formats').FormatDataTable = {
this.add('rule', 'Sleep Clause Mod: Limit one foe put to sleep');
},
onSetStatus(status, target, source) {
if (source && source.isAlly(target)) {
if (source?.isAlly(target)) {
return;
}
if (status.id === 'slp') {
for (const pokemon of target.side.pokemon) {
if (pokemon.hp && pokemon.status === 'slp') {
if (!pokemon.statusState.source || !pokemon.statusState.source.isAlly(pokemon)) {
if (!pokemon.statusState.source?.isAlly(pokemon)) {
this.add('-message', 'Sleep Clause Mod activated.');
this.hint("Sleep Clause Mod prevents players from putting more than one of their opponent's Pokémon to sleep at a time");
return false;
@ -1336,7 +1336,7 @@ export const Rulesets: import('../sim/dex-formats').FormatDataTable = {
this.add('rule', 'Stadium Sleep Clause: Limit one foe put to sleep');
},
onSetStatus(status, target, source) {
if (source && source.isAlly(target)) {
if (source?.isAlly(target)) {
return;
}
if (status.id === 'slp') {
@ -1384,7 +1384,7 @@ export const Rulesets: import('../sim/dex-formats').FormatDataTable = {
this.add('rule', 'Freeze Clause Mod: Limit one foe frozen');
},
onSetStatus(status, target, source) {
if (source && source.isAlly(target)) {
if (source?.isAlly(target)) {
return;
}
if (status.id === 'frz') {
@ -1673,7 +1673,7 @@ export const Rulesets: import('../sim/dex-formats').FormatDataTable = {
if (!target) return; // Chat command
if (effect && ['imposter', 'transform'].includes(effect.id)) return;
const types = [...new Set(target.baseMoveSlots.slice(0, 2).map(move => this.dex.moves.get(move.id).type))];
return {...species, types: types};
return { ...species, types };
},
onSwitchIn(pokemon) {
this.add('-start', pokemon, 'typechange', (pokemon.illusion || pokemon).getTypes(true).join('/'), '[silent]');
@ -2432,7 +2432,7 @@ export const Rulesets: import('../sim/dex-formats').FormatDataTable = {
if (!subtarget.side.addSlotCondition(subtarget, 'futuremove')) return false;
Object.assign(subtarget.side.slotConditions[subtarget.position]['futuremove'], {
move: 'doomdesire',
source: source,
source,
moveData: {
id: 'doomdesire',
name: "Doom Desire",
@ -2456,7 +2456,7 @@ export const Rulesets: import('../sim/dex-formats').FormatDataTable = {
Object.assign(subtarget.side.slotConditions[subtarget.position]['futuremove'], {
duration: 3,
move: 'futuresight',
source: source,
source,
moveData: {
id: 'futuresight',
name: "Future Sight",

435
eslint-ps-standard.mjs Normal file
View File

@ -0,0 +1,435 @@
/**
* Pokemon Showdown standard style
*
* This is Showdown's shared ESLint configuration. Each project overrides
* at least a little of it here and there, but these are the rules we use
* unless there's a good reason otherwise.
*/
// @ts-check
import eslint from '@eslint/js';
import globals from 'globals';
import tseslint from 'typescript-eslint';
import stylistic from '@stylistic/eslint-plugin';
/** @typedef {import('typescript-eslint').Config} ConfigFile */
/** @typedef {Awaited<ConfigFile>[number]} Config */
/** @typedef {NonNullable<Config['rules']>} Rules */
export { eslint, globals, tseslint, stylistic };
/** @type {Config} */
export const plugin = {
plugins: {
'@stylistic': stylistic,
'@typescript-eslint': tseslint.plugin,
},
};
/** @type {typeof tseslint.config} */
export const configure = (...args) => [
plugin,
...tseslint.config(...args),
];
/** @type {NonNullable<Config['rules']>} */
export const defaultRules = {
...stylistic.configs.customize({
braceStyle: '1tbs',
indent: 'tab',
semi: true,
jsx: true,
// ...
}).rules,
// TODO rules to revisit
// =====================
// nice to have but we mostly know && || precedence so not urgent to fix
"@stylistic/no-mixed-operators": "off",
// test only (should never be committed, but useful when testing)
// ==============================================================
// do we want unused args/destructures to start with _? unsure
"no-unused-vars": ["warn", {
args: "all",
argsIgnorePattern: ".",
caughtErrors: "all",
destructuredArrayIgnorePattern: ".",
ignoreRestSiblings: true,
}],
// "no-unused-vars": ["warn", {
// args: "all",
// argsIgnorePattern: "^_",
// caughtErrors: "all",
// destructuredArrayIgnorePattern: "^_",
// ignoreRestSiblings: true
// }],
"@stylistic/max-len": ["warn", {
"code": 120, "tabWidth": 0,
// DO NOT EDIT DIRECTLY: 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" }],
// PS code (code specific to PS)
// =============================
"@stylistic/new-parens": "off", // used for the `new class {...}` pattern
"no-prototype-builtins": "off",
// defaults too strict
// ===================
"no-empty": ["error", { "allowEmptyCatch": true }],
"no-case-declarations": "off",
// probably bugs
// =============
"array-callback-return": "error",
"no-constructor-return": "error",
"no-dupe-class-members": "error",
"no-extend-native": "error",
"no-extra-bind": "warn",
"no-extra-label": "warn",
"no-eval": "error",
"no-implied-eval": "error",
"no-inner-declarations": ["error", "functions"],
"no-iterator": "error",
"no-fallthrough": ["error", { allowEmptyCase: true, reportUnusedFallthroughComment: true }],
"no-promise-executor-return": ["error", { allowVoid: true }],
"no-return-assign": "error",
"no-self-compare": "error",
"no-sequences": "error",
"no-shadow": "error",
"no-template-curly-in-string": "error",
"no-throw-literal": "warn",
"no-unmodified-loop-condition": "error",
// best way to read first key of object
// "no-unreachable-loop": "error",
// ternary is used to convert callbacks to Promises
// tagged templates are used for the SQL library
"no-unused-expressions": ["error", { allowTernary: true, allowTaggedTemplates: true, enforceForJSX: true }],
"no-useless-call": "error",
// "no-useless-assignment": "error",
"require-atomic-updates": "error",
// syntax style (local syntactical, usually autofixable formatting decisions)
// ===========================================================================
"@stylistic/member-delimiter-style": ["error", {
multiline: { delimiter: "comma", requireLast: true },
singleline: { delimiter: "comma", requireLast: false },
overrides: { interface: {
multiline: { delimiter: "semi", requireLast: true },
singleline: { delimiter: "semi", requireLast: false },
} },
}],
"default-case-last": "error",
"eqeqeq": ["error", "always", { null: "ignore" }],
"no-array-constructor": "error",
"no-duplicate-imports": "error",
"no-implicit-coercion": ["error", { allow: ["!!", "+"] }],
"no-multi-str": "error",
"no-object-constructor": "error",
"no-proto": "error",
"no-unneeded-ternary": "error",
"no-useless-computed-key": "error",
"no-useless-constructor": "error",
"no-useless-rename": "error",
"no-useless-return": "error",
"no-var": "error",
"object-shorthand": ["error", "always"],
"operator-assignment": ["error", "always"],
"prefer-arrow-callback": "error",
"prefer-exponentiation-operator": "error",
"prefer-numeric-literals": "error",
"prefer-object-has-own": "error",
"prefer-object-spread": "error",
"prefer-promise-reject-errors": "error",
"prefer-regex-literals": "error",
"prefer-rest-params": "error",
"prefer-spread": "error",
"radix": ["error", "as-needed"],
// syntax style, overriding base
// =============================
"@stylistic/quotes": "off",
"@stylistic/quote-props": "off",
"@stylistic/function-call-spacing": "error",
"@stylistic/arrow-parens": ["error", "as-needed"],
"@stylistic/comma-dangle": ["error", {
"arrays": "always-multiline",
"objects": "always-multiline",
"imports": "always-multiline",
"exports": "always-multiline",
"functions": "never",
"importAttributes": "always-multiline",
"dynamicImports": "always-multiline",
"enums": "always-multiline",
"generics": "always-multiline",
"tuples": "always-multiline",
}],
"@stylistic/jsx-wrap-multilines": "off",
"@stylistic/jsx-closing-bracket-location": ["error", "line-aligned"],
// "@stylistic/jsx-closing-tag-location": ["error", "line-aligned"],
"@stylistic/jsx-closing-tag-location": "off",
"@stylistic/jsx-one-expression-per-line": "off",
"@stylistic/jsx-max-props-per-line": "off",
"@stylistic/jsx-function-call-newline": "off",
"no-restricted-syntax": ["error",
{ selector: "CallExpression[callee.name='Symbol']", message: "Annoying to serialize, just use a string" },
],
// whitespace
// ==========
"@stylistic/block-spacing": "error",
"@stylistic/operator-linebreak": ["error", "after"],
"@stylistic/max-statements-per-line": ["error", { max: 3, ignoredNodes: ['BreakStatement'] }],
"@stylistic/lines-between-class-members": "off",
"@stylistic/multiline-ternary": "off",
"@stylistic/object-curly-spacing": ["error", "always"],
"@stylistic/indent": ["error", "tab", { "flatTernaryExpressions": true }],
};
/** @type {NonNullable<Config['rules']>} */
export const defaultRulesTS = {
...defaultRules,
// TODO: revisit
// we should do this someday but it'd have to be a gradual manual process
// "@typescript-eslint/explicit-module-boundary-types": "off",
// like above but slightly harder, so do that one first
// "@typescript-eslint/explicit-function-return-type": "off",
// probably we should settle on a standard someday
// "@typescript-eslint/member-ordering": "off",
// "@typescript-eslint/no-extraneous-class": "error",
// maybe we should consider this
"@typescript-eslint/consistent-indexed-object-style": "off",
// typescript-eslint specific
// ==========================
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": defaultRules["no-unused-vars"],
"no-shadow": "off",
"@typescript-eslint/no-shadow": defaultRules["no-shadow"],
"no-dupe-class-members": "off",
"@typescript-eslint/no-dupe-class-members": defaultRules["no-dupe-class-members"],
"no-unused-expressions": "off",
"@typescript-eslint/no-unused-expressions": defaultRules["no-unused-expressions"],
// defaults too strict
// ===================
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-non-null-assertion": "off",
// probably bugs
// =============
"@typescript-eslint/no-empty-object-type": "error",
"@typescript-eslint/no-extra-non-null-assertion": "error",
"@typescript-eslint/no-misused-new": "error",
// no way to get it to be less strict unfortunately
// "@typescript-eslint/no-misused-spread": "error",
"@typescript-eslint/no-non-null-asserted-optional-chain": "error",
// naming style
// ============
"@typescript-eslint/naming-convention": ["error", {
"selector": ["class", "interface", "typeAlias"],
"format": ["PascalCase"],
}],
// syntax style (local syntactical, usually autofixable formatting decisions)
// ===========================================================================
"@typescript-eslint/no-namespace": ["error", { allowDeclarations: true }],
"@typescript-eslint/prefer-namespace-keyword": "error",
"@typescript-eslint/adjacent-overload-signatures": "error",
"@typescript-eslint/array-type": "error",
"@typescript-eslint/consistent-type-assertions": ["error", { "assertionStyle": "as" }],
"@typescript-eslint/consistent-type-definitions": "off",
"@typescript-eslint/consistent-type-imports": ["error", { fixStyle: "inline-type-imports" }],
"@typescript-eslint/explicit-member-accessibility": ["error", { "accessibility": "no-public" }],
"@typescript-eslint/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"] }],
// unfortunately this has lots of false positives without strict array/object property access
// "@typescript-eslint/no-unnecessary-boolean-literal-compare": "error",
"@typescript-eslint/prefer-as-const": "error",
"@typescript-eslint/prefer-for-of": "error",
"@typescript-eslint/prefer-function-type": "error",
"@typescript-eslint/prefer-return-this-type": "error",
"@typescript-eslint/triple-slash-reference": "error",
"@typescript-eslint/unified-signatures": "error",
};
/** @type {NonNullable<Config['rules']>} */
export const defaultRulesTSChecked = {
...defaultRulesTS,
// style
// =====
"@typescript-eslint/no-unnecessary-type-arguments": "error",
"@typescript-eslint/restrict-plus-operands": ["error", {
allowBoolean: false, allowNullish: false, allowNumberAndString: false, allowRegExp: false,
}],
"@typescript-eslint/restrict-template-expressions": ["error", {
allow: [{ name: ['Error', 'URL', 'URLSearchParams'], from: 'lib' }],
allowBoolean: false, allowNever: false, allowNullish: false, allowRegExp: false,
}],
// we use `any`
// ============
"@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/no-unsafe-argument": "off",
// yes-types syntax style, overriding base
// =======================================
"@typescript-eslint/prefer-includes": "error",
"@typescript-eslint/prefer-nullish-coalescing": "off",
"@typescript-eslint/dot-notation": "off",
"@typescript-eslint/no-confusing-non-null-assertion": "off",
};
/** @type {NonNullable<Config['rules']>} */
export const defaultRulesES3 = {
...defaultRules,
// required in ES3
// ================
"no-var": "off",
"object-shorthand": ["error", "never"],
"prefer-arrow-callback": "off",
"prefer-exponentiation-operator": "off",
"prefer-object-has-own": "off",
"prefer-object-spread": "off",
"prefer-rest-params": "off",
"prefer-spread": "off",
"radix": "off",
"@stylistic/comma-dangle": "error",
"no-unused-vars": ["warn", {
args: "all",
argsIgnorePattern: ".",
caughtErrors: "all",
caughtErrorsIgnorePattern: "^e(rr)?$",
destructuredArrayIgnorePattern: ".",
ignoreRestSiblings: true,
}],
"no-restricted-syntax": ["error",
{ selector: "TaggedTemplateExpression", message: "Hard to compile down to ES3" },
{ selector: "CallExpression[callee.name='Symbol']", message: "Annoying to serialize, just use a string" },
],
// with no block scoping, coming up with original variable names is too hard
"no-redeclare": "off",
// treat var as let
// unfortunately doesn't actually let me redeclare
// "block-scoped-var": "error",
"no-caller": "error",
"no-invalid-this": "error",
"no-new-wrappers": "error",
// Map/Set can be polyfilled but it's nontrivial and it's easier just to use bare objects
"no-restricted-globals": ["error", "Proxy", "Reflect", "Symbol", "WeakSet", "WeakMap", "Set", "Map"],
"unicode-bom": "error",
};
/**
* Actually very different from defaultRulesES3, because we don't have to
* worry about syntax that's easy to transpile to ES3 (which is basically
* all syntax).
* @type {NonNullable<Config['rules']>}
*/
export const defaultRulesES3TSChecked = {
...defaultRulesTSChecked,
"radix": "off",
"no-restricted-globals": ["error", "Proxy", "Reflect", "Symbol", "WeakSet", "WeakMap", "Set", "Map"],
"no-restricted-syntax": ["error", "TaggedTemplateExpression", "YieldExpression", "AwaitExpression", "BigIntLiteral"],
};
/**
* @param {Config[]} configs
* @returns {Config}
*/
function extractPlugin(configs) {
return configs.find(config => !config.rules) ||
(() => { throw new Error('No plugin found'); })();
}
/**
* @param {Config[]} configs
* @returns {Rules}
*/
function extractRules(configs) {
const rules = {};
for (const config of configs.filter(c => c.rules)) {
Object.assign(rules, config.rules);
}
return rules;
}
const tseslintPlugin = extractPlugin(tseslint.configs.stylisticTypeChecked);
/** @type {{[k: string]: Config[]}} */
export const configs = {
js: [{
rules: {
...eslint.configs.recommended.rules,
...defaultRules,
},
}],
ts: [tseslintPlugin, {
rules: {
...eslint.configs.recommended.rules,
...extractRules(tseslint.configs.recommendedTypeChecked),
...extractRules(tseslint.configs.stylisticTypeChecked),
...defaultRulesTSChecked,
},
}],
es3: [{
rules: {
...eslint.configs.recommended.rules,
...defaultRulesES3,
},
}],
es3ts: [tseslintPlugin, {
rules: {
...eslint.configs.recommended.rules,
...extractRules(tseslint.configs.recommendedTypeChecked),
...extractRules(tseslint.configs.stylisticTypeChecked),
...defaultRulesES3TSChecked,
},
}],
};
/*
SOURCE FOR IGNOREPATTERN (compile with https://regexfree.k55.io/ )
# 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
['"`\/]
*/

111
eslint.config.mjs Normal file
View File

@ -0,0 +1,111 @@
// @ts-check
import { configs, configure, globals } from './eslint-ps-standard.mjs';
export default configure([
{
ignores: [
"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: "JavaScript",
files: [
'*.mjs', // look mom I'm linting myself!
'**/*.js',
],
extends: [configs.js],
languageOptions: {
globals: {
...globals.builtin,
...globals.node,
...globals.mocha,
// globals in test
Dex: false, toID: false, Teams: false,
Config: false,
Users: false, Rooms: false, Ladders: false, Chat: false, Punishments: false, LoginServer: false,
},
},
rules: {
"@stylistic/max-len": "off",
"no-shadow": "off", // mostly just too lazy, someone should fix this sometime
},
},
{
name: "TypeScript",
files: [
"config/*.ts", "data/**/*.ts", "lib/*.ts",
"server/**/*.ts", "server/**/*.tsx",
"sim/**/*.ts",
"tools/set-import/*.ts",
],
extends: [configs.ts],
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
rules: {
// TEMPORARY
// "@typescript-eslint/restrict-plus-operands": "off",
// we use these for grouping
// "@typescript-eslint/restrict-template-expressions": ["error", {
// allow: [
// {name: ['Error', 'URL', 'URLSearchParams', 'unknown'], from: 'lib'},
// // {name: ['ModifiableValue'], from: 'file'},
// ],
// allowBoolean: false, allowNever: false, allowNullish: false, allowRegExp: false,
// }],
"@typescript-eslint/restrict-template-expressions": "off",
// hotpatching, of course
"@typescript-eslint/no-require-imports": "off",
// too new, let's give it more time
"prefer-object-has-own": "off",
// we do use these for documentation
"@typescript-eslint/no-redundant-type-constituents": "off",
// we actually pass around unbound methods a lot (event handlers in Sim, mainly)
"@typescript-eslint/unbound-method": "off",
// event handlers frequently don't have known types
"@typescript-eslint/no-unsafe-function-type": "off",
// too strict when there's no way to ensure that catch catches an error
"@typescript-eslint/prefer-promise-reject-errors": "off",
// we use import() everywhere
"@typescript-eslint/consistent-type-imports": ["error", { disallowTypeAnnotations: false, fixStyle: "inline-type-imports" }],
// TS has _way_ too many issues to require comments on all of them
// most commonly:
// - closed types https://github.com/microsoft/TypeScript/issues/12936
// - unknown property access
"@typescript-eslint/ban-ts-comment": ["error", {
'ts-check': false,
'ts-expect-error': false,
'ts-ignore': true,
'ts-nocheck': true,
}],
// we're inconsistent about comma dangle in functions. TODO: fix later
"@stylistic/comma-dangle": ["error", {
"arrays": "always-multiline",
"objects": "always-multiline",
"imports": "always-multiline",
"exports": "always-multiline",
"functions": "only-multiline",
"importAttributes": "always-multiline",
"dynamicImports": "always-multiline",
"enums": "always-multiline",
"generics": "always-multiline",
"tuples": "always-multiline",
}],
// there are a few of these that make sense, in scripts
"no-useless-return": "off",
},
},
]);

View File

@ -159,18 +159,18 @@ export function encode(str: string, allowCaps = false) {
let unsafePart = streamGetCode(unsafeStream);
if (safePart.startsWith('-')) {
safePart = safePart.slice(1);
unsafePart = unsafePart + '2';
unsafePart = `${unsafePart}2`;
}
if (safePart.endsWith('-')) {
safePart = safePart.slice(0, -1);
}
if (!safePart) {
safePart = '0';
unsafePart = '0' + unsafePart;
unsafePart = `0${unsafePart}`;
if (unsafePart.endsWith('2')) unsafePart = unsafePart.slice(0, -1);
}
if (!unsafePart) return safePart;
return safePart + '--' + unsafePart;
return `${safePart}--${unsafePart}`;
}
export function decode(codedStr: string) {
@ -283,7 +283,6 @@ export function vizStream(codeBuf: string, translate = true) {
function vizBlock(s: DashyStream, bufLen: number) {
const buf = streamRead(s, bufLen);
// @ts-ignore
return buf.toString(2).padStart(bufLen, '0');
}

View File

@ -10,7 +10,6 @@ import * as mysql from 'mysql2';
import * as pg from 'pg';
export type BasicSQLValue = string | number | null;
// eslint-disable-next-line
export type SQLRow = { [k: string]: BasicSQLValue };
export type SQLValue = BasicSQLValue | SQLStatement | PartialOrSQL<SQLRow> | BasicSQLValue[] | undefined;
@ -328,7 +327,7 @@ export class MySQLDatabase extends Database<mysql.Pool, mysql.OkPacket> {
for (let i = 0; i < query.values.length; i++) {
const value = query.values[i];
if (query.sql[i + 1].startsWith('`') || query.sql[i + 1].startsWith('"')) {
sql = sql.slice(0, -1) + this.escapeId('' + value) + query.sql[i + 1].slice(1);
sql = sql.slice(0, -1) + this.escapeId(`${value}`) + query.sql[i + 1].slice(1);
} else {
sql += '?' + query.sql[i + 1];
values.push(value);
@ -373,7 +372,7 @@ export class PGDatabase extends Database<pg.Pool, {affectedRows: number | null}>
for (let i = 0; i < query.values.length; i++) {
const value = query.values[i];
if (query.sql[i + 1].startsWith('`') || query.sql[i + 1].startsWith('"')) {
sql = sql.slice(0, -1) + this.escapeId('' + value) + query.sql[i + 1].slice(1);
sql = sql.slice(0, -1) + this.escapeId(`${value}`) + query.sql[i + 1].slice(1);
} else {
paramCount++;
sql += `$${paramCount}` + query.sql[i + 1];

View File

@ -35,7 +35,7 @@ interface PendingUpdate {
pendingDataFetcher: (() => string | Buffer) | null;
pendingOptions: AnyObject | null;
throttleTime: number; // throttling until time (0 for no throttle)
throttleTimer: NodeJS.Timer | null;
throttleTimer: NodeJS.Timeout | null;
}
declare const __fsState: { pendingUpdates: Map<string, PendingUpdate> };
@ -313,21 +313,16 @@ export class FSPath {
createWriteStream(options = {}): WriteStream {
if (global.Config?.nofswriting) {
// @ts-ignore
return new WriteStream({ write() {} });
}
// @ts-ignore
return new WriteStream(fs.createWriteStream(this.path, options));
}
createAppendStream(options = {}): WriteStream {
createAppendStream(options: AnyObject = {}): WriteStream {
if (global.Config?.nofswriting) {
// @ts-ignore
return new WriteStream({ write() {} });
}
// @ts-ignore
options.flags = options.flags || 'a';
// @ts-ignore
return new WriteStream(fs.createWriteStream(this.path, options));
}
@ -487,7 +482,7 @@ class FileReadStream extends ReadStream {
_read(size = 16384): Promise<void> {
return new Promise<void>((resolve, reject) => {
if (this.atEOF) return resolve();
if (this.atEOF) return void resolve();
this.ensureCapacity(size);
void this.fd.then(fd => {
fs.read(fd, this.buf, this.bufEnd, size, null, (err, bytesRead, buf) => {

View File

@ -76,7 +76,7 @@ export class NetStream extends Streams.ReadWriteStream {
}
}
const protocol = url.parse(this.uri).protocol as string;
const protocol = url.parse(this.uri).protocol;
const net = protocol === 'https:' ? https : http;
let resolveResponse: ((value: http.IncomingMessage | null) => void) | null;
@ -143,7 +143,7 @@ export class NetStream extends Streams.ReadWriteStream {
let out = '';
for (const key in data) {
if (out) out += `&`;
out += `${key}=${encodeURIComponent('' + data[key])}`;
out += `${key}=${encodeURIComponent(`${data[key]}`)}`;
}
return out;
}

View File

@ -4,6 +4,7 @@
* @author mia-pi-git
*/
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore in case module doesn't exist
import type * as PG from 'pg';
import type { SQLStatement } from 'sql-template-strings';
@ -22,7 +23,7 @@ export class PostgresDatabase {
constructor(config = PostgresDatabase.getConfig()) {
try {
this.pool = new (require('pg').Pool)(config);
} catch (e: any) {
} catch {
this.pool = null!;
}
}
@ -47,7 +48,7 @@ export class PostgresDatabase {
try {
config = require(FS.ROOT_PATH + '/config/config').usepostgres;
if (!config) throw new Error('Missing config for pg database');
} catch (e: any) {}
} catch {}
return config;
}
async transaction(callback: (conn: PG.PoolClient) => any, depth = 0): Promise<any> {
@ -55,7 +56,6 @@ export class PostgresDatabase {
await conn.query(`BEGIN`);
let result;
try {
// eslint-disable-next-line callback-return
result = await callback(conn);
} catch (e: any) {
await conn.query(`ROLLBACK`);
@ -97,7 +97,7 @@ export class PostgresDatabase {
if (stored.length) {
value = stored[0].value || "0";
}
} catch (e) {
} catch {
await this.query(`CREATE TABLE db_info (name TEXT NOT NULL, key TEXT NOT NULL, value TEXT NOT NULL)`);
}
if (!value) { // means nothing inserted - create row

View File

@ -20,7 +20,9 @@ type Worker = cluster.Worker;
export const processManagers: ProcessManager[] = [];
export function exec(args: string, execOptions?: child_process.ExecOptions): Promise<{stderr: string, stdout: string}>;
export function exec(
args: string, execOptions?: child_process.ExecOptions
): Promise<{ stderr: string, stdout: string }>;
export function exec(
args: [string, ...string[]], execOptions?: child_process.ExecFileOptions
): Promise<{ stderr: string, stdout: string }>;
@ -192,7 +194,7 @@ export class QueryProcessWrapper<T, U> implements ProcessWrapper {
this.resolveRelease = resolve;
});
}
return this.pendingRelease as Promise<void>;
return this.pendingRelease!;
}
destroy() {
@ -265,7 +267,6 @@ export class StreamProcessWrapper implements ProcessWrapper {
if (messageType === 'END') {
stream.pushEnd();
this.deleteStream(taskId);
return;
} else if (messageType === 'PUSH') {
stream.push(message);
} else if (messageType === 'THROW') {
@ -309,7 +310,7 @@ export class StreamProcessWrapper implements ProcessWrapper {
this.resolveRelease = resolve;
});
}
return this.pendingRelease as Promise<void>;
return this.pendingRelease!;
}
destroy() {
@ -395,7 +396,7 @@ export class RawProcessWrapper implements ProcessWrapper, StreamWorker {
this.resolveRelease = resolve;
});
}
return this.pendingRelease as Promise<void>;
return this.pendingRelease!;
}
destroy() {
@ -405,7 +406,6 @@ export class RawProcessWrapper implements ProcessWrapper, StreamWorker {
}
void this.stream.destroy();
this.process.disconnect();
return;
}
}
@ -718,7 +718,6 @@ export class RawProcessManager extends ProcessManager<RawProcessWrapper> {
if (this.isCluster && this.isParentProcess) {
cluster.setupMaster({
exec: this.filename,
// @ts-ignore TODO: update type definition
cwd: FS.ROOT_PATH,
});
}

View File

@ -5,6 +5,7 @@
import { QueryProcessManager } from './process-manager';
import type * as sqlite from 'better-sqlite3';
import { FS } from './fs';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore in case not installed
import type { SQLStatement } from 'sql-template-strings';
@ -453,7 +454,7 @@ export const SQL = Object.assign(getSQL, {
})() as typeof import('sql-template-strings').SQL,
});
export namespace SQL {
export declare namespace SQL {
export type DatabaseManager = import('./sql').SQLDatabaseManager;
export type Statement = import('./sql').Statement;
export type Options = import('./sql').SQLOptions;

View File

@ -371,13 +371,13 @@ export class ReadStream {
async next(byteCount: number | null = null) {
const value = await this.read(byteCount);
return {value, done: value === null};
return { value, done: value === null } as { value: string, done: false } | { value: null, done: true };
}
async pipeTo(outStream: WriteStream, options: { noEnd?: boolean } = {}) {
let value, done;
while (({value, done} = await this.next(), !done)) {
await outStream.write(value!);
let next;
while ((next = await this.next(), !next.done)) {
await outStream.write(next.value);
}
if (!options.noEnd) return outStream.writeEnd();
}
@ -385,7 +385,7 @@ export class ReadStream {
interface WriteStreamOptions {
nodeStream?: NodeJS.WritableStream;
write?: (this: WriteStream, data: string | Buffer) => (Promise<undefined> | undefined);
write?: (this: WriteStream, data: string | Buffer) => (Promise<undefined> | undefined | void);
writeEnd?: (this: WriteStream) => Promise<any>;
}
@ -721,7 +721,6 @@ export class ObjectReadStream<T> {
return this._destroy();
}
// eslint-disable-next-line no-restricted-globals
[Symbol.asyncIterator]() { return this; }
async next() {
if (this.buf.length) return { value: this.buf.shift() as T, done: false as const };
@ -731,9 +730,9 @@ export class ObjectReadStream<T> {
}
async pipeTo(outStream: ObjectWriteStream<T>, options: { noEnd?: boolean } = {}) {
let value, done;
while (({value, done} = await this.next(), !done)) {
await outStream.write(value!);
let next;
while ((next = await this.next(), !next.done)) {
await outStream.write(next.value);
}
if (!options.noEnd) return outStream.writeEnd();
}

View File

@ -33,7 +33,7 @@ export type Comparable = number | string | boolean | Comparable[] | {reverse: Co
*/
export function getString(str: any): string {
return (typeof str === 'string' || typeof str === 'number') ? '' + str : '';
return (typeof str === 'string' || typeof str === 'number') ? `${str}` : '';
}
export function escapeRegex(str: string) {
@ -45,7 +45,7 @@ export function escapeRegex(str: string) {
*/
export function escapeHTML(str: string | number) {
if (str === null || str === undefined) return '';
return ('' + str)
return `${str}`
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
@ -69,14 +69,14 @@ export function stripHTML(htmlContent: string) {
export function formatOrder(place: number) {
// anything between 10 and 20 should always end with -th
let remainder = place % 100;
if (remainder >= 10 && remainder <= 20) return place + 'th';
if (remainder >= 10 && remainder <= 20) return `${place}th`;
// follow standard rules with -st, -nd, -rd, and -th
remainder = place % 10;
if (remainder === 1) return place + 'st';
if (remainder === 2) return place + 'nd';
if (remainder === 3) return place + 'rd';
return place + 'th';
if (remainder === 1) return `${place}st`;
if (remainder === 2) return `${place}nd`;
if (remainder === 3) return `${place}rd`;
return `${place}th`;
}
/**
@ -103,7 +103,7 @@ export function visualize(value: any, depth = 0): string {
return `${value}`;
}
let constructor = '';
if (value.constructor && value.constructor.name && typeof value.constructor.name === 'string') {
if (typeof value.constructor?.name === 'string') {
constructor = value.constructor.name;
if (constructor === 'Object') constructor = '';
} else {
@ -128,9 +128,11 @@ export function visualize(value: any, depth = 0): string {
if (value.toString) {
try {
const stringValue = value.toString();
if (typeof stringValue === 'string' &&
if (
typeof stringValue === 'string' &&
stringValue !== '[object Object]' &&
stringValue !== `[object ${constructor}]`) {
stringValue !== `[object ${constructor}]`
) {
return `${constructor}(${stringValue})`;
}
} catch {}

1963
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -35,15 +35,14 @@
"start": "node pokemon-showdown start",
"build": "node build",
"tsc": "tsc",
"fast-lint": "eslint . --config .eslintrc-no-types.json --cache --cache-location .eslintcache-no-types --ext .js,.ts,.tsx",
"lint": "eslint . --cache --ext .js,.ts,.tsx --max-warnings 0",
"fix": "eslint . --cache --ext .js,.ts,.tsx --fix",
"lint": "eslint --cache",
"fix": "eslint --cache --fix",
"full-lint": "npm run lint",
"pretest": "npm run lint",
"test": "mocha",
"posttest": "npm run tsc",
"full-test": "npm run lint && npm run tsc && mocha --timeout 8000 --forbid-only -g \".*\"",
"full-test-ci": "eslint --no-error-on-unmatched-pattern ${FILES} --max-warnings 0 && npm run tsc && (([ \"$SKIPSIMTESTS\" = true ] && mocha --timeout 8000 --forbid-only -g \".*\" --exclude \"test/{sim,random-battles}/**\") || mocha --timeout 8000 --forbid-only -g \".*\")",
"full-test-ci": "eslint --max-warnings 0 && tsc && (([ \"$SKIPSIMTESTS\" = true ] && mocha --timeout 8000 --forbid-only -g \".*\" --exclude \"test/{sim,random-battles}/**\") || mocha --timeout 8000 --forbid-only -g \".*\")",
"postinstall": "npm run build postinstall"
},
"bin": "./pokemon-showdown",
@ -66,19 +65,20 @@
],
"license": "MIT",
"devDependencies": {
"@stylistic/eslint-plugin": "^4.0.1",
"@types/better-sqlite3": "^7.6.2",
"@types/cloud-env": "^0.2.2",
"@types/node": "^14.18.36",
"@types/node": "^14.18.63",
"@types/node-static": "^0.7.7",
"@types/nodemailer": "^6.4.4",
"@types/pg": "^8.6.5",
"@types/sockjs": "^0.3.33",
"@types/sodium-native": "^2.3.9",
"@typescript-eslint/eslint-plugin": "^5.8.0",
"@typescript-eslint/parser": "^5.8.0",
"eslint": "8.5.0",
"eslint": "^9.21.0",
"globals": "^16.0.0",
"mocha": "^8.2.0",
"smogon": "^3.0.0",
"typescript": "^5.0.4"
"typescript": "^5.7.3",
"typescript-eslint": "^8.24.1"
}
}

View File

@ -22,7 +22,7 @@ class ArtemisStream extends Streams.ObjectReadWriteStream<string> {
listen() {
this.process.stdout.setEncoding('utf8');
this.process.stderr.setEncoding('utf8');
this.process.stdout.on('data', (data) => {
this.process.stdout.on('data', data => {
// so many bugs were created by \nready\n
data = data.trim();
const [taskId, dataStr] = data.split("|");

View File

@ -19,7 +19,6 @@ export const ATTRIBUTES = {
"FLIRTATION": {},
};
export interface PerspectiveRequest {
languages: string[];
requestedAttributes: AnyObject;
@ -89,6 +88,7 @@ export const PM = new ProcessManager.QueryProcessManager<string, Record<string,
}
return result;
} catch (e: any) {
// eslint-disable-next-line require-atomic-updates
throttleTime = Date.now();
if (e.message.startsWith('Request timeout') || e.statusCode === 429) {
// request timeout: just ignore this. error on their end not ours.
@ -100,7 +100,6 @@ export const PM = new ProcessManager.QueryProcessManager<string, Record<string,
}
}, PM_TIMEOUT);
// main module check necessary since this gets required in other non-parent processes sometimes
// when that happens we do not want to take over or set up or anything
if (require.main === module) {
@ -114,7 +113,7 @@ if (require.main === module) {
slow(text: string) {
process.send!(`CALLBACK\nSLOW\n${text}`);
},
};
} as any;
global.toID = toID;
process.on('uncaughtException', err => {
if (Config.crashguard) {
@ -172,4 +171,3 @@ export class RemoteClassifier {
return PM.processes.length;
}
}

View File

@ -530,7 +530,7 @@ export const commands: Chat.ChatCommands = {
return errors.push(`${targetUser.name} [locked]`);
}
if (!(targetUser.id in room!.users)) {
if (!(targetUser.id in room.users)) {
return errors.push(`${targetUser.name} [not in room]`);
}
@ -538,7 +538,6 @@ export const commands: Chat.ChatCommands = {
targetUser.sendTo(room, `|${messageType}|${html}`);
});
if (successes.length) this.sendReply(`Sent private HTML to ${Chat.toListString(successes)}.`);
if (errors.length) this.errorReply(`Unable to send private HTML to ${Chat.toListString(errors)}.`);
@ -551,7 +550,7 @@ export const commands: Chat.ChatCommands = {
],
botmsg(target, room, user, connection) {
if (!target || !target.includes(',')) {
if (!target?.includes(',')) {
return this.parse('/help botmsg');
}
this.checkRecursion();
@ -589,7 +588,7 @@ export const commands: Chat.ChatCommands = {
const units = ["B", "KiB", "MiB", "GiB", "TiB"];
const results = resultNums.map(num => {
const unitIndex = Math.floor(Math.log2(num) / 10); // 2^10 base log
return `${(num / Math.pow(2, 10 * unitIndex)).toFixed(2)} ${units[unitIndex]}`;
return `${(num / (2 ** (10 * unitIndex))).toFixed(2)} ${units[unitIndex]}`;
});
this.sendReply(`||[Main process] RSS: ${results[0]}, Heap: ${results[1]} / ${results[2]}`);
},
@ -945,7 +944,7 @@ export const commands: Chat.ChatCommands = {
const ramNum = parseInt(ram);
if (!isNaN(ramNum)) {
const unitIndex = Math.floor(Math.log2(ramNum) / 10); // 2^10 base log
entry.ram = `${(ramNum / Math.pow(2, 10 * unitIndex)).toFixed(2)} ${ramUnits[unitIndex]}`;
entry.ram = `${(ramNum / (2 ** (10 * unitIndex))).toFixed(2)} ${ramUnits[unitIndex]}`;
}
processes.set(pid, entry);
}
@ -1368,7 +1367,6 @@ export const commands: Chat.ChatCommands = {
target = toID(target);
Monitor.updateServerLock = true;
let success = true;
if (target === 'private') {
if (!validPrivateCodePath) {
@ -1403,7 +1401,7 @@ export const commands: Chat.ChatCommands = {
['staff', 'development'],
`|c|${user.getIdentity()}|/log ${user.name} used /updateloginserver - but something failed while updating.`
);
return this.errorReply(err.message + '\n' + err.stack);
return this.errorReply(`${err.message}\n${err.stack}`);
}
if (!result) return this.errorReply('No result received.');
this.stafflog(`[o] ${result.success || ""} [e] ${result.actionerror || ""}`);
@ -1436,7 +1434,7 @@ export const commands: Chat.ChatCommands = {
['staff', 'development'],
`|c|${user.getIdentity()}|/log ${user.name} used /updateclient - but something failed while updating.`
);
return this.errorReply(err.message + '\n' + err.stack);
return this.errorReply(`${err.message}\n${err.stack}`);
}
if (!result) return this.errorReply('No result received.');
this.stafflog(`[o] ${result.success || ""} [e] ${result.actionerror || ""}`);

View File

@ -751,10 +751,11 @@ export const commands: Chat.ChatCommands = {
<p>Custom avatars from account <strong>{id}</strong>:</p>,
allowed.filter(Boolean).map(avatar => (
<p>
{hasButton ?
<button name="send" value={`/avatar ${avatar}`} class="button">{Avatars.img(avatar!)}</button> :
{hasButton ? (
<button name="send" value={`/avatar ${avatar}`} class="button">{Avatars.img(avatar!)}</button>
) : (
Avatars.img(avatar!)
} {}
)} {}
<code>/avatar {avatar!.replace('#', '')}</code>
</p>
))

View File

@ -65,7 +65,7 @@ export const crqHandlers: {[k: string]: Chat.CRQHandler} = {
userid: targetUser.id,
name: targetUser.name,
avatar: targetUser.avatar,
group: group,
group,
customgroup: sectionleader ? "Section Leader" : undefined,
autoconfirmed: targetUser.autoconfirmed ? true : undefined,
status: targetUser.getStatus() || undefined,
@ -111,7 +111,7 @@ export const crqHandlers: {[k: string]: Chat.CRQHandler} = {
roomid: targetRoom.roomid,
title: targetRoom.title,
type: targetRoom.type,
visibility: visibility,
visibility,
modchat: targetRoom.settings.modchat,
modjoin: targetRoom.settings.modjoin,
auth: {},
@ -533,6 +533,7 @@ export const commands: Chat.ChatCommands = {
if (isOffline) {
await Chat.PrivateMessages.deleteSettings(user.id);
} else {
// eslint-disable-next-line require-atomic-updates
user.settings.blockPMs = false;
}
user.update();
@ -905,10 +906,8 @@ export const commands: Chat.ChatCommands = {
if (!showAll) {
const parsed = parseInt(target);
if (isNaN(parsed)) {
const matchedSet = team.filter(set => {
const id = toID(target);
return toID(set.name) === id || toID(set.species) === id;
})[0];
const matchedSet = team.find(set => toID(set.name) === id || toID(set.species) === id);
if (!matchedSet) return this.errorReply(this.tr`You don't have a Pokémon matching "${target}" in your team.`);
team = [matchedSet];
} else {
@ -1673,7 +1672,7 @@ export const commands: Chat.ChatCommands = {
const handler = Chat.crqHandlers[cmd];
if (!handler) return connection.send(`|queryresponse|${cmd}|null`);
let data = handler.call(this, target, user, trustable);
if (data && data.then) data = await data;
if (data?.then) data = await data;
connection.send(`|queryresponse|${cmd}|${JSON.stringify(data)}`);
},

View File

@ -541,7 +541,7 @@ export const commands: Chat.ChatCommands = {
this.errorReply(`This command must be broadcast:`);
return this.parse(`/help checkchallenges`);
}
if (!target || !target.includes(',')) return this.parse(`/help checkchallenges`);
if (!target?.includes(',')) return this.parse(`/help checkchallenges`);
const { targetUser: user1, rest } = this.requireUser(target);
const { targetUser: user2, rest: rest2 } = this.requireUser(rest);
if (user1 === user2 || rest2) return this.parse(`/help checkchallenges`);
@ -602,7 +602,7 @@ export const commands: Chat.ChatCommands = {
}
const newTargets = dex.dataSearch(target);
const showDetails = (cmd.startsWith('dt') || cmd === 'details');
if (!newTargets || !newTargets.length) {
if (!newTargets?.length) {
return this.errorReply(`No Pok\u00e9mon, item, move, ability or nature named '${target}' was found${Dex.gen > dex.gen ? ` in Gen ${dex.gen}` : ""}. (Check your spelling?)`);
}
@ -1118,7 +1118,7 @@ export const commands: Chat.ChatCommands = {
totalTypeMod += typeof moveMod === 'number' ? moveMod : baseMod;
}
}
factor = Math.pow(2, totalTypeMod);
factor = 2 ** totalTypeMod;
}
const hasThousandArrows = source.id === 'thousandarrows' && defender.types.includes('Flying');
@ -1205,7 +1205,7 @@ export const commands: Chat.ChatCommands = {
bestCoverage[type] = 0;
continue;
}
bestCoverage[type] = Math.pow(2, bestCoverage[type]);
bestCoverage[type] = 2 ** bestCoverage[type];
}
if (!dispTable) {
@ -1281,7 +1281,7 @@ export const commands: Chat.ChatCommands = {
if (bestEff === -5) {
bestEff = 0;
} else {
bestEff = Math.pow(2, bestEff);
bestEff = 2 ** bestEff;
}
}
if (bestEff === 0) {
@ -1552,7 +1552,7 @@ export const commands: Chat.ChatCommands = {
if (ev < 0) iv += ev;
ev *= 4;
if (iv < 0 || ev > 255) {
return this.sendReplyBox('No valid EV/IV combination possible with given parameters. Maybe try a different nature?' + ev);
return this.sendReplyBox(`No valid EV/IV combination possible with given parameters. Maybe try a different nature?${ev}`);
}
} else {
return this.sendReplyBox('Too many parameters given; nothing to calculate.');
@ -1592,13 +1592,13 @@ export const commands: Chat.ChatCommands = {
let uptimeText;
if (uptime > 24 * 60 * 60) {
const uptimeDays = Math.floor(uptime / (24 * 60 * 60));
uptimeText = uptimeDays + " " + (uptimeDays === 1 ? "day" : "days");
uptimeText = `${uptimeDays} ${uptimeDays === 1 ? "day" : "days"}`;
const uptimeHours = Math.floor(uptime / (60 * 60)) - uptimeDays * 24;
if (uptimeHours) uptimeText += ", " + uptimeHours + " " + (uptimeHours === 1 ? "hour" : "hours");
if (uptimeHours) uptimeText += `, ${uptimeHours} ${uptimeHours === 1 ? "hour" : "hours"}`;
} else {
uptimeText = Chat.toDurationString(uptime * 1000);
}
this.sendReplyBox("Uptime: <b>" + uptimeText + "</b>");
this.sendReplyBox(`Uptime: <b>${uptimeText}</b>`);
},
uptimehelp: [`/uptime - Shows how long the server has been online for.`],
@ -2499,7 +2499,7 @@ export const commands: Chat.ChatCommands = {
let maxRoll = 0;
let minRoll = Number.MAX_SAFE_INTEGER;
const trackRolls = diceQuantity * (('' + diceFaces).length + 1) <= 60;
const trackRolls = diceQuantity * (`${diceFaces}`.length + 1) <= 60;
const rolls = [];
let rollSum = 0;
@ -2544,7 +2544,7 @@ export const commands: Chat.ChatCommands = {
pr: 'pickrandom',
pick: 'pickrandom',
pickrandom(target, room, user) {
if (!target || !target.includes(',')) return this.parse('/help pick');
if (!target?.includes(',')) return this.parse('/help pick');
if (!this.runBroadcast(true)) return false;
if (this.broadcasting) {
[, target] = Utils.splitFirst(this.message, ' ');
@ -2600,9 +2600,9 @@ export const commands: Chat.ChatCommands = {
if (!room.pendingApprovals) room.pendingApprovals = new Map();
room.pendingApprovals.set(user.id, {
name: user.name,
link: link,
comment: comment,
dimensions: dimensions,
link,
comment,
dimensions,
});
this.sendReply(`You have requested to show the link: ${link}${comment ? ` (with the comment ${comment})` : ''}.`);
const message = `|tempnotify|pendingapprovals|Pending media request!` +
@ -3321,7 +3321,7 @@ export const pages: Chat.PageTable = {
return buf;
},
approvals(args) {
const room = Rooms.get(args[0]) as ChatRoom | GameRoom;
const room = Rooms.get(args[0])!;
this.checkCan('mute', null, room);
if (!room.pendingApprovals) room.pendingApprovals = new Map();
if (room.pendingApprovals.size < 1) return `<h2>No pending approvals on ${room.title}</h2>`;

View File

@ -9,7 +9,7 @@
* @license MIT
*/
import { Utils } from '../../lib';
import {RoomSection, RoomSections} from './room-settings';
import { type RoomSection, RoomSections } from './room-settings';
/* eslint no-else-return: "error" */
@ -350,7 +350,7 @@ export const commands: Chat.ChatCommands = {
Utils.sortBy(names).map(userid => {
const isOnline = Users.get(userid)?.statusType === 'online';
// targetRoom guaranteed to exist above
return userid in targetRoom!.users && isOnline ? `**${userid}**` : userid;
return userid in targetRoom.users && isOnline ? `**${userid}**` : userid;
}).join(', ');
});
@ -481,6 +481,7 @@ export const commands: Chat.ChatCommands = {
);
await Promise.all(promises);
// eslint-disable-next-line require-atomic-updates
connection.autojoins = autojoins.join(',');
},
autojoinhelp: [`/autojoin [rooms] - Automatically joins all the given rooms.`],
@ -911,7 +912,6 @@ export const commands: Chat.ChatCommands = {
const { privateReason, publicReason } = this.parseSpoiler(reason);
// Use default time for locks.
const duration = week ? Date.now() + 7 * 24 * 60 * 60 * 1000 : (month ? Date.now() + 30 * 24 * 60 * 60 * 1000 : null);
let affected = [];
@ -2144,7 +2144,6 @@ export const commands: Chat.ChatCommands = {
);
}
const expireTime = cmd.includes('perma') ? Date.now() + (10 * 365 * 24 * 60 * 60 * 1000) : null;
const action = expireTime ? 'PERMABLACKLIST' : 'BLACKLIST';
@ -2356,7 +2355,7 @@ export const commands: Chat.ChatCommands = {
const duplicates = targets.filter(userid => (
// can be asserted, room should always exist
Punishments.roomUserids.nestedGetByType(room!.roomid, userid, 'BLACKLIST')
Punishments.roomUserids.nestedGetByType(room.roomid, userid, 'BLACKLIST')
));
if (duplicates.length) {
return this.errorReply(`[${duplicates.join(', ')}] ${Chat.plural(duplicates, "are", "is")} already blacklisted.`);

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