Compare commits

..

No commits in common. "master" and "v0.11.10" have entirely different histories.

482 changed files with 19372 additions and 207040 deletions

View File

@ -15,23 +15,23 @@ jobs:
last_version: ${{ steps.last_version.outputs.version }}
token_exists: ${{ steps.check_token.outputs.token }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v3
with:
fetch-depth: 50
# Check if the package.json version field has changed since the last push
- name: Get current version from package.json
id: current_version
run: |
echo "version=$(jq -r .version package.json)" >> "$GITHUB_OUTPUT"
echo "version=$(jq -r .version package.json)" >> $GITHUB_OUTPUT
- name: Get the version from the last push
id: last_version
run: |
git checkout ${{ github.event.before }}
echo "version=$(jq -r .version package.json)" >> "$GITHUB_OUTPUT"
echo "version=$(jq -r .version package.json)" >> $GITHUB_OUTPUT
- name: Check if NPM_TOKEN exists
id: check_token
run: |
echo "token=$(if [ -n "${{ secrets.NPM_TOKEN }}" ]; then echo true; else echo false; fi)" >> "$GITHUB_OUTPUT"
echo "token=$(if [ -n "${{ secrets.NPM_TOKEN }}" ]; then echo true; else echo false; fi)" >> $GITHUB_OUTPUT
npm-publish:
needs:
- test
@ -40,8 +40,8 @@ jobs:
# We only want to publish if the package.json version field has changed
if: needs.get-version.outputs.current_version != needs.get-version.outputs.last_version && needs.get-version.outputs.token_exists == 'true'
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
cache: 'npm'

View File

@ -17,23 +17,15 @@ jobs:
strategy:
matrix:
# Testing multiple Node versions makes CI take forever, and basically
# never actually finds anything we care about. Testing one is enough.
#
# This number should be left at the oldest Node LTS version capable of
# running Node without errors (it doesn't matter if it's unsupported).
# Please freely bump this version (and the check in `pokemon-showdown`
# and `server/index.ts`) if you want to use features from newer versions;
# this is purely for our own reference, not to constrain programmers.
node-version: ['18.x']
node-version: [18.x]
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v3
with:
fetch-depth: 100 # assumes PR/push to master is no larger than 100 commits. Other solutions are needlessly complex.
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v6
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
@ -43,7 +35,7 @@ jobs:
- name: Determine which files to lint (if pull request)
if: ${{ github.event_name == 'pull_request' }}
id: changed-files
uses: tj-actions/changed-files@v47
uses: tj-actions/changed-files@v35
with:
files: |
./config/*.ts
@ -66,14 +58,14 @@ jobs:
- name: Determine whether test/sim or test/random-battles need to run (if pull request)
if: ${{ github.event_name == 'pull_request' }}
id: changed-directories
uses: tj-actions/changed-files@v47
uses: tj-actions/changed-files@v35
with:
files: |
config/formats.ts
data/**
sim/**
- name: Run selective lint & necessary tests (if pull request)
- name: Run selective lint & neccessary tests (if pull request)
if: ${{ github.event_name == 'pull_request' }}
run: npm run full-test-ci
env:

View File

@ -3,12 +3,12 @@ name: Update the npm package version
on:
workflow_dispatch:
inputs:
version:
required: true
type: choice
description: Version type
default: patch
options:
version:
required: true
type: choice
description: Version type
default: patch
options:
- major
- minor
- patch
@ -16,30 +16,27 @@ on:
- preminor
- prepatch
- prerelease
jobs:
update_version:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
cache: 'npm'
- id: bump_version
run: |
echo "old_version=$(jq -r .version package.json)" >> "$GITHUB_OUTPUT"
echo "old_version=$(jq -r .version package.json)" >> $GITHUB_OUTPUT
npm version ${{ github.event.inputs.version }} --no-git-tag-version
echo "new_version=$(jq -r .version package.json)" >> "$GITHUB_OUTPUT"
echo "new_version=$(jq -r .version package.json)" >> $GITHUB_OUTPUT
- uses: peter-evans/create-pull-request@v8
- uses: peter-evans/create-pull-request@v4
with:
title: Bump package.json version to v${{ steps.bump_version.outputs.new_version }}
title: Bump package.json version to v${{ steps.bump_version.outputs.new_version }}}
body: |
Bump package.json version from `v${{ steps.bump_version.outputs.old_version }}` to `v${{ steps.bump_version.outputs.new_version }}`
commit-message: Bump package.json version to v${{ steps.bump_version.outputs.new_version }}
branch: npm-version-bump
base: master

View File

@ -1,25 +1,25 @@
config/formats.ts @KrisXV @Marty-D
data/mods/*/random-teams.ts @AnnikaCodes
data/mods/gen9ssb/ @HoeenCoder @HisuianZoroark @KrisXV
data/random-battles/ @KrisXV @MathyFurret @ACakeWearingAHat @livid-washed @adrivrie
data/random-sets.json @MathyFurret @ACakeWearingAHat @livid-washed @adrivrie
data/random-teams.ts @AnnikaCodes @KrisXV @MathyFurret @ACakeWearingAHat @livid-washed @adrivrie
data/text/ @Marty-D
databases/ @monsanto
lib/sql.ts @mia-pi-git
server/artemis/* @mia-pi-git
server/chat-plugins/random-battles/ @KrisXV @AnnikaCodes
server/chat-plugins/abuse-monitor.ts @mia-pi-git
server/chat-plugins/auction.ts @Karthik99999
server/chat-plugins/datasearch.ts @KrisXV
server/chat-plugins/friends.ts @mia-pi-git
server/chat-plugins/github.ts @mia-pi-git
server/chat-plugins/hosts.ts @AnnikaCodes
server/chat-plugins/helptickets*.ts @mia-pi-git
server/chat-plugins/laddertours.ts @mia-pi-git
server/chat-plugins/mafia.ts @HoeenCoder
server/chat-plugins/othermetas.ts @KrisXV
server/chat-plugins/permalocks.ts @mia-pi-git
server/chat-plugins/quotes.ts @mia-pi-git @KrisXV
server/chat-plugins/random-battles.ts @KrisXV @AnnikaCodes
server/chat-plugins/repeats.ts @AnnikaCodes
server/chat-plugins/responder.ts @mia-pi-git
server/chat-plugins/rock-paper-scissors.ts @mia-pi-git
server/chat-plugins/sample-teams.ts @KrisXV
server/chat-plugins/scavenger*.ts @xfix @sparkychildcharlie @PartMan7
sever/chat-plugins/teams.ts @mia-pi-git

View File

@ -301,13 +301,13 @@ In general, we prefer modern ways of writing things as long as they're supported
- Multiline template strings: A frequent source of bugs (and also weird for readability), so we prefer to explicitly use `\n` and concatenate over multiple lines.
- `async`/`await`: We prefer it for readability, but in certain cases we use raw Promises or even callbacks for performance. Don't worry about it too much; we usually won't nitpick code that uses either async implementation (although we might insist on `async`/`await` if the readability difference is huge).
- `async`/`await`: We prefer it for readability, but in certain cases we use raw Promises or even callbacks for performance. Don't worry about it too much; we usually won't nitpick code that uses any async implementation (although we might insist on `async`/`await` if the readability difference is huge).
- getters/setters/`Proxy`: We are generally very anti-magic. There are certain places in the code we do use magic where it's massively DRYer (or for historical reasons), but we prefer to explicitly mark that setting a variable is actually running a function with many and varied side effects. Please have a better reason than "`.foo` is less visual clutter than `.getFoo()`".
- Constant Enums: Don't use; we prefer constant union types, like `type Category = 'Physical' | 'Special' | 'Status'`
- Default Properties: Use.
- Default Properties: Mediocre performance when compiled with `sucrase`. This is fine for objects that are rarely created, but prefer setting properties directly in a constructor, for objects created in inner loops.
Dependencies

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2011-2026 Guangcong Luo and other contributors http://pokemonshowdown.com/
Copyright (c) 2011-2024 Guangcong Luo and other contributors http://pokemonshowdown.com/
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in

View File

@ -144,7 +144,7 @@ represented by a space), and the rest of the string being their username.
`|uhtml|NAME|HTML`
> We received an HTML message (NAME) that can change what it's displaying,
> We recieved an HTML message (NAME) that can change what it's displaying,
> this is used in things like our Polls system, for example.
`|uhtmlchange|NAME|HTML`
@ -305,7 +305,7 @@ represented by a space), and the rest of the string being their username.
`|tournament|update|JSON`
> `JSON` is a JSON object representing the changes in the tournament
> since the last update you received or the start of the tournament.
> since the last update you recieved or the start of the tournament.
> These include:
>
format: the tournament's custom name or the format being used
@ -478,9 +478,7 @@ If the challenge is accepted, you will receive a room initialization message.
`JSON.searching` will be an array of format IDs you're currently searching for
games in.
`JSON.games` will be a `{roomid: title}` table of games you're currently in,
or `null` if you're in no games.
`JSON.games` will be a `{roomid: title}` table of games you're currently in.
Note that this includes ALL games, so `|updatesearch|` will be sent when you
start/end challenge battles, and even non-Pokémon games like Mafia.

17
build
View File

@ -2,12 +2,10 @@
"use strict";
try {
// fetch was introduced in Node 18, which is EOL,
// so we'll ask for the most recent "Active LTS" with it to be safe
// https://nodejs.org/en/about/previous-releases
fetch;
// technically this was introduced in Node 17, but we'll ask for the most recent LTS with it to be safe
structuredClone({});
} catch (e) {
console.error("We require Node.js version 22 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);
}
@ -24,10 +22,13 @@ function shell(cmd) {
// Check to make sure the most recently added or updated dependency is installed at the correct version
try {
require.resolve('ts-chacha20');
var version = require('esbuild').version.split('.');
if (parseInt(version[1]) < 16) {
throw new Error("esbuild version too old");
}
} catch (e) {
console.log('Installing dependencies...');
shell('npm ci');
shell('npm install');
}
// Make sure config.js exists. If not, copy it over synchronously from
@ -47,5 +48,7 @@ try {
// for some reason, esbuild won't be requirable until a tick has passed
// see https://stackoverflow.com/questions/53270058/node-cant-find-certain-modules-after-synchronous-install
setImmediate(() => {
// npm package, don't rebuild
if (process.argv[2] === 'postinstall' && fs.existsSync('dist')) return;
require('./tools/build-utils').transpile(force, decl);
});

View File

@ -45,7 +45,7 @@ Bans are just a `-` followed by the thing you want to ban.
`- Future` - ban things that only appears in a future generation (such as Arceus in Gen 1)
`- Custom` - (DEPRECATED) ban miscellaneous other things
`- Custom` - ban made-up things other than CAP (such as Magikarp's Revenge, or Staff Bros moves)
`- Nonexistent` - catch-all to ban all nonexistent Pokémon, items, etc. Includes: `- CAP, - Past, - Future, - LGPE`
@ -83,20 +83,10 @@ Syntax is identical to bans, just replace `-` with `+`, like:
More specific always trumps less specific:
`- all pokemon, + Uber, - Giratina, + Giratina-Altered` - allow only Ubers other than Giratina-Origin
`- all pokemon, + Giratina-Altered, - Giratina, + Uber` - allow only Ubers other than Giratina-Origin
`- all Pokemon, + Uber, - Giratina, + Giratina-Altered` - allow only Ubers other than Giratina-Origin
`- Nonexistent, + Necturna` - don't allow anything from outside the game, except the CAP Necturna
Except `all pokemon`, which removes all bans/unbans of pokemon before it:
`- all pokemon, + Pikachu, + Raichu` - allow Pikachu and Raichu
`+ Pikachu, - all pokemon, + Raichu` - allow only Raichu
(Note that `all pokemon` does not affect obtainability rules. `+ all pokemon` will not allow CAPs or anything like that.)
For equally specific rules, the last rule wins:
`- Pikachu, - Pikachu, + Pikachu` - allow Pikachu
@ -138,7 +128,7 @@ Whitelisting
Instead of a banlist, you can have a list of allowed things:
`- all pokemon, + Charmander, + Squirtle, + Bulbasaur` - allow only Kanto starters
`- all Pokemon, + Charmander, + Squirtle, + Bulbasaur` - allow only Kanto starters
`- all moves, + move: Metronome` - allow only the move Metronome

View File

@ -15,6 +15,23 @@ exports.port = 8000;
*/
exports.bindaddress = '0.0.0.0';
/**
* workers - the number of networking child processes to spawn
* This should be no greater than the number of threads available on your
* server's CPU. If you're not sure how many you have, you can check from a
* terminal by running:
*
* $ node -e "console.log(require('os').cpus().length)"
*
* Using more workers than there are available threads will cause performance
* issues. Keeping a couple threads available for use for OS-related work and
* other PS processes will likely give you the best performance, if your
* server's CPU is capable of multithreading. If you don't know what any of
* this means or you are unfamiliar with PS' networking code, leave this set
* to 1.
*/
exports.workers = 1;
/**
* wsdeflate - compresses WebSocket messages
* Toggles use of the Sec-WebSocket-Extension permessage-deflate extension.
@ -25,15 +42,6 @@ exports.bindaddress = '0.0.0.0';
*/
exports.wsdeflate = null;
/**
* lazysockets - disables eager initialization of network services
* Turn this on if you'd prefer to manually connect Showdown to the network,
* or you intend to run it offline.
*
* @type {boolean}
*/
exports.lazysockets = false;
/*
// example:
exports.wsdeflate = {
@ -84,50 +92,6 @@ Main's SSL deploy script from Let's Encrypt looks like:
*/
exports.proxyip = false;
// subprocesses - the number of child processes to use for various tasks.
// Can be set to `0` instead of `{...}` to stop using subprocesses, if you're running out of RAM.
exports.subprocesses = {
/**
* network - the number of networking child processes to spawn
* This should be no greater than the number of threads available on your
* server's CPU. If you're not sure how many you have, you can check from a
* terminal by running:
*
* $ node -e "console.log(require('os').cpus().length)"
*
* Using more workers than there are available threads will cause performance
* issues. Keeping a couple threads available for use for OS-related work and
* other PS processes will likely give you the best performance, if your
* server's CPU is capable of multithreading. If you don't know what any of
* this means or you are unfamiliar with PS' networking code, leave this set
* to 1.
*/
network: 1,
/**
* for simulating battles
* You should leave this at 1 unless your server has a very large
* amount of traffic (i.e. hundreds of concurrent battles).
*/
simulator: 1,
// beyond this point, it'd be very weird if you needed more than one of each of these
/** for validating teams */
validator: 1,
/** for user authentication */
verifier: 1,
localartemis: 1,
remoteartemis: 1,
friends: 1,
chatdb: 1,
modlog: 1,
pm: 1,
/** for the battlesearch chat plugin */
battlesearch: 1,
/** datasearch - for the datasearch chat plugin */
datasearch: 1,
};
/**
* Various debug options
*
@ -437,6 +401,15 @@ exports.logchallenges = false;
*/
exports.loguserstats = 1000 * 60 * 10; // 10 minutes
/**
* validatorprocesses - the number of processes to use for validating teams
* simulatorprocesses - the number of processes to use for handling battles
* You should leave both of these at 1 unless your server has a very large
* amount of traffic (i.e. hundreds of concurrent battles).
*/
exports.validatorprocesses = 1;
exports.simulatorprocesses = 1;
/**
* inactiveuserthreshold - how long a user must be inactive before being pruned
* from the `users` array. The default is 1 hour.
@ -527,7 +500,7 @@ exports.lastfmkey = '';
exports.chatlogreader = 'fs';
/**
* permissions and groups:
* Each entry in `grouplist` is a separate group. Some of the members are "special"
* Each entry in `grouplist` is a seperate group. Some of the members are "special"
* while the rest is just a normal permission.
* The order of the groups determines their ranking.
* The special members are as follows:

File diff suppressed because it is too large Load Diff

View File

@ -127,7 +127,6 @@ List of all in-battle forme changes:
- Darmanitan (Zen Mode)
- Meloetta (Relic Song)
- Shaymin-Sky (Frozen status)
- Ramnarok (Polar Flare)
- Mega evolutions
- Primal reversions
- Ultra Burst

View File

@ -60,7 +60,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
const noModifyType = [
'judgment', 'multiattack', 'naturalgift', 'revelationdance', 'technoblast', 'terrainpulse', 'weatherball',
];
if (move.type === 'Normal' && (!noModifyType.includes(move.id) || this.activeMove?.isMax) &&
if (move.type === 'Normal' && !noModifyType.includes(move.id) &&
!(move.isZ && move.category !== 'Status') && !(move.name === 'Tera Blast' && pokemon.terastallized)) {
move.type = 'Flying';
move.typeChangerBoosted = this.effect;
@ -145,7 +145,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
if (
effect.effectType === "Move" &&
!effect.multihit &&
!(effect.hasSheerForce && source.hasAbility('sheerforce'))
(!effect.negateSecondary && !(effect.hasSheerForce && source.hasAbility('sheerforce')))
) {
this.effectState.checkedAngerShell = false;
} else {
@ -301,6 +301,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
},
aurabreak: {
onStart(pokemon) {
if (this.suppressingAbility(pokemon)) return;
this.add('-ability', pokemon, 'Aura Break');
},
onAnyTryPrimaryHit(target, source, move) {
@ -356,19 +357,12 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
},
battlebond: {
onSourceAfterFaint(length, target, source, effect) {
if (source.bondTriggered) return;
if (effect?.effectType !== 'Move') return;
if (source.abilityState.battleBondTriggered) return;
if (source.species.id === 'greninjabond' && source.hp && !source.transformed && source.side.foePokemonLeft()) {
this.boost({ atk: 1, spa: 1, spe: 1 }, source, source, this.effect);
this.add('-activate', source, 'ability: Battle Bond');
source.bondTriggered = true;
}
},
onModifyMovePriority: -1,
onModifyMove(move, attacker) {
if (move.id === 'watershuriken' && attacker.species.name === 'Greninja-Ash' &&
!attacker.transformed) {
move.multihit = 3;
source.abilityState.battleBondTriggered = true;
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, cantsuppress: 1 },
@ -411,7 +405,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
if (
effect.effectType === "Move" &&
!effect.multihit &&
!(effect.hasSheerForce && source.hasAbility('sheerforce'))
(!effect.negateSecondary && !(effect.hasSheerForce && source.hasAbility('sheerforce')))
) {
this.effectState.checkedBerserk = false;
} else {
@ -740,29 +734,33 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
num: 238,
},
cudchew: {
onEatItem(item, pokemon, source, effect) {
if (item.isBerry && (!effect || !['bugbite', 'pluck'].includes(effect.id))) {
this.effectState.berry = item;
this.effectState.counter = 2;
// This is needed in case the berry was eaten during residuals, preventing the timer from decreasing this turn
if (!this.queue.peek()) this.effectState.counter--;
onEatItem(item, pokemon) {
if (item.isBerry && pokemon.addVolatile('cudchew')) {
pokemon.volatiles['cudchew'].berry = item;
}
},
onResidualOrder: 28,
onResidualSubOrder: 2,
onResidual(pokemon) {
if (!this.effectState.berry || !pokemon.hp) return;
if (--this.effectState.counter <= 0) {
const item = this.effectState.berry;
this.add('-activate', pokemon, 'ability: Cud Chew');
this.add('-enditem', pokemon, item.name, '[eat]');
if (this.singleEvent('Eat', item, null, pokemon, null, null)) {
this.runEvent('EatItem', pokemon, null, null, item);
onEnd(pokemon) {
delete pokemon.volatiles['cudchew'];
},
condition: {
noCopy: true,
duration: 2,
onRestart() {
this.effectState.duration = 2;
},
onResidualOrder: 28,
onResidualSubOrder: 2,
onEnd(pokemon) {
if (pokemon.hp) {
const item = this.effectState.berry;
this.add('-activate', pokemon, 'ability: Cud Chew');
this.add('-enditem', pokemon, item.name, '[eat]');
if (this.singleEvent('Eat', item, null, pokemon, null, null)) {
this.runEvent('EatItem', pokemon, null, null, item);
}
if (item.onEat) pokemon.ateBerry = true;
}
if (item.onEat) pokemon.ateBerry = true;
delete this.effectState.berry;
delete this.effectState.counter;
}
},
},
flags: {},
name: "Cud Chew",
@ -984,7 +982,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
const hitSub = target.volatiles['substitute'] && !move.flags['bypasssub'] && !(move.infiltrates && this.gen >= 6);
if (hitSub) return;
if (!target.runImmunity(move)) return;
if (!target.runImmunity(move.type)) return;
return false;
},
onEffectiveness(typeMod, target, type, move) {
@ -996,7 +994,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
const hitSub = target.volatiles['substitute'] && !move.flags['bypasssub'] && !(move.infiltrates && this.gen >= 6);
if (hitSub) return;
if (!target.runImmunity(move)) return;
if (!target.runImmunity(move.type)) return;
return 0;
},
onUpdate(pokemon) {
@ -1161,9 +1159,9 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
},
embodyaspectcornerstone: {
onStart(pokemon) {
if (pokemon.baseSpecies.name === 'Ogerpon-Cornerstone-Tera' && pokemon.terastallized &&
!this.effectState.embodied) {
this.effectState.embodied = true;
if (pokemon.baseSpecies.name === 'Ogerpon-Cornerstone-Tera' &&
this.effectState.embodied !== pokemon.previouslySwitchedIn) {
this.effectState.embodied = pokemon.previouslySwitchedIn;
this.boost({ def: 1 }, pokemon);
}
},
@ -1174,9 +1172,9 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
},
embodyaspecthearthflame: {
onStart(pokemon) {
if (pokemon.baseSpecies.name === 'Ogerpon-Hearthflame-Tera' && pokemon.terastallized &&
!this.effectState.embodied) {
this.effectState.embodied = true;
if (pokemon.baseSpecies.name === 'Ogerpon-Hearthflame-Tera' &&
this.effectState.embodied !== pokemon.previouslySwitchedIn) {
this.effectState.embodied = pokemon.previouslySwitchedIn;
this.boost({ atk: 1 }, pokemon);
}
},
@ -1187,9 +1185,9 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
},
embodyaspectteal: {
onStart(pokemon) {
if (pokemon.baseSpecies.name === 'Ogerpon-Teal-Tera' && pokemon.terastallized &&
!this.effectState.embodied) {
this.effectState.embodied = true;
if (pokemon.baseSpecies.name === 'Ogerpon-Teal-Tera' &&
this.effectState.embodied !== pokemon.previouslySwitchedIn) {
this.effectState.embodied = pokemon.previouslySwitchedIn;
this.boost({ spe: 1 }, pokemon);
}
},
@ -1200,9 +1198,9 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
},
embodyaspectwellspring: {
onStart(pokemon) {
if (pokemon.baseSpecies.name === 'Ogerpon-Wellspring-Tera' && pokemon.terastallized &&
!this.effectState.embodied) {
this.effectState.embodied = true;
if (pokemon.baseSpecies.name === 'Ogerpon-Wellspring-Tera' &&
this.effectState.embodied !== pokemon.previouslySwitchedIn) {
this.effectState.embodied = pokemon.previouslySwitchedIn;
this.boost({ spd: 1 }, pokemon);
}
},
@ -1543,7 +1541,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
const noModifyType = [
'judgment', 'multiattack', 'naturalgift', 'revelationdance', 'technoblast', 'terrainpulse', 'weatherball',
];
if (move.type === 'Normal' && (!noModifyType.includes(move.id) || this.activeMove?.isMax) &&
if (move.type === 'Normal' && !noModifyType.includes(move.id) &&
!(move.isZ && move.category !== 'Status') && !(move.name === 'Tera Blast' && pokemon.terastallized)) {
move.type = 'Electric';
move.typeChangerBoosted = this.effect;
@ -1930,7 +1928,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
if (!target) return;
if (move.category !== 'Physical' || target.species.id !== 'eiscue') return;
if (target.volatiles['substitute'] && !(move.flags['bypasssub'] || move.infiltrates)) return;
if (!target.runImmunity(move)) return;
if (!target.runImmunity(move.type)) return;
return false;
},
onEffectiveness(typeMod, target, type, move) {
@ -1940,7 +1938,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
const hitSub = target.volatiles['substitute'] && !move.flags['bypasssub'] && !(move.infiltrates && this.gen >= 6);
if (hitSub) return;
if (!target.runImmunity(move)) return;
if (!target.runImmunity(move.type)) return;
return 0;
},
onUpdate(pokemon) {
@ -2004,7 +2002,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
if (!possibleTarget.fainted) {
// If Ogerpon is in the last slot while the Illusion Pokemon is Terastallized
// Illusion will not disguise as anything
if (!pokemon.terastallized || !['Ogerpon', 'Terapagos'].includes(possibleTarget.species.baseSpecies)) {
if (!pokemon.terastallized || possibleTarget.species.baseSpecies !== 'Ogerpon') {
pokemon.illusion = possibleTarget;
}
break;
@ -2017,7 +2015,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
}
},
onEnd(pokemon) {
if (pokemon.illusion && !pokemon.beingCalledBack) {
if (pokemon.illusion) {
this.debug('illusion cleared');
pokemon.illusion = null;
const details = pokemon.getUpdatedDetails();
@ -2259,12 +2257,12 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
},
libero: {
onPrepareHit(source, target, move) {
if (this.effectState.libero) return;
if (this.effectState.libero === source.previouslySwitchedIn) return;
if (move.hasBounced || move.flags['futuremove'] || move.sourceEffect === 'snatch' || move.callsMove) return;
const type = move.type;
if (type && type !== '???' && source.getTypes().join() !== type) {
if (!source.setType(type)) return;
this.effectState.libero = true;
this.effectState.libero = source.previouslySwitchedIn;
this.add('-start', source, 'typechange', type, '[from] ability: Libero');
}
},
@ -2333,7 +2331,10 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
return;
}
if (this.checkMoveMakesContact(move, source, target, !source.isAlly(target))) {
source.setAbility('lingeringaroma', target);
const oldAbility = source.setAbility('lingeringaroma', target);
if (oldAbility) {
this.add('-activate', target, 'ability: Lingering Aroma', this.dex.abilities.get(oldAbility).name, `[of] ${source}`);
}
}
},
flags: {},
@ -2396,9 +2397,11 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
newMove.hasBounced = true;
newMove.pranksterBoosted = false;
this.actions.useMove(newMove, this.effectState.target, { target: source });
move.hasBounced = true; // only bounce once in free-for-all battles
return null;
},
condition: {
duration: 1,
},
flags: { breakable: 1 },
name: "Magic Bounce",
rating: 4,
@ -2418,21 +2421,16 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
},
magician: {
onAfterMoveSecondarySelf(source, target, move) {
if (!move || source.switchFlag === true || !move.hitTargets || source.item || source.volatiles['gem'] ||
move.id === 'fling' || move.category === 'Status') return;
const hitTargets = move.hitTargets;
this.speedSort(hitTargets);
for (const pokemon of hitTargets) {
if (pokemon !== source) {
const yourItem = pokemon.takeItem(source);
if (!yourItem) continue;
if (!source.setItem(yourItem)) {
pokemon.item = yourItem.id; // bypass setItem so we don't break choicelock or anything
continue;
}
this.add('-item', source, yourItem, '[from] ability: Magician', `[of] ${pokemon}`);
if (!move || !target || source.switchFlag === true) return;
if (target !== source && move.category !== 'Status') {
if (source.item || source.volatiles['gem'] || move.id === 'fling') return;
const yourItem = target.takeItem(source);
if (!yourItem) return;
if (!source.setItem(yourItem)) {
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}`);
}
},
flags: {},
@ -2711,7 +2709,10 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
return;
}
if (this.checkMoveMakesContact(move, source, target, !source.isAlly(target))) {
source.setAbility('mummy', target);
const oldAbility = source.setAbility('mummy', target);
if (oldAbility) {
this.add('-activate', target, 'ability: Mummy', this.dex.abilities.get(oldAbility).name, `[of] ${source}`);
}
}
},
flags: {},
@ -2917,9 +2918,9 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
const noModifyType = [
'hiddenpower', 'judgment', 'multiattack', 'naturalgift', 'revelationdance', 'struggle', 'technoblast', 'terrainpulse', 'weatherball',
];
if (!(move.isZ && move.category !== 'Status') &&
if (!(move.isZ && move.category !== 'Status') && !noModifyType.includes(move.id) &&
// TODO: Figure out actual interaction
(!noModifyType.includes(move.id) || this.activeMove?.isMax) && !(move.name === 'Tera Blast' && pokemon.terastallized)) {
!(move.name === 'Tera Blast' && pokemon.terastallized)) {
move.type = 'Normal';
move.typeChangerBoosted = this.effect;
}
@ -2984,16 +2985,6 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
this.boost(this.effectState.boosts, this.effectState.target);
delete this.effectState.boosts;
},
onAnyAfterMega() {
if (!this.effectState.boosts) return;
this.boost(this.effectState.boosts, this.effectState.target);
delete this.effectState.boosts;
},
onAnyAfterTerastallization() {
if (!this.effectState.boosts) return;
this.boost(this.effectState.boosts, this.effectState.target);
delete this.effectState.boosts;
},
onAnyAfterMove() {
if (!this.effectState.boosts) return;
this.boost(this.effectState.boosts, this.effectState.target);
@ -3213,7 +3204,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
const noModifyType = [
'judgment', 'multiattack', 'naturalgift', 'revelationdance', 'technoblast', 'terrainpulse', 'weatherball',
];
if (move.type === 'Normal' && (!noModifyType.includes(move.id) || this.activeMove?.isMax) &&
if (move.type === 'Normal' && !noModifyType.includes(move.id) &&
!(move.isZ && move.category !== 'Status') && !(move.name === 'Tera Blast' && pokemon.terastallized)) {
move.type = 'Fairy';
move.typeChangerBoosted = this.effect;
@ -3303,8 +3294,13 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
if (pokemon.species.id === 'zygardecomplete' || pokemon.hp > pokemon.maxhp / 2) return;
this.add('-activate', pokemon, 'ability: Power Construct');
pokemon.formeChange('Zygarde-Complete', this.effect, true);
pokemon.canMegaEvo = pokemon.canMegaEvo === false ? false : this.actions.canMegaEvo(pokemon);
pokemon.formeRegression = true;
pokemon.baseMaxhp = Math.floor(Math.floor(
2 * pokemon.species.baseStats['hp'] + pokemon.set.ivs['hp'] + Math.floor(pokemon.set.evs['hp'] / 4) + 100
) * pokemon.level / 100 + 10);
const newMaxHP = pokemon.volatiles['dynamax'] ? (2 * pokemon.baseMaxhp) : pokemon.baseMaxhp;
pokemon.hp = newMaxHP - (pokemon.maxhp - pokemon.hp);
pokemon.maxhp = newMaxHP;
this.add('-heal', pokemon, pokemon.getHealth, '[silent]');
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, cantsuppress: 1 },
name: "Power Construct",
@ -3316,7 +3312,9 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
if (!this.effectState.target.hp) return;
const ability = target.getAbility();
if (ability.flags['noreceiver'] || ability.id === 'noability') return;
this.effectState.target.setAbility(ability, target);
if (this.effectState.target.setAbility(ability)) {
this.add('-ability', this.effectState.target, ability, '[from] ability: Power of Alchemy', `[of] ${target}`);
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1 },
name: "Power of Alchemy",
@ -3410,12 +3408,12 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
},
protean: {
onPrepareHit(source, target, move) {
if (this.effectState.protean) return;
if (this.effectState.protean === source.previouslySwitchedIn) return;
if (move.hasBounced || move.flags['futuremove'] || move.sourceEffect === 'snatch' || move.callsMove) return;
const type = move.type;
if (type && type !== '???' && source.getTypes().join() !== type) {
if (!source.setType(type)) return;
this.effectState.protean = true;
this.effectState.protean = source.previouslySwitchedIn;
this.add('-start', source, 'typechange', type, '[from] ability: Protean');
}
},
@ -3703,7 +3701,9 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
if (!this.effectState.target.hp) return;
const ability = target.getAbility();
if (ability.flags['noreceiver'] || ability.id === 'noability') return;
this.effectState.target.setAbility(ability, target);
if (this.effectState.target.setAbility(ability)) {
this.add('-ability', this.effectState.target, ability, '[from] ability: Receiver', `[of] ${target}`);
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1 },
name: "Receiver",
@ -3729,7 +3729,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
const noModifyType = [
'judgment', 'multiattack', 'naturalgift', 'revelationdance', 'technoblast', 'terrainpulse', 'weatherball',
];
if (move.type === 'Normal' && (!noModifyType.includes(move.id) || this.activeMove?.isMax) &&
if (move.type === 'Normal' && !noModifyType.includes(move.id) &&
!(move.isZ && move.category !== 'Status') && !(move.name === 'Tera Blast' && pokemon.terastallized)) {
move.type = 'Ice';
move.typeChangerBoosted = this.effect;
@ -4143,7 +4143,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
shielddust: {
onModifySecondaries(secondaries) {
this.debug('Shield Dust prevent secondary');
return secondaries.filter(effect => !!effect.self);
return secondaries.filter(effect => !!(effect.self || effect.dustproof));
},
flags: { breakable: 1 },
name: "Shield Dust",
@ -4224,35 +4224,35 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
},
slowstart: {
onStart(pokemon) {
this.add('-start', pokemon, 'ability: Slow Start');
this.effectState.counter = 5;
},
onResidualOrder: 28,
onResidualSubOrder: 2,
onResidual(pokemon) {
if (pokemon.activeTurns && this.effectState.counter) {
this.effectState.counter--;
if (!this.effectState.counter) {
this.add('-end', pokemon, 'Slow Start');
delete this.effectState.counter;
}
}
},
onModifyAtkPriority: 5,
onModifyAtk(atk, pokemon) {
if (this.effectState.counter) {
return this.chainModify(0.5);
}
},
onModifySpe(spe, pokemon) {
if (this.effectState.counter) {
return this.chainModify(0.5);
}
pokemon.addVolatile('slowstart');
},
onEnd(pokemon) {
if (pokemon.beingCalledBack) return;
delete pokemon.volatiles['slowstart'];
this.add('-end', pokemon, 'Slow Start', '[silent]');
},
condition: {
duration: 5,
onResidualOrder: 28,
onResidualSubOrder: 2,
onStart(target) {
this.add('-start', target, 'ability: Slow Start');
},
onResidual(pokemon) {
if (!pokemon.activeTurns) {
this.effectState.duration! += 1;
}
},
onModifyAtkPriority: 5,
onModifyAtk(atk, pokemon) {
return this.chainModify(0.5);
},
onModifySpe(spe, pokemon) {
return this.chainModify(0.5);
},
onEnd(target) {
this.add('-end', target, 'Slow Start');
},
},
flags: {},
name: "Slow Start",
rating: -1,
@ -4720,24 +4720,6 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
rating: 3,
num: 33,
},
swordofruin: {
onStart(pokemon) {
if (this.suppressingAbility(pokemon)) return;
this.add('-ability', pokemon, 'Sword of Ruin');
},
onAnyModifyDef(def, target, source, move) {
const abilityHolder = this.effectState.target;
if (target.hasAbility('Sword of Ruin')) return;
if (!move.ruinedDef?.hasAbility('Sword of Ruin')) move.ruinedDef = abilityHolder;
if (move.ruinedDef !== abilityHolder) return;
this.debug('Sword of Ruin Def drop');
return this.chainModify(0.75);
},
flags: {},
name: "Sword of Ruin",
rating: 4.5,
num: 285,
},
symbiosis: {
onAllyAfterUseItem(item, pokemon) {
if (pokemon.switchFlag) return;
@ -4773,6 +4755,24 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
rating: 2,
num: 28,
},
swordofruin: {
onStart(pokemon) {
if (this.suppressingAbility(pokemon)) return;
this.add('-ability', pokemon, 'Sword of Ruin');
},
onAnyModifyDef(def, target, source, move) {
const abilityHolder = this.effectState.target;
if (target.hasAbility('Sword of Ruin')) return;
if (!move.ruinedDef?.hasAbility('Sword of Ruin')) move.ruinedDef = abilityHolder;
if (move.ruinedDef !== abilityHolder) return;
this.debug('Sword of Ruin Def drop');
return this.chainModify(0.75);
},
flags: {},
name: "Sword of Ruin",
rating: 4.5,
num: 285,
},
tabletsofruin: {
onStart(pokemon) {
if (this.suppressingAbility(pokemon)) return;
@ -4879,6 +4879,14 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
if (pokemon.species.forme !== 'Terastal') {
this.add('-activate', pokemon, 'ability: Tera Shift');
pokemon.formeChange('Terapagos-Terastal', this.effect, true);
pokemon.regressionForme = false;
pokemon.baseMaxhp = Math.floor(Math.floor(
2 * pokemon.species.baseStats['hp'] + pokemon.set.ivs['hp'] + Math.floor(pokemon.set.evs['hp'] / 4) + 100
) * pokemon.level / 100 + 10);
const newMaxHP = pokemon.baseMaxhp;
pokemon.hp = newMaxHP - (pokemon.maxhp - pokemon.hp);
pokemon.maxhp = newMaxHP;
this.add('-heal', pokemon, pokemon.getHealth, '[silent]');
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, cantsuppress: 1, notransform: 1 },
@ -5053,7 +5061,9 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
const target = this.sample(possibleTargets);
const ability = target.getAbility();
pokemon.setAbility(ability, target);
if (pokemon.setAbility(ability)) {
this.add('-ability', pokemon, ability, '[from] ability: Trace', `[of] ${target}`);
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1 },
name: "Trace",
@ -5264,7 +5274,20 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
},
wanderingspirit: {
onDamagingHit(damage, target, source, move) {
if (this.checkMoveMakesContact(move, source, target)) this.skillSwap(source, target);
if (source.getAbility().flags['failskillswap'] || target.volatiles['dynamax']) return;
if (this.checkMoveMakesContact(move, source, target)) {
const targetCanBeSet = this.runEvent('SetAbility', target, source, this.effect, source.ability);
if (!targetCanBeSet) return targetCanBeSet;
const sourceAbility = source.setAbility('wanderingspirit', target);
if (!sourceAbility) return;
if (target.isAlly(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}`);
}
target.setAbility(sourceAbility);
}
},
flags: {},
name: "Wandering Spirit",
@ -5424,7 +5447,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
target.addVolatile('charge');
}
},
onSideConditionStart(side, source, sideCondition) {
onAllySideConditionStart(target, source, sideCondition) {
const pokemon = this.effectState.target;
if (sideCondition.id === 'tailwind') {
pokemon.addVolatile('charge');
@ -5449,7 +5472,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
return null;
}
},
onSideConditionStart(side, source, sideCondition) {
onAllySideConditionStart(target, source, sideCondition) {
const pokemon = this.effectState.target;
if (sideCondition.id === 'tailwind') {
this.boost({ atk: 1 }, pokemon, pokemon);
@ -5463,10 +5486,10 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
},
wonderguard: {
onTryHit(target, source, move) {
if (target === source || move.category === 'Status' || move.id === 'struggle') return;
if (target === source || move.category === 'Status' || move.type === '???' || move.id === 'struggle') return;
if (move.id === 'skydrop' && !source.volatiles['skydrop']) return;
this.debug('Wonder Guard immunity: ' + move.id);
if (target.runEffectiveness(move) <= 0 || !target.runImmunity(move)) {
if (target.runEffectiveness(move) <= 0) {
if (move.smartTarget) {
move.smartTarget = false;
} else {
@ -5538,14 +5561,14 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
if (pokemon.baseSpecies.baseSpecies !== 'Palafin') return;
if (pokemon.species.forme !== 'Hero') {
pokemon.formeChange('Palafin-Hero', this.effect, true);
pokemon.heroMessageDisplayed = false;
pokemon.regressionForme = false;
}
},
onSwitchIn(pokemon) {
if (pokemon.baseSpecies.baseSpecies !== 'Palafin') return;
if (!pokemon.heroMessageDisplayed && pokemon.species.forme === 'Hero') {
if (!this.effectState.heroMessageDisplayed && pokemon.species.forme === 'Hero') {
this.add('-activate', pokemon, 'ability: Zero to Hero');
pokemon.heroMessageDisplayed = true;
this.effectState.heroMessageDisplayed = true;
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, cantsuppress: 1, notransform: 1 },
@ -5571,7 +5594,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
flags: { breakable: 1 },
name: "Mountaineer",
rating: 3,
num: -1,
num: -2,
},
rebound: {
isNonstandard: "CAP",
@ -5579,32 +5602,32 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
onTryHit(target, source, move) {
if (this.effectState.target.activeTurns) return;
if (target === source || move.hasBounced || !move.flags['reflectable'] || target.isSemiInvulnerable()) {
if (target === source || move.hasBounced || !move.flags['reflectable']) {
return;
}
const newMove = this.dex.getActiveMove(move.id);
newMove.hasBounced = true;
newMove.pranksterBoosted = false;
this.actions.useMove(newMove, target, { target: source });
return null;
},
onAllyTryHitSide(target, source, move) {
if (this.effectState.target.activeTurns) return;
if (target.isAlly(source) || move.hasBounced || !move.flags['reflectable'] || target.isSemiInvulnerable()) {
if (target.isAlly(source) || move.hasBounced || !move.flags['reflectable']) {
return;
}
const newMove = this.dex.getActiveMove(move.id);
newMove.hasBounced = true;
newMove.pranksterBoosted = false;
this.actions.useMove(newMove, this.effectState.target, { target: source });
move.hasBounced = true; // only bounce once in free-for-all battles
return null;
},
condition: {
duration: 1,
},
flags: { breakable: 1 },
name: "Rebound",
rating: 3,
num: -2,
num: -3,
},
persistent: {
isNonstandard: "CAP",
@ -5612,6 +5635,6 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
flags: {},
name: "Persistent",
rating: 3,
num: -3,
num: -4,
},
};

File diff suppressed because it is too large Load Diff

78
data/cg-team-data.ts Normal file
View File

@ -0,0 +1,78 @@
// Data for computer-generated teams
export const MOVE_PAIRINGS: { [moveID: IDEntry]: IDEntry } = {
rest: 'sleeptalk',
sleeptalk: 'rest',
};
// Bonuses to move ratings by ability
export const ABILITY_MOVE_BONUSES: { [abilityID: IDEntry]: { [moveID: IDEntry]: number } } = {
contrary: { terablast: 2 },
drought: { sunnyday: 0.2, solarbeam: 2 },
drizzle: { raindance: 0.2, solarbeam: 0.2, hurricane: 2 },
};
// Bonuses to move ratings by move type
export const ABILITY_MOVE_TYPE_BONUSES: { [abilityID: IDEntry]: { [typeName: string]: number } } = {
darkaura: { Dark: 1.33 },
dragonsmaw: { Dragon: 1.5 },
fairyaura: { Fairy: 1.33 },
steelworker: { Steel: 1.5 },
steelyspirit: { Steel: 1.5 },
transistor: { Electric: 1.3 },
// -ate moves
pixilate: { Normal: 1.5 * 1.2 },
refrigerate: { Normal: 1.5 * 1.2 },
aerilate: { Normal: 1.5 * 1.2 },
normalize: { Normal: 1.2 },
// weather
drizzle: { Water: 1.4, Fire: 0.6 },
drought: { Fire: 1.4, Water: 0.6 },
};
// For moves whose quality isn't obvious from data
// USE SPARINGLY!
export const HARDCODED_MOVE_WEIGHTS: { [moveID: IDEntry]: number } = {
// Fails unless user is asleep
snore: 0,
// Hard to use
lastresort: 0.1, dreameater: 0.1,
// Useless without Berry + sucks even then
belch: 0.2,
// Power increases in conditions out of our control that may occur
avalanche: 1.2,
ficklebeam: 1.3,
hex: 1.2,
stompingtantrum: 1.2,
temperflare: 1.2,
// Attacks that set hazards on hit
// We REALLY like hazards
stoneaxe: 16,
ceaselessedge: 16,
// screens
lightscreen: 3, reflect: 3, auroraveil: 3, // TODO: make sure AVeil always gets Snow?
tailwind: 2,
// mess with the opponent
taunt: 2, disable: 2, encore: 3,
// healing moves
// TODO: should healing moves be more common on bulkier pokemon?
// 25%
junglehealing: 3, lifedew: 3,
// 50%
milkdrink: 5, moonlight: 5, morningsun: 5, recover: 5, roost: 5,
shoreup: 5, slackoff: 5, softboiled: 5, synthesis: 5,
// delayed/consequence
rest: 3, // has sleeptalk potential
wish: 2,
// requires terrain
steelroller: 0.1,
};
export const WEIGHT_BASED_MOVES = ['heatcrash', 'heavyslam', 'lowkick', 'grassknot'];
export const TARGET_HP_BASED_MOVES = ['crushgrip', 'hardpress'];

1098
data/cg-teams.ts Normal file

File diff suppressed because it is too large Load Diff

View File

@ -91,11 +91,12 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
}
if (target.species.name === 'Shaymin-Sky' && target.baseSpecies.baseSpecies === 'Shaymin') {
target.formeChange('Shaymin', this.effect, true);
target.regressionForme = false;
}
},
onBeforeMovePriority: 10,
onBeforeMove(pokemon, target, move) {
if (move.flags['defrost'] && !(move.id === 'burnup' && !pokemon.hasType('Fire'))) return;
if (move.flags['defrost']) return;
if (this.randomChance(1, 5)) {
pokemon.cureStatus();
return;
@ -115,7 +116,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
}
},
onDamagingHit(damage, target, source, move) {
if (move.type === 'Fire' && move.category !== 'Status' && move.id !== 'polarflare') {
if (move.type === 'Fire' && move.category !== 'Status') {
target.cureStatus();
}
},
@ -270,11 +271,6 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
this.effectState.duration = 2;
}
},
onAfterMove(pokemon) {
if (this.effectState.duration === 1) {
pokemon.removeVolatile('lockedmove');
}
},
onEnd(target) {
if (this.effectState.trueDuration > 1) return;
target.addVolatile('confusion');
@ -879,65 +875,6 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
return [type];
},
},
zacian: {
name: 'Zacian',
onBattleStart(pokemon) {
if (pokemon.item !== 'rustedsword') return;
const rawSpecies = this.dex.species.get('Zacian-Crowned');
const species = pokemon.setSpecies(rawSpecies);
if (!species) return;
pokemon.baseSpecies = rawSpecies;
pokemon.details = pokemon.getUpdatedDetails();
pokemon.setAbility(species.abilities['0'], null, null, true);
pokemon.baseAbility = pokemon.ability;
const ironHeadIndex = pokemon.baseMoves.indexOf('ironhead');
if (ironHeadIndex >= 0) {
const move = this.dex.moves.get('behemothblade');
pokemon.baseMoveSlots[ironHeadIndex] = {
move: move.name,
id: move.id,
pp: move.noPPBoosts ? move.pp : move.pp * 8 / 5,
maxpp: move.noPPBoosts ? move.pp : move.pp * 8 / 5,
target: move.target,
disabled: false,
disabledSource: '',
used: false,
};
pokemon.moveSlots = pokemon.baseMoveSlots.slice();
}
},
},
zamazenta: {
name: 'Zamazenta',
onBattleStart(pokemon) {
if (pokemon.item !== 'rustedshield') return;
const rawSpecies = this.dex.species.get('Zamazenta-Crowned');
const species = pokemon.setSpecies(rawSpecies);
if (!species) return;
pokemon.baseSpecies = rawSpecies;
pokemon.details = pokemon.getUpdatedDetails();
pokemon.setAbility(species.abilities['0'], null, null, true);
pokemon.baseAbility = pokemon.ability;
const ironHeadIndex = pokemon.baseMoves.indexOf('ironhead');
if (ironHeadIndex >= 0) {
const move = this.dex.moves.get('behemothbash');
pokemon.baseMoveSlots[ironHeadIndex] = {
move: move.name,
id: move.id,
pp: move.noPPBoosts ? move.pp : move.pp * 8 / 5,
maxpp: move.noPPBoosts ? move.pp : move.pp * 8 / 5,
target: move.target,
disabled: false,
disabledSource: '',
used: false,
};
pokemon.moveSlots = pokemon.baseMoveSlots.slice();
}
},
},
rolloutstorage: {
name: 'rolloutstorage',
duration: 2,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,206 +0,0 @@
export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTable = {
magician: {
inherit: true,
onAfterMoveSecondarySelf(source, target, move) {
if (!move || source.switchFlag === true || !move.hitTargets || source.item || source.volatiles['gem'] ||
move.id === 'fling' || move.category === 'Status') return;
const hitTargets = move.hitTargets;
this.speedSort(hitTargets);
for (const pokemon of hitTargets) {
if (pokemon !== source) {
const yourItem = pokemon.takeItem(source);
if (!yourItem) continue;
if (!source.setItem(yourItem)) {
if (!this.dex.items.get(yourItem.id).exists) {
pokemon.setItem(yourItem.id);
continue;
}
pokemon.item = yourItem.id; // bypass setItem so we don't break choicelock or anything
continue;
}
this.add('-item', source, yourItem, '[from] ability: Magician', `[of] ${pokemon}`);
return;
}
}
},
},
neutralizinggas: {
inherit: true,
onSwitchIn(pokemon) {
this.add('-ability', pokemon, 'Neutralizing Gas');
pokemon.abilityState.ending = false;
const strongWeathers = ['desolateland', 'primordialsea', 'deltastream'];
for (const target of this.getAllActive()) {
if (target.hasItem('Ability Shield')) {
this.add('-block', target, 'item: Ability Shield');
continue;
}
// Can't suppress a Tatsugiri inside of Dondozo already
if (target.volatiles['commanding']) {
continue;
}
if (target.illusion) {
this.singleEvent('End', this.dex.abilities.get('Illusion'), target.abilityState, target, pokemon, 'neutralizinggas');
}
if (target.volatiles['slowstart']) {
delete target.volatiles['slowstart'];
this.add('-end', target, 'Slow Start', '[silent]');
}
if (strongWeathers.includes(target.getAbility().id)) {
this.singleEvent('End', this.dex.abilities.get(target.getAbility().id), target.abilityState, target, pokemon, 'neutralizinggas');
}
if (!this.dex.abilities.get(target.ability).exists) {
const isItem = (target.m.scrambled.items as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
if (isItem >= 0) {
target.removeVolatile('item:' + this.toID(target.m.scrambled.items[isItem].thing));
} else if ((target.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability') >= 0) {
const isMove = (target.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
const indexOfMove = target.moveSlots.findIndex(m => this.toID(target.m.scrambled.moves[isMove].thing) === m.id);
if (indexOfMove >= 0) target.moveSlots.splice(indexOfMove, 1);
}
}
}
},
onEnd(source) {
if (source.transformed) return;
for (const pokemon of this.getAllActive()) {
if (pokemon !== source && pokemon.hasAbility('Neutralizing Gas')) {
return;
}
}
this.add('-end', source, 'ability: Neutralizing Gas');
// FIXME this happens before the pokemon switches out, should be the opposite order.
// Not an easy fix since we cant use a supported event. Would need some kind of special event that
// gathers events to run after the switch and then runs them when the ability is no longer accessible.
// (If you're tackling this, do note extreme weathers have the same issue)
// Mark this pokemon's ability as ending so Pokemon#ignoringAbility skips it
if (source.abilityState.ending) return;
source.abilityState.ending = true;
const sortedActive = this.getAllActive();
this.speedSort(sortedActive);
for (const pokemon of sortedActive) {
if (pokemon !== source) {
if (pokemon.getAbility().flags['cantsuppress']) continue; // does not interact with e.g Ice Face, Zen Mode
if (pokemon.hasItem('abilityshield')) continue; // don't restart abilities that weren't suppressed
// Will be suppressed by Pokemon#ignoringAbility if needed
this.singleEvent('Start', pokemon.getAbility(), pokemon.abilityState, pokemon);
if (pokemon.ability === "gluttony") {
pokemon.abilityState.gluttony = false;
}
}
if (!this.dex.abilities.get(pokemon.ability).exists) {
const isItem = (pokemon.m.scrambled.items as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
if (isItem >= 0) {
pokemon.addVolatile('item:' + this.toID(pokemon.m.scrambled.items[isItem].thing));
} else if ((pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability') >= 0) {
const findMove = (pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
const findSlot = pokemon.baseMoveSlots.find(e => e.id === this.toID(pokemon.m.scrambled.moves[findMove].thing));
pokemon.moveSlots.push(this.dex.deepClone(findSlot));
}
}
}
},
},
pickpocket: {
inherit: true,
onAfterMoveSecondary(target, source, move) {
if (source && source !== target && move?.flags['contact']) {
if (target.item || target.switchFlag || target.forceSwitchFlag || source.switchFlag === true) {
return;
}
const yourItem = source.takeItem(target);
if (!yourItem) {
return;
}
if (!target.setItem(yourItem)) {
if (!this.dex.items.get(yourItem.id).exists) {
target.setItem(yourItem.id);
return;
}
source.item = yourItem.id;
return;
}
this.add('-enditem', source, yourItem, '[silent]', '[from] ability: Pickpocket', `[of] ${source}`);
this.add('-item', target, yourItem, '[from] ability: Pickpocket', `[of] ${source}`);
}
},
},
trace: {
inherit: true,
onStart(pokemon) {
this.effectState.seek = true;
// n.b. only affects Hackmons
// interaction with No Ability is complicated: https://www.smogon.com/forums/threads/pokemon-sun-moon-battle-mechanics-research.3586701/page-76#post-7790209
if (pokemon.adjacentFoes().some(foeActive => foeActive.ability === 'noability')) {
this.effectState.seek = false;
}
// interaction with Ability Shield is similar to No Ability
if (pokemon.hasItem('Ability Shield') && this.toID(pokemon.ability) === 'trace') {
this.add('-block', pokemon, 'item: Ability Shield');
this.effectState.seek = false;
}
if (this.effectState.seek) {
this.singleEvent('Update', this.effect, this.effectState, pokemon);
}
},
onUpdate(pokemon) {
if (!this.effectState.seek) return;
const possibleTargets = pokemon.adjacentFoes().filter(
target => !target.getAbility().flags['notrace'] && target.ability !== 'noability'
);
if (!possibleTargets.length) return;
const target = this.sample(possibleTargets);
const ability = target.getAbility();
if (this.toID(pokemon.item) === 'trace') {
this.add('-ability', pokemon, ability.name, 'Trace');
pokemon.setItem(ability.name);
return;
} else if (pokemon.volatiles['ability:trace']?.inSlot === 'Move') {
if (this.dex.abilities.get(ability.name).exists) {
pokemon.removeVolatile('ability:trace');
pokemon.m.scrambled.abilities.splice(
(pokemon.m.scrambled.abilities as { thing: string, inSlot: string }[]).findIndex(e =>
this.toID(e.thing) === 'trace' && e.inSlot === 'Move'), 1);
this.add('-ability', pokemon, ability.name, 'Trace');
pokemon.addVolatile(`ability:${ability.id}`);
pokemon.m.scrambled.abilities.push({ thing: ability.name, inSlot: 'Move' });
} else if (this.dex.items.get(ability.name).exists) {
pokemon.removeVolatile('ability:trace');
pokemon.m.scrambled.abilities.splice(
(pokemon.m.scrambled.abilities as { thing: string, inSlot: string }[]).findIndex(e =>
this.toID(e.thing) === 'trace' && e.inSlot === 'Move'), 1);
this.add('-ability', pokemon, ability.name, 'Trace');
pokemon.addVolatile(`item:${ability.id}`);
pokemon.m.scrambled.items.push({ thing: this.dex.items.get(ability.name).name, inSlot: 'Move' });
} else {
const move = this.dex.moves.get(ability.name);
if (move.exists) {
pokemon.removeVolatile('ability:trace');
pokemon.m.scrambled.abilities.splice(
(pokemon.m.scrambled.abilities as { thing: string, inSlot: string }[]).findIndex(e =>
this.toID(e.thing) === 'trace' && e.inSlot === 'Move'), 1);
this.add('-ability', pokemon, move.name, 'Trace');
const newMove = {
move: move.name,
id: move.id,
pp: move.noPPBoosts ? move.pp : move.pp * 8 / 5,
maxpp: move.noPPBoosts ? move.pp : move.pp * 8 / 5,
target: move.target,
disabled: false,
used: false,
};
pokemon.baseMoveSlots.push(newMove);
pokemon.moveSlots.push(newMove);
}
}
return;
}
pokemon.setAbility(ability, target);
},
},
};

View File

@ -1,44 +0,0 @@
export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDataTable = {
choicelock: {
inherit: true,
onBeforeMove(pokemon, target, move) {
const choiceItem = pokemon.getItem().isChoice ||
Object.keys(pokemon.volatiles).some(v => (
v.startsWith('item:') && this.dex.items.get(v.split(':')[1]).isChoice
));
if (!choiceItem) {
pokemon.removeVolatile('choicelock');
return;
}
if (
!pokemon.ignoringItem() && !pokemon.volatiles['dynamax'] &&
move.id !== this.effectState.move && move.id !== 'struggle'
) {
// Fails unless the Choice item is being ignored, and no PP is lost
this.addMove('move', pokemon, move.name);
this.attrLastMove('[still]');
this.debug("Disabled by Choice item lock");
this.add('-fail', pokemon);
return false;
}
},
onDisableMove(pokemon) {
const choiceItem = pokemon.getItem().isChoice ||
Object.keys(pokemon.volatiles).some(v => (
v.startsWith('item:') && this.dex.items.get(v.split(':')[1]).isChoice
));
if (!choiceItem || !pokemon.hasMove(this.effectState.move)) {
pokemon.removeVolatile('choicelock');
return;
}
if (pokemon.ignoringItem() || pokemon.volatiles['dynamax']) {
return;
}
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id !== this.effectState.move) {
pokemon.disableMove(moveSlot.id, false, this.effectState.sourceEffect);
}
}
},
},
};

View File

@ -1,41 +0,0 @@
export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
airballoon: {
inherit: true,
// airborneness implemented in sim/pokemon.js:Pokemon#isGrounded
onDamagingHit(damage, target, source, move) {
this.add('-enditem', target, 'Air Balloon');
if (target.item === 'airballoon') {
target.item = '';
this.clearEffectState(target.itemState);
} else {
const isBMM = target.volatiles['item:airballoon']?.inSlot;
if (isBMM) {
target.removeVolatile('item:airballoon');
target.m.scrambled.items.splice((target.m.scrambled.items as { thing: string, inSlot: string }[]).findIndex(e =>
this.toID(e.thing) === 'airballoon' && e.inSlot === isBMM), 1);
if (isBMM === 'Ability') target.setAbility('No Ability');
}
}
this.runEvent('AfterUseItem', target, null, null, this.dex.items.get('airballoon'));
},
onAfterSubDamage(damage, target, source, effect) {
this.debug('effect: ' + effect.id);
if (effect.effectType === 'Move') {
this.add('-enditem', target, 'Air Balloon');
if (target.item === 'airballoon') {
target.item = '';
this.clearEffectState(target.itemState);
} else {
const isBMM = target.volatiles['item:airballoon']?.inSlot;
if (isBMM) {
target.removeVolatile('item:airballoon');
target.m.scrambled.items.splice((target.m.scrambled.items as { thing: string, inSlot: string }[]).findIndex(e =>
this.toID(e.thing) === 'airballoon' && e.inSlot === isBMM), 1);
if (isBMM === 'Ability') target.setAbility('No Ability');
}
}
this.runEvent('AfterUseItem', target, null, null, this.dex.items.get('airballoon'));
}
},
},
};

View File

@ -1,419 +0,0 @@
export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
// Remember, everything deals with SLOTS not with properties as they are!
covet: {
inherit: true,
onAfterHit(target, source, move) {
if (source.item || source.volatiles['gem']) {
return;
}
const yourItem = target.takeItem(source);
if (!yourItem) {
return;
}
if (
!this.singleEvent('TakeItem', yourItem, target.itemState, source, target, move, yourItem) ||
!source.setItem(yourItem)
) {
if (!this.dex.items.get(yourItem.id).exists) {
target.setItem(yourItem.id);
return;
}
target.item = yourItem.id; // bypass setItem so we don't break choicelock or anything
return;
}
this.add('-item', source, yourItem, '[from] move: Covet', `[of] ${target}`);
},
},
embargo: {
inherit: true,
condition: {
duration: 5,
onStart(pokemon) {
this.add('-start', pokemon, 'Embargo');
this.singleEvent('End', pokemon.getItem(), pokemon.itemState, pokemon);
if (!this.dex.items.get(pokemon.item).exists) {
const isAbil = (pokemon.m.scrambled.abilities as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
if (isAbil >= 0) {
pokemon.removeVolatile('ability:' + this.toID(pokemon.m.scrambled.abilities[isAbil].thing));
} else if ((pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item') >= 0) {
const isMove = (pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
const slotNo = pokemon.moveSlots.findIndex(m => this.toID(pokemon.m.scrambled.moves[isMove].thing) === m.id);
if (slotNo >= 0) pokemon.moveSlots.splice(slotNo, 1);
}
}
},
// Item suppression implemented in Pokemon.ignoringItem() within sim/pokemon.js
onResidualOrder: 21,
onEnd(pokemon) {
this.add('-end', pokemon, 'Embargo');
if (!this.dex.items.get(pokemon.item).exists) {
const isAbil = (pokemon.m.scrambled.abilities as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
if (isAbil >= 0) {
pokemon.addVolatile('ability:' + this.toID(pokemon.m.scrambled.abilities[isAbil].thing));
} else if ((pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item') >= 0) {
const findMove = (pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
const findSlot = pokemon.baseMoveSlots.find(e => e.id === this.toID(pokemon.m.scrambled.moves[findMove].thing));
pokemon.moveSlots.push(this.dex.deepClone(findSlot));
}
}
},
},
},
magicroom: {
inherit: true,
condition: {
duration: 5,
durationCallback(source, effect) {
if (source?.hasAbility('persistent')) {
this.add('-activate', source, 'ability: Persistent', '[move] Magic Room');
return 7;
}
return 5;
},
onFieldStart(target, source) {
if (source?.hasAbility('persistent')) {
this.add('-fieldstart', 'move: Magic Room', `[of] ${source}`, '[persistent]');
} else {
this.add('-fieldstart', 'move: Magic Room', `[of] ${source}`);
}
for (const mon of this.getAllActive()) {
this.singleEvent('End', mon.getItem(), mon.itemState, mon);
if (!this.dex.items.get(mon.item).exists) {
const isAbil = (mon.m.scrambled.abilities as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
if (isAbil >= 0) {
mon.removeVolatile('ability:' + this.toID(mon.m.scrambled.abilities[isAbil].thing));
} else if ((mon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item') >= 0) {
const isMove = (mon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
const slotNo = mon.moveSlots.findIndex(m => this.toID(mon.m.scrambled.moves[isMove].thing) === m.id);
if (slotNo >= 0) mon.moveSlots.splice(slotNo, 1);
}
}
}
},
onFieldRestart(target, source) {
this.field.removePseudoWeather('magicroom');
},
// Item suppression implemented in Pokemon.ignoringItem() within sim/pokemon.js
onFieldResidualOrder: 27,
onFieldResidualSubOrder: 6,
onFieldEnd() {
this.add('-fieldend', 'move: Magic Room', '[of] ' + this.effectState.source);
for (const pokemon of this.getAllActive()) {
if (!this.dex.items.get(pokemon.item).exists) {
const isAbil = (pokemon.m.scrambled.abilities as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
if (isAbil >= 0) {
pokemon.addVolatile('ability:' + this.toID(pokemon.m.scrambled.abilities[isAbil].thing));
} else if ((pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item') >= 0) {
const findMove = (pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
const findSlot = pokemon.baseMoveSlots.find(e => e.id === this.toID(pokemon.m.scrambled.moves[findMove].thing));
pokemon.moveSlots.push(this.dex.deepClone(findSlot));
}
}
}
},
},
},
gastroacid: {
inherit: true,
condition: {
// Ability suppression implemented in Pokemon.ignoringAbility() within sim/pokemon.js
onStart(pokemon) {
this.add('-endability', pokemon);
this.singleEvent('End', pokemon.getAbility(), pokemon.abilityState, pokemon, pokemon, 'gastroacid');
if (!this.dex.abilities.get(pokemon.ability).exists) {
const isItem = (pokemon.m.scrambled.items as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
if (isItem >= 0) {
pokemon.removeVolatile('item:' + this.toID(pokemon.m.scrambled.items[isItem].thing));
} else if ((pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability') >= 0) {
const isMove = (pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
const slotNo = pokemon.moveSlots.findIndex(m => this.toID(pokemon.m.scrambled.moves[isMove].thing) === m.id);
if (slotNo >= 0) pokemon.moveSlots.splice(slotNo, 1);
}
}
},
},
},
trick: {
inherit: true,
onHit(target, source, move) {
const yourItem = target.takeItem(source);
const myItem = source.takeItem();
if (target.item || source.item || (!yourItem && !myItem)) {
if (yourItem) {
if (!this.dex.items.get(yourItem.id).exists) {
target.setItem(yourItem.id);
} else {
target.item = yourItem.id;
}
}
if (myItem) {
if (!this.dex.items.get(myItem.id).exists) {
source.setItem(myItem.id);
} else {
source.item = myItem.id;
}
}
return false;
}
if (
(myItem && !this.singleEvent('TakeItem', myItem, source.itemState, target, source, move, myItem)) ||
(yourItem && !this.singleEvent('TakeItem', yourItem, target.itemState, source, target, move, yourItem))
) {
if (yourItem) {
if (!this.dex.items.get(yourItem.id).exists) {
target.setItem(yourItem.id);
} else {
target.item = yourItem.id;
}
}
if (myItem) {
if (!this.dex.items.get(myItem.id).exists) {
source.setItem(myItem.id);
} else {
source.item = myItem.id;
}
}
return false;
}
this.add('-activate', source, 'move: Trick', `[of] ${target}`);
if (myItem) {
target.setItem(myItem);
this.add('-item', target, myItem, '[from] move: Trick');
} else {
this.add('-enditem', target, yourItem, '[silent]', '[from] move: Trick');
}
if (yourItem) {
source.setItem(yourItem);
this.add('-item', source, yourItem, '[from] move: Trick');
} else {
this.add('-enditem', source, myItem, '[silent]', '[from] move: Trick');
}
},
},
sketch: {
inherit: true,
onHit(target, source) {
const move = target.lastMove;
if (source.transformed || !move || source.moves.includes(move.id)) return false;
if (move.flags['nosketch'] || move.isZ || move.isMax) return false;
const sketchIndex = source.moves.indexOf('sketch');
if (sketchIndex < 0) return false;
if (this.toID(source.item) === 'sketch') {
source.setItem(move.name);
this.add('-activate', source, 'move: Sketch', move.name);
return;
} else if (this.toID(source.ability) === 'sketch') {
source.setAbility(move.name);
this.add('-activate', source, 'move: Sketch', move.name);
return;
}
const sketchedMove = {
move: move.name,
id: move.id,
pp: move.pp,
maxpp: move.pp,
target: move.target,
disabled: false,
used: false,
};
source.moveSlots[sketchIndex] = sketchedMove;
source.baseMoveSlots[sketchIndex] = sketchedMove;
this.add('-activate', source, 'move: Sketch', move.name);
},
},
skillswap: {
inherit: true,
onTryHit(target, source) {
const targetAbility = target.getAbility();
const sourceAbility = source.getAbility();
if (sourceAbility.flags['failskillswap'] || targetAbility.flags['failskillswap'] || target.volatiles['dynamax']) {
return false;
}
let sourceCanBeSet = this.runEvent('SetAbility', source, source, this.effect, targetAbility);
if (!this.dex.abilities.get(sourceAbility).exists && this.dex.items.get(sourceAbility.id).exists) {
sourceCanBeSet = this.runEvent('TakeItem', source, source, this.effect, this.dex.items.get(sourceAbility.id));
}
if (!sourceCanBeSet) return sourceCanBeSet;
let targetCanBeSet = this.runEvent('SetAbility', target, source, this.effect, sourceAbility);
if (!this.dex.abilities.get(targetAbility).exists && this.dex.items.get(targetAbility.id).exists) {
targetCanBeSet = this.runEvent('TakeItem', target, source, this.effect, this.dex.items.get(targetAbility.id));
}
if (!targetCanBeSet) return targetCanBeSet;
},
onHit(target, source, move) {
const targetAbility = target.getAbility();
const sourceAbility = source.getAbility();
const sourceIsBMM = !this.dex.abilities.get(sourceAbility).exists;
const targetIsBMM = !this.dex.abilities.get(targetAbility).exists;
if (target.isAlly(source)) {
this.add('-activate', source, 'move: Skill Swap', '', '', `[of] ${target}`);
} else {
this.add('-activate', source, 'move: Skill Swap', targetAbility, sourceAbility, `[of] ${target}`);
}
this.singleEvent('End', sourceAbility, source.abilityState, source);
if (sourceIsBMM) {
const isItem = (source.m.scrambled.items as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
if (isItem >= 0) {
source.removeVolatile('item:' + this.toID(source.m.scrambled.items[isItem].thing));
source.m.scrambled.items.splice(isItem, 1);
} else if ((source.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability') >= 0) {
const isMove = (source.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
source.baseMoveSlots.splice(
source.baseMoveSlots.findIndex(m => this.toID(source.m.scrambled.moves[isMove].thing) === m.id), 1);
source.moveSlots.splice(source.moveSlots.findIndex(m => this.toID(source.m.scrambled.moves[isMove].thing) === m.id), 1);
source.m.scrambled.moves.splice(isMove, 1);
}
}
this.singleEvent('End', targetAbility, target.abilityState, target);
if (targetIsBMM) {
const isItem = (target.m.scrambled.items as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
if (isItem >= 0) {
target.removeVolatile('item:' + this.toID(target.m.scrambled.items[isItem].thing));
target.m.scrambled.items.splice(isItem, 1);
} else if ((target.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability') >= 0) {
const isMove = (target.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
target.baseMoveSlots.splice(
target.baseMoveSlots.findIndex(m => this.toID(target.m.scrambled.moves[isMove].thing) === m.id), 1);
target.moveSlots.splice(target.moveSlots.findIndex(m => this.toID(target.m.scrambled.moves[isMove].thing) === m.id), 1);
target.m.scrambled.moves.splice(isMove, 1);
}
}
source.ability = source.baseAbility = targetAbility.id;
target.ability = target.baseAbility = sourceAbility.id;
source.abilityState = this.initEffectState({ id: this.toID(source.ability), target: source });
target.abilityState = this.initEffectState({ id: this.toID(target.ability), target });
source.volatileStaleness = undefined;
if (!target.isAlly(source)) target.volatileStaleness = 'external';
this.singleEvent('Start', targetAbility, source.abilityState, source);
if (targetIsBMM) {
if (this.dex.items.get(targetAbility.id).exists) {
source.m.scrambled.items.push({ thing: targetAbility.id, inSlot: 'Ability' });
const effect = 'item:' + this.toID(targetAbility.id);
source.addVolatile(effect);
source.volatiles[effect].inSlot = 'Ability';
} else {
source.m.scrambled.moves.push({ thing: targetAbility.id, inSlot: 'Ability' });
const bmmMove = Dex.moves.get(targetAbility.id);
const newMove = {
move: bmmMove.name,
id: bmmMove.id,
pp: bmmMove.noPPBoosts ? bmmMove.pp : bmmMove.pp * 8 / 5,
maxpp: bmmMove.noPPBoosts ? bmmMove.pp : bmmMove.pp * 8 / 5,
target: bmmMove.target,
disabled: false,
used: false,
};
source.baseMoveSlots.push(newMove);
source.moveSlots.push(newMove);
}
}
this.singleEvent('Start', sourceAbility, target.abilityState, target);
if (sourceIsBMM) {
if (this.dex.items.get(sourceAbility.id).exists) {
target.m.scrambled.items.push({ thing: sourceAbility.id, inSlot: 'Ability' });
const effect = 'item:' + this.toID(sourceAbility.id);
target.addVolatile(effect);
target.volatiles[effect].inSlot = 'Ability';
} else {
target.m.scrambled.moves.push({ thing: sourceAbility.id, inSlot: 'Ability' });
const bmmMove = Dex.moves.get(sourceAbility.id);
const newMove = {
move: bmmMove.name,
id: bmmMove.id,
pp: bmmMove.noPPBoosts ? bmmMove.pp : bmmMove.pp * 8 / 5,
maxpp: bmmMove.noPPBoosts ? bmmMove.pp : bmmMove.pp * 8 / 5,
target: bmmMove.target,
disabled: false,
used: false,
};
target.baseMoveSlots.push(newMove);
target.moveSlots.push(newMove);
}
}
},
},
switcheroo: {
inherit: true,
onHit(target, source, move) {
const yourItem = target.takeItem(source);
const myItem = source.takeItem();
if (target.item || source.item || (!yourItem && !myItem)) {
if (yourItem) {
if (!this.dex.items.get(yourItem.id).exists) {
target.setItem(yourItem.id);
} else {
target.item = yourItem.id;
}
}
if (myItem) {
if (!this.dex.items.get(myItem.id).exists) {
source.setItem(myItem.id);
} else {
source.item = myItem.id;
}
}
return false;
}
if (
(myItem && !this.singleEvent('TakeItem', myItem, source.itemState, target, source, move, myItem)) ||
(yourItem && !this.singleEvent('TakeItem', yourItem, target.itemState, source, target, move, yourItem))
) {
if (yourItem) {
if (!this.dex.items.get(yourItem.id).exists) {
target.setItem(yourItem.id);
} else {
target.item = yourItem.id;
}
}
if (myItem) {
if (!this.dex.items.get(myItem.id).exists) {
source.setItem(myItem.id);
} else {
source.item = myItem.id;
}
}
return false;
}
this.add('-activate', source, 'move: Trick', `[of] ${target}`);
if (myItem) {
target.setItem(myItem);
this.add('-item', target, myItem, '[from] move: Switcheroo');
} else {
this.add('-enditem', target, yourItem, '[silent]', '[from] move: Switcheroo');
}
if (yourItem) {
source.setItem(yourItem);
this.add('-item', source, yourItem, '[from] move: Switcheroo');
} else {
this.add('-enditem', source, myItem, '[silent]', '[from] move: Switcheroo');
}
},
},
thief: {
inherit: true,
onAfterHit(target, source, move) {
if (source.item || source.volatiles['gem']) {
return;
}
const yourItem = target.takeItem(source);
if (!yourItem) {
return;
}
if (!this.singleEvent('TakeItem', yourItem, target.itemState, source, target, move, yourItem) ||
!source.setItem(yourItem)) {
if (!this.dex.items.get(yourItem.id).exists) {
target.setItem(yourItem.id);
return;
}
target.item = yourItem.id; // bypass setItem so we don't break choicelock or anything
return;
}
this.add('-enditem', target, yourItem, '[silent]', '[from] move: Thief', `[of] ${source}`);
this.add('-item', source, yourItem, '[from] move: Thief', `[of] ${target}`);
},
},
};

View File

@ -1,584 +0,0 @@
import { RESTORATIVE_BERRIES } from "../../../sim/pokemon";
export const Scripts: ModdedBattleScriptsData = {
pokemon: {
isGrounded(negateImmunity) {
if ('gravity' in this.battle.field.pseudoWeather) return true;
if ('ingrain' in this.volatiles && this.battle.gen >= 4) return true;
if ('smackdown' in this.volatiles) return true;
const item = (this.ignoringItem() ? '' : this.item);
if (item === 'ironball' || (this.volatiles['item:ironball'] && !this.ignoringItem())) return true;
// If a Fire/Flying type uses Burn Up and Roost, it becomes ???/Flying-type, but it's still grounded.
if (!negateImmunity && this.hasType('Flying') && !(this.hasType('???') && 'roost' in this.volatiles)) return false;
if (this.hasAbility('levitate') && !this.battle.suppressingAbility(this)) return null;
if ('magnetrise' in this.volatiles) return false;
if ('telekinesis' in this.volatiles) return false;
if (item === 'airballoon' || (this.volatiles['item:airballoon'] && !this.ignoringItem())) return false;
return true;
},
getAbility() {
const ability = this.battle.dex.abilities.getByID(this.ability);
if (ability.exists) return ability;
let abil = this.battle.dex.items.getByID(this.ability) as Item | Move;
if (!abil.exists) abil = this.battle.dex.moves.getByID(this.ability);
return {
id: this.ability,
name: abil.name || this.ability,
flags: {},
effectType: "Ability",
toString() {
return abil.name || this.id;
},
} as Ability;
},
hasAbility(ability) {
if (this.ignoringAbility()) return false;
if (Array.isArray(ability)) return ability.some(abil => this.hasAbility(abil));
const abilityid = this.battle.toID(ability);
return this.ability === abilityid || !!this.volatiles['ability:' + abilityid];
},
ignoringAbility() {
// Check if any active pokemon have the ability Neutralizing Gas
let neutralizinggas = false;
for (const pokemon of this.battle.getAllActive()) {
// can't use hasAbility because it would lead to infinite recursion
if (
(pokemon.ability === ('neutralizinggas' as ID) ||
(pokemon.m.scrambled.abilities as { thing: string }[]).some(
abils => this.battle.toID(abils.thing) === 'neutralizinggas')) &&
!pokemon.volatiles['gastroacid'] && !pokemon.abilityState.ending
) {
neutralizinggas = true;
break;
}
}
return !!(
(this.battle.gen >= 5 && !this.isActive) ||
((this.volatiles['gastroacid'] ||
(neutralizinggas && (this.ability !== ('neutralizinggas' as ID) ||
(this.m.scrambled.abilities as { thing: string }[]).some(abils => this.battle.toID(abils.thing) === 'neutralizinggas'))
)) && !this.getAbility().flags['cantsuppress']
)
);
},
setAbility(ability, source, sourceEffect, isFromFormeChange = false, isTransform = false) {
const allThings = new Set([
...(this.m.scrambled.abilities as { thing: string }[]).map(e => e.thing),
...(this.m.scrambled.items as { thing: string }[]).map(e => e.thing),
...(this.m.scrambled.moves as { thing: string }[]).map(e => e.thing),
this.ability, ...this.moveSlots.map(e => e.move), this.item,
].map(this.battle.toID));
let isBMMAbil = false;
let isOldBMMAbil = false;
if (!this.hp) return false;
if (typeof ability === 'string') {
if (this.battle.dex.abilities.get(ability).exists) {
ability = this.battle.dex.abilities.get(ability);
} else {
const abilString = ability;
let abil = this.battle.dex.items.get(abilString) as Item | Move;
if (!abil.exists) abil = this.battle.dex.moves.get(abilString);
ability = {
id: abil.id || abilString,
name: abil.name || abilString,
flags: {},
effectType: "Ability",
toString() {
return abil.name || abilString;
},
} as Ability;
}
}
if (ability.name.length && !this.battle.dex.abilities.get(ability).exists) isBMMAbil = true;
if (!sourceEffect && this.battle.effect) sourceEffect = this.battle.effect;
let oldAbility;
if (this.battle.dex.abilities.get(this.ability).exists) {
oldAbility = this.battle.dex.abilities.get(this.ability);
} else {
let abil = this.battle.dex.items.getByID(this.ability) as Item | Move;
if (!abil.exists) {
abil = this.battle.dex.moves.getByID(this.ability);
} else {
if (!this.battle.runEvent('TakeItem', this, source, null, abil as Item)) return false;
}
oldAbility = {
id: this.ability,
name: abil.name || this.ability,
flags: {},
effectType: "Ability",
toString() {
return abil.name || this.id;
},
} as Ability;
isOldBMMAbil = true;
}
if (allThings.has(ability.id)) return false;
if (!isFromFormeChange) {
if (ability.flags['cantsuppress'] || this.getAbility().flags['cantsuppress']) return false;
}
if (!isFromFormeChange && !isTransform) {
const setAbilityEvent: boolean | null = this.battle.runEvent('SetAbility', this, source, sourceEffect, ability);
if (!setAbilityEvent) return setAbilityEvent;
}
this.battle.singleEvent('End', oldAbility, this.abilityState, this, source);
if (isOldBMMAbil) {
const isItem = (this.m.scrambled.items as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
if (isItem >= 0) {
this.removeVolatile('item:' + this.battle.toID(this.m.scrambled.items[isItem].thing));
this.m.scrambled.items.splice(isItem, 1);
} else if ((this.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability') >= 0) {
const isMove = (this.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
if (!isTransform) {
let indexOfMove = this.baseMoveSlots.findIndex(m => this.battle.toID(this.m.scrambled.moves[isMove].thing) === m.id);
if (indexOfMove >= 0) this.baseMoveSlots.splice(indexOfMove, 1);
if (oldAbility.id !== 'mimic') {
indexOfMove = this.moveSlots.findIndex(m => this.battle.toID(this.m.scrambled.moves[isMove].thing) === m.id);
}
if (indexOfMove >= 0) this.moveSlots.splice(indexOfMove, 1);
}
this.m.scrambled.moves.splice(isMove, 1);
}
}
this.ability = ability.id;
// ability changes are permanent in BioMechMons
if (!isTransform && !this.transformed) this.baseAbility = ability.id;
this.abilityState = this.battle.initEffectState({ id: ability.id, target: this });
if (sourceEffect && !isFromFormeChange && !isTransform) {
if (source) {
this.battle.add('-ability', this, ability.name, oldAbility.name, `[from] ${sourceEffect.fullname}`, `[of] ${source}`);
} else {
this.battle.add('-ability', this, ability.name, oldAbility.name, `[from] ${sourceEffect.fullname}`);
}
}
if (ability.id && this.battle.gen > 3 &&
(!isTransform || oldAbility.id !== ability.id || this.battle.gen <= 4)) {
this.battle.singleEvent('Start', ability, this.abilityState, this, source);
}
if (isBMMAbil) {
if (this.battle.dex.items.get(ability.id).exists) {
this.m.scrambled.items.push({ thing: ability.id, inSlot: 'Ability' });
const effect = 'item:' + this.battle.toID(ability.id);
this.addVolatile(effect);
this.volatiles[effect].inSlot = 'Ability';
} else {
this.m.scrambled.moves.push({ thing: ability.id, inSlot: 'Ability' });
const move = Dex.moves.get(ability.id);
const newMove = {
move: move.name,
id: move.id,
pp: move.noPPBoosts ? move.pp : move.pp * 8 / 5,
maxpp: move.noPPBoosts ? move.pp : move.pp * 8 / 5,
target: move.target,
disabled: false,
used: false,
};
if (!isTransform) {
this.baseMoveSlots.push(newMove);
this.moveSlots.push(newMove);
}
}
}
return oldAbility.id;
},
getItem() {
const item = this.battle.dex.items.getByID(this.item);
if (item.exists) return item;
let bmmItem = this.battle.dex.abilities.getByID(this.item) as Ability | Move;
if (!bmmItem.exists) bmmItem = this.battle.dex.moves.getByID(this.item);
return {
id: this.item,
name: bmmItem.name || this.name,
effectType: "Item",
toString() {
return bmmItem.name || this.id;
},
} as Item;
},
hasItem(item) {
if (this.ignoringItem()) return false;
if (Array.isArray(item)) return item.some(i => this.hasItem(i));
const itemId = this.battle.toID(item);
return this.item === itemId || !!this.volatiles['item:' + itemId];
},
takeItem(source) {
if (!this.item) return false;
if (!source) source = this;
if (this.battle.gen <= 4) {
if (source.itemKnockedOff) return false;
if (this.battle.toID(this.ability) === 'multitype' || (this.m.scrambled.abilities as { thing: string }[])
.findIndex(e => this.battle.toID(e.thing) === 'multitype') >= 0) {
return false;
}
if (this.battle.toID(source.ability) === 'multitype' || (source.m.scrambled.abilities as { thing: string }[])
.findIndex(e => this.battle.toID(e.thing) === 'multitype') >= 0) {
return false;
}
}
const item = this.getItem();
if (this.battle.runEvent('TakeItem', this, source, null, item)) {
this.item = '';
let wrongSlot = (this.m.scrambled.abilities as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
if (wrongSlot >= 0) {
const dexAbil = this.battle.dex.abilities.get(this.m.scrambled.abilities[wrongSlot].thing);
if (dexAbil.flags['failskillswap']) return false;
this.removeVolatile('ability:' + this.battle.toID(this.m.scrambled.abilities[wrongSlot].thing));
this.m.scrambled.abilities.splice(wrongSlot, 1);
} else if ((this.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item') >= 0) {
wrongSlot = (this.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
let indexOfMove = this.baseMoveSlots.findIndex(m => this.battle.toID(this.m.scrambled.moves[wrongSlot].thing) === m.id);
if (indexOfMove >= 0) this.baseMoveSlots.splice(indexOfMove, 1);
if (item.id !== 'mimic') {
indexOfMove = this.moveSlots.findIndex(m => this.battle.toID(this.m.scrambled.moves[wrongSlot].thing) === m.id);
}
if (indexOfMove >= 0) this.moveSlots.splice(indexOfMove, 1);
this.m.scrambled.moves.splice(wrongSlot, 1);
}
const oldItemState = this.itemState;
this.battle.clearEffectState(this.itemState);
this.pendingStaleness = undefined;
this.battle.singleEvent('End', item, oldItemState, this);
this.battle.runEvent('AfterTakeItem', this, null, null, item);
return item;
}
return false;
},
setItem(item, source, effect) {
const allThings = new Set([
...(this.m.scrambled.abilities as { thing: string }[]).map(e => e.thing),
...(this.m.scrambled.items as { thing: string }[]).map(e => e.thing),
...(this.m.scrambled.moves as { thing: string }[]).map(e => e.thing),
this.ability, ...this.moveSlots.map(e => e.move), this.item,
].map(this.battle.toID));
let isBMMItem = false;
let isOldBMMItem = false;
if (!this.hp || !this.isActive) return false;
if (typeof item === 'string') {
if (!item.length || this.battle.dex.items.get(item).exists) {
item = this.battle.dex.items.get(item);
} else {
const itemString = item;
let newData = this.battle.dex.abilities.get(itemString) as Ability | Move;
if (!newData.exists) {
newData = this.battle.dex.moves.get(itemString);
} else {
if ((newData as Ability).flags['failskillswap']) return false;
}
item = {
id: newData.id || itemString,
name: newData.name || itemString,
effectType: "Item",
toString() {
return newData.name || itemString;
},
} as Item;
}
}
if (item.name.length && !this.battle.dex.items.get(item).exists) isBMMItem = true;
if (allThings.has(item.id)) return false;
const effectid = this.battle.effect ? this.battle.effect.id : '';
if (RESTORATIVE_BERRIES.has('leppaberry' as ID)) {
const inflicted = ['trick', 'switcheroo'].includes(effectid);
const external = inflicted && source && !source.isAlly(this);
this.pendingStaleness = external ? 'external' : 'internal';
} else {
this.pendingStaleness = undefined;
}
const oldItem = this.getItem();
if (!this.battle.dex.items.get(oldItem).exists) isOldBMMItem = true;
const oldItemState = this.itemState;
this.item = item.id;
this.itemState = this.battle.initEffectState({ id: item.id, target: this });
if (oldItem.exists) this.battle.singleEvent('End', oldItem, oldItemState, this);
if (isOldBMMItem) {
const isAbil = (this.m.scrambled.abilities as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
if (isAbil >= 0) {
this.removeVolatile('ability:' + this.battle.toID(this.m.scrambled.items[isAbil].thing));
this.m.scrambled.abilities.splice(isAbil, 1);
} else if ((this.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item') >= 0) {
const isMove = (this.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
let indexOfMove = this.baseMoveSlots.findIndex(m => this.battle.toID(this.m.scrambled.moves[isMove].thing) === m.id);
if (indexOfMove >= 0) this.baseMoveSlots.splice(indexOfMove, 1);
if (oldItem.id !== 'mimic') {
indexOfMove = this.moveSlots.findIndex(m => this.battle.toID(this.m.scrambled.moves[isMove].thing) === m.id);
}
if (indexOfMove >= 0) this.moveSlots.splice(indexOfMove, 1);
this.m.scrambled.moves.splice(isMove, 1);
}
}
if (item.id) {
this.battle.singleEvent('Start', item, this.itemState, this, source, effect);
}
if (isBMMItem) {
if (this.battle.dex.abilities.get(item.id).exists) {
this.m.scrambled.abilities.push({ thing: item.id, inSlot: 'Item' });
const abileffect = 'ability:' + this.battle.toID(item.id);
this.addVolatile(abileffect);
this.volatiles[abileffect].inSlot = 'Item';
} else {
this.m.scrambled.moves.push({ thing: item.id, inSlot: 'Item' });
const move = Dex.moves.get(item.id);
const newMove = {
move: move.name,
id: move.id,
pp: move.noPPBoosts ? move.pp : move.pp * 8 / 5,
maxpp: move.noPPBoosts ? move.pp : move.pp * 8 / 5,
target: move.target,
disabled: false,
used: false,
};
this.baseMoveSlots.push(newMove);
this.moveSlots.push(newMove);
}
}
return true;
},
eatItem(force, source, sourceEffect) {
const item = sourceEffect?.effectType === 'Item' ? sourceEffect :
this.battle.effect.effectType === 'Item' ? this.battle.effect : this.getItem();
if (!item) return false;
if ((!this.hp && this.battle.toID(item.name) !== 'jabocaberry' && this.battle.toID(item.name) !== 'rowapberry') ||
!this.isActive) return false;
if (!sourceEffect && this.battle.effect) sourceEffect = this.battle.effect;
if (!source && this.battle.event?.target) source = this.battle.event.target;
// if (sourceEffect?.effectType === 'Item' && this.item !== sourceEffect.id && source === this) {
// // if an item is telling us to eat it but we aren't holding it, we probably shouldn't eat what we are holding
// return false;
// }
if (
this.battle.runEvent('UseItem', this, null, null, Dex.items.get(item.name)) &&
(force || this.battle.runEvent('TryEatItem', this, null, null, Dex.items.get(item.name)))
) {
this.battle.add('-enditem', this, Dex.items.get(item.name), '[eat]');
this.battle.singleEvent('Eat', Dex.items.get(item.name), this.itemState, this, source, sourceEffect);
this.battle.runEvent('EatItem', this, source, sourceEffect, Dex.items.get(item.name));
if (RESTORATIVE_BERRIES.has(item.id)) {
switch (this.pendingStaleness) {
case 'internal':
if (this.staleness !== 'external') this.staleness = 'internal';
break;
case 'external':
this.staleness = 'external';
break;
}
this.pendingStaleness = undefined;
}
const isBMM = this.volatiles[item.id]?.inSlot;
if (isBMM) {
const dexItem = this.battle.dex.items.get(item.name);
this.removeVolatile(item.id);
const itemIndex = (this.m.scrambled.items as { thing: string, inSlot: string }[]).findIndex(e =>
this.battle.toID(e.thing) === dexItem.id && e.inSlot === isBMM);
if (itemIndex >= 0) this.m.scrambled.items.splice(itemIndex, 1);
if (isBMM === 'Ability') this.setAbility('No Ability');
} else {
this.lastItem = this.item;
this.item = '';
}
this.battle.clearEffectState(this.itemState);
this.usedItemThisTurn = true;
this.ateBerry = true;
this.battle.runEvent('AfterUseItem', this, null, null, Dex.items.get(item.name));
return true;
}
return false;
},
useItem(source, sourceEffect) {
const item = sourceEffect?.effectType === 'Item' ? sourceEffect :
this.battle.effect.effectType === 'Item' ? this.battle.effect : this.getItem();
if ((!this.hp && !item.isGem) || !this.isActive) return false;
if (!item) return false;
if (!sourceEffect && this.battle.effect) sourceEffect = this.battle.effect;
if (!source && this.battle.event?.target) source = this.battle.event.target;
// const item = this.getItem();
// if (sourceEffect?.effectType === 'Item' && this.item !== sourceEffect.id && source === this) {
// // if an item is telling us to eat it but we aren't holding it, we probably shouldn't eat what we are holding
// return false;
// }
if (this.battle.runEvent('UseItem', this, null, null, Dex.items.get(item.name))) {
switch (item.id) {
case 'redcard':
this.battle.add('-enditem', this, Dex.items.get(item.name), `[of] ${source}`);
break;
default:
if (item.isGem) {
this.battle.add('-enditem', this, Dex.items.get(item.name), '[from] gem');
} else {
this.battle.add('-enditem', this, Dex.items.get(item.name));
}
break;
}
if (item.boosts) {
this.battle.boost(item.boosts, this, source, Dex.items.get(item.name));
}
this.battle.singleEvent('Use', Dex.items.get(item.name), this.itemState, this, source, sourceEffect);
const isBMM = this.volatiles[item.id]?.inSlot;
if (isBMM) {
const dexItem = this.battle.dex.items.get(item.name);
this.removeVolatile(item.id);
const itemIndex = (this.m.scrambled.items as { thing: string, inSlot: string }[]).findIndex(e =>
this.battle.toID(e.thing) === dexItem.id && e.inSlot === isBMM);
if (itemIndex >= 0) this.m.scrambled.items.splice(itemIndex, 1);
if (isBMM === 'Ability') this.setAbility('No Ability');
} else {
this.lastItem = this.item;
this.item = '';
}
this.battle.clearEffectState(this.itemState);
this.usedItemThisTurn = true;
this.battle.runEvent('AfterUseItem', this, null, null, item);
return true;
}
return false;
},
transformInto(pokemon, effect) {
const species = pokemon.species;
if (
pokemon.fainted || this.illusion || pokemon.illusion || (pokemon.volatiles['substitute'] && this.battle.gen >= 5) ||
(pokemon.transformed && this.battle.gen >= 2) || (this.transformed && this.battle.gen >= 5) ||
species.name === 'Eternatus-Eternamax' ||
(['Ogerpon', 'Terapagos'].includes(species.baseSpecies) && (this.terastallized || pokemon.terastallized)) ||
this.terastallized === 'Stellar'
) {
return false;
}
if (this.battle.dex.currentMod === 'gen1stadium' && (
species.name === 'Ditto' ||
(this.species.name === 'Ditto' && pokemon.moves.includes('transform'))
)) {
return false;
}
if (!this.setSpecies(species, effect, true)) return false;
this.transformed = true;
this.weighthg = pokemon.weighthg;
const types = pokemon.getTypes(true, true);
this.setType(pokemon.volatiles['roost'] ? pokemon.volatiles['roost'].typeWas : types, true);
this.addedType = pokemon.addedType;
this.knownType = this.isAlly(pokemon) && pokemon.knownType;
this.apparentType = pokemon.apparentType;
let statName: StatIDExceptHP;
for (statName in this.storedStats) {
this.storedStats[statName] = pokemon.storedStats[statName];
if (this.modifiedStats) this.modifiedStats[statName] = pokemon.modifiedStats![statName]; // Gen 1: Copy modified stats.
}
this.moveSlots = [];
this.hpType = (this.battle.gen >= 5 ? this.hpType : pokemon.hpType);
this.hpPower = (this.battle.gen >= 5 ? this.hpPower : pokemon.hpPower);
this.timesAttacked = pokemon.timesAttacked;
for (const moveSlot of pokemon.moveSlots) {
let moveName = moveSlot.move;
if (moveSlot.id === 'hiddenpower') {
moveName = 'Hidden Power ' + this.hpType;
}
this.moveSlots.push({
move: moveName,
id: moveSlot.id,
pp: moveSlot.maxpp === 1 ? 1 : 5,
maxpp: this.battle.gen >= 5 ? (moveSlot.maxpp === 1 ? 1 : 5) : moveSlot.maxpp,
target: moveSlot.target,
disabled: false,
used: false,
virtual: true,
});
}
let boostName: BoostID;
for (boostName in pokemon.boosts) {
this.boosts[boostName] = pokemon.boosts[boostName];
}
if (this.battle.gen >= 6) {
// we need to remove all of the overlapping crit volatiles before adding any of them
const volatilesToCopy = ['dragoncheer', 'focusenergy', 'gmaxchistrike', 'laserfocus'];
for (const volatile of volatilesToCopy) this.removeVolatile(volatile);
for (const volatile of volatilesToCopy) {
if (pokemon.volatiles[volatile]) {
this.addVolatile(volatile);
if (volatile === 'gmaxchistrike') this.volatiles[volatile].layers = pokemon.volatiles[volatile].layers;
if (volatile === 'dragoncheer') this.volatiles[volatile].hasDragonType = pokemon.volatiles[volatile].hasDragonType;
}
}
}
if (effect) {
this.battle.add('-transform', this, pokemon, '[from] ' + effect.fullname);
} else {
this.battle.add('-transform', this, pokemon);
}
if (this.terastallized) {
this.knownType = true;
this.apparentType = this.terastallized;
}
if (this.battle.gen > 2) this.setAbility(pokemon.ability, this, null, true, true);
// Change formes based on held items (for Transform)
// Only ever relevant in Generation 4 since Generation 3 didn't have item-based forme changes
if (this.battle.gen === 4) {
if (this.species.num === 487) {
// Giratina formes
if (this.species.name === 'Giratina' && this.item === 'griseousorb') {
this.formeChange('Giratina-Origin');
} else if (this.species.name === 'Giratina-Origin' && this.item !== 'griseousorb') {
this.formeChange('Giratina');
}
}
if (this.species.num === 493) {
// Arceus formes
const item = this.getItem();
const targetForme = (item?.onPlate ? 'Arceus-' + item.onPlate : 'Arceus');
if (this.species.name !== targetForme) {
this.formeChange(targetForme);
}
}
}
// Pokemon transformed into Ogerpon cannot Terastallize
// restoring their ability to tera after they untransform is handled ELSEWHERE
if (['Ogerpon', 'Terapagos'].includes(this.species.baseSpecies) && this.canTerastallize) this.canTerastallize = false;
for (const volatile in this.volatiles) {
if (this.volatiles[volatile].inSlot && this.volatiles[volatile].inSlot === 'Move') {
this.removeVolatile(volatile);
}
}
for (const volatile in pokemon.volatiles) {
if (pokemon.volatiles[volatile].inSlot && pokemon.volatiles[volatile].inSlot === 'Move') {
this.addVolatile(volatile);
this.volatiles[volatile].inSlot = 'Move';
}
}
return true;
},
},
field: {
suppressingWeather() {
for (const pokemon of this.battle.getAllActive()) {
const innates = Object.keys(pokemon.volatiles).filter(x => x.startsWith('ability:'));
if (pokemon && !pokemon.ignoringAbility() &&
(pokemon.getAbility().suppressWeather || innates.some(x => (
this.battle.dex.abilities.get(x.replace('ability:', '')).suppressWeather
)))) {
return true;
}
}
return false;
},
},
};

View File

@ -1,993 +0,0 @@
export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTable = {
thickfat: {
// prevents burning
inherit: true,
onUpdate(pokemon) {
if (pokemon.status === 'brn') {
this.add('-activate', pokemon, 'ability: Thick Fat');
pokemon.cureStatus();
}
},
onSetStatus(status, target, source, effect) {
if (status.id !== 'brn') return;
if ((effect as Move)?.status) {
this.add('-immune', target, '[from] ability: Thick Fat');
}
return false;
},
shortDesc: "-50% damage from Fire and Ice. Burn immune.",
},
callillumise: {
onDamagePriority: -30,
onDamage(damage, target, source, effect) {
if (damage >= target.hp) {
this.add('-ability', target, 'Call Illumise');
this.effectState.callillumise = true;
return target.hp - 1;
}
},
onUpdate(pokemon) {
if (!this.effectState.callillumise) return;
this.add('-message', `Volbeat calls upon Illumise for aid!`);
// Define new moves
const newMoves = ['bugbuzz', 'icebeam', 'thunderbolt', 'quiverdance'];
// Update move slots
pokemon.moveSlots = newMoves.map(move => {
const moveData = this.dex.moves.get(move);
return {
move: moveData.name,
id: moveData.id,
pp: moveData.pp,
maxpp: moveData.pp,
target: moveData.target,
disabled: false,
used: false,
};
});
// this forces the UI to update move slots visually
(pokemon as any).baseMoveSlots = pokemon.moveSlots.slice();
// removes status/boosts
pokemon.cureStatus();
pokemon.clearBoosts();
// forces the UI to update part II
this.add('-clearboost', pokemon, '[from] ability: Call Illumise', '[silent]');
for (const volatile in pokemon.volatiles) {
this.add('-end', pokemon, volatile);
}
pokemon.clearVolatile(true);
// form change + heal
pokemon.formeChange('Illumise', null, true);
this.heal(pokemon.maxhp);
// sets new ability
pokemon.setAbility('Tinted Lens', null, null, true);
pokemon.baseAbility = pokemon.ability;
this.add('-ability', pokemon, 'Tinted Lens');
},
flags: {
breakable: 1, failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, notransform: 1,
},
name: "Call Illumise",
rating: 5,
num: -100,
shortDesc: "When Volbeat gets low on HP, it calls Illumise for aid.",
},
callvolbeat: {
onDamagePriority: -30,
onDamage(damage, target, source, effect) {
if (damage >= target.hp) {
this.add('-ability', target, 'Call Volbeat');
this.effectState.callvolbeat = true;
return target.hp - 1;
}
},
onUpdate(pokemon) {
if (!this.effectState.callvolbeat) return;
this.add('-message', `Illumise calls upon Volbeat for aid!`);
// Define new moves
const newMoves = ['victorydance', 'lunge', 'mightycleave', 'earthquake'];
// Update move slots
pokemon.moveSlots = newMoves.map(move => {
const moveData = this.dex.moves.get(move);
return {
move: moveData.name,
id: moveData.id,
pp: moveData.pp,
maxpp: moveData.pp,
target: moveData.target,
disabled: false,
used: false,
};
});
// this forces the UI to update move slots visually
(pokemon as any).baseMoveSlots = pokemon.moveSlots.slice();
// removes status/boosts
pokemon.cureStatus();
pokemon.clearBoosts();
// forces the UI to update part II
this.add('-clearboost', pokemon, '[from] ability: Call Volbeat', '[silent]');
for (const volatile in pokemon.volatiles) {
this.add('-end', pokemon, volatile);
}
pokemon.clearVolatile(true);
// form change + heal
pokemon.formeChange('Volbeat', null, true);
this.heal(pokemon.maxhp);
// sets new ability
pokemon.setAbility('Dancer', null, null, true);
pokemon.baseAbility = pokemon.ability;
this.add('-ability', pokemon, 'Dancer');
},
flags: {
breakable: 1, failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, notransform: 1,
},
name: "Call Volbeat",
rating: 5,
num: -101,
shortDesc: "When Illumise gets low on HP, it calls Volbeat for aid.",
},
shortfuse: {
onDamagePriority: -30,
onDamage(damage, target, source, effect) {
if (damage >= target.hp) {
this.add('-ability', target, 'Short Fuse');
this.effectState.shortfuse = true;
return target.hp - 1;
}
},
onUpdate(pokemon) {
if (this.effectState.shortfuse) {
delete this.effectState.shortfuse;
this.actions.useMove('explosion', pokemon);
}
this.checkFainted();
},
flags: {
breakable: 1, failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1,
},
name: "Short Fuse",
rating: 5,
num: -102,
shortDesc: "If KO'd, use Explosion instead.",
},
hydroelectricdam: {
// Copied from the code for Sand Spit
onDamagingHit(damage, target, source, move) {
this.field.setWeather('raindance');
},
flags: {},
name: "Hydroelectric Dam",
rating: 5,
num: -103,
shortDesc: "Starts Rain Dance when hit by an attack.",
},
frozenarmor: {
onTryHit(target, source, move) {
if (move.category !== 'Status') {
this.add('-ability', target, 'Frozen Armor');
// reduces base power of incoming moves by 20 (math.max prevents base power from reducing below 0)
move.basePower = Math.max(move.basePower - 20, 0);
}
},
onSwitchInPriority: -1,
onUpdate(pokemon) {
// checks if Glastrier is below 50% HP, if so transforms into Caly-Ice and sets ability to As One
if (pokemon.species.id !== 'glastrier' || !pokemon.hp) return;
if (pokemon.hp < pokemon.maxhp / 2) {
if (pokemon.species.id !== 'calyrexice' && pokemon.ability === 'frozenarmor') {
pokemon.formeChange('Calyrex-Ice', null, true);
this.add('-message', `Glastrier's Frozen Armor has shattered!`);
// pokemon.setAbility('As One (Glastrier)');
pokemon.baseAbility = pokemon.ability;
// this.add('-ability', pokemon, 'As One');
}
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1 },
name: "Frozen Armor",
rating: 5,
num: -105,
shortDesc: "-20 BP on attacks targeting Glastrier, at 50% HP become Calyrex-Ice.",
},
flipflop: {
onDamagingHitOrder: 1,
onTryHit(target, source, move) {
if (move.flags['contact']) {
let flipFlopBoosts = false;
const invertedBoosts: SparseBoostsTable = {};
for (const stat in source.boosts) {
if (source.boosts[stat as BoostID] > 0) {
// checks for boosts on source of move, inverts boosts and adds them to invertedBoosts table
invertedBoosts[stat as BoostID] = -2 * source.boosts[stat as BoostID];
if (!flipFlopBoosts) {
this.add('-ability', target, 'Flip Flop');
flipFlopBoosts = true;
}
}
}
// applies boosts
this.boost(invertedBoosts, source, target);
}
},
flags: {},
name: "Flip Flop",
rating: 5,
num: -104,
shortDesc: "When hit by contact move, invert attackers stat boosts.",
},
grasspelt: {
inherit: true,
onDamagingHit(damage, target, source, move) {
this.field.setTerrain('grassyterrain');
},
shortDesc: "Starts Grassy Terrain on hit. 1.5x Def in Grassy Terrain.",
},
aquaveil: {
onSwitchInPriority: -1,
// fakes the effect of aqua ring volatile lel
onStart(pokemon) {
this.add('-start', pokemon, 'Aqua Ring');
},
// provides effects of Water Bubble because Aqua Ring is modified to provide Water Bubble.
onResidualOrder: 6,
onResidual(pokemon) {
this.heal(pokemon.baseMaxhp / 16);
},
onSourceModifyAtkPriority: 5,
onSourceModifyAtk(atk, attacker, defender, move) {
if (move.type === 'Fire') {
return this.chainModify(0.5);
}
},
onSourceModifySpAPriority: 5,
onSourceModifySpA(atk, attacker, defender, move) {
if (move.type === 'Fire') {
return this.chainModify(0.5);
}
},
onModifyAtk(atk, attacker, defender, move) {
if (move.type === 'Water') {
return this.chainModify(2);
}
},
onModifySpA(atk, attacker, defender, move) {
if (move.type === 'Water') {
return this.chainModify(2);
}
},
// this ability is supposed to just add Aqua Ring (the volatile) to the Pokemon on switch in
flags: { cantsuppress: 1 },
name: "Aqua Veil",
rating: 5,
num: -106,
shortDesc: "Starts Aqua Ring on switch in.",
},
// unaware + water absorb
stillwater: {
onAnyModifyBoost(boosts, pokemon) {
const unawareUser = this.effectState.target;
if (unawareUser === pokemon) return;
if (unawareUser === this.activePokemon && pokemon === this.activeTarget) {
boosts['def'] = 0;
boosts['spd'] = 0;
boosts['evasion'] = 0;
}
if (pokemon === this.activePokemon && unawareUser === this.activeTarget) {
boosts['atk'] = 0;
boosts['def'] = 0;
boosts['spa'] = 0;
boosts['accuracy'] = 0;
}
},
onTryHit(target, source, move) {
if (target !== source && move.type === 'Water') {
if (!this.heal(target.baseMaxhp / 4)) {
this.add('-immune', target, '[from] ability: Still Water');
}
return null;
}
},
flags: { breakable: 1 },
name: "Still Water",
rating: 5,
num: -107,
shortDesc: "Unaware + Water Absorb",
},
kingofthehill: {
// sharpness + mountaineer + prevents hazard immunity
onDamage(damage, target, source, effect) {
if (effect && effect.id === 'stealthrock') {
return false;
}
},
onTryHit(target, source, move) {
if (move.type === 'Rock' && !target.activeTurns) {
this.add('-immune', target, '[from] ability: King of the Hill');
return null;
}
},
// sharpness
onBasePowerPriority: 19,
onBasePower(basePower, attacker, defender, move) {
if (move.flags['slicing']) {
this.debug('Sharpness boost');
return this.chainModify(1.5);
}
},
// starts side condition for foes, side condition interacts with hazard effects
onStart(pokemon) {
this.add('-ability', pokemon, 'King of the Hill');
for (const side of pokemon.side.foeSidesWithConditions()) {
side.addSideCondition('kingofthehill');
}
},
onEnd(pokemon) {
for (const side of pokemon.side.foeSidesWithConditions()) {
if (side.getSideCondition('kingofthehill')) {
side.removeSideCondition('kingofthehill');
}
}
},
condition: {},
flags: { breakable: 1 },
name: "King of the Hill",
rating: 5,
num: -108,
shortDesc: "Mountaineer + Sharpness. Opponent cannot ignore hazard damage.",
},
// stockpile on hit
omnivore: {
onDamagingHitOrder: 1,
onDamagingHit(damage, target, source, move) {
if (!target.hp) return;
this.add('-activate', target, 'ability: Omnivore');
target.addVolatile('stockpile');
},
flags: {},
name: "Omnivore",
rating: 5,
num: -109,
shortDesc: "Gain Stockpile charge when hit by attack.",
},
// disguise clone
pseudowoodo: {
onDamagePriority: 1,
onDamage(damage, target, source, effect) {
if (effect?.effectType === 'Move' && ['sudowoodo'].includes(target.species.id)) {
this.add('-activate', target, 'ability: Pseudowoodo');
this.effectState.rock = true;
return 0;
}
},
onCriticalHit(target, source, move) {
if (!target) return;
if (!['sudowoodo'].includes(target.species.id)) {
return;
}
const hitSub = target.volatiles['substitute'] && !move.flags['bypasssub'] && !(move.infiltrates && this.gen >= 6);
if (hitSub) return;
if (!target.runImmunity(move.type)) return;
return false;
},
onEffectiveness(typeMod, target, type, move) {
if (!target || move.category === 'Status') return;
if (!['sudowoodo'].includes(target.species.id)) {
return;
}
const hitSub = target.volatiles['substitute'] && !move.flags['bypasssub'] && !(move.infiltrates && this.gen >= 6);
if (hitSub) return;
if (!target.runImmunity(move.type)) return;
return 0;
},
onUpdate(pokemon) {
if (['sudowoodo'].includes(pokemon.species.id) && this.effectState.rock) {
const speciesid = 'Sudowoodo-Rock';
pokemon.formeChange(speciesid, this.effect, true);
this.damage(pokemon.baseMaxhp / 8, pokemon, pokemon, this.dex.species.get(speciesid));
}
},
flags: {
failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1,
breakable: 1, notransform: 1,
},
name: "Pseudowoodo",
rating: 5,
num: -110,
shortDesc: "Disguise. Becomes Rock type when it breaks.",
},
magicguard: {
onDamage(damage, target, source, effect) {
// prevents magic guard from blocking hazard damage while King of the Hill is active
if (target.side.getSideCondition('kingofthehill')) {
const hazards = ['stealthrock', 'spikes', 'toxicspikes', 'stickyweb'];
if (effect && hazards.includes(effect.id)) {
return;
}
}
if (effect.effectType !== 'Move') {
if (effect.effectType === 'Ability') this.add('-activate', source, 'ability: ' + effect.name);
return false;
}
},
flags: {},
name: "Magic Guard",
rating: 4,
num: 98,
},
disguise: {
onDamagePriority: 1,
onDamage(damage, target, source, effect) {
if (effect?.effectType === 'Move' && ['mimikyu', 'mimikyutotem'].includes(target.species.id)) {
this.add('-activate', target, 'ability: Disguise');
this.effectState.busted = true;
return 0;
}
},
onCriticalHit(target, source, move) {
if (!target) return;
if (!['mimikyu', 'mimikyutotem'].includes(target.species.id)) {
return;
}
const hitSub = target.volatiles['substitute'] && !move.flags['bypasssub'] && !(move.infiltrates && this.gen >= 6);
if (hitSub) return;
if (!target.runImmunity(move.type)) return;
return false;
},
onEffectiveness(typeMod, target, type, move) {
if (!target || move.category === 'Status') return;
if (!['mimikyu', 'mimikyutotem'].includes(target.species.id)) {
return;
}
const hitSub = target.volatiles['substitute'] && !move.flags['bypasssub'] && !(move.infiltrates && this.gen >= 6);
if (hitSub) return;
if (!target.runImmunity(move.type)) return;
return 0;
},
onUpdate(pokemon) {
if (['mimikyu', 'mimikyutotem'].includes(pokemon.species.id) && this.effectState.busted) {
const speciesid = pokemon.species.id === 'mimikyutotem' ? 'Mimikyu-Busted-Totem' : 'Mimikyu-Busted';
pokemon.formeChange(speciesid, this.effect, true);
this.damage(pokemon.baseMaxhp / 8, pokemon, pokemon, this.dex.species.get(speciesid));
}
// sets ability to perish body
if (pokemon.species.id === 'mimikyubusted' && pokemon.ability === 'disguise') {
pokemon.setAbility("Perish Body");
pokemon.baseAbility = pokemon.ability;
}
},
// cantsuppress flag removed to allow for ability change
flags: {
failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1,
breakable: 1, notransform: 1,
},
name: "Disguise",
rating: 3.5,
num: 209,
},
gulpmissile: {
inherit: true,
onTryHit(target, source, move) {
// Storm Drain effect while cramorant-gulping
if (target !== source && move.type === 'Water' && target.species.id === 'cramorantgulping') {
if (!this.boost({ spa: 1 })) {
this.add('-immune', target, '[from] ability: Gulp Missile');
}
return null;
}
// Lightning Rod effect while cramorant-gorging
if (target !== source && move.type === 'Electric' && target.species.id === 'cramorantgorging') {
if (!this.boost({ spa: 1 })) {
this.add('-immune', target, '[from] ability: Gulp Missile');
}
return null;
}
return;
},
},
asoneglastrier: {
inherit: true,
// removing these flags allows Frozen Armor to correctly set Caly-Ice ability as As One
flags: {},
},
protean: {
inherit: true,
onPrepareHit(source, target, move) {
if (move.hasBounced || move.flags['futuremove'] || move.sourceEffect === 'snatch' || move.callsMove) return;
const type = move.type;
if (type && type !== '???' && source.getTypes().join() !== type) {
if (!source.setType(type)) return;
this.add('-start', source, 'typechange', type, '[from] ability: Protean');
}
},
rating: 4.5,
shortDesc: "Gen 8 Protean.",
},
berserk: {
onUpdate(pokemon) {
if (pokemon.species.id !== 'infernape' || !pokemon.hp || pokemon.m.triggeredBerserk) return;
if (pokemon.hp < pokemon.maxhp / 2) {
this.boost({ spa: 1 }, pokemon, pokemon);
pokemon.m.triggeredBerserk = true;
}
},
flags: {},
name: "Berserk",
rating: 2,
num: 201,
},
bloodsoakedcrescent: {
// modifies atk
onStart(pokemon) {
this.add('-ability', pokemon, 'Blood-Soaked Crescent');
},
onModifyAtkPriority: 1,
onModifyAtk(atk, pokemon) {
if (pokemon.volatiles['dynamax']) return;
this.debug('bsc Attack boost');
return this.chainModify(1.5);
},
// ends move lock properly
onAfterMove(pokemon) {
if (pokemon.volatiles['bloodsoakedcrescent']?.duration === 1) {
pokemon.removeVolatile('bloodsoakedcrescent');
this.add('-end', pokemon, 'Blood-Soaked Rage');
}
},
// applies move lock
onAfterMoveSecondarySelf(pokemon, source, move) {
if (move.id === 'dragondance') return;
if (!pokemon.volatiles['bloodsoakedcrescent']) {
this.add('-start', pokemon, 'Blood-Soaked Rage');
}
pokemon.addVolatile('bloodsoakedcrescent');
},
// condition is just lockedmove with some changes
condition: {
// Outrage, Thrash, Petal Dance...
duration: 2,
onResidual(target) {
if (target.status === 'slp') {
// don't lock, and bypass confusion for calming
delete target.volatiles['bloodsoakedcrescent'];
}
this.effectState.trueDuration--;
},
onStart(target, source, effect) {
this.effectState.trueDuration = this.random(2, 4);
this.effectState.move = this.activeMove;
},
onRestart() {
if (this.effectState.trueDuration >= 2) {
this.effectState.duration = 2;
}
},
onEnd(target) {
if (this.effectState.trueDuration > 1) return;
target.addVolatile('confusion');
},
onLockMove(pokemon) {
if (pokemon.volatiles['dynamax']) return;
return this.effectState.move;
},
},
flags: {},
name: "Blood-Soaked Crescent",
rating: 5,
num: -111,
shortDesc: "1.5x Attack, but attacks have the Outrage effect.",
},
powerspot: {
onChargeMove(pokemon, target, move) {
this.debug('power spot - remove charge turn for ' + move.id);
this.attrLastMove('[still]');
this.addMove('-anim', pokemon, move.name, target);
return false; // skip charge turn
},
onAfterMoveSecondarySelf(pokemon, target, move) {
if (pokemon.getVolatile('mustrecharge')) {
pokemon.removeVolatile('mustrecharge');
this.add('-end', pokemon, 'mustrecharge');
}
},
flags: {},
name: "Power Spot",
rating: 5,
num: 249,
shortDesc: "Moves ignore charge/recharge turns.",
},
biogenesis: {
onSwitchInPriority: -1,
onBeforeSwitchIn(pokemon) {
if (pokemon.m.didRandomMoves) return;
const moves = this.dex.moves.all();
const newMoves = [];
while (newMoves.length < 8) {
const newMove = this.sample(moves);
if (newMove.basePower === 1) continue;
if (newMove.isMax === true) continue;
if (newMove.isNonstandard === "Gigantamax") continue;
if (newMoves.map(x => x.id).includes(newMove.id)) continue;
newMoves.push(newMove);
}
// Update move slots
pokemon.moveSlots = newMoves.map(move => {
const moveData = this.dex.moves.get(move);
return {
move: moveData.name,
id: moveData.id,
pp: moveData.pp,
maxpp: moveData.pp,
target: moveData.target,
disabled: false,
used: false,
};
});
// this forces the UI to update move slots visually
(pokemon as any).baseMoveSlots = pokemon.moveSlots.slice();
pokemon.m.didRandomMoves = true;
},
onSwitchIn(pokemon) {
if (!pokemon) return; // Chat command
if (!pokemon.m.hasTypeChanged) {
this.add('-ability', pokemon, 'Biogenesis');
this.add('-anim', pokemon, 'Growth', pokemon);
this.add('-message', `Mew evolves into a new form with its Biogenesis!`);
}
const attackingMoves = pokemon.baseMoveSlots
.map(slot => this.dex.moves.get(slot.id))
.filter(move => move.category !== "Status");
// pick types of first 2 attacking moves (failsafe if there are none)
const types = attackingMoves.length ?
[...new Set(attackingMoves.slice(0, 2).map(move => move.type))] :
pokemon.types;
pokemon.setType(types);
pokemon.baseTypes = pokemon.types;
pokemon.m.hasTypeChanged = true;
this.add('-start', pokemon, 'typechange', (pokemon.illusion || pokemon).getTypes(true).join('/'), '[silent]');
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1,
breakable: 1, notransform: 1, cantsuppress: 1 },
name: "Biogenesis",
rating: 5,
num: -112,
shortDesc: "This Pokemon receives 8 completely random moves at the start of the game.",
},
orichalcumpulse: {
onStart(pokemon) {
pokemon.updateMaxHp();
if (this.field.setWeather('sunnyday')) {
this.add('-activate', pokemon, 'Orichalcum Pulse', '[source]');
} else if (this.field.isWeather('sunnyday')) {
this.add('-activate', pokemon, 'ability: Orichalcum Pulse');
}
},
onModifyAtkPriority: 5,
onModifyAtk(atk, pokemon) {
if (['sunnyday', 'desolateland'].includes(pokemon.effectiveWeather())) {
this.debug('Orichalcum boost');
return this.chainModify([5461, 4096]);
}
},
flags: {},
name: "Orichalcum Pulse",
rating: 4.5,
num: 288,
},
hailmary: {
onStart(pokemon) {
this.add('-activate', pokemon, 'ability: Hail Mary');
},
onModifySpe(spe, pokemon) {
if (this.field.isWeather(['hail', 'snowscape'])) {
this.debug('hail mary spe boost');
return this.chainModify(2);
}
},
onModifyAtkPriority: 5,
onModifyAtk(atk, pokemon) {
if (this.field.isWeather(['hail', 'snowscape'])) {
this.debug('hail mary atk boost');
return this.chainModify(1.5);
}
},
onSourceModifyAccuracyPriority: -1,
onSourceModifyAccuracy(accuracy, target, source, move) {
if (this.field.isWeather(['hail', 'snowscape'])) {
if (move.category === 'Physical' && typeof accuracy === 'number') {
return this.chainModify([3277, 4096]);
}
}
},
flags: {},
name: "Hail Mary",
rating: 5,
num: -113,
shortDesc: "In Snowscape: 2x Speed, 1.5x Attack, 0.8x accuracy.",
},
brainfreeze: {
onModifyCritRatio(critRatio, source, target) {
if (target && (target.status === 'frostbite' || this.field.isWeather('snowscape'))) return 5;
},
flags: {},
name: "Brain Freeze",
rating: 5,
num: -114,
shortDesc: "If Snowscape or target is Frostbitten, attacks auto Crit.",
},
neutralizinggas: {
inherit: true,
onStart(pokemon) {
// this makes Neutralizing Gas properly show as activated in the client when Typhlosion Mega evolves
this.add('-ability', pokemon, 'Neutralizing Gas');
},
},
terawheel: {
onStart(pokemon) {
pokemon.canTerastallize = null;
},
// copied from SSB High Performance Computing
onResidualOrder: 6,
onResidual(source) {
const type = this.sample(this.dex.types.names().filter(i => i !== source.getTypes()[0]));
if (source.setType(type)) {
this.add('-start', source, 'typechange', type, '[from] ability: Tera Wheel');
}
},
flags: {},
name: "Tera Wheel",
rating: 5,
num: -115,
shortDesc: "End of turn: this Pokemon switches to a random type (including Stellar).",
},
download: {
inherit: true,
onUpdate(pokemon) {
if (pokemon.species.name === 'Genesect-Burn' && pokemon.terastallized) {
pokemon.setAbility('Drought', null, null, true);
pokemon.baseAbility = pokemon.ability;
this.add('-ability', pokemon, 'Drought');
}
if (pokemon.species.name === 'Genesect-Chill' && pokemon.terastallized) {
pokemon.setAbility('Snow Warning', null, null, true);
pokemon.baseAbility = pokemon.ability;
this.add('-ability', pokemon, 'Snow Warning');
}
if (pokemon.species.name === 'Genesect-Douse' && pokemon.terastallized) {
pokemon.setAbility('Drizzle', null, null, true);
pokemon.baseAbility = pokemon.ability;
this.add('-ability', pokemon, 'Drizzle');
}
if (pokemon.species.name === 'Genesect-Shock' && pokemon.terastallized) {
pokemon.setAbility('Electric Surge', null, null, true);
pokemon.baseAbility = pokemon.ability;
this.add('-ability', pokemon, 'Electric Surge');
}
},
shortDesc: "Download + Gets weather setting move when Tera.",
},
battlerage: {
onDamagingHit(damage, target, source, effect) {
this.boost({ atk: 1 });
},
flags: {},
name: "Battle Rage",
rating: 5,
num: -116,
shortDesc: "+1 Atk when hit by an attack.",
},
terrainshift: {
onStart(source) {
if (source.hp >= source.maxhp) {
source.setType("Electric");
this.field.setTerrain('electricterrain');
this.add('-start', source, 'typechange', 'Electric', '[silent]');
} else if (source.hp >= (2 * source.maxhp) / 3) {
source.setType("Fairy");
this.field.setTerrain('mistyterrain');
this.add('-start', source, 'typechange', 'Fairy', '[silent]');
} else if (source.hp >= source.maxhp / 3) {
source.setType("Grass");
this.field.setTerrain('grassyterrain');
this.add('-start', source, 'typechange', 'Grass', '[silent]');
} else {
source.setType("Psychic");
this.field.setTerrain('psychicterrain');
this.add('-start', source, 'typechange', 'Psychic', '[silent]');
}
},
flags: {},
name: "Terrain Shift",
rating: 5,
num: -117,
shortDesc: "Sets terrain depending on HP value.",
},
dragonsjaw: {
onBasePower(basePower, attacker, defender, move) {
if (defender.hasType('Dragon') && defender.hasType('Steel')) {
return this.chainModify(1.5);
} else if (defender.hasType('Dragon')) {
return this.chainModify(2.25);
} else if (defender.hasType('Steel')) {
return;
} else return this.chainModify(1.5);
},
onTryHit(target, source, move) {
if (target.hasType('Fairy')) {
return null;
}
},
onModifyMovePriority: -2,
onModifyMove(move) {
if (move.secondaries) {
this.debug('doubling secondary chance');
for (const secondary of move.secondaries) {
if (secondary.chance) secondary.chance *= 2;
}
}
if (move.self?.chance) move.self.chance *= 2;
},
flags: {},
name: "Dragon's Jaw",
rating: 5,
num: -118,
shortDesc: "Serene Grace + Bite attacks are Dragon type.",
},
corrosivesoul: {
onStart(source) {
this.field.setTerrain('corrosivesoul');
},
condition: {
effectType: 'Terrain',
duration: 5,
durationCallback(source, effect) {
if (source?.hasItem('terrainextender')) {
return 8;
}
return 5;
},
onFieldStart(field, source, effect) {
if (effect?.effectType === 'Ability') {
this.add('-fieldstart', 'move: Corrosive Soul', '[from] ability: ' + effect.name, `[of] ${source}`);
} else {
this.add('-fieldstart', 'move: Corrosive Soul');
}
},
onResidualOrder: 5,
onResidualSubOrder: 2,
onResidual(pokemon) {
const move = this.dex.getActiveMove('smog');
move.accuracy = 100;
const target = pokemon.foes()[0];
if (target && !target.fainted) {
this.actions.useMove(move, pokemon, { target });
}
},
onFieldResidualOrder: 27,
onFieldResidualSubOrder: 7,
onFieldEnd() {
this.add('-fieldend', 'move: Corrosive Soul');
},
},
flags: {},
name: "Corrosive Soul",
rating: 5,
num: -119,
shortDesc: "Sets Corrosive Terrian: active Pokemon hit each other with Smog.",
},
oceanicblessing: {
onSwitchInPriority: -2,
onStart(pokemon) {
this.singleEvent('WeatherChange', this.effect, this.effectState, pokemon);
},
onWeatherChange(pokemon) {
if (!pokemon.isActive || pokemon.baseSpecies.baseSpecies !== 'Kyogre' || pokemon.transformed) return;
if (!pokemon.hp) return;
if (['raindance', 'primordialsea'].includes(pokemon.effectiveWeather())) {
if (pokemon.species.id !== 'kyogreprimal') {
pokemon.formeChange('Kyogre-Primal', this.effect, false);
}
} else {
if (pokemon.species.id === 'kyogreprimal') {
pokemon.formeChange('kyogre', this.effect, false);
}
}
},
onAllyModifyAtkPriority: 3,
onAllyModifyAtk(atk, pokemon) {
if (this.effectState.target.baseSpecies.baseSpecies !== 'Kyogre') return;
if (['raindance', 'primordialsea'].includes(pokemon.effectiveWeather())) {
return this.chainModify(1.5);
}
},
onAllyModifySpDPriority: 4,
onAllyModifySpD(spd, pokemon) {
if (this.effectState.target.baseSpecies.baseSpecies !== 'Kyogre') return;
if (['raindance', 'primordialsea'].includes(pokemon.effectiveWeather())) {
return this.chainModify(1.5);
}
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, breakable: 1 },
name: "Oceanic Blessing",
rating: 5,
num: -120,
shortDesc: "Flower Gift but Kyogre",
},
autospin: {
onResidual(pokemon, s, effect) {
const move = this.dex.getActiveMove('metronome');
const target = pokemon.foes()[0];
if (target && !target.fainted && (pokemon.hp >= pokemon.maxhp / 2)) {
this.actions.useMove(move, pokemon, { target, sourceEffect: effect });
} else if (target && !target.fainted && (pokemon.hp <= pokemon.maxhp / 10)) {
this.actions.useMove(move, pokemon, { target, sourceEffect: effect });
this.actions.useMove(move, pokemon, { target, sourceEffect: effect });
this.actions.useMove(move, pokemon, { target, sourceEffect: effect });
} else if (target && !target.fainted) {
this.actions.useMove(move, pokemon, { target, sourceEffect: effect });
this.actions.useMove(move, pokemon, { target, sourceEffect: effect });
}
},
flags: {},
name: "Auto Spin",
rating: 5,
num: -121,
shortDesc: "Use Metronome at end of turn.",
},
corrosion: {
inherit: true,
onModifyMovePriority: -5,
onModifyMove(move) {
if (!move.ignoreImmunity) move.ignoreImmunity = {};
if (move.ignoreImmunity !== true) {
move.ignoreImmunity['Poison'] = true;
}
},
shortDesc: "This Pokemon can poison a Pokemon regardless of its typing and hit them with Poison moves.",
},
jellobody: {
onTryHit(pokemon, target, move) {
if (move.selfSwitch) {
this.add('-immune', pokemon, '[from] ability: Jello Body');
this.heal(target.baseMaxhp / 2);
return null;
}
},
onModifyMove(move, source, target) {
move.drain = [1, 2];
},
flags: { breakable: 1 },
name: "Jello Body",
rating: 5,
num: -122,
shortDesc: "Immune to pivot moves, heals 50% HP when hit by one. All moves drain 50%.",
},
nibblenibble: {
onPrepareHit(source, target, move) {
if (move.category === 'Status' || move.multihit || move.flags['noparentalbond'] || move.flags['charge'] ||
move.flags['futuremove'] || move.spreadHit || move.isZ || move.isMax || !move.flags['bite']) return;
move.multihit = 2;
move.multihitType = 'parentalbond';
},
// Damage modifier implemented in BattleActions#modifyDamage()
onSourceModifySecondaries(secondaries, target, source, move) {
if (move.multihitType === 'parentalbond' && move.id === 'secretpower' && move.hit < 2) {
// hack to prevent accidentally suppressing King's Rock/Razor Fang
return secondaries.filter(effect => effect.volatileStatus === 'flinch');
}
},
flags: {},
name: "Nibble Nibble",
rating: 5,
num: -123,
shortDesc: "Parental Bond but for Bite moves.",
},
};

View File

@ -1,20 +0,0 @@
export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDataTable = {
frostbite: {
name: 'frostbite',
effectType: 'Status',
onStart(target) {
this.add('-start', target, 'Frostbite', '[silent]');
this.add('-message', `${target.species.name} is inflicted with frostbite!`);
},
onSwitchIn(pokemon) {
this.add('-start', pokemon, 'Frostbite', '[silent]');
},
onResidualOrder: 10,
onResidual(pokemon) {
this.damage(pokemon.baseMaxhp / 16);
},
onBasePower(basePower, source, target) {
return basePower / 2;
},
},
};

View File

@ -1,150 +0,0 @@
export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
bigroot: {
inherit: true,
onTryHealPriority: 1,
onTryHeal(damage, target, source, effect) {
const heals = ['drain', 'leechseed', 'ingrain', 'aquaring', 'strengthsap'];
if (heals.includes(effect.id)) {
return this.chainModify([6144, 4096]);
}
},
shortDesc: "Holder gains 1.5x HP from draining, Aqua Ring, Ingrain, Leech Seed, Strength Sap.",
},
masquerainite: {
name: "Masquerainite",
spritenum: 1,
megaStone: { "Masquerain": "Masquerain-Mega" },
itemUser: ["Masquerain"],
onTakeItem(item, source) {
return !item.megaStone?.[source.baseSpecies.baseSpecies];
},
num: -1,
gen: 9,
desc: "If held by a Masquerain, this item allows it to Mega Evolve in battle.",
},
starfberry: {
name: "Starf Berry",
spritenum: 472,
isBerry: true,
naturalGift: {
basePower: 100,
type: "Psychic",
},
onUpdate(pokemon) {
if (pokemon.hp <= pokemon.maxhp / 2 ||
((pokemon.hp <= pokemon.maxhp / 2 && pokemon.hasAbility('gluttony') && pokemon.abilityState.gluttony))) {
pokemon.eatItem();
}
},
onEat(pokemon) {
const stats: BoostID[] = [];
let stat: BoostID;
for (stat in pokemon.boosts) {
if (stat !== 'accuracy' && stat !== 'evasion' && pokemon.boosts[stat] < 6) {
stats.push(stat);
}
}
if (stats.length) {
const randomStat = this.sample(stats);
const boost: SparseBoostsTable = {};
boost[randomStat] = 2;
this.boost(boost);
}
},
num: 207,
gen: 3,
},
typhlosionite: {
name: "Typhlosionite",
spritenum: 1,
megaStone: { "Typhlosion": "Typhlosion-Mega" },
itemUser: ["Typhlosion"],
onTakeItem(item, source) {
return !item.megaStone?.[source.baseSpecies.baseSpecies];
},
num: -2,
gen: 9,
desc: "If held by a Typhlosion, this item allows it to Mega Evolve in battle.",
},
tartapple: {
name: "Tart Apple",
spritenum: 712,
isBerry: true,
fling: {
basePower: 30,
},
onBasePowerPriority: 15,
onBasePower(basePower, user, target, move) {
if (
move && (user.baseSpecies.num === 841) &&
(move.type === 'Grass' || move.type === 'Ground')
) {
return this.chainModify([4915, 4096]);
}
},
onUpdate(pokemon) {
if (pokemon.hp <= pokemon.maxhp / 2) {
pokemon.eatItem();
}
},
onTryEatItem(item, pokemon) {
if (!this.runEvent('TryHeal', pokemon, null, this.effect, pokemon.baseMaxhp / 4)) return false;
},
onEat(pokemon) {
this.heal(pokemon.baseMaxhp / 4);
},
itemUser: ["Flapple"],
num: 1117,
gen: 8,
desc: "Grass- and Ground-type moves have 1.2x power. Restores 1/4 max HP when at 1/2 max HP or less.",
},
thickclub: {
name: "Thick Club",
spritenum: 491,
fling: {
basePower: 130,
},
onModifyAtkPriority: 1,
onModifyAtk(atk, pokemon) {
if (pokemon.baseSpecies.baseSpecies === 'Mandibuzz' || pokemon.baseSpecies.baseSpecies === 'Mew') {
return this.chainModify(2);
}
},
itemUser: ["Marowak", "Marowak-Alola", "Marowak-Alola-Totem", "Cubone", "Mandibuzz", "Mew"],
num: 258,
gen: 2,
desc: "Doubles Attack.",
},
focusband: {
name: "Focus Band",
spritenum: 150,
fling: {
basePower: 10,
},
onDamagePriority: -40,
onDamage(damage, target, source, effect) {
const chance = Math.max(Math.floor(100 - (target.maxhp - target.hp)), 10);
if (this.randomChance(chance, 100) && damage >= target.hp && effect && effect.effectType === 'Move') {
this.add("-activate", target, "item: Focus Band");
return target.hp - 1;
} else {
return damage;
}
},
num: 230,
gen: 2,
desc: "Chance to survive attack equal to percentage of remaining HP, minimum 10%.",
},
raticite: {
name: "Raticite",
spritenum: 1,
megaStone: { "Raticate": "Raticate-Mega" },
itemUser: ["Raticate"],
onTakeItem(item, source) {
return !item.megaStone?.[source.baseSpecies.baseSpecies];
},
num: -3,
gen: 9,
desc: "If held by a Raticate, this item allows it to Mega Evolve in battle.",
},
};

File diff suppressed because it is too large Load Diff

View File

@ -1,514 +0,0 @@
export const Pokedex: import('../../../sim/dex-species').ModdedSpeciesDataTable = {
volcarona: {
inherit: true,
abilities: { 0: "Fluffy" },
},
golemalola: {
inherit: true,
},
lurantis: {
inherit: true,
baseStats: { hp: 85, atk: 105, def: 90, spa: 95, spd: 90, spe: 75 },
},
ironcrown: {
inherit: true,
abilities: { 0: "Queenly Majesty", H: "Battle Armor" },
},
mamoswine: {
inherit: true,
},
ceruledge: {
inherit: true,
},
carbink: {
inherit: true,
abilities: { 0: "Magic Bounce" },
},
moltres: {
inherit: true,
abilities: { 0: "Magic Guard" },
},
kommoo: {
inherit: true,
baseStats: { hp: 75, atk: 100, def: 125, spa: 110, spd: 105, spe: 85 },
abilities: { 0: "Punk Rock" },
},
illumise: {
inherit: true,
abilities: { 0: "Call Volbeat" },
},
volbeat: {
inherit: true,
abilities: { 0: "Call Illumise" },
},
abomasnow: {
inherit: true,
},
abomasnowmega: {
inherit: true,
baseStats: { hp: 90, atk: 132, def: 105, spa: 92, spd: 105, spe: 70 },
abilities: { 0: "Slush Rush" },
},
dugtrio: {
inherit: true,
},
altaria: {
inherit: true,
abilities: { 0: "Fluffy" },
},
altariamega: {
inherit: true,
},
tyranitar: {
inherit: true,
abilities: { 0: "Sand Stream", H: "Sharpness" },
},
tyranitarmega: {
inherit: true,
baseStats: { hp: 100, atk: 114, def: 150, spa: 155, spd: 110, spe: 71 },
types: ["Rock", "Dragon"],
},
mimikyu: {
inherit: true,
baseStats: { hp: 65, atk: 110, def: 80, spa: 50, spd: 105, spe: 96 },
},
mimikyubusted: {
inherit: true,
abilities: { 0: "Perish Body" },
baseStats: { hp: 65, atk: 90, def: 80, spa: 50, spd: 105, spe: 116 },
},
mesprit: {
inherit: true,
abilities: { 0: "Liquid Voice" },
types: ["Psychic", "Water"],
},
electrode: {
inherit: true,
abilities: { 0: "Short Fuse" },
types: ["Electric", "Normal"],
},
taurospaldeacombat: {
inherit: true,
abilities: { 0: "Adaptability" },
},
chiyu: {
inherit: true,
abilities: { 0: "Water Absorb" },
baseStats: { hp: 55, atk: 135, def: 80, spa: 80, spd: 120, spe: 100 },
},
wochien: {
inherit: true,
abilities: { 0: "Liquid Ooze" },
types: ["Grass", "Water"],
},
staraptor: {
inherit: true,
types: ["Flying"],
},
archaludon: {
inherit: true,
abilities: { 0: "Hydroelectric Dam", 1: "Stamina" },
},
malamar: {
inherit: true,
abilities: { 0: "Flip Flop" },
baseStats: { hp: 86, atk: 92, def: 88, spa: 88, spd: 75, spe: 73 },
},
empoleon: {
inherit: true,
abilities: { 0: "Sharpness" },
types: ["Water", "Steel", "Flying"],
},
glastrier: {
inherit: true,
abilities: { 0: "Frozen Armor" },
},
calyrexice: {
inherit: true,
baseStats: { hp: 100, atk: 165, def: 130, spa: 85, spd: 110, spe: 90 },
},
regieleki: {
inherit: true,
abilities: { 0: "Galvanize" },
},
lycanrocmidnight: {
inherit: true,
abilities: { 0: "Technician" },
},
lycanroc: {
inherit: true,
abilities: { 0: "Drought" },
},
lycanrocdusk: {
inherit: true,
abilities: { 0: "Strong Jaw" },
},
dodrio: {
inherit: true,
abilities: { 0: "Speed Boost" },
types: ["Flying", "Fighting"],
},
whiscash: {
inherit: true,
abilities: { 0: "Regenerator" },
baseStats: { hp: 110, atk: 78, def: 88, spa: 76, spd: 86, spe: 60 },
},
hippowdon: {
inherit: true,
abilities: { 0: "Earth Eater" },
},
cramorant: {
inherit: true,
baseStats: { hp: 90, atk: 85, def: 75, spa: 85, spd: 95, spe: 85 },
},
cramorantgulping: {
inherit: true,
baseStats: { hp: 90, atk: 85, def: 75, spa: 85, spd: 95, spe: 85 },
abilities: { 0: "Storm Drain" },
},
cramorantgorging: {
inherit: true,
baseStats: { hp: 90, atk: 85, def: 75, spa: 85, spd: 95, spe: 85 },
abilities: { 0: "Lightning Rod" },
},
grafaiai: {
inherit: true,
baseStats: { hp: 83, atk: 95, def: 65, spa: 80, spd: 72, spe: 110 },
},
tatsugiri: {
inherit: true,
abilities: { 0: "Regenerator" },
baseStats: { hp: 78, atk: 50, def: 70, spa: 120, spd: 95, spe: 82 },
},
kyurem: {
inherit: true,
abilities: { 0: "Skill Link" },
},
roaringmoon: {
inherit: true,
abilities: { 0: "Shadow Shield" },
},
milotic: {
inherit: true,
abilities: { 0: "Aqua Veil" },
types: ["Water", "Fairy"],
},
gogoat: {
inherit: true,
types: ["Grass", "Rock"],
},
clodsire: {
inherit: true,
abilities: { 0: "Still Water" },
},
masquerain: {
inherit: true,
abilities: { 0: "Intimidate" },
},
masquerainmega: {
num: -999,
name: "Masquerain-Mega",
baseSpecies: "Masquerain",
forme: "Mega",
types: ["Bug", "Dark"],
genderRatio: { M: 0.5, F: 0.5 },
baseStats: { hp: 70, atk: 60, def: 82, spa: 140, spd: 82, spe: 120 },
abilities: { 0: "Primordial Sea" },
heightm: 0.8,
weightkg: 3.6,
color: "Blue",
eggGroups: ["Water 1", "Bug"],
requiredItem: "Masquerainite",
},
kyuremblack: {
inherit: true,
abilities: { 0: "Teravolt" },
types: ["Dragon", "Ice", "Electric"],
},
ironthorns: {
inherit: true,
abilities: { 0: "Iron Barbs" },
},
dudunsparce: {
inherit: true,
abilities: { 0: "Earth Eater" },
types: ["Normal", "Ground"],
},
dudunsparcethreesegment: {
inherit: true,
abilities: { 0: "Earth Eater" },
types: ["Normal", "Ground"],
},
chienpao: {
inherit: true,
abilities: { 0: "Tablets of Ruin" },
},
pelipper: {
inherit: true,
},
kleavor: {
inherit: true,
abilities: { 0: "King of the Hill" },
baseStats: { hp: 120, atk: 135, def: 95, spa: 45, spd: 75, spe: 85 },
},
araquanid: {
inherit: true,
},
avalugghisui: {
inherit: true,
abilities: { 0: "Multiscale" },
baseStats: { hp: 95, atk: 127, def: 184, spa: 68, spd: 72, spe: 76 },
},
swalot: {
inherit: true,
abilities: { 0: "Omnivore" },
},
zapdosgalar: {
inherit: true,
types: ["Electric", "Fighting"],
},
phione: {
inherit: true,
},
sudowoodo: {
inherit: true,
abilities: { 0: "Pseudowoodo" },
types: ["Grass"],
baseForme: "Grass",
otherFormes: ["Sudowoodo-Rock"],
formeOrder: ["Sudowoodo", "Sudowoodo-Rock"],
},
sudowoodorock: {
num: 185,
name: "Sudowoodo-Rock",
baseSpecies: "Sudowoodo",
forme: "Rock",
types: ["Rock"],
baseStats: { hp: 70, atk: 100, def: 110, spa: 30, spd: 65, spe: 30 },
abilities: { 0: "Pseudowoodo" },
heightm: 1.7,
weightkg: 38,
color: "Brown",
eggGroups: ["Mineral"],
requiredAbility: "Pseudowoodo",
battleOnly: "Sudowoodo",
},
dondozo: {
inherit: true,
},
golurk: {
inherit: true,
},
meowscarada: {
inherit: true,
},
infernape: {
inherit: true,
abilities: { 0: "Berserk" },
},
salamence: {
inherit: true,
abilities: { 0: "Aerilate" },
},
salamencemega: {
num: 373,
name: "Salamence-Mega",
baseSpecies: "Salamence",
forme: "Mega",
types: ["Dragon", "Flying"],
baseStats: { hp: 95, atk: 145, def: 130, spa: 120, spd: 90, spe: 120 },
abilities: { 0: "Blood-Soaked Crescent" },
heightm: 1.8,
weightkg: 112.6,
color: "Blue",
eggGroups: ["Dragon"],
requiredItem: "Salamencite",
},
urshifu: {
inherit: true,
abilities: { 0: "Sniper" },
},
urshifurapidstrike: {
inherit: true,
abilities: { 0: "Sniper" },
},
stonjourner: {
inherit: true,
},
veluza: {
inherit: true,
types: ["Water", "Ghost"],
},
ogerponhearthflame: {
inherit: true,
abilities: { 0: "Intimidate" },
},
dachsbun: {
inherit: true,
},
koraidon: {
inherit: true,
},
mew: {
inherit: true,
abilities: { 0: "Biogenesis" },
},
magneton: {
inherit: true,
},
delibird: {
inherit: true,
abilities: { 0: "Hail Mary" },
baseStats: { hp: 45, atk: 90, def: 45, spa: 65, spd: 45, spe: 136 },
},
articunogalar: {
inherit: true,
abilities: { 0: "Brain Freeze" },
},
vaporeon: {
inherit: true,
abilities: { 0: "Marvel Scale" },
},
jolteon: {
inherit: true,
abilities: { 0: "Quick Feet" },
},
flareon: {
inherit: true,
abilities: { 0: "Guts" },
baseStats: { hp: 65, atk: 130, def: 65, spa: 60, spd: 110, spe: 95 },
},
garganacl: {
inherit: true,
},
swanna: {
inherit: true,
abilities: { 0: "Serene Grace" },
baseStats: { hp: 75, atk: 117, def: 93, spa: 117, spd: 93, spe: 128 },
},
typhlosion: {
inherit: true,
abilities: { 0: "Magic Guard" },
},
typhlosionmega: {
num: -998,
name: "Typhlosion-Mega",
baseSpecies: "Typhlosion",
forme: "Mega",
types: ["Fire", "Water"],
genderRatio: { M: 0.5, F: 0.5 },
baseStats: { hp: 78, atk: 103, def: 98, spa: 140, spd: 115, spe: 100 },
abilities: { 0: "Neutralizing Gas" },
heightm: 1.7,
weightkg: 84.5,
color: "Blue",
eggGroups: ["Field"],
requiredItem: "Typhlosionite",
},
terapagos: {
inherit: true,
},
terapagosterastal: {
inherit: true,
abilities: { 0: "Tera Wheel" },
},
terapagosstellar: {
inherit: true,
types: ["Stellar"],
},
flapple: {
inherit: true,
abilities: { 0: "Ripen" },
types: ["Grass", "Ground"],
},
genesect: {
inherit: true,
abilities: { 0: "Download" },
},
honchkrow: {
inherit: true,
abilities: { 0: "Supreme Overlord" },
baseStats: { hp: 100, atk: 125, def: 52, spa: 125, spd: 52, spe: 71 },
},
primeape: {
inherit: true,
abilities: { 0: "Battle Rage" },
},
rillaboom: {
inherit: true,
abilities: { 0: "Terrain Shift" },
},
mandibuzz: {
inherit: true,
abilities: { 0: "Weak Armor" },
types: ["Dark", "Ground"],
},
feraligatr: {
inherit: true,
},
feraligatrmega: {
num: -988,
name: "Feraligatr-Mega",
baseSpecies: "Feraligatr",
forme: "Mega",
types: ["Dragon"],
genderRatio: { M: 0.875, F: 0.125 },
baseStats: { hp: 85, atk: 145, def: 120, spa: 99, spd: 103, spe: 78 },
abilities: { 0: "Dragon's Jaw" },
heightm: 2.3,
weightkg: 108.8,
color: "Blue",
eggGroups: ["Monster", "Water 1"],
requiredItem: "Feraligite",
gen: 9,
},
salazzle: {
inherit: true,
abilities: { 0: "Corrosive Soul" },
},
kyogre: {
inherit: true,
abilities: { 0: "Oceanic Blessing" },
},
azelf: {
inherit: true,
abilities: { 0: "Auto Spin" },
types: ["Psychic", "Normal"],
},
decidueye: {
inherit: true,
abilities: { 0: "Overgrow", 1: "Sniper" },
},
ogerponcornerstone: {
inherit: true,
abilities: { 0: "Solid Rock" },
},
glimmora: {
inherit: true,
abilities: { 0: "Corrosion" },
},
wobbuffet: {
inherit: true,
abilities: { 0: "Jello Body" },
},
raticate: {
inherit: true,
abilities: { 0: "Hustle" },
baseStats: { hp: 90, atk: 81, def: 60, spa: 50, spd: 70, spe: 97 },
},
raticatemega: {
num: -977,
name: "Raticate-Mega",
baseSpecies: "Raticate",
forme: "Mega",
types: ["Normal", "Ghost"],
genderRatio: { M: 0.5, F: 0.5 },
baseStats: { hp: 90, atk: 105, def: 60, spa: 50, spd: 70, spe: 173 },
abilities: { 0: "Nibble Nibble" },
heightm: 0.7,
weightkg: 5,
color: "Black",
eggGroups: ["Field"],
requiredItem: "Raticite",
},
};

View File

@ -1,304 +0,0 @@
export const Scripts: ModdedBattleScriptsData = {
gen: 9,
init() {
this.modData('Learnsets', 'lurantis').learnset.icehammer = ['9L1'];
this.modData('Learnsets', 'ironcrown').learnset.kingsshield = ['9L1'];
this.modData('Learnsets', 'ironcrown').learnset.bodypress = ['9L1'];
this.modData('Learnsets', 'carbink').learnset.moonlight = ['9L1'];
this.modData('Learnsets', 'carbink').learnset.voltswitch = ['9L1'];
this.modData('Learnsets', 'carbink').learnset.spikes = ['9L1'];
this.modData('Learnsets', 'moltres').learnset.woodhammer = ['9L1'];
this.modData('Learnsets', 'moltres').learnset.wavecrash = ['9L1'];
this.modData('Learnsets', 'moltres').learnset.defog = ['9L1'];
this.modData('Learnsets', 'kommoo').learnset.aurasphere = ['9L1'];
this.modData('Learnsets', 'illumise').learnset.quiverdance = ['9L1'];
this.modData('Learnsets', 'illumise').learnset.thunderbolt = ['9L1'];
this.modData('Learnsets', 'illumise').learnset.icebeam = ['9L1'];
this.modData('Learnsets', 'volbeat').learnset.victorydance = ['9L1'];
this.modData('Learnsets', 'volbeat').learnset.mightycleave = ['9L1'];
this.modData('Learnsets', 'volbeat').learnset.earthquake = ['9L1'];
this.modData('Learnsets', 'abomasnow').learnset.glaciallance = ['9L1'];
this.modData('Learnsets', 'abomasnow').learnset.appleacid = ['9L1'];
this.modData('Learnsets', 'abomasnow').learnset.partingshot = ['9L1'];
this.modData('Learnsets', 'dugtrio').learnset.mightycleave = ['9L1'];
this.modData('Learnsets', 'dugtrio').learnset.saltcure = ['9L1'];
this.modData('Learnsets', 'dugtrio').learnset.acrobatics = ['9L1'];
this.modData('Learnsets', 'altaria').learnset.beakblast = ['9L1'];
this.modData('Learnsets', 'altaria').learnset.return = ['9L1'];
this.modData('Learnsets', 'altaria').learnset.explosion = ['9L1'];
this.modData('Learnsets', 'tyranitar').learnset.stoneaxe = ['9L1'];
this.modData('Learnsets', 'tyranitar').learnset.ceaselessedge = ['9L1'];
this.modData('Learnsets', 'tyranitar').learnset.kowtowcleave = ['9L1'];
this.modData('Learnsets', 'tyranitar').learnset.pursuit = ['9L1'];
this.modData('Learnsets', 'tyranitar').learnset.switcheroo = ['9L1'];
this.modData('Learnsets', 'tyranitar').learnset.accelerock = ['9L1'];
this.modData('Learnsets', 'tyranitar').learnset.dracometeor = ['9L1'];
this.modData('Learnsets', 'tyranitar').learnset.mysticalpower = ['9L1'];
this.modData('Learnsets', 'tyranitar').learnset.sandsearstorm = ['9L1'];
this.modData('Learnsets', 'mimikyu').learnset.spiritshackle = ['9L1'];
this.modData('Learnsets', 'mimikyu').learnset.uturn = ['9L1'];
this.modData('Learnsets', 'mimikyu').learnset.obstruct = ['9L1'];
this.modData('Learnsets', 'mesprit').learnset.agility = ['9L1'];
this.modData('Learnsets', 'mesprit').learnset.storedpower = ['9L1'];
this.modData('Learnsets', 'mesprit').learnset.torchsong = ['9L1'];
this.modData('Learnsets', 'mesprit').learnset.cosmicpower = ['9L1'];
this.modData('Learnsets', 'mesprit').learnset.aquaring = ['9L1'];
this.modData('Learnsets', 'mesprit').learnset.freezedry = ['9L1'];
this.modData('Learnsets', 'electrode').learnset.encore = ['9L1'];
this.modData('Learnsets', 'electrode').learnset.rapidspin = ['9L1'];
this.modData('Learnsets', 'taurospaldeacombat').learnset.extremespeed = ['9L1'];
this.modData('Learnsets', 'taurospaldeacombat').learnset.uturn = ['9L1'];
this.modData('Learnsets', 'taurospaldeacombat').learnset.knockoff = ['9L1'];
this.modData('Learnsets', 'chiyu').learnset.splash = ['9L1'];
this.modData('Learnsets', 'chiyu').learnset.tripledive = ['9L1'];
this.modData('Learnsets', 'chiyu').learnset.pyroball = ['9L1'];
this.modData('Learnsets', 'chiyu').learnset.knockoff = ['9L1'];
this.modData('Learnsets', 'chiyu').learnset.suckerpunch = ['9L1'];
this.modData('Learnsets', 'wochien').learnset.partingshot = ['9L1'];
this.modData('Learnsets', 'wochien').learnset.strengthsap = ['9L1'];
this.modData('Learnsets', 'wochien').learnset.bouncingbubble = ['9L1'];
this.modData('Learnsets', 'staraptor').learnset.jumpkick = ['9L1'];
this.modData('Learnsets', 'staraptor').learnset.flareblitz = ['9L1'];
this.modData('Learnsets', 'staraptor').learnset.wavecrash = ['9L1'];
this.modData('Learnsets', 'staraptor').learnset.headsmash = ['9L1'];
this.modData('Learnsets', 'archaludon').learnset.scald = ['9L1'];
this.modData('Learnsets', 'archaludon').learnset.hydropump = ['9L1'];
this.modData('Learnsets', 'malamar').learnset.willowisp = ['9L1'];
this.modData('Learnsets', 'malamar').learnset.recover = ['9L1'];
this.modData('Learnsets', 'malamar').learnset.eeriespell = ['9L1'];
this.modData('Learnsets', 'malamar').learnset.sweetkiss = ['9L1'];
this.modData('Learnsets', 'malamar').learnset.spiritbreak = ['9L1'];
this.modData('Learnsets', 'empoleon').learnset.nastyplot = ['9L1'];
this.modData('Learnsets', 'empoleon').learnset.watershuriken = ['9L1'];
this.modData('Learnsets', 'empoleon').learnset.tachyoncutter = ['9L1'];
this.modData('Learnsets', 'empoleon').learnset.secretsword = ['9L1'];
this.modData('Learnsets', 'regieleki').learnset.blazingtorque = ['9L1'];
this.modData('Learnsets', 'regieleki').learnset.soak = ['9L1'];
this.modData('Learnsets', 'lycanrocmidnight').learnset.accelerock = ['9L1'];
this.modData('Learnsets', 'lycanrocmidnight').learnset.bonerush = ['9L1'];
this.modData('Learnsets', 'lycanrocmidnight').learnset.stormthrow = ['9L1'];
this.modData('Learnsets', 'lycanroc').learnset.firelash = ['9L1'];
this.modData('Learnsets', 'lycanroc').learnset.uturn = ['9L1'];
this.modData('Learnsets', 'lycanroc').learnset.spikes = ['9L1'];
this.modData('Learnsets', 'lycanrocdusk').learnset.mountainmaw = ['9L1'];
this.modData('Learnsets', 'lycanrocdusk').learnset.icefang = ['9L1'];
this.modData('Learnsets', 'dodrio').learnset.triplearrows = ['9L1'];
this.modData('Learnsets', 'dodrio').learnset.obstruct = ['9L1'];
this.modData('Learnsets', 'whiscash').learnset.toxic = ['9L1'];
this.modData('Learnsets', 'whiscash').learnset.flipturn = ['9L1'];
this.modData('Learnsets', 'whiscash').learnset.scald = ['9L1'];
this.modData('Learnsets', 'hippowdon').learnset.saltcure = ['9L1'];
this.modData('Learnsets', 'cramorant').learnset.beakblast = ['9L1'];
this.modData('Learnsets', 'grafaiai').learnset.bulkup = ['9L1'];
this.modData('Learnsets', 'grafaiai').learnset.scavenge = ['9L1'];
this.modData('Learnsets', 'grafaiai').learnset.drainpunch = ['9L1'];
this.modData('Learnsets', 'kyurem').learnset.earthquake = ['9L1'];
this.modData('Learnsets', 'roaringmoon').learnset.firelash = ['9L1'];
this.modData('Learnsets', 'roaringmoon').learnset.glaiverush = ['9L1'];
this.modData('Learnsets', 'milotic').learnset.bouncybubble = ['9L1'];
this.modData('Learnsets', 'milotic').learnset.moonblast = ['9L1'];
this.modData('Learnsets', 'gogoat').learnset.headsmash = ['9L1'];
this.modData('Learnsets', 'clodsire').learnset.barbbarrage = ['9L1'];
this.modData('Learnsets', 'masquerain').learnset.roost = ['9L1'];
this.modData('Learnsets', 'masquerain').learnset.darkpulse = ['9L1'];
this.modData('Learnsets', 'kyuremblack').learnset.icehammer = ['9L1'];
this.modData('Learnsets', 'kyuremblack').learnset.dragonhammer = ['9L1'];
this.modData('Learnsets', 'kyuremblack').learnset.roost = ['9L1'];
this.modData('Learnsets', 'kyuremblack').learnset.earthquake = ['9L1'];
this.modData('Learnsets', 'ironthorns').learnset.ironstrike = ['9L1'];
this.modData('Learnsets', 'ironthorns').learnset.knockoff = ['9L1'];
this.modData('Learnsets', 'chienpao').learnset.bulkup = ['9L1'];
this.modData('Learnsets', 'chienpao').learnset.iciclestorm = ['9L1'];
this.modData('Learnsets', 'pelipper').learnset.bleakwindstorm = ['9L1'];
this.modData('Learnsets', 'pelipper').learnset.sandsearstorm = ['9L1'];
this.modData('Learnsets', 'pelipper').learnset.wildboltstorm = ['9L1'];
this.modData('Learnsets', 'pelipper').learnset.springtidestorm = ['9L1'];
this.modData('Learnsets', 'araquanid').learnset.surgingstrikes = ['9L1'];
this.modData('Learnsets', 'araquanid').learnset.flipturn = ['9L1'];
this.modData('Learnsets', 'araquanid').learnset.silktrap = ['9L1'];
this.modData('Learnsets', 'araquanid').learnset.firstimpression = ['9L1'];
this.modData('Learnsets', 'avalugghisui').learnset.mountainmaw = ['9L1'];
this.modData('Learnsets', 'swalot').learnset.earthpower = ['9L1'];
this.modData('Learnsets', 'zapdosgalar').learnset.wildcharge = ['9L1'];
this.modData('Learnsets', 'phione').learnset.workup = ['9L1'];
this.modData('Learnsets', 'phione').learnset.tidalsurge = ['9L1'];
this.modData('Learnsets', 'phione').learnset.geyser = ['9L1'];
this.modData('Learnsets', 'sudowoodo').learnset.bonsaibounce = ['9L1'];
this.modData('Learnsets', 'sudowoodo').learnset.synthesis = ['9L1'];
this.modData('Learnsets', 'dondozo').learnset.hornleech = ['9L1'];
this.modData('Learnsets', 'dondozo').learnset.fishiousrend = ['9L1'];
this.modData('Learnsets', 'dondozo').learnset.recover = ['9L1'];
this.modData('Learnsets', 'dondozo').learnset.flipturn = ['9L1'];
this.modData('Learnsets', 'golurk').learnset.shatteredseal = ['9L1'];
this.modData('Learnsets', 'golurk').learnset.trickroom = ['9L1'];
this.modData('Learnsets', 'golurk').learnset.headlongrush = ['9L1'];
this.modData('Learnsets', 'meowscarada').learnset.encore = ['9L1'];
this.modData('Learnsets', 'meowscarada').learnset.spectralthief = ['9L1'];
this.modData('Learnsets', 'infernape').learnset.alloutassault = ['9L1'];
this.modData('Learnsets', 'infernape').learnset.mindblown = ['9L1'];
this.modData('Learnsets', 'infernape').learnset.bitterblade = ['9L1'];
this.modData('Learnsets', 'salamence').learnset.uturn = ['9L1'];
this.modData('Learnsets', 'salamence').learnset.dragonascent = ['9L1'];
this.modData('Learnsets', 'salamence').learnset.bloodmoon = ['9L1'];
this.modData('Learnsets', 'urshifu').learnset.agility = ['9L1'];
this.modData('Learnsets', 'urshifu').learnset.aquajet = ['9L1'];
this.modData('Learnsets', 'urshifurapidstrike').learnset.agility = ['9L1'];
this.modData('Learnsets', 'urshifurapidstrike').learnset.suckerpunch = ['9L1'];
this.modData('Learnsets', 'stonjourner').learnset.rockwrecker = ['9L1'];
this.modData('Learnsets', 'stonjourner').learnset.meteorassault = ['9L1'];
this.modData('Learnsets', 'stonjourner').learnset.skyattack = ['9L1'];
this.modData('Learnsets', 'stonjourner').learnset.solarblade = ['9L1'];
this.modData('Learnsets', 'veluza').learnset.ragefist = ['9L1'];
this.modData('Learnsets', 'ogerpon').learnset.leafblade = ['9L1'];
this.modData('Learnsets', 'ogerpon').learnset.crabhammer = ['9L1'];
this.modData('Learnsets', 'ogerpon').learnset.stoneedge = ['9L1'];
this.modData('Learnsets', 'dachsbun').learnset.nuzzle = ['9L1'];
this.modData('Learnsets', 'dachsbun').learnset.spiritbreak = ['9L1'];
this.modData('Learnsets', 'dachsbun').learnset.morningsun = ['9L1'];
this.modData('Learnsets', 'magneton').learnset.magnetbomb = ['9L1'];
this.modData('Learnsets', 'delibird').learnset.iciclestorm = ['9L1'];
this.modData('Learnsets', 'hitmontop').learnset.bulletseed = ['9L1'];
this.modData('Learnsets', 'articunogalar').learnset.aeroblast = ['9L1'];
this.modData('Learnsets', 'articunogalar').learnset.oblivionwing = ['9L1'];
this.modData('Learnsets', 'articunogalar').learnset.aurasphere = ['9L1'];
this.modData('Learnsets', 'vaporeon').learnset.voltswitch = ['9L1'];
this.modData('Learnsets', 'vaporeon').learnset.burnout = ['9L1'];
this.modData('Learnsets', 'garganacl').learnset.thunderwave = ['9L1'];
this.modData('Learnsets', 'garganacl').learnset.saltcurse = ['9L1'];
this.modData('Learnsets', 'garganacl').learnset.purify = ['9L1'];
this.modData('Learnsets', 'swanna').learnset.bleakwindstorm = ['9L1'];
this.modData('Learnsets', 'swanna').learnset.steameruption = ['9L1'];
this.modData('Learnsets', 'swanna').learnset.flyby = ['9L1'];
this.modData('Learnsets', 'typhlosion').learnset.heatsink = ['9L1'];
this.modData('Learnsets', 'typhlosion').learnset.steameruption = ['9L1'];
this.modData('Learnsets', 'typhlosion').learnset.matchagotcha = ['9L1'];
this.modData('Learnsets', 'typhlosion').learnset.calmmind = ['9L1'];
this.modData('Learnsets', 'typhlosion').learnset.morningsun = ['9L1'];
this.modData('Learnsets', 'terapagos').learnset.nastyplot = ['9L1'];
this.modData('Learnsets', 'tatsugiri').learnset.switcheroo = ['9L1'];
this.modData('Learnsets', 'tatsugiri').learnset.sashimishuffle = ['9L1'];
this.modData('Learnsets', 'tatsugiri').learnset.twister = ['9L1'];
this.modData('Learnsets', 'tatsugiri').learnset.waterspout = ['9L1'];
this.modData('Learnsets', 'flapple').learnset.earthquake = ['9L1'];
this.modData('Learnsets', 'flapple').learnset.grabapple = ['9L1'];
this.modData('Learnsets', 'flapple').learnset.flareblitz = ['9L1'];
this.modData('Learnsets', 'genesect').learnset.earthquake = ['9L1'];
this.modData('Learnsets', 'genesect').learnset.sunsteelstrike = ['9L1'];
this.modData('Learnsets', 'genesect').learnset.behemothblade = ['9L1'];
this.modData('Learnsets', 'genesect').learnset.makeitrain = ['9L1'];
this.modData('Learnsets', 'genesect').learnset.tachyoncutter = ['9L1'];
this.modData('Learnsets', 'honchkrow').learnset.crowverload = ['9L1'];
this.modData('Learnsets', 'honchkrow').learnset.oblivionwing = ['9L1'];
this.modData('Learnsets', 'honchkrow').learnset.closecombat = ['9L1'];
this.modData('Learnsets', 'primeape').learnset.knockoff = ['9L1'];
this.modData('Learnsets', 'primeape').learnset.ironhead = ['9L1'];
this.modData('Learnsets', 'rillaboom').learnset.naturesfury = ['9L1'];
this.modData('Learnsets', 'rillaboom').learnset.landswrath = ['9L1'];
this.modData('Learnsets', 'mandibuzz').learnset.fling = ['9L1'];
this.modData('Learnsets', 'mandibuzz').learnset.scavenge = ['9L1'];
this.modData('Learnsets', 'mandibuzz').learnset.bonemerang = ['9L1'];
this.modData('Learnsets', 'feraligatr').learnset.firefang = ['9L1'];
this.modData('Learnsets', 'feraligatr').learnset.thunderfang = ['9L1'];
this.modData('Learnsets', 'feraligatr').learnset.poisonfang = ['9L1'];
this.modData('Learnsets', 'salazzle').learnset.magmastorm = ['9L1'];
this.modData('Learnsets', 'salazzle').learnset.malignantchain = ['9L1'];
this.modData('Learnsets', 'salazzle').learnset.psychicnoise = ['9L1'];
this.modData('Learnsets', 'salazzle').learnset.banefulbunker = ['9L1'];
this.modData('Learnsets', 'kyogre').learnset.hurricane = ['9L1'];
this.modData('Learnsets', 'kyogre').learnset.tidalsurge = ['9L1'];
this.modData('Learnsets', 'azelf').learnset.rapidspin = ['9L1'];
this.modData('Learnsets', 'azelf').learnset.lootbox = ['9L1'];
this.modData('Learnsets', 'azelf').learnset.acupressure = ['9L1'];
this.modData('Learnsets', 'decidueye').learnset.sinisterarrows = ['9L1'];
this.modData('Learnsets', 'ogerpon').learnset.sappyseed = ['9L1'];
this.modData('Learnsets', 'ogerpon').learnset.thousandwaves = ['9L1'];
this.modData('Learnsets', 'glimmora').learnset.icebeam = ['9L1'];
this.modData('Learnsets', 'glimmora').learnset.malignantchain = ['9L1'];
this.modData('Learnsets', 'wobbuffet').learnset.nightshade = ['9L1'];
this.modData('Learnsets', 'wobbuffet').learnset.guillotine = ['9L1'];
this.modData('Learnsets', 'wobbuffet').learnset.shedtail = ['9L1'];
this.modData('Learnsets', 'raticate').learnset.lastbreakfast = ['9L1'];
},
};

View File

@ -15,8 +15,10 @@ export const Scripts: ModdedBattleScriptsData = {
move.hit = 0;
}
if (!target.runImmunity(move, !suppressMessages)) {
return false;
if (!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) {
if (!target.runImmunity(move.type, !suppressMessages)) {
return false;
}
}
if (move.ohko) return target.maxhp;

View File

@ -10,7 +10,7 @@ There were only 151 Pokémon plus MissingNo, just a handful of moves, no abiliti
EVd to the max and we had some kind of different IVs, which maxed at 15 and every point gave 2 to the stat, so in
a similar fashion, Pokes used to have 30 IVs on each stat.
The following sources have been used and extremely useful when developing this mod:
The following sources have been used and extremly useful when developing this mod:
https://raw.github.com/po-devs/pokemon-online/master/bin/database/rby-stuff.txt
https://www.smogon.com/rb/articles/differences
https://www.smogon.com/forums/threads/past-gens-research-thread.3506992/#post-5878612

View File

@ -185,84 +185,31 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
},
partiallytrapped: {
name: 'partiallytrapped',
// this is the duration of Wrap if it doesn't continue.
// (i.e. if the attacker switches out.)
// the full duration is tracked in partialtrappinglock
duration: 2,
// defender still takes PSN damage, etc
// TODO: research exact mechanics
onBeforeMovePriority: 9,
onBeforeMove(pokemon) {
this.add('cant', pokemon, 'partiallytrapped');
return false;
},
onRestart() {
this.effectState.duration = 2;
},
onAccuracy(accuracy, target, source, move) {
if (source === this.effectState.source) return true;
},
onLockMove() {
// exact move doesn't matter, no move is ever actually used
return 'struggle';
},
onDisableMove(target) {
target.maybeLocked = true;
},
},
fakepartiallytrapped: {
name: 'fakepartiallytrapped',
// Wrap ended this turn, but you don't know that
// until you try to use an attack
duration: 2,
onDisableMove(target) {
target.maybeLocked = true;
},
},
partialtrappinglock: {
name: 'partialtrappinglock',
durationCallback() {
return this.sample([2, 2, 2, 3, 3, 3, 4, 5]);
const duration = this.sample([2, 2, 2, 3, 3, 3, 4, 5]);
return duration;
},
onStart(target, source, effect) {
const foe = target.foes()[0];
if (!foe) return false;
this.effectState.move = effect.id;
this.effectState.totalDuration = this.effectState.duration!;
this.effectState.damage = this.lastDamage;
this.effectState.locked = foe;
foe.addVolatile('partiallytrapped', target, effect);
},
onOverrideAction(pokemon, target, move) {
return this.effectState.move;
},
onBeforeMove(pokemon, target, move) {
if (target !== this.effectState.locked) {
pokemon.removeVolatile('partialtrappinglock');
}
},
onAfterMove(pokemon, target, move) {
if (target && target.hp <= 0) {
delete pokemon.volatiles['partialtrappinglock'];
return;
}
if (this.effectState.duration === 1) {
if (this.effectState.totalDuration !== 5) {
pokemon.addVolatile('fakepartiallytrapped');
pokemon.volatiles['fakepartiallytrapped'].counterpart = target;
target.addVolatile('fakepartiallytrapped');
target.volatiles['fakepartiallytrapped'].counterpart = pokemon;
}
} else {
target.addVolatile('partiallytrapped', pokemon, move);
}
},
onLockMove() {
return this.effectState.move;
},
onDisableMove(pokemon) {
pokemon.maybeLocked = true;
if (!pokemon.hasMove(this.effectState.move)) {
return;
}
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id !== this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
}
},
},
mustrecharge: {
@ -270,13 +217,6 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
duration: 0,
onBeforeMovePriority: 7,
onStart() {},
onAfterMove(pokemon, target, move) {
if (target && target.hp <= 0) {
delete pokemon.volatiles['mustrecharge'];
return;
}
this.add('-mustrecharge', pokemon);
},
},
lockedmove: {
// Thrash and Petal Dance.
@ -296,11 +236,6 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
this.queue.changeAction(pokemon, { choice: 'move', moveid: move.id });
}
},
onAfterMove(pokemon) {
if (pokemon.volatiles['lockedmove'].time <= 0) {
pokemon.removeVolatile('lockedmove');
}
},
},
twoturnmove: {
// Skull Bash, Solar Beam, ...

View File

@ -21,7 +21,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
wartortle: {
tier: "NFE",
tier: "ZU",
},
blastoise: {
tier: "NU",
@ -51,7 +51,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "NFE",
},
pidgeot: {
tier: "PU",
tier: "ZU",
},
rattata: {
tier: "LC",
@ -90,7 +90,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "NFE",
},
nidoqueen: {
tier: "ZU",
tier: "PU",
},
nidoranm: {
tier: "LC",
@ -117,7 +117,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
wigglytuff: {
tier: "ZU",
tier: "PU",
},
zubat: {
tier: "LC",
@ -132,7 +132,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "NFE",
},
vileplume: {
tier: "ZU",
tier: "PU",
},
paras: {
tier: "LC",
@ -168,7 +168,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
primeape: {
tier: "PU",
tier: "ZU",
},
growlithe: {
tier: "LC",
@ -189,7 +189,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "PU",
},
kadabra: {
tier: "NU",
tier: "UU",
},
alakazam: {
tier: "OU",
@ -201,7 +201,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "NFE",
},
machamp: {
tier: "ZU",
tier: "PU",
},
bellsprout: {
tier: "LC",
@ -210,13 +210,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "NFE",
},
victreebel: {
tier: "NU",
tier: "OU",
},
tentacool: {
tier: "ZU",
},
tentacruel: {
tier: "NU",
tier: "UU",
},
geodude: {
tier: "LC",
@ -225,19 +225,19 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "PU",
},
golem: {
tier: "NU",
tier: "UU",
},
ponyta: {
tier: "LC",
tier: "ZU",
},
rapidash: {
tier: "UU",
tier: "PU",
},
slowpoke: {
tier: "ZU",
},
slowbro: {
tier: "UU",
tier: "OU",
},
magnemite: {
tier: "LC",
@ -258,7 +258,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
dewgong: {
tier: "NU",
tier: "UU",
},
grimer: {
tier: "LC",
@ -288,19 +288,19 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "ZU",
},
hypno: {
tier: "UU",
tier: "UUBL",
},
krabby: {
tier: "LC",
},
kingler: {
tier: "ZU",
tier: "PU",
},
voltorb: {
tier: "LC",
},
electrode: {
tier: "NU",
tier: "UU",
},
exeggcute: {
tier: "PU",
@ -339,7 +339,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "OU",
},
tangela: {
tier: "NU",
tier: "UU",
},
kangaskhan: {
tier: "UU",
@ -366,7 +366,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "NU",
},
scyther: {
tier: "PU",
tier: "ZU",
},
jynx: {
tier: "OU",
@ -375,10 +375,10 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "UU",
},
magmar: {
tier: "PU",
tier: "ZU",
},
pinsir: {
tier: "ZU",
tier: "PU",
},
tauros: {
tier: "OU",
@ -390,7 +390,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "UU",
},
lapras: {
tier: "UU",
tier: "UUBL",
},
ditto: {
tier: "ZU",
@ -399,7 +399,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
vaporeon: {
tier: "NU",
tier: "UU",
},
jolteon: {
tier: "OU",
@ -414,7 +414,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "ZU",
},
omastar: {
tier: "NU",
tier: "UU",
},
kabuto: {
tier: "LC",
@ -429,13 +429,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "OU",
},
articuno: {
tier: "UU",
tier: "UUBL",
},
zapdos: {
tier: "OU",
},
moltres: {
tier: "UU",
tier: "NU",
},
dratini: {
tier: "LC",

View File

@ -76,6 +76,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
bind: {
inherit: true,
ignoreImmunity: true,
volatileStatus: 'partiallytrapped',
self: {
volatileStatus: 'partialtrappinglock',
},
@ -85,6 +86,19 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.hint("In Gen 1, partial trapping moves negate the recharge turn of Hyper Beam, even if they miss.", true);
}
},
onHit(target, source) {
/**
* The duration of the partially trapped must be always renewed to 2
* so target doesn't move on trapper switch out as happens in gen 1.
* However, this won't happen if there's no switch and the trapper is
* about to end its partial trapping.
**/
if (target.volatiles['partiallytrapped']) {
if (source.volatiles['partialtrappinglock'] && source.volatiles['partialtrappinglock'].duration! > 1) {
target.volatiles['partiallytrapped'].duration = 2;
}
}
},
},
bite: {
inherit: true,
@ -123,6 +137,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
accuracy: 75,
pp: 10,
volatileStatus: 'partiallytrapped',
self: {
volatileStatus: 'partialtrappinglock',
},
@ -132,6 +147,19 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.hint("In Gen 1, partial trapping moves negate the recharge turn of Hyper Beam, even if they miss.", true);
}
},
onHit(target, source) {
/**
* The duration of the partially trapped must be always renewed to 2
* so target doesn't move on trapper switch out as happens in gen 1.
* However, this won't happen if there's no switch and the trapper is
* about to end its partial trapping.
**/
if (target.volatiles['partiallytrapped']) {
if (source.volatiles['partialtrappinglock'] && source.volatiles['partialtrappinglock'].duration! > 1) {
target.volatiles['partiallytrapped'].duration = 2;
}
}
},
},
constrict: {
inherit: true,
@ -211,13 +239,22 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
},
disable: {
inherit: true,
num: 50,
accuracy: 55,
basePower: 0,
category: "Status",
name: "Disable",
pp: 20,
priority: 0,
flags: { protect: 1, mirror: 1, bypasssub: 1, metronome: 1 },
volatileStatus: 'disable',
onTryHit(target) {
return target.moveSlots.some(ms => ms.pp > 0);
// This function should not return if the checks are met. Adding && undefined ensures this happens.
return target.moveSlots.some(ms => ms.pp > 0) &&
!('disable' in target.volatiles) &&
undefined;
},
condition: {
inherit: true,
durationCallback: undefined,
onStart(pokemon) {
// disable can only select moves that have pp > 0, hence the onTryHit modification
const moveSlot = this.sample(pokemon.moveSlots.filter(ms => ms.pp > 0));
@ -226,6 +263,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
// 1-8 turns (which will in effect translate to 0-7 missed turns for the target)
this.effectState.time = this.random(1, 9);
},
onEnd(pokemon) {
this.add('-end', pokemon, 'Disable');
},
onBeforeMovePriority: 6,
onBeforeMove(pokemon, target, move) {
pokemon.volatiles['disable'].time--;
@ -240,7 +280,17 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
return false;
}
},
onDisableMove(pokemon) {
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id === this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
}
},
},
secondary: null,
target: "normal",
type: "Normal",
},
dizzypunch: {
inherit: true,
@ -270,6 +320,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
accuracy: 70,
basePower: 15,
volatileStatus: 'partiallytrapped',
self: {
volatileStatus: 'partialtrappinglock',
},
@ -279,6 +330,19 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.hint("In Gen 1, partial trapping moves negate the recharge turn of Hyper Beam, even if they miss.", true);
}
},
onHit(target, source) {
/**
* The duration of the partially trapped must be always renewed to 2
* so target doesn't move on trapper switch out as happens in gen 1.
* However, this won't happen if there's no switch and the trapper is
* about to end its partial trapping.
**/
if (target.volatiles['partiallytrapped']) {
if (source.volatiles['partialtrappinglock'] && source.volatiles['partialtrappinglock'].duration! > 1) {
target.volatiles['partiallytrapped'].duration = 2;
}
}
},
},
fly: {
inherit: true,
@ -297,9 +361,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
focusenergy: {
inherit: true,
condition: {
inherit: true,
onStart(pokemon) {
this.add('-start', pokemon, 'move: Focus Energy');
},
// This does nothing as it's dealt with on critical hit calculation.
onModifyCritRatio() {},
onModifyMove() {},
},
},
glare: {
@ -384,7 +450,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
onHit() {},
condition: {
inherit: true,
onStart(target) {
this.add('-start', target, 'move: Leech Seed');
},
onAfterMoveSelfPriority: 1,
onAfterMoveSelf(pokemon) {
const leecher = this.getAtSlot(pokemon.volatiles['leechseed'].sourceSlot);
@ -410,9 +478,15 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
},
lightscreen: {
inherit: true,
num: 113,
accuracy: true,
basePower: 0,
category: "Status",
name: "Light Screen",
pp: 30,
priority: 0,
flags: { metronome: 1 },
volatileStatus: 'lightscreen',
sideCondition: undefined,
onTryHit(pokemon) {
if (pokemon.volatiles['lightscreen']) {
return false;
@ -424,22 +498,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
},
target: "self",
},
metronome: {
inherit: true,
onHit(pokemon) {
const moves = this.dex.moves.all().filter(move => (
(!move.isNonstandard || move.isNonstandard === 'Unobtainable') && move.flags['metronome']
));
let randomMove = '';
if (moves.length) {
moves.sort((a, b) => a.num - b.num);
randomMove = this.sample(moves).id;
}
if (!randomMove) return false;
pokemon.side.lastSelectedMove = this.toID(randomMove);
this.actions.useMove(randomMove, pokemon);
},
type: "Psychic",
},
mimic: {
inherit: true,
@ -464,13 +523,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.add('-start', source, 'Mimic', move.name);
},
},
minimize: {
inherit: true,
condition: {
inherit: true,
onSourceModifyDamage() {},
},
},
mirrormove: {
inherit: true,
onHit(pokemon) {
@ -485,7 +537,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
mist: {
inherit: true,
condition: {
inherit: true,
onStart(pokemon) {
this.add('-start', pokemon, 'Mist');
},
onTryBoost(boost, target, source, effect) {
if (effect.effectType === 'Move' && effect.category !== 'Status') return;
if (source && target !== source) {
@ -601,9 +655,15 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
},
reflect: {
inherit: true,
num: 115,
accuracy: true,
basePower: 0,
category: "Status",
name: "Reflect",
pp: 20,
priority: 0,
flags: { metronome: 1 },
volatileStatus: 'reflect',
sideCondition: undefined,
onTryHit(pokemon) {
if (pokemon.volatiles['reflect']) {
return false;
@ -614,7 +674,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.add('-start', pokemon, 'Reflect');
},
},
secondary: null,
target: "self",
type: "Psychic",
},
rest: {
inherit: true,
@ -746,7 +808,15 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
onModifyMove() {},
},
substitute: {
inherit: true,
num: 164,
accuracy: true,
basePower: 0,
category: "Status",
name: "Substitute",
pp: 10,
priority: 0,
flags: { metronome: 1 },
volatileStatus: 'substitute',
onTryHit(target) {
if (target.volatiles['substitute']) {
this.add('-fail', target, 'move: Substitute');
@ -766,16 +836,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
},
condition: {
inherit: true,
onStart(target) {
this.add('-start', target, 'Substitute');
this.effectState.hp = Math.floor(target.maxhp / 4) + 1;
if (target.volatiles['partiallytrapped']) {
this.add('-end', target, target.volatiles['partiallytrapped'].sourceEffect, '[partiallytrapped]', '[silent]');
delete target.volatiles['partiallytrapped'];
}
delete target.volatiles['partiallytrapped'];
},
onTryPrimaryHit() {},
onTryHitPriority: -1,
onTryHit(target, source, move) {
if (move.category === 'Status') {
@ -797,6 +862,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
let uncappedDamage = move.hit > 1 ? this.lastDamage : this.actions.getDamage(source, target, move);
if (move.id === 'bide') uncappedDamage = source.volatiles['bide'].damage * 2;
if (!uncappedDamage && uncappedDamage !== 0) return null;
uncappedDamage = this.runEvent('SubDamage', target, source, move, uncappedDamage);
if (!uncappedDamage && uncappedDamage !== 0) return uncappedDamage;
this.lastDamage = uncappedDamage;
target.volatiles['substitute'].hp -= uncappedDamage > target.volatiles['substitute'].hp ?
target.volatiles['substitute'].hp : uncappedDamage;
@ -839,7 +906,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
return 0;
},
onEnd(target) {
this.add('-end', target, 'Substitute');
},
},
secondary: null,
target: "self",
type: "Normal",
},
superfang: {
inherit: true,
@ -877,6 +950,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
accuracy: 85,
ignoreImmunity: true,
volatileStatus: 'partiallytrapped',
self: {
volatileStatus: 'partialtrappinglock',
},
@ -886,5 +960,18 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.hint("In Gen 1, partial trapping moves negate the recharge turn of Hyper Beam, even if they miss.", true);
}
},
onHit(target, source) {
/**
* The duration of the partially trapped must be always renewed to 2
* so target doesn't move on trapper switch out as happens in gen 1.
* However, this won't happen if there's no switch and the trapper is
* about to end its partial trapping.
**/
if (target.volatiles['partiallytrapped']) {
if (source.volatiles['partialtrappinglock'] && source.volatiles['partialtrappinglock'].duration! > 1) {
target.volatiles['partiallytrapped'].duration = 2;
}
}
},
},
};

View File

@ -1,17 +1,8 @@
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
standardag: {
inherit: true,
ruleset: [
'Obtainable', 'Desync Clause Mod', 'HP Percentage Mod', 'Cancel Mod', 'Endless Battle Clause',
],
},
standard: {
effectType: 'ValidatorRule',
name: 'Standard',
ruleset: [
'Standard AG',
'Sleep Clause Mod', 'Freeze Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause',
],
ruleset: ['Obtainable', 'Desync Clause Mod', 'Sleep Clause Mod', 'Freeze Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod'],
banlist: ['Dig', 'Fly'],
},
'350cupmod': {

View File

@ -25,25 +25,6 @@ export const Scripts: ModdedBattleScriptsData = {
// BattlePokemon scripts.
pokemon: {
inherit: true,
// In gen 1, a Pokémon can have two instances of the same move using Mimic
// we need to make sure to deduct PP from a move that has PP left
deductPP(move, amount, target) {
move = this.battle.dex.moves.get(move);
// first loop: get the first instance with PP left
// second loop: get the first instance, even if it has no PP left
for (let i = 0; i < 2; i++) {
for (const ppData of this.moveSlots) {
if (ppData.id !== move.id) continue;
ppData.used = true;
if (!ppData.pp && i === 0) continue;
if (!amount) amount = 1;
ppData.pp -= amount;
return amount;
}
}
return 0;
},
getStat(statName, unmodified) {
// @ts-expect-error type checking prevents 'hp' from being passed, but we're paranoid
if (statName === 'hp') throw new Error("Please read `maxhp` directly");
@ -148,19 +129,16 @@ export const Scripts: ModdedBattleScriptsData = {
let sourceEffect = options?.sourceEffect;
const target = this.battle.getTarget(pokemon, moveOrMoveName, targetLoc);
let move = this.battle.dex.getActiveMove(moveOrMoveName);
if (move.id !== 'struggle') {
const changedMove = this.battle.runEvent('OverrideAction', pokemon, target, move);
if (changedMove && changedMove !== true) {
move = this.battle.dex.getActiveMove(changedMove);
}
}
// If a faster partial trapping move misses against a user of Hyper Beam during a recharge turn,
// the user of Hyper Beam will automatically use Hyper Beam during that turn.
if (move.id === 'recharge' && !pokemon.volatiles['mustrecharge'] && !pokemon.volatiles['partiallytrapped']) {
const autoHyperBeam = (
move.id === 'recharge' && !pokemon.volatiles['mustrecharge'] && !pokemon.volatiles['partiallytrapped']
);
if (autoHyperBeam) {
move = this.battle.dex.getActiveMove('hyperbeam');
this.battle.hint(`In Gen 1, partial trapping moves like Wrap remove Hyper Beam recharges. ` +
`If the target would have recharged, it will automatically use Hyper Beam instead.`, true);
this.battle.hint(`In Gen 1, If a faster partial trapping move misses against a user of Hyper Beam during a recharge turn, ` +
`the user of Hyper Beam will automatically use Hyper Beam during that turn.`, true);
}
if (target?.subFainted) target.subFainted = null;
@ -173,31 +151,41 @@ export const Scripts: ModdedBattleScriptsData = {
this.battle.runEvent('AfterMoveSelf', pokemon, target, move);
return;
}
if (move.beforeMoveCallback?.call(this.battle, pokemon, target, move)) {
this.battle.clearActiveMove(true);
return;
}
const lockedMove = pokemon.getLockedMove();
if (lockedMove) sourceEffect = move;
// Locked moves don't deduct PP
// Two-turn moves like Sky Attack deduct PP on their second turn.
if (!lockedMove || pokemon.volatiles['twoturnmove']) {
const ppMove = pokemon.volatiles['twoturnmove']?.ppMove || move.id;
pokemon.deductPP(ppMove, null, target);
const moveSlot = pokemon.getMoveData(ppMove);
if (moveSlot && moveSlot.pp < 0) {
moveSlot.pp += 64;
this.battle.hint("In Gen 1, if a pokemon is forced to use a move with 0 PP, the move will underflow to have 63 PP.");
if (move.beforeMoveCallback) {
if (move.beforeMoveCallback.call(this.battle, pokemon, target, move)) {
this.battle.clearActiveMove(true);
return;
}
}
let lockedMove = this.battle.runEvent('LockMove', pokemon);
if (lockedMove === true) lockedMove = false;
if (
!lockedMove &&
(!pokemon.volatiles['partialtrappinglock'] || pokemon.volatiles['partialtrappinglock'].locked !== target)
) {
pokemon.deductPP(move, null, target);
} else {
sourceEffect = move;
if (pokemon.volatiles['twoturnmove']) {
// Two-turn moves like Sky Attack deduct PP on their second turn.
pokemon.deductPP(pokemon.volatiles['twoturnmove'].originalMove, null, target);
}
}
if (
(pokemon.volatiles['partialtrappinglock'] && target !== pokemon.volatiles['partialtrappinglock'].locked) ||
autoHyperBeam
) {
const moveSlot = pokemon.moveSlots.find(ms => ms.id === move.id);
if (moveSlot && moveSlot.pp < 0) {
moveSlot.pp = 63;
this.battle.hint("In Gen 1, if a player is forced to use a move with 0 PP, the move will underflow to have 63 PP.");
}
}
this.useMove(move, pokemon, { target, sourceEffect });
// Restore PP if the move is the first turn of a charging move. Save the move from which PP should be deducted if the move succeeds.
if (pokemon.volatiles['twoturnmove']) {
pokemon.deductPP(move, -1, target);
pokemon.volatiles['twoturnmove'].ppMove = move.id;
pokemon.volatiles['twoturnmove'].originalMove = move.id;
}
},
// This function deals with AfterMoveSelf events.
@ -235,9 +223,37 @@ export const Scripts: ModdedBattleScriptsData = {
// The move is our 'final' move (a failed Mirror Move, or any move that isn't Metronome or Mirror Move).
pokemon.side.lastMove = move;
this.battle.runEvent('AfterMove', pokemon, target, move);
if (!target || target.hp > 0) {
this.battle.runEvent('AfterMoveSelf', pokemon, target, move);
if (pokemon.volatiles['lockedmove']?.time <= 0) pokemon.removeVolatile('lockedmove');
// If target fainted
if (target && target.hp <= 0) {
// We remove recharge
if (pokemon.volatiles['mustrecharge']) pokemon.removeVolatile('mustrecharge');
delete pokemon.volatiles['partialtrappinglock'];
} else {
if (pokemon.volatiles['mustrecharge']) this.battle.add('-mustrecharge', pokemon);
if (pokemon.hp) this.battle.runEvent('AfterMoveSelf', pokemon, target, move);
}
// For partial trapping moves, we are saving the target
if (move.volatileStatus === 'partiallytrapped' && target && target.hp > 0) {
// Let's check if the lock exists
if (pokemon.volatiles['partialtrappinglock'] && target.volatiles['partiallytrapped']) {
// Here the partialtrappinglock volatile has been already applied
const sourceVolatile = pokemon.volatiles['partialtrappinglock'];
const targetVolatile = target.volatiles['partiallytrapped'];
if (!sourceVolatile.locked) {
// If it's the first hit, we save the target
sourceVolatile.locked = target;
} else if (target !== pokemon && target !== sourceVolatile.locked) {
// Our target switched out! Re-roll the duration, damage, and accuracy.
const duration = this.battle.sample([2, 2, 2, 3, 3, 3, 4, 5]);
sourceVolatile.duration = duration;
sourceVolatile.locked = target;
// Duration reset thus partially trapped at 2 always.
targetVolatile.duration = 2;
}
} // If we move to here, the move failed and there's no partial trapping lock.
}
}
}
@ -277,7 +293,7 @@ export const Scripts: ModdedBattleScriptsData = {
return false;
}
if (sourceEffect) attrs += `|[from] ${this.battle.dex.conditions.get(sourceEffect).name}`;
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)) {
@ -316,8 +332,10 @@ export const Scripts: ModdedBattleScriptsData = {
return true;
}
this.battle.singleEvent('AfterMoveSecondarySelf', move, null, pokemon, target, move);
this.battle.runEvent('AfterMoveSecondarySelf', pokemon, target, move);
if (!move.negateSecondary) {
this.battle.singleEvent('AfterMoveSecondarySelf', move, null, pokemon, target, move);
this.battle.runEvent('AfterMoveSecondarySelf', pokemon, target, move);
}
return true;
},
// This function attempts a move hit and returns the attempt result before the actual hit happens.
@ -352,7 +370,10 @@ export const Scripts: ModdedBattleScriptsData = {
}
// Then, check if the Pokémon is immune to this move.
if (!target.runImmunity(move, true)) {
if (
(!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) &&
!target.runImmunity(move.type, true)
) {
if (move.selfdestruct) {
this.battle.faint(pokemon, pokemon, move);
}
@ -367,6 +388,11 @@ export const Scripts: ModdedBattleScriptsData = {
// Now, let's calculate the accuracy.
let accuracy = move.accuracy;
// Partial trapping moves: true accuracy while it lasts
if (move.volatileStatus === 'partiallytrapped' && target === pokemon.volatiles['partialtrappinglock']?.locked) {
accuracy = true;
}
// If a sleep inducing move is used while the user is recharging, the accuracy is true.
if (move.status === 'slp' && target?.volatiles['mustrecharge']) {
accuracy = true;
@ -473,8 +499,10 @@ export const Scripts: ModdedBattleScriptsData = {
if (move.ohko) this.battle.add('-ohko');
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
if (!move.negateSecondary) {
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
}
return damage;
},
@ -499,6 +527,14 @@ export const Scripts: ModdedBattleScriptsData = {
if (target) {
hitResult = this.battle.singleEvent('TryHit', moveData, {}, target, pokemon, move);
// Handle here the applying of partial trapping moves to Pokémon with Substitute
if (targetSub && moveData.volatileStatus && moveData.volatileStatus === 'partiallytrapped') {
target.addVolatile(moveData.volatileStatus, pokemon, move);
if (!pokemon.volatiles['partialtrappinglock'] || pokemon.volatiles['partialtrappinglock'].duration! > 1) {
target.volatiles[moveData.volatileStatus].duration = 2;
}
}
if (!hitResult) {
if (hitResult === false) this.battle.add('-fail', target);
return false;
@ -573,7 +609,7 @@ export const Scripts: ModdedBattleScriptsData = {
didSomething = true;
// Check the status of the Pokémon whose turn is not.
// When a move that affects stat levels is used, if the Pokémon whose turn it is not right now is paralyzed or
// burned, the corresponding stat penalties will be applied again to that Pokémon.
// burned, the correspoding stat penalties will be applied again to that Pokémon.
if (pokemon.side.foe.active[0].status) {
// If it's paralysed, quarter its speed.
if (pokemon.side.foe.active[0].status === 'par') {
@ -664,6 +700,11 @@ export const Scripts: ModdedBattleScriptsData = {
this.moveHit(pokemon, pokemon, move, moveData.self, isSecondary, true);
}
// Now we can save the partial trapping damage.
if (pokemon.volatiles['partialtrappinglock']) {
pokemon.volatiles['partialtrappinglock'].damage = this.battle.lastDamage;
}
// Apply move secondaries.
if (moveData.secondaries && target && target.hp > 0) {
for (const secondary of moveData.secondaries) {
@ -710,8 +751,10 @@ export const Scripts: ModdedBattleScriptsData = {
}
// Let's see if the target is immune to the move.
if (!target.runImmunity(move, true)) {
return false;
if (!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) {
if (!target.runImmunity(move.type, true)) {
return false;
}
}
// Is it an OHKO move?
@ -735,7 +778,7 @@ export const Scripts: ModdedBattleScriptsData = {
}
// If it's the first hit on a Normal-type partially trap move, it hits Ghosts anyways but damage is 0.
if (move.self?.volatileStatus === 'partialtrappinglock' && move.type === 'Normal' && target.hasType('Ghost')) {
if (move.volatileStatus === 'partiallytrapped' && move.type === 'Normal' && target.hasType('Ghost')) {
return 0;
}

View File

@ -13,7 +13,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
substitute: {
inherit: true,
condition: {
inherit: true,
onStart(target) {
this.add('-start', target, 'Substitute');
this.effectState.hp = Math.floor(target.maxhp / 4) + 1;
delete target.volatiles['partiallytrapped'];
},
onTryHitPriority: -1,
onTryHit(target, source, move) {
if (move.drain) {
this.add('-miss', source);
@ -34,8 +39,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
// NOTE: In future generations the damage is capped to the remaining HP of the
// Substitute, here we deliberately use the uncapped damage when tracking lastDamage etc.
// Also, multi-hit moves must always deal the same damage as the first hit for any subsequent hits
const uncappedDamage = move.hit > 1 ? this.lastDamage : this.actions.getDamage(source, target, move);
let uncappedDamage = move.hit > 1 ? this.lastDamage : this.actions.getDamage(source, target, move);
if (!uncappedDamage && uncappedDamage !== 0) return null;
uncappedDamage = this.runEvent('SubDamage', target, source, move, uncappedDamage);
if (!uncappedDamage && uncappedDamage !== 0) return uncappedDamage;
this.lastDamage = uncappedDamage;
target.volatiles['substitute'].hp -= uncappedDamage > target.volatiles['substitute'].hp ?
target.volatiles['substitute'].hp : uncappedDamage;
@ -71,6 +78,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
return accuracy;
},
onEnd(target) {
this.add('-end', target, 'Substitute');
},
},
},
swift: {

View File

@ -2,10 +2,7 @@ export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable
standard: {
effectType: 'ValidatorRule',
name: 'Standard',
ruleset: [
'Standard AG',
'Sleep Clause Mod', 'Freeze Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause',
],
ruleset: ['Obtainable', 'Desync Clause Mod', 'Sleep Clause Mod', 'Freeze Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod'],
banlist: ['Dig', 'Fly'],
},
nc1997movelegality: {

View File

@ -225,7 +225,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "NFE",
},
golem: {
tier: "UU",
tier: "OU",
},
ponyta: {
tier: "LC",
@ -270,7 +270,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
cloyster: {
tier: "UU",
tier: "OU",
},
gastly: {
tier: "LC",
@ -279,7 +279,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "UU",
},
gengar: {
tier: "UU",
tier: "OU",
},
onix: {
tier: "UU",
@ -342,7 +342,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "UU",
},
kangaskhan: {
tier: "UU",
tier: "OU",
},
horsea: {
tier: "LC",
@ -369,7 +369,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "UU",
},
jynx: {
tier: "UU",
tier: "OU",
},
electabuzz: {
tier: "UU",
@ -402,7 +402,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "UU",
},
jolteon: {
tier: "UU",
tier: "OU",
},
flareon: {
tier: "UU",

View File

@ -160,11 +160,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
volatileStatus: 'rage',
},
condition: {
inherit: true,
// Rage lock
onStart(target, source, effect) {
this.effectState.move = 'rage';
},
onLockMove: 'rage',
onHit(target, source, move) {
if (target.boosts.atk < 6 && (move.category !== 'Status' || move.id === 'disable')) {
this.boost({ atk: 1 });
@ -220,7 +220,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
},
condition: {
inherit: true,
onStart(target) {
this.add('-start', target, 'Substitute');
this.effectState.hp = Math.floor(target.maxhp / 4);
delete target.volatiles['partiallytrapped'];
},
onTryHitPriority: -1,
onTryHit(target, source, move) {
if (target === source) {
this.debug('sub bypass: self hit');
@ -244,6 +249,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
damage = target.volatiles['substitute'].hp;
}
if (!damage && damage !== 0) return null;
damage = this.runEvent('SubDamage', target, source, move, damage);
if (!damage && damage !== 0) return damage;
target.volatiles['substitute'].hp -= damage;
this.lastDamage = damage;
if (target.volatiles['substitute'].hp <= 0) {
@ -270,6 +277,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
return 0;
},
onEnd(target) {
this.add('-end', target, 'Substitute');
},
},
secondary: null,
target: "self",

View File

@ -1,763 +1,7 @@
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
standardag: {
inherit: true,
ruleset: [
'Obtainable', 'Exact HP Mod', 'Cancel Mod',
],
},
standard: {
effectType: 'ValidatorRule',
name: 'Standard',
ruleset: [
'Standard AG',
'Stadium Sleep Clause', 'Freeze Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause',
],
},
stadiumpokecuprentals: {
inherit: true,
onChangeSet(set, format, setHas, teamHas) {
set.level = 50;
switch (this.dex.species.get(set.species).name) {
case 'Bulbasaur':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Leech Seed', 'Toxic', 'Body Slam', 'Razor Leaf'];
break;
case 'Ivysaur':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Razor Leaf', 'Sleep Powder', 'Growth', 'Double-Edge'];
break;
case 'Venusaur':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Psychic', 'Seismic Toss', 'Reflect', 'Thunder Wave'];
break;
case 'Charmander':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Flamethrower', 'Slash', 'Dig', 'Fire Spin'];
break;
case 'Charmeleon':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Flamethrower', 'Counter', 'Seismic Toss', 'Strength'];
break;
case 'Charizard':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Fly', 'Swords Dance', 'Fire Spin', 'Fire Blast'];
break;
case 'Squirtle':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Surf', 'Blizzard', 'Body Slam', 'Dig'];
break;
case 'Wartortle':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Surf', 'Strength', 'Rest', 'Ice Beam'];
break;
case 'Blastoise':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Hydro Pump', 'Skull Bash', 'Withdraw', 'Seismic Toss'];
break;
case 'Caterpie':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['String Shot', 'Tackle'];
break;
case 'Metapod':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['String Shot', 'Tackle'];
break;
case 'Butterfree':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Psychic', 'Supersonic', 'Mega Drain', 'Stun Spore'];
break;
case 'Weedle':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['String Shot', 'Poison Sting'];
break;
case 'Kakuna':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['String Shot', 'Poison Sting'];
break;
case 'Beedrill':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Twineedle', 'Hyper Beam', 'Toxic', 'Focus Energy'];
break;
case 'Pidgey':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Fly', 'Toxic', 'Double-Edge', 'Double Team'];
break;
case 'Pidgeotto':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Fly', 'Quick Attack', 'Sand Attack', 'Take Down'];
break;
case 'Pidgeot':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Mirror Move', 'Fly', 'Quick Attack', 'Sand Attack'];
break;
case 'Rattata':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Super Fang', 'Blizzard', 'Quick Attack', 'Hyper Fang'];
break;
case 'Raticate':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Hyper Fang', 'Hyper Beam', 'Focus Energy', 'Thunder'];
break;
case 'Spearow':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Drill Peck', 'Mirror Move', 'Double Team', 'Double-Edge'];
break;
case 'Fearow':
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
set.moves = ['Drill Peck', 'Mirror Move', 'Fury Attack', 'Swift'];
break;
case 'Ekans':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Earthquake', 'Acid', 'Screech', 'Body Slam'];
break;
case 'Arbok':
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
set.moves = ['Glare', 'Wrap', 'Dig', 'Strength'];
break;
case 'Pikachu':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Thunderbolt', 'Slam', 'Thunder Wave', 'Seismic Toss'];
break;
case 'Raichu':
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
set.moves = ['Thunder', 'Thunder Wave', 'Flash', 'Mega Kick'];
break;
case 'Sandshrew':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Earthquake', 'Slash', 'Seismic Toss', 'Sand Attack'];
break;
case 'Sandslash':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Dig', 'Swift', 'Seismic Toss', 'Sand Attack'];
break;
case 'Nidoran-F':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Toxic', 'Thunderbolt', 'Body Slam', 'Blizzard'];
break;
case 'Nidorina':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Toxic', 'Thunder', 'Double-Edge', 'Ice Beam'];
break;
case 'Nidoqueen':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Toxic', 'Double Kick', 'Bite', 'Earthquake'];
break;
case 'Nidoran-M':
set.evs = { hp: 177, atk: 176, def: 176, spa: 176, spd: 176, spe: 176 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Blizzard', 'Body Slam', 'Thunderbolt', 'Focus Energy'];
break;
case 'Nidorino':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Double-Edge', 'Horn Drill', 'Focus Energy', 'Thunder'];
break;
case 'Nidoking':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Earthquake', 'Horn Drill', 'Rage', 'Substitute'];
break;
case 'Clefairy':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Thunderbolt', 'Psychic', 'Body Slam', 'Blizzard'];
break;
case 'Clefable':
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
set.moves = ['Sing', 'Tri Attack', 'Minimize', 'Ice Beam'];
break;
case 'Vulpix':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Flamethrower', 'Dig', 'Confuse Ray', 'Double-Edge'];
break;
case 'Ninetales':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Fire Blast', 'Skull Bash', 'Confuse Ray', 'Tail Whip'];
break;
case 'Jigglypuff':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Sing', 'Body Slam', 'Seismic Toss', 'Psychic'];
break;
case 'Wigglytuff':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Sing', 'Double-Edge', 'Submission', 'Thunderbolt'];
break;
case 'Zubat':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Confuse Ray', 'Mega Drain', 'Toxic', 'Double-Edge'];
break;
case 'Golbat':
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
set.moves = ['Confuse Ray', 'Mega Drain', 'Bite', 'Haze'];
break;
case 'Oddish':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Petal Dance', 'Toxic', 'Mega Drain', 'Double-Edge'];
break;
case 'Gloom':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Petal Dance', 'Take Down', 'Mega Drain', 'Stun Spore'];
break;
case 'Vileplume':
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
set.moves = ['Petal Dance', 'Sleep Powder', 'Acid', 'Cut'];
break;
case 'Paras':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Spore', 'Slash', 'Dig', 'Mega Drain'];
break;
case 'Parasect':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Spore', 'Take Down', 'Dig', 'Solar Beam'];
break;
case 'Venonat':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Psychic', 'Mega Drain', 'Double-Edge', 'Stun Spore'];
break;
case 'Venomoth':
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
set.moves = ['Psychic', 'Supersonic', 'Solar Beam', 'Swift'];
break;
case 'Diglett':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Earthquake', 'Slash', 'Sand Attack', 'Rock Slide'];
break;
case 'Dugtrio':
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
set.moves = ['Dig', 'Sand Attack', 'Toxic', 'Hyper Beam'];
break;
case 'Meowth':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Slash', 'Thunderbolt', 'Swift', 'Double Team'];
break;
case 'Persian':
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
set.moves = ['Slash', 'Bubble Beam', 'Mimic', 'Growl'];
break;
case 'Psyduck':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Surf', 'Confusion', 'Dig', 'Blizzard'];
break;
case 'Golduck':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Ice Beam', 'Surf', 'Toxic', 'Disable'];
break;
case 'Mankey':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Submission', 'Rock Slide', 'Seismic Toss', 'Screech'];
break;
case 'Primeape':
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
set.moves = ['Fury Swipes', 'Rock Slide', 'Low Kick', 'Screech'];
break;
case 'Growlithe':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Flamethrower', 'Body Slam', 'Reflect', 'Dig'];
break;
case 'Arcanine':
set.evs = { hp: 105, atk: 104, def: 104, spa: 104, spd: 104, spe: 104 };
set.ivs = { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 };
set.moves = ['Fire Blast', 'Take Down', 'Dragon Rage', 'Substitute'];
break;
case 'Poliwag':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Body Slam', 'Blizzard', 'Surf', 'Amnesia'];
break;
case 'Poliwhirl':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Hypnosis', 'Surf', 'Ice Beam', 'Earthquake'];
break;
case 'Poliwrath':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Hypnosis', 'Submission', 'Counter', 'Hydro Pump'];
break;
case 'Abra':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Psychic', 'Seismic Toss', 'Reflect', 'Thunder Wave'];
break;
case 'Kadabra':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Psychic', 'Counter', 'Recover', 'Dig'];
break;
case 'Alakazam':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Psybeam', 'Metronome', 'Disable', 'Tri Attack'];
break;
case 'Machop':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Submission', 'Rock Slide', 'Earthquake', 'Focus Energy'];
break;
case 'Machoke':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Submission', 'Strength', 'Rock Slide', 'Focus Energy'];
break;
case 'Machamp':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Low Kick', 'Strength', 'Counter', 'Focus Energy'];
break;
case 'Bellsprout':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Razor Leaf', 'Growth', 'Mega Drain', 'Stun Spore'];
break;
case 'Weepinbell':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Razor Leaf', 'Acid', 'Wrap', 'Toxic'];
break;
case 'Victreebel':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Solar Beam', 'Acid', 'Reflect', 'Slam'];
break;
case 'Tentacool':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Surf', 'Supersonic', 'Mega Drain', 'Blizzard'];
break;
case 'Tentacruel':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Acid', 'Supersonic', 'Hydro Pump', 'Cut'];
break;
case 'Geodude':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Earthquake', 'Seismic Toss', 'Rock Slide', 'Explosion'];
break;
case 'Graveler':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Earthquake', 'Seismic Toss', 'Strength', 'Self-Destruct'];
break;
case 'Golem':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Dig', 'Seismic Toss', 'Fire Blast', 'Metronome'];
break;
case 'Ponyta':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Fire Blast', 'Agility', 'Horn Drill', 'Body Slam'];
break;
case 'Rapidash':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Fire Blast', 'Stomp', 'Toxic', 'Fire Spin'];
break;
case 'Slowpoke':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Surf', 'Psychic', 'Thunder Wave', 'Amnesia'];
break;
case 'Slowbro':
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
set.moves = ['Surf', 'Psychic', 'Disable', 'Withdraw'];
break;
case 'Magnemite':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Thunderbolt', 'Thunder Wave', 'Supersonic', 'Double-Edge'];
break;
case 'Magneton':
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
set.moves = ['Thunderbolt', 'Screech', 'Supersonic', 'Swift'];
break;
case 'Farfetch\u2019d':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Slash', 'Sand Attack', 'Toxic', 'Fly'];
break;
case 'Doduo':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Drill Peck', 'Tri Attack', 'Double Team', 'Reflect'];
break;
case 'Dodrio':
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
set.moves = ['Fly', 'Tri Attack', 'Agility', 'Reflect'];
break;
case 'Seel':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Ice Beam', 'Body Slam', 'Horn Drill', 'Surf'];
break;
case 'Dewgong':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Aurora Beam', 'Heabutt', 'Rest', 'Surf'];
break;
case 'Grimer':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Sludge', 'Body Slam', 'Explosion', 'Screech'];
break;
case 'Muk':
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
set.moves = ['Sludge', 'Thunderbolt', 'Hyper Beam', 'Self-Destruct'];
break;
case 'Shellder':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Surf', 'Explosion', 'Blizzard', 'Tri Attack'];
break;
case 'Cloyster':
set.evs = { hp: 105, atk: 104, def: 104, spa: 104, spd: 104, spe: 104 };
set.ivs = { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 };
set.moves = ['Clamp', 'Spike Cannon', 'Ice Beam', 'Supersonic'];
break;
case 'Gastly':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Hypnosis', 'Dream Eater', 'Psychic', 'Confuse Ray'];
break;
case 'Haunter':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Mega Drain', 'Psychic', 'Explosion', 'Confuse Ray'];
break;
case 'Gengar':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Thunderbolt', 'Night Shade', 'Hypnosis', 'Confuse Ray'];
break;
case 'Onix':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Earthquake', 'Rock Slide', 'Strength', 'Explosion'];
break;
case 'Drowzee':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Hypnois', 'Dream Eater', 'Psychic', 'Tri Attack'];
break;
case 'Hypno':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Hypnosis', 'Headbutt', 'Dream Eater', 'Meditate'];
break;
case 'Krabby':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Crabhammer', 'Guillotine', 'Double-Edge', 'Blizzard'];
break;
case 'Kingler':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Crabhammer', 'Guillotine', 'Stomp', 'Substitute'];
break;
case 'Voltorb':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Thunderbolt', 'Thunder Wave', 'Swift', 'Explosion'];
break;
case 'Electrode':
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
set.moves = ['Thunder', 'Thunder Wave', 'Swift', 'Self-Destruct'];
break;
case 'Exeggcute':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Psychic', 'Explosion', 'Leech Seed', 'Toxic'];
break;
case 'Exeggutor':
set.evs = { hp: 105, atk: 104, def: 104, spa: 104, spd: 104, spe: 104 };
set.ivs = { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 };
set.moves = ['Mega Drain', 'Stun Spore', 'Leech Seed', 'Egg Bomb'];
break;
case 'Cubone':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Earthquake', 'Submission', 'Blizzard', 'Strength'];
break;
case 'Marowak':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Bonemerang', 'Thrash', 'Fire Blast', 'Focus Energy'];
break;
case 'Hitmonlee':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['High Jump Kick', 'Mega Kick', 'Metronome', 'Seismic Toss'];
break;
case 'Hitmonchan':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Submission', 'Thunder Punch', 'Ice Punch', 'Strength'];
break;
case 'Lickitung':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Strength', 'Blizzard', 'Thunder', 'Fire Blast'];
break;
case 'Koffing':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Sludge', 'Toxic', 'Thunderbolt', 'Explosion'];
break;
case 'Weezing':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Sludge', 'Hyper Beam', 'Fire Blast', 'Self-Destruct'];
break;
case 'Rhyhorn':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Earthquake', 'Body Slam', 'Rock Slide', 'Fire Blast'];
break;
case 'Rhydon':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Dig', 'Strength', 'Thunder', 'Surf'];
break;
case 'Chansey':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Thunder', 'Fire Blast', 'Minimize', 'Rest'];
break;
case 'Tangela':
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
set.moves = ['Mega Drain', 'Growth', 'Toxic', 'Double-Edge'];
break;
case 'Kangaskhan':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Dizzy Punch', 'Rock Slide', 'Surf', 'Thunderbolt'];
break;
case 'Horsea':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Hydro Pump', 'Toxic', 'Smokescreen', 'Ice Beam'];
break;
case 'Seadra':
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
set.moves = ['Surf', 'Toxic', 'Smokescreen', 'Swift'];
break;
case 'Goldeen':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Surf', 'Supersonic', 'Horn Drill', 'Blizzard'];
break;
case 'Seaking':
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
set.moves = ['Waterfall', 'Supersonic', 'Horn Attack', 'Ice Beam'];
break;
case 'Staryu':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Hydro Pump', 'Recover', 'Thunderbolt', 'Psychic'];
break;
case 'Starmie':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Surf', 'Thunder', 'Swift', 'Harden'];
break;
case 'Mr. Mime':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Barrier', 'Psychic', 'Metronome', 'Seismic Toss'];
break;
case 'Scyther':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Slash', 'Wing Attack', 'Leer', 'Double Team'];
break;
case 'Jynx':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Ice Punch', 'Mega Punch', 'Psychic', 'Lovely Kiss'];
break;
case 'Electabuzz':
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
set.moves = ['Thunder Punch', 'Mega Punch', 'Psychic', 'Thunder Wave'];
break;
case 'Magmar':
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
set.moves = ['Fire Punch', 'Mega Punch', 'Psychic', 'Smokescreen'];
break;
case 'Pinsir':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Strength', 'Harden', 'Seismic Toss', 'Guillotine'];
break;
case 'Tauros':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Double-Edge', 'Fire Blast', 'Tail Whip', 'Bide'];
break;
case 'Magikarp':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Splash', 'Tackle'];
break;
case 'Gyarados':
set.evs = { hp: 105, atk: 104, def: 104, spa: 104, spd: 104, spe: 104 };
set.ivs = { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 };
set.moves = ['Surf', 'Dragon Rage', 'Bite', 'Fire Blast'];
break;
case 'Lapras':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Ice Beam', 'Solar Beam', 'Body Slam', 'Sing'];
break;
case 'Ditto':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Transform'];
break;
case 'Eevee':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Body Slam', 'Swift', 'Sand Attack', 'Toxic'];
break;
case 'Vaporeon':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Surf', 'Quick Attack', 'Sand Attack', 'Acid Armor'];
break;
case 'Jolteon':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Thunderbolt', 'Pin Missile', 'Toxic', 'Sand Attack'];
break;
case 'Flareon':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Fire Blast', 'Take Down', 'Smog', 'Sand Attack'];
break;
case 'Omanyte':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Surf', 'Ice Beam', 'Double Edge', 'Double Team'];
break;
case 'Omastar':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Hydro Pump', 'Submission', 'Spike Cannon', 'Withdraw'];
break;
case 'Kabuto':
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
set.moves = ['Hydro Pump', 'Blizzard', 'Slash', 'Double Team'];
break;
case 'Kabutops':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Surf', 'Swords Dance', 'Mega Kick', 'Submission'];
break;
case 'Aerodactyl':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Fly', 'Hyper Beam', 'Supersonic', 'Dragon Rage'];
break;
case 'Snorlax':
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
set.moves = ['Mega Kick', 'Rock Slide', 'Metronome', 'Rest'];
break;
case 'Articuno':
set.evs = { hp: 97, atk: 96, def: 96, spa: 96, spd: 96, spe: 96 };
set.ivs = { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 };
set.moves = ['Ice Beam', 'Sky Attack', 'Razor Wind', 'Substitute'];
break;
case 'Zapdos':
set.evs = { hp: 97, atk: 96, def: 96, spa: 96, spd: 96, spe: 96 };
set.ivs = { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 };
set.moves = ['Thunderbolt', 'Sky Attack', 'Thunder Wave', 'Flash'];
break;
case 'Moltres':
set.evs = { hp: 97, atk: 96, def: 96, spa: 96, spd: 96, spe: 96 };
set.ivs = { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 };
set.moves = ['Fire Blast', 'Fly', 'Swift', 'Substitute'];
break;
case 'Dratini':
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
set.moves = ['Hyper Beam', 'Body Slam', 'Thunderbolt', 'Thunder Wave'];
break;
case 'Dragonair':
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
set.moves = ['Hyper Beam', 'Swift', 'Ice Beam', 'Thunder Wave'];
break;
case 'Dragonite':
set.evs = { hp: 97, atk: 96, def: 96, spa: 96, spd: 96, spe: 96 };
set.ivs = { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 };
set.moves = ['Slam', 'Dragon Rage', 'Thunder', 'Agility'];
}
},
ruleset: ['Obtainable', 'Stadium Sleep Clause', 'Freeze Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'Exact HP Mod', 'Cancel Mod'],
},
};

View File

@ -199,7 +199,7 @@ export const Scripts: ModdedBattleScriptsData = {
return false;
}
if (sourceEffect) attrs += `|[from] ${this.battle.dex.conditions.get(sourceEffect).name}`;
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)) {
@ -231,8 +231,10 @@ export const Scripts: ModdedBattleScriptsData = {
return true;
}
this.battle.singleEvent('AfterMoveSecondarySelf', move, null, pokemon, target, move);
this.battle.runEvent('AfterMoveSecondarySelf', pokemon, target, move);
if (!move.negateSecondary) {
this.battle.singleEvent('AfterMoveSecondarySelf', move, null, pokemon, target, move);
this.battle.runEvent('AfterMoveSecondarySelf', pokemon, target, move);
}
return true;
},
tryMoveHit(target, pokemon, move) {
@ -250,7 +252,10 @@ export const Scripts: ModdedBattleScriptsData = {
}
// Then, check if the Pokemon is immune to this move.
if (!target.runImmunity(move, true)) {
if (
(!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) &&
!target.runImmunity(move.type, true)
) {
if (move.selfdestruct) {
this.battle.faint(pokemon, pokemon, move);
}
@ -300,16 +305,10 @@ export const Scripts: ModdedBattleScriptsData = {
}
accuracy = this.battle.runEvent('Accuracy', target, pokemon, move, accuracy);
// Stadium attempts to fix the 1/256 miss by rerolling if the first value
// would trigger the 1/256 miss.
let randomValue = this.battle.random(256);
if (randomValue === 256) randomValue = this.battle.random(256);
if (accuracy !== true && randomValue > accuracy) {
// Stadium fixes the 1/256 accuracy bug.
if (accuracy !== true && !this.battle.randomChance(accuracy + 1, 256)) {
this.battle.attrLastMove('[miss]');
this.battle.add('-miss', pokemon);
if (accuracy === 255) {
this.battle.hint("In Pokemon Stadium, moves with 100% accuracy can still miss 1/65536 of the time.");
}
damage = false;
this.battle.lastDamage = 0;
}
@ -366,8 +365,10 @@ export const Scripts: ModdedBattleScriptsData = {
if (move.ohko) this.battle.add('-ohko');
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
if (!move.negateSecondary) {
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
}
return damage;
},
@ -548,8 +549,10 @@ export const Scripts: ModdedBattleScriptsData = {
}
// Let's see if the target is immune to the move.
if (!target.runImmunity(move, true)) {
return false;
if (!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) {
if (!target.runImmunity(move.type, true)) {
return false;
}
}
// Is it an OHKO move?

View File

@ -18,7 +18,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
inherit: true,
onBeforeMovePriority: 2,
onBeforeMove(pokemon) {
if (this.randomChance(63, 256)) {
if (this.randomChance(1, 4)) {
this.add('cant', pokemon, 'par');
return false;
}
@ -177,11 +177,6 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
onStart(target, source, effect) {
this.effectState.move = effect.id;
},
onAfterMove(pokemon) {
if (this.effectState.duration === 1) {
pokemon.removeVolatile('lockedmove');
}
},
onEnd(target) {
// Confusion begins even if already confused
delete target.volatiles['confusion'];

View File

@ -12,7 +12,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
charmeleon: {
tier: "ZUBL",
tier: "ZU",
},
charizard: {
tier: "UUBL",
@ -21,7 +21,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
wartortle: {
tier: "PU",
tier: "ZU",
},
blastoise: {
tier: "UU",
@ -57,7 +57,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
raticate: {
tier: "PU",
tier: "NU",
},
spearow: {
tier: "LC",
@ -69,7 +69,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
arbok: {
tier: "PU",
tier: "NU",
},
pichu: {
tier: "LC",
@ -162,7 +162,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "PU",
},
diglett: {
tier: "LC",
tier: "ZU",
},
dugtrio: {
tier: "NU",
@ -192,10 +192,10 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "UU",
},
poliwag: {
tier: "ZUBL",
tier: "ZU",
},
poliwhirl: {
tier: "PUBL",
tier: "ZUBL",
},
poliwrath: {
tier: "NUBL",
@ -237,7 +237,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "UUBL",
},
geodude: {
tier: "PU",
tier: "ZU",
},
graveler: {
tier: "NU",
@ -246,13 +246,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "OU",
},
ponyta: {
tier: "ZU",
tier: "PU",
},
rapidash: {
tier: "NU",
},
slowpoke: {
tier: "LC",
tier: "ZU",
},
slowbro: {
tier: "UU",
@ -267,7 +267,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "UU",
},
farfetchd: {
tier: "PU",
tier: "NU",
},
doduo: {
tier: "ZU",
@ -321,7 +321,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "NU",
},
voltorb: {
tier: "PU",
tier: "ZU",
},
electrode: {
tier: "UU",
@ -345,10 +345,10 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "NU",
},
hitmonchan: {
tier: "PU",
tier: "PUBL",
},
hitmontop: {
tier: "NU",
tier: "PU",
},
lickitung: {
tier: "NU",
@ -513,7 +513,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
bayleef: {
tier: "PU",
tier: "ZU",
},
meganium: {
tier: "UUBL",
@ -534,13 +534,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "ZU",
},
feraligatr: {
tier: "UU",
tier: "NUBL",
},
sentret: {
tier: "LC",
},
furret: {
tier: "PU",
tier: "PUBL",
},
hoothoot: {
tier: "LC",
@ -558,7 +558,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
ariados: {
tier: "ZUBL",
tier: "PU",
},
chinchou: {
tier: "NU",
@ -591,7 +591,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
azumarill: {
tier: "PU",
tier: "NU",
},
sudowoodo: {
tier: "NU",
@ -645,7 +645,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "OU",
},
dunsparce: {
tier: "PU",
tier: "NU",
},
gligar: {
tier: "UU",
@ -699,13 +699,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "PU",
},
mantine: {
tier: "ZUBL",
tier: "ZU",
},
skarmory: {
tier: "OU",
},
houndour: {
tier: "PU",
tier: "NU",
},
houndoom: {
tier: "UUBL",

View File

@ -252,11 +252,11 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
}
},
},
berry: {
berserkgene: {
inherit: true,
isNonstandard: null,
},
berserkgene: {
berry: {
inherit: true,
isNonstandard: null,
},

View File

@ -51,10 +51,64 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
bide: {
inherit: true,
condition: {
inherit: true,
duration: 3,
durationCallback(target, source, effect) {
return this.random(3, 5);
},
onLockMove: 'bide',
onStart(pokemon) {
this.effectState.totalDamage = 0;
this.add('-start', pokemon, 'move: Bide');
},
onDamagePriority: -101,
onDamage(damage, target, source, move) {
if (!move || move.effectType !== 'Move' || !source) return;
this.effectState.totalDamage += damage;
this.effectState.lastDamageSource = source;
},
onBeforeMove(pokemon, target, move) {
if (this.effectState.duration === 1) {
this.add('-end', pokemon, 'move: Bide');
if (!this.effectState.totalDamage) {
this.add('-fail', pokemon);
return false;
}
target = this.effectState.lastDamageSource;
if (!target) {
this.add('-fail', pokemon);
return false;
}
if (!target.isActive) {
const possibleTarget = this.getRandomTarget(pokemon, this.dex.moves.get('pound'));
if (!possibleTarget) {
this.add('-miss', pokemon);
return false;
}
target = possibleTarget;
}
const moveData = {
id: 'bide',
name: "Bide",
accuracy: 100,
damage: this.effectState.totalDamage * 2,
category: "Physical",
priority: 0,
flags: { contact: 1, protect: 1 },
effectType: 'Move',
type: 'Normal',
} as unknown as ActiveMove;
this.actions.tryMoveHit(target, pokemon, moveData);
pokemon.removeVolatile('bide');
return false;
}
this.add('-activate', pokemon, 'move: Bide');
},
onMoveAborted(pokemon) {
pokemon.removeVolatile('bide');
},
onEnd(pokemon) {
this.add('-end', pokemon, 'move: Bide', '[silent]');
},
},
},
counter: {
@ -85,12 +139,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
curse: {
inherit: true,
condition: {
inherit: true,
onAfterMoveSelfPriority: 0, // explicit
onStart(pokemon, source) {
this.add('-start', pokemon, 'Curse', `[of] ${source}`);
},
onAfterMoveSelf(pokemon) {
this.damage(pokemon.baseMaxhp / 4);
},
onResidual() {},
},
},
detect: {
@ -103,7 +157,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
return source.status !== 'slp';
},
condition: {
inherit: true,
duration: 2,
onImmunity(type, pokemon) {
if (type === 'sandstorm') return false;
},
onInvulnerability(target, source, move) {
if (move.id === 'earthquake' || move.id === 'magnitude' || move.id === 'fissure') {
return;
@ -115,7 +172,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
if (source.volatiles['lockon'] && target === source.volatiles['lockon'].source) return;
return false;
},
onSourceModifyDamage() {},
onSourceBasePower(basePower, target, source, move) {
if (move.id === 'earthquake' || move.id === 'magnitude') {
return this.chainModify(2);
@ -130,19 +186,43 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
encore: {
inherit: true,
condition: {
inherit: true,
durationCallback() {
return this.random(3, 7);
},
onStart(target) {
const lockedMove = target.lastMoveEncore?.id || '';
const moveSlot = lockedMove ? target.getMoveData(lockedMove) : null;
if (!moveSlot || target.lastMoveEncore?.flags['failencore'] || moveSlot.pp <= 0) {
const moveIndex = lockedMove ? target.moves.indexOf(lockedMove) : -1;
if (moveIndex < 0 || target.lastMoveEncore?.flags['failencore'] || target.moveSlots[moveIndex].pp <= 0) {
// it failed
return false;
}
this.effectState.move = lockedMove;
this.add('-start', target, 'Encore');
},
onOverrideAction(pokemon) {
return this.effectState.move;
},
onResidualOrder: 13,
onResidualSubOrder: undefined,
onResidual(target) {
const lockedMoveIndex = target.moves.indexOf(this.effectState.move);
if (lockedMoveIndex >= 0 && target.moveSlots[lockedMoveIndex].pp <= 0) {
// early termination if you run out of PP
target.removeVolatile('encore');
}
},
onEnd(target) {
this.add('-end', target, 'Encore');
},
onDisableMove(pokemon) {
if (!this.effectState.move || !pokemon.hasMove(this.effectState.move)) {
return;
}
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id !== this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
}
},
},
},
endure: {
@ -164,7 +244,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
return source.status !== 'slp';
},
condition: {
inherit: true,
duration: 2,
onInvulnerability(target, source, move) {
if (move.id === 'gust' || move.id === 'twister' || move.id === 'thunder' || move.id === 'whirlwind') {
return;
@ -180,7 +260,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
if (source.volatiles['lockon'] && target === source.volatiles['lockon'].source) return;
return false;
},
onSourceModifyDamage() {},
onSourceBasePower(basePower, target, source, move) {
if (move.id === 'gust' || move.id === 'twister') {
return this.chainModify(2);
@ -191,7 +270,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
focusenergy: {
inherit: true,
condition: {
inherit: true,
onStart(pokemon) {
this.add('-start', pokemon, 'move: Focus Energy');
},
onModifyCritRatio(critRatio) {
return critRatio + 1;
},
@ -203,8 +284,17 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
if (target.volatiles['foresight']) return false;
},
condition: {
inherit: true,
noCopy: false,
onStart(pokemon) {
this.add('-start', pokemon, 'Foresight');
},
onNegateImmunity(pokemon, type) {
if (pokemon.hasType('Ghost') && ['Normal', 'Fighting'].includes(type)) return false;
},
onModifyBoost(boosts) {
if (boosts.evasion && boosts.evasion > 0) {
boosts.evasion = 0;
}
},
},
},
frustration: {
@ -250,8 +340,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
onHit() {},
condition: {
inherit: true,
onResidual() {},
onStart(target) {
this.add('-start', target, 'move: Leech Seed');
},
onAfterMoveSelfPriority: 2,
onAfterMoveSelf(pokemon) {
if (!pokemon.hp) return;
@ -287,8 +378,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
if (target.volatiles['foresight'] || target.volatiles['lockon']) return false;
},
condition: {
inherit: true,
onSourceInvulnerability() {},
duration: 2,
onSourceAccuracy(accuracy, target, source, move) {
if (move && source === this.effectState.target && target === this.effectState.source) return true;
},
},
},
lowkick: {
@ -356,9 +449,15 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
},
mist: {
inherit: true,
num: 54,
accuracy: true,
basePower: 0,
category: "Status",
name: "Mist",
pp: 30,
priority: 0,
flags: { metronome: 1 },
volatileStatus: 'mist',
sideCondition: undefined,
condition: {
onStart(pokemon) {
this.add('-start', pokemon, 'Mist');
@ -379,7 +478,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
},
},
secondary: null,
target: "self",
type: "Ice",
},
moonlight: {
inherit: true,
@ -408,8 +509,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
nightmare: {
inherit: true,
condition: {
inherit: true,
onResidual() {},
noCopy: true,
onStart(pokemon) {
if (pokemon.status !== 'slp') {
return false;
}
this.add('-start', pokemon, 'Nightmare');
},
onAfterMoveSelfPriority: 1,
onAfterMoveSelf(pokemon) {
if (pokemon.status === 'slp') this.damage(pokemon.baseMaxhp / 4);
@ -421,6 +527,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
onMoveFail(target, source, move) {
source.addVolatile('lockedmove');
},
onAfterMove(pokemon) {
if (pokemon.volatiles['lockedmove'] && pokemon.volatiles['lockedmove'].duration === 1) {
pokemon.removeVolatile('lockedmove');
}
},
},
painsplit: {
inherit: true,
@ -429,8 +540,16 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
perishsong: {
inherit: true,
condition: {
inherit: true,
duration: 4,
onEnd(target) {
this.add('-start', target, 'perish0');
target.faint();
},
onResidualOrder: 4,
onResidual(pokemon) {
const duration = pokemon.volatiles['perishsong'].duration;
this.add('-start', pokemon, `perish${duration}`);
},
},
},
petaldance: {
@ -438,6 +557,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
onMoveFail(target, source, move) {
source.addVolatile('lockedmove');
},
onAfterMove(pokemon) {
if (pokemon.volatiles['lockedmove'] && pokemon.volatiles['lockedmove'].duration === 1) {
pokemon.removeVolatile('lockedmove');
}
},
},
poisongas: {
inherit: true,
@ -459,18 +583,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
pursuit: {
inherit: true,
beforeTurnCallback(pokemon, target) {
if (pokemon.isAlly(target)) return;
target.addVolatile('pursuit');
const data = target.volatiles['pursuit'];
if (!data.sources) {
data.sources = [];
}
data.sources.push(pokemon);
},
onModifyMove() {},
condition: {
inherit: true,
duration: 1,
onBeforeSwitchOut(pokemon) {
this.debug('Pursuit start');
let alreadyAdded = false;
@ -570,8 +685,41 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
safeguard: {
inherit: true,
condition: {
inherit: true,
duration: 5,
durationCallback(target, source, effect) {
if (source?.hasAbility('persistent')) {
this.add('-activate', source, 'ability: Persistent', effect);
return 7;
}
return 5;
},
onSetStatus(status, target, source, effect) {
if (!effect || !source) return;
if (effect.id === 'yawn') return;
if (effect.effectType === 'Move' && effect.infiltrates && !target.isAlly(source)) return;
if (target !== source) {
this.debug('interrupting setStatus');
if (effect.id === 'synchronize' || (effect.effectType === 'Move' && !effect.secondaries)) {
this.add('-activate', target, 'move: Safeguard');
}
return null;
}
},
onTryAddVolatile(status, target, source, effect) {
if (!effect || !source) return;
if (effect.effectType === 'Move' && effect.infiltrates && !target.isAlly(source)) return;
if ((status.id === 'confusion' || status.id === 'yawn') && target !== source) {
if (effect.effectType === 'Move' && !effect.secondaries) this.add('-activate', target, 'move: Safeguard');
return null;
}
},
onSideStart(side) {
this.add('-sidestart', side, 'Safeguard');
},
onSideResidualOrder: 8,
onSideEnd(side) {
this.add('-sideend', side, 'Safeguard');
},
},
},
selfdestruct: {
@ -637,14 +785,31 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
spikes: {
inherit: true,
condition: {
inherit: true,
onSideRestart: undefined,
// this is a side condition
onSideStart(side) {
if (!this.effectState.layers || this.effectState.layers === 0) {
this.add('-sidestart', side, 'Spikes');
this.effectState.layers = 1;
} else {
return false;
}
},
onSwitchIn(pokemon) {
if (!pokemon.runImmunity('Ground')) return;
const damageAmounts = [0, 3];
this.damage(damageAmounts[this.effectState.layers] * pokemon.maxhp / 24);
},
},
},
substitute: {
inherit: true,
condition: {
inherit: true,
onStart(target) {
this.add('-start', target, 'Substitute');
this.effectState.hp = Math.floor(target.maxhp / 4);
delete target.volatiles['partiallytrapped'];
},
onTryPrimaryHitPriority: -1,
onTryPrimaryHit(target, source, move) {
if (move.stallingMove) {
this.add('-fail', source);
@ -681,6 +846,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
if (!damage) {
return null;
}
damage = this.runEvent('SubDamage', target, source, move, damage);
if (!damage) {
return damage;
}
if (damage > target.volatiles['substitute'].hp) {
damage = target.volatiles['substitute'].hp as number;
}
@ -697,6 +866,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.runEvent('AfterSubDamage', target, source, move, damage);
return this.HIT_SUBSTITUTE;
},
onEnd(target) {
this.add('-end', target, 'Substitute');
},
},
},
swagger: {
@ -746,6 +918,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
onMoveFail(target, source, move) {
source.addVolatile('lockedmove');
},
onAfterMove(pokemon) {
if (pokemon.volatiles['lockedmove'] && pokemon.volatiles['lockedmove'].duration === 1) {
pokemon.removeVolatile('lockedmove');
}
},
},
toxic: {
inherit: true,

View File

@ -28,10 +28,7 @@ export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable
standard: {
effectType: 'ValidatorRule',
name: 'Standard',
ruleset: [
'Standard AG',
'Sleep Clause Mod', 'Freeze Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Items Clause', 'Evasion Moves Clause',
],
ruleset: ['Obtainable', 'Sleep Clause Mod', 'Freeze Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Items Clause', 'Evasion Moves Clause', 'Endless battle Clause', 'HP Percentage Mod', 'Cancel Mod'],
banlist: [
'Hypnosis + Mean Look',
'Hypnosis + Spider Web',

View File

@ -187,7 +187,10 @@ export const Scripts: ModdedBattleScriptsData = {
move.ignoreImmunity = (move.category === 'Status');
}
if (!target.runImmunity(move, true)) {
if (
(!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) &&
!target.runImmunity(move.type, true)
) {
return false;
}
@ -203,11 +206,6 @@ export const Scripts: ModdedBattleScriptsData = {
return false;
}
if (move.ohko && pokemon.level < target.level) {
this.battle.add('-immune', target, '[ohko]');
return false;
}
let accuracy = move.accuracy;
if (move.alwaysHit) {
accuracy = true;
@ -218,8 +216,13 @@ export const Scripts: ModdedBattleScriptsData = {
if (accuracy !== true) {
accuracy = Math.floor(accuracy * 255 / 100);
if (move.ohko) {
accuracy += (pokemon.level - target.level) * 2;
accuracy = Math.min(accuracy, 255);
if (pokemon.level >= target.level) {
accuracy += (pokemon.level - target.level) * 2;
accuracy = Math.min(accuracy, 255);
} else {
this.battle.add('-immune', target, '[ohko]');
return false;
}
}
if (!move.ignoreAccuracy) {
if (pokemon.boosts.accuracy > 0) {
@ -293,8 +296,10 @@ export const Scripts: ModdedBattleScriptsData = {
}
if (move.ohko) this.battle.add('-ohko');
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
if (!move.negateSecondary) {
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
}
if (move.recoil && move.totalDamage) {
this.battle.damage(this.calcRecoilDamage(move.totalDamage, move, pokemon), pokemon, target, 'recoil');
@ -492,8 +497,10 @@ export const Scripts: ModdedBattleScriptsData = {
}
// Let's test for immunities.
if (!target.runImmunity(move, true)) {
return false;
if (!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) {
if (!target.runImmunity(move.type, true)) {
return false;
}
}
// Is it an OHKO move?

View File

@ -0,0 +1,898 @@
export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormatsDataTable = {
bulbasaur: {
tier: "LC",
},
ivysaur: {
tier: "NFE",
},
venusaur: {
tier: "OU",
doublesTier: "DOU",
},
charmander: {
tier: "LC",
},
charmeleon: {
tier: "NFE",
},
charizard: {
tier: "OU",
doublesTier: "DOU",
},
squirtle: {
tier: "LC",
},
wartortle: {
tier: "NFE",
},
blastoise: {
tier: "OU",
doublesTier: "DOU",
},
caterpie: {
tier: "LC",
},
metapod: {
tier: "NFE",
},
butterfree: {
tier: "OU",
doublesTier: "DOU",
},
weedle: {
tier: "LC",
},
kakuna: {
tier: "NFE",
},
beedrill: {
tier: "OU",
doublesTier: "DOU",
},
pidgey: {
tier: "LC",
},
pidgeotto: {
tier: "NFE",
},
pidgeot: {
tier: "OU",
doublesTier: "DOU",
},
rattata: {
tier: "LC",
},
raticate: {
tier: "OU",
doublesTier: "DOU",
},
spearow: {
tier: "LC",
},
fearow: {
tier: "OU",
doublesTier: "DOU",
},
ekans: {
tier: "LC",
},
arbok: {
tier: "OU",
doublesTier: "DOU",
},
pichu: {
tier: "LC",
},
pikachu: {
tier: "OU",
doublesTier: "NFE",
},
raichu: {
tier: "OU",
doublesTier: "DOU",
},
sandshrew: {
tier: "LC",
},
sandslash: {
tier: "OU",
doublesTier: "DOU",
},
nidoranf: {
tier: "LC",
},
nidorina: {
tier: "NFE",
},
nidoqueen: {
tier: "OU",
doublesTier: "DOU",
},
nidoranm: {
tier: "LC",
},
nidorino: {
tier: "NFE",
},
nidoking: {
tier: "OU",
doublesTier: "DOU",
},
cleffa: {
tier: "LC",
},
clefairy: {
tier: "NFE",
},
clefable: {
tier: "OU",
doublesTier: "DOU",
},
vulpix: {
tier: "LC",
},
ninetales: {
tier: "OU",
doublesTier: "DOU",
},
igglybuff: {
tier: "LC",
},
jigglypuff: {
tier: "NFE",
},
wigglytuff: {
tier: "OU",
doublesTier: "DOU",
},
zubat: {
tier: "LC",
},
golbat: {
tier: "NFE",
},
crobat: {
tier: "OU",
doublesTier: "DOU",
},
oddish: {
tier: "LC",
},
gloom: {
tier: "NFE",
},
vileplume: {
tier: "OU",
doublesTier: "DOU",
},
bellossom: {
tier: "OU",
doublesTier: "DOU",
},
paras: {
tier: "LC",
},
parasect: {
tier: "OU",
doublesTier: "DOU",
},
venonat: {
tier: "LC",
},
venomoth: {
tier: "OU",
doublesTier: "DOU",
},
diglett: {
tier: "LC",
},
dugtrio: {
tier: "OU",
doublesTier: "DOU",
},
meowth: {
tier: "LC",
},
persian: {
tier: "OU",
doublesTier: "DOU",
},
psyduck: {
tier: "LC",
},
golduck: {
tier: "OU",
doublesTier: "DOU",
},
mankey: {
tier: "LC",
},
primeape: {
tier: "OU",
doublesTier: "DOU",
},
growlithe: {
tier: "LC",
},
arcanine: {
tier: "OU",
doublesTier: "DOU",
},
poliwag: {
tier: "LC",
},
poliwhirl: {
tier: "NFE",
},
poliwrath: {
tier: "OU",
doublesTier: "DOU",
},
politoed: {
tier: "OU",
doublesTier: "DOU",
},
abra: {
tier: "LC",
},
kadabra: {
tier: "OU",
doublesTier: "NFE",
},
alakazam: {
tier: "OU",
doublesTier: "DOU",
},
machop: {
tier: "LC",
},
machoke: {
tier: "NFE",
},
machamp: {
tier: "OU",
doublesTier: "DOU",
},
bellsprout: {
tier: "LC",
},
weepinbell: {
tier: "NFE",
},
victreebel: {
tier: "OU",
doublesTier: "DOU",
},
tentacool: {
tier: "LC",
},
tentacruel: {
tier: "OU",
doublesTier: "DOU",
},
geodude: {
tier: "LC",
},
graveler: {
tier: "NFE",
},
golem: {
tier: "OU",
doublesTier: "DOU",
},
ponyta: {
tier: "LC",
},
rapidash: {
tier: "OU",
doublesTier: "DOU",
},
slowpoke: {
tier: "LC",
},
slowbro: {
tier: "OU",
doublesTier: "DOU",
},
slowking: {
tier: "OU",
doublesTier: "DOU",
},
magnemite: {
tier: "LC",
},
magneton: {
tier: "OU",
doublesTier: "DOU",
},
farfetchd: {
tier: "OU",
doublesTier: "DOU",
},
doduo: {
tier: "LC",
},
dodrio: {
tier: "OU",
doublesTier: "DOU",
},
seel: {
tier: "LC",
},
dewgong: {
tier: "OU",
doublesTier: "DOU",
},
grimer: {
tier: "LC",
},
muk: {
tier: "OU",
doublesTier: "DOU",
},
shellder: {
tier: "LC",
},
cloyster: {
tier: "OU",
doublesTier: "DOU",
},
gastly: {
tier: "LC",
},
haunter: {
tier: "OU",
doublesTier: "DOU",
},
gengar: {
tier: "OU",
doublesTier: "DOU",
},
onix: {
tier: "LC",
},
steelix: {
tier: "OU",
doublesTier: "DOU",
},
drowzee: {
tier: "LC",
},
hypno: {
tier: "OU",
doublesTier: "DOU",
},
krabby: {
tier: "LC",
},
kingler: {
tier: "OU",
doublesTier: "DOU",
},
voltorb: {
tier: "LC",
},
electrode: {
tier: "OU",
doublesTier: "DOU",
},
exeggcute: {
tier: "LC",
},
exeggutor: {
tier: "OU",
doublesTier: "DOU",
},
cubone: {
tier: "LC",
},
marowak: {
tier: "OU",
doublesTier: "DOU",
},
tyrogue: {
tier: "LC",
},
hitmonlee: {
tier: "OU",
doublesTier: "DOU",
},
hitmonchan: {
tier: "OU",
doublesTier: "DOU",
},
hitmontop: {
tier: "OU",
doublesTier: "DOU",
},
lickitung: {
tier: "OU",
doublesTier: "DOU",
},
koffing: {
tier: "LC",
},
weezing: {
tier: "OU",
doublesTier: "DOU",
},
rhyhorn: {
tier: "LC",
},
rhydon: {
tier: "OU",
doublesTier: "DOU",
},
chansey: {
tier: "OU",
doublesTier: "NFE",
},
blissey: {
tier: "OU",
doublesTier: "DOU",
},
tangela: {
tier: "OU",
doublesTier: "DOU",
},
kangaskhan: {
tier: "OU",
doublesTier: "DOU",
},
horsea: {
tier: "LC",
},
seadra: {
tier: "NFE",
},
kingdra: {
tier: "OU",
doublesTier: "DOU",
},
goldeen: {
tier: "LC",
},
seaking: {
tier: "OU",
doublesTier: "DOU",
},
staryu: {
tier: "LC",
},
starmie: {
tier: "OU",
doublesTier: "DOU",
},
mrmime: {
tier: "OU",
doublesTier: "DOU",
},
scyther: {
tier: "OU",
doublesTier: "NFE",
},
scizor: {
tier: "OU",
doublesTier: "DOU",
},
smoochum: {
tier: "LC",
},
jynx: {
tier: "OU",
doublesTier: "DOU",
},
elekid: {
tier: "LC",
},
electabuzz: {
tier: "OU",
doublesTier: "DOU",
},
magby: {
tier: "LC",
},
magmar: {
tier: "OU",
doublesTier: "DOU",
},
pinsir: {
tier: "OU",
doublesTier: "DOU",
},
tauros: {
tier: "OU",
doublesTier: "DOU",
},
magikarp: {
tier: "LC",
},
gyarados: {
tier: "OU",
doublesTier: "DOU",
},
lapras: {
tier: "OU",
doublesTier: "DOU",
},
ditto: {
tier: "OU",
doublesTier: "DOU",
},
eevee: {
tier: "LC",
},
vaporeon: {
tier: "OU",
doublesTier: "DOU",
},
jolteon: {
tier: "OU",
doublesTier: "DOU",
},
flareon: {
tier: "OU",
doublesTier: "DOU",
},
espeon: {
tier: "OU",
doublesTier: "DOU",
},
umbreon: {
tier: "OU",
doublesTier: "DOU",
},
porygon: {
tier: "LC",
},
porygon2: {
tier: "OU",
doublesTier: "DOU",
},
omanyte: {
tier: "LC",
},
omastar: {
tier: "OU",
doublesTier: "DOU",
},
kabuto: {
tier: "LC",
},
kabutops: {
tier: "OU",
doublesTier: "DOU",
},
aerodactyl: {
tier: "OU",
doublesTier: "DOU",
},
snorlax: {
tier: "OU",
doublesTier: "DOU",
},
articuno: {
tier: "OU",
doublesTier: "DOU",
},
zapdos: {
tier: "OU",
doublesTier: "DOU",
},
moltres: {
tier: "OU",
doublesTier: "DOU",
},
dratini: {
tier: "LC",
},
dragonair: {
tier: "NFE",
},
dragonite: {
tier: "OU",
doublesTier: "DOU",
},
mewtwo: {
tier: "Uber",
doublesTier: "DUber",
},
mew: {
tier: "Uber",
doublesTier: "DUber",
},
chikorita: {
tier: "LC",
},
bayleef: {
tier: "NFE",
},
meganium: {
tier: "OU",
doublesTier: "DOU",
},
cyndaquil: {
tier: "LC",
},
quilava: {
tier: "NFE",
},
typhlosion: {
tier: "OU",
doublesTier: "DOU",
},
totodile: {
tier: "LC",
},
croconaw: {
tier: "NFE",
},
feraligatr: {
tier: "OU",
doublesTier: "DOU",
},
sentret: {
tier: "LC",
},
furret: {
tier: "OU",
doublesTier: "DOU",
},
hoothoot: {
tier: "LC",
},
noctowl: {
tier: "OU",
doublesTier: "DOU",
},
ledyba: {
tier: "LC",
},
ledian: {
tier: "OU",
doublesTier: "DOU",
},
spinarak: {
tier: "LC",
},
ariados: {
tier: "OU",
doublesTier: "DOU",
},
chinchou: {
tier: "LC",
},
lanturn: {
tier: "OU",
doublesTier: "DOU",
},
togepi: {
tier: "LC",
},
togetic: {
tier: "OU",
doublesTier: "DOU",
},
natu: {
tier: "LC",
},
xatu: {
tier: "OU",
doublesTier: "DOU",
},
mareep: {
tier: "LC",
},
flaaffy: {
tier: "NFE",
},
ampharos: {
tier: "OU",
doublesTier: "DOU",
},
marill: {
tier: "LC",
},
azumarill: {
tier: "OU",
doublesTier: "DOU",
},
sudowoodo: {
tier: "OU",
doublesTier: "DOU",
},
hoppip: {
tier: "LC",
},
skiploom: {
tier: "NFE",
},
jumpluff: {
tier: "OU",
doublesTier: "DOU",
},
aipom: {
tier: "OU",
doublesTier: "DOU",
},
sunkern: {
tier: "LC",
},
sunflora: {
tier: "OU",
doublesTier: "DOU",
},
yanma: {
tier: "OU",
doublesTier: "DOU",
},
wooper: {
tier: "LC",
},
quagsire: {
tier: "OU",
doublesTier: "DOU",
},
murkrow: {
tier: "OU",
doublesTier: "DOU",
},
misdreavus: {
tier: "OU",
doublesTier: "DOU",
},
unown: {
tier: "OU",
doublesTier: "DOU",
},
wobbuffet: {
tier: "OU",
doublesTier: "DOU",
},
girafarig: {
tier: "OU",
doublesTier: "DOU",
},
pineco: {
tier: "LC",
},
forretress: {
tier: "OU",
doublesTier: "DOU",
},
dunsparce: {
tier: "OU",
doublesTier: "DOU",
},
gligar: {
tier: "OU",
doublesTier: "DOU",
},
snubbull: {
tier: "LC",
},
granbull: {
tier: "OU",
doublesTier: "DOU",
},
qwilfish: {
tier: "OU",
doublesTier: "DOU",
},
shuckle: {
tier: "OU",
doublesTier: "DOU",
},
heracross: {
tier: "OU",
doublesTier: "DOU",
},
sneasel: {
tier: "OU",
doublesTier: "DOU",
},
teddiursa: {
tier: "LC",
},
ursaring: {
tier: "OU",
doublesTier: "DOU",
},
slugma: {
tier: "LC",
},
magcargo: {
tier: "OU",
doublesTier: "DOU",
},
swinub: {
tier: "LC",
},
piloswine: {
tier: "OU",
doublesTier: "DOU",
},
corsola: {
tier: "OU",
doublesTier: "DOU",
},
remoraid: {
tier: "LC",
},
octillery: {
tier: "OU",
doublesTier: "DOU",
},
delibird: {
tier: "OU",
doublesTier: "DOU",
},
mantine: {
tier: "OU",
doublesTier: "DOU",
},
skarmory: {
tier: "OU",
doublesTier: "DOU",
},
houndour: {
tier: "LC",
},
houndoom: {
tier: "OU",
doublesTier: "DOU",
},
phanpy: {
tier: "LC",
},
donphan: {
tier: "OU",
doublesTier: "DOU",
},
stantler: {
tier: "OU",
doublesTier: "DOU",
},
smeargle: {
tier: "OU",
doublesTier: "DOU",
},
miltank: {
tier: "OU",
doublesTier: "DOU",
},
raikou: {
tier: "OU",
doublesTier: "DOU",
},
entei: {
tier: "OU",
doublesTier: "DOU",
},
suicune: {
tier: "OU",
doublesTier: "DOU",
},
larvitar: {
tier: "LC",
},
pupitar: {
tier: "NFE",
},
tyranitar: {
tier: "OU",
doublesTier: "DOU",
},
lugia: {
tier: "Uber",
doublesTier: "DUber",
},
hooh: {
tier: "Uber",
doublesTier: "DUber",
},
celebi: {
tier: "OU",
doublesTier: "DOU",
},
};

View File

@ -0,0 +1,49 @@
export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
encore: {
inherit: true,
condition: {
durationCallback() {
return this.random(3, 7);
},
onStart(target) {
const lockedMove = target.lastMoveEncore?.id || '';
const moveIndex = lockedMove ? target.moves.indexOf(lockedMove) : -1;
if (moveIndex < 0 || target.lastMoveEncore?.flags['failencore'] || target.moveSlots[moveIndex].pp <= 0) {
// it failed
return false;
}
this.effectState.move = lockedMove;
this.add('-start', target, 'Encore');
},
onOverrideAction(pokemon) {
return this.effectState.move;
},
onModifyMove(move, pokemon) {
if (['normal', 'any', 'adjacentFoe'].includes(move.target)) {
move.target = 'randomNormal';
}
},
onResidualOrder: 13,
onResidual(target) {
const lockedMoveIndex = target.moves.indexOf(this.effectState.move);
if (lockedMoveIndex >= 0 && target.moveSlots[lockedMoveIndex].pp <= 0) {
// early termination if you run out of PP
target.removeVolatile('encore');
}
},
onEnd(target) {
this.add('-end', target, 'Encore');
},
onDisableMove(pokemon) {
if (!this.effectState.move || !pokemon.hasMove(this.effectState.move)) {
return;
}
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id !== this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
}
},
},
},
};

View File

@ -0,0 +1,19 @@
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
standarddoubles: {
effectType: 'ValidatorRule',
name: 'Standard Doubles',
ruleset: ['Obtainable', 'Sleep Clause Mod', 'Freeze Clause Mod', 'Species Clause', 'OHKO Clause', 'Evasion Moves Clause', 'Endless battle Clause', 'HP Percentage Mod', 'Cancel Mod'],
banlist: [
'Hypnosis + Mean Look',
'Hypnosis + Spider Web',
'Lovely Kiss + Mean Look',
'Lovely Kiss + Spider Web',
'Sing + Mean Look',
'Sing + Spider Web',
'Sleep Powder + Mean Look',
'Sleep Powder + Spider Web',
'Spore + Mean Look',
'Spore + Spider Web',
],
},
};

View File

@ -0,0 +1,319 @@
export const Scripts: ModdedBattleScriptsData = {
inherit: 'gen2',
gen: 2,
pokemon: {
inherit: true,
getStat(statName, unboosted, unmodified, fastReturn) {
// @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
let stat = this.storedStats[statName];
// Stat boosts.
if (!unboosted) {
let boost = this.boosts[statName];
if (boost > 6) boost = 6;
if (boost < -6) boost = -6;
if (boost >= 0) {
const boostTable = [1, 1.5, 2, 2.5, 3, 3.5, 4];
stat = Math.floor(stat * boostTable[boost]);
} else {
const numerators = [100, 66, 50, 40, 33, 28, 25];
stat = Math.floor(stat * numerators[-boost] / 100);
}
}
if (this.status === 'par' && statName === 'spe') {
stat = Math.floor(stat / 4);
}
if (!unmodified) {
// Burn attack drop is checked when you get the attack stat upon switch in and used until switch out.
if (this.status === 'brn' && statName === 'atk') {
stat = Math.floor(stat / 2);
}
}
// Gen 2 caps stats at 999 and min is 1.
stat = this.battle.clampIntRange(stat, 1, 999);
if (fastReturn) return stat;
// Screens
if (!unboosted) {
if (
(statName === 'def' && this.side.sideConditions['reflect']) ||
(statName === 'spd' && this.side.sideConditions['lightscreen'])
) {
if (this.side.active.length === 1) {
stat *= 2;
} else {
stat *= 1.5;
}
}
}
// Handle boosting items
if (
(['Cubone', 'Marowak'].includes(this.baseSpecies.name) && this.item === 'thickclub' && statName === 'atk') ||
(this.baseSpecies.name === 'Pikachu' && this.item === 'lightball' && statName === 'spa')
) {
stat *= 2;
} else if (this.baseSpecies.name === 'Ditto' && this.item === 'metalpowder' && ['def', 'spd'].includes(statName)) {
stat = Math.floor(stat * 1.5);
}
return stat;
},
},
actions: {
inherit: true,
getDamage(source, target, move, suppressMessages) {
// First of all, we get the move.
if (typeof move === 'string') {
move = this.dex.getActiveMove(move);
} else if (typeof move === 'number') {
move = {
basePower: move,
type: '???',
category: 'Physical',
willCrit: false,
flags: {},
} as unknown as ActiveMove;
}
// Let's test for immunities.
if (!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) {
if (!target.runImmunity(move.type, true)) {
return false;
}
}
// Is it an OHKO move?
if (move.ohko) {
return target.maxhp;
}
// We edit the damage through move's damage callback
if (move.damageCallback) {
return move.damageCallback.call(this.battle, source, target);
}
// We take damage from damage=level moves
if (move.damage === 'level') {
return source.level;
}
// If there's a fix move damage, we run it
if (move.damage) {
return move.damage;
}
// We check the category and typing to calculate later on the damage
move.category = this.battle.getCategory(move);
// '???' is typeless damage: used for Struggle and Confusion etc
if (!move.type) move.type = '???';
const type = move.type;
// We get the base power and apply basePowerCallback if necessary
let basePower: number | false | null | undefined = move.basePower;
if (move.basePowerCallback) {
basePower = move.basePowerCallback.call(this.battle, source, target, move);
}
// We check for Base Power
if (!basePower) {
if (basePower === 0) return; // Returning undefined means not dealing damage
return basePower;
}
basePower = this.battle.clampIntRange(basePower, 1);
// Checking for the move's Critical Hit ratio
let critRatio = this.battle.runEvent('ModifyCritRatio', source, target, move, move.critRatio || 0);
critRatio = this.battle.clampIntRange(critRatio, 0, 5);
const critMult = [0, 17, 32, 64, 85, 128];
let isCrit = move.willCrit || false;
if (typeof move.willCrit === 'undefined') {
if (critRatio) {
isCrit = this.battle.random(256) < critMult[critRatio];
}
}
if (isCrit && this.battle.runEvent('CriticalHit', target, null, move)) {
target.getMoveHitData(move).crit = true;
}
// Happens after crit calculation
if (basePower) {
// confusion damage
if (move.isConfusionSelfHit) {
move.type = move.baseMoveType!;
basePower = this.battle.runEvent('BasePower', source, target, move, basePower, true);
move.type = '???';
} else {
basePower = this.battle.runEvent('BasePower', source, target, move, basePower, true);
}
if (basePower && move.basePowerModifier) {
basePower *= move.basePowerModifier;
}
}
if (!basePower) return 0;
basePower = this.battle.clampIntRange(basePower, 1);
// We now check for attacker and defender
let level = source.level;
// Using Beat Up
if (move.allies) {
this.battle.add('-activate', source, 'move: Beat Up', '[of] ' + move.allies[0].name);
level = move.allies[0].level;
}
const attacker = move.overrideOffensivePokemon === 'target' ? target : source;
const defender = move.overrideDefensivePokemon === 'source' ? source : target;
const isPhysical = move.category === 'Physical';
const atkType: StatIDExceptHP = move.overrideOffensiveStat || (isPhysical ? 'atk' : 'spa');
const defType: StatIDExceptHP = move.overrideDefensiveStat || (isPhysical ? 'def' : 'spd');
let unboosted = false;
let noburndrop = false;
if (isCrit) {
if (!suppressMessages) this.battle.add('-crit', target);
// Stat level modifications are ignored if they are neutral to or favour the defender.
// Reflect and Light Screen defensive boosts are only ignored if stat level modifications were also ignored as a result of that.
if (attacker.boosts[atkType] <= defender.boosts[defType]) {
unboosted = true;
noburndrop = true;
}
}
let attack = attacker.getStat(atkType, unboosted, noburndrop);
let defense = defender.getStat(defType, unboosted);
// Using Beat Up
if (move.allies) {
attack = move.allies[0].species.baseStats.atk;
move.allies.shift();
defense = defender.species.baseStats.def;
}
// Moves that ignore offense and defense respectively.
if (move.ignoreOffensive) {
this.battle.debug('Negating (sp)atk boost/penalty.');
// The attack drop from the burn is only applied when attacker's attack level is higher than defender's defense level.
attack = attacker.getStat(atkType, true, true);
}
if (move.ignoreDefensive) {
this.battle.debug('Negating (sp)def boost/penalty.');
defense = target.getStat(defType, true, true);
}
if (move.id === 'present') {
const typeIndexes: { [k: string]: number } = {
Normal: 0, Fighting: 1, Flying: 2, Poison: 3, Ground: 4, Rock: 5, Bug: 7, Ghost: 8, Steel: 9,
Fire: 20, Water: 21, Grass: 22, Electric: 23, Psychic: 24, Ice: 25, Dragon: 26, Dark: 27,
};
attack = 10;
const attackerLastType = attacker.getTypes().slice(-1)[0];
const defenderLastType = defender.getTypes().slice(-1)[0];
defense = typeIndexes[attackerLastType] || 1;
level = typeIndexes[defenderLastType] || 1;
this.battle.hint("Gen 2 Present has a glitched damage calculation using the secondary types of the Pokemon for the Attacker's Level and Defender's Defense.", true);
}
// When either attack or defense are higher than 256, they are both divided by 4 and modded by 256.
// This is what causes the rollover bugs.
if (attack >= 256 || defense >= 256) {
if (attack >= 1024 || defense >= 1024) {
this.battle.hint("In Gen 2, a stat will roll over to a small number if it is larger than 1024.");
}
attack = this.battle.clampIntRange(Math.floor(attack / 4) % 256, 1);
defense = this.battle.clampIntRange(Math.floor(defense / 4) % 256, 1);
}
// Self destruct moves halve defense at this point.
if (move.selfdestruct && defType === 'def') {
defense = this.battle.clampIntRange(Math.floor(defense / 2), 1);
}
// Let's go with the calculation now that we have what we need.
// We do it step by step just like the game does.
let damage = level * 2;
damage = Math.floor(damage / 5);
damage += 2;
damage *= basePower;
damage *= attack;
damage = Math.floor(damage / defense);
damage = Math.floor(damage / 50);
if (isCrit) damage *= 2;
damage = Math.floor(this.battle.runEvent('ModifyDamage', attacker, defender, move, damage));
damage = this.battle.clampIntRange(damage, 1, 997);
damage += 2;
// Weather modifiers
if (
(type === 'Water' && this.battle.field.isWeather('raindance')) ||
(type === 'Fire' && this.battle.field.isWeather('sunnyday'))
) {
damage = Math.floor(damage * 1.5);
} else if (
((type === 'Fire' || move.id === 'solarbeam') && this.battle.field.isWeather('raindance')) ||
(type === 'Water' && this.battle.field.isWeather('sunnyday'))
) {
damage = Math.floor(damage / 2);
}
// STAB damage bonus, the "???" type never gets STAB
if (type !== '???' && source.hasType(type)) {
damage += Math.floor(damage / 2);
}
// Type effectiveness
const totalTypeMod = target.runEffectiveness(move);
// Super effective attack
if (totalTypeMod > 0) {
if (!suppressMessages) this.battle.add('-supereffective', target);
damage *= 2;
if (totalTypeMod >= 2) {
damage *= 2;
}
}
// Resisted attack
if (totalTypeMod < 0) {
if (!suppressMessages) this.battle.add('-resisted', target);
damage = Math.floor(damage / 2);
if (totalTypeMod <= -2) {
damage = Math.floor(damage / 2);
}
}
// Attempting to add correct spread damage nerf
const { targets } = source.getMoveTargets(move, target);
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}`);
damage = this.battle.modify(damage, spreadModifier);
}
// Apply random factor if damage is greater than 1, except for Flail and Reversal
if (!move.noDamageVariance && damage > 1) {
damage *= this.battle.random(217, 256);
damage = Math.floor(damage / 255);
}
// If damage is less than 1, we return 1
if (basePower && !Math.floor(damage)) {
return 1;
}
// We are done, this is the final damage
return damage;
},
},
};

View File

@ -1,17 +1,8 @@
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
standardag: {
inherit: true,
ruleset: [
'Obtainable', 'Team Preview', 'Exact HP Mod', 'Cancel Mod', 'Beat Up Nicknames Mod',
],
},
standard: {
effectType: 'ValidatorRule',
name: 'Standard',
ruleset: [
'Standard AG',
'Stadium Sleep Clause', 'Freeze Clause Mod', 'Self-KO Clause', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'Stadium Items Clause',
],
ruleset: ['Obtainable', 'Team Preview', 'Stadium Sleep Clause', 'Freeze Clause Mod', 'Self-KO Clause', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'Exact HP Mod', 'Cancel Mod', 'Stadium Items Clause'],
},
selfkoclause: {
effectType: 'Rule',

View File

@ -122,7 +122,10 @@ export const Scripts: ModdedBattleScriptsData = {
move.ignoreImmunity = (move.category === 'Status');
}
if (!target.runImmunity(move, true)) {
if (
(!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) &&
!target.runImmunity(move.type, true)
) {
return false;
}
@ -228,8 +231,10 @@ export const Scripts: ModdedBattleScriptsData = {
}
if (move.ohko) this.battle.add('-ohko');
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
if (!move.negateSecondary) {
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
}
// Implementing Recoil mechanics from Stadium 2.
// If a pokemon caused the other to faint with a recoil move and only one pokemon remains on both sides,
// recoil damage will not be taken.
@ -253,8 +258,10 @@ export const Scripts: ModdedBattleScriptsData = {
}
// Let's test for immunities.
if (!target.runImmunity(move, true)) {
return false;
if (!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) {
if (!target.runImmunity(move.type, true)) {
return false;
}
}
// Is it an OHKO move?

View File

@ -91,8 +91,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
},
},
lightningrod: {
inherit: true,
onAnyRedirectTarget() {},
onFoeRedirectTarget(target, source, source2, move) {
// don't count Hidden Power as Electric-type
if (this.dex.moves.get(move.id).type !== 'Electric') return;
@ -100,23 +98,10 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
return this.effectState.target;
}
},
},
magnetpull: {
inherit: true,
onFoeTrapPokemon() {},
onFoeMaybeTrapPokemon() {},
onAnyTrapPokemon(pokemon) {
if (pokemon.hasType('Steel') && pokemon.isAdjacent(this.effectState.target)) {
pokemon.tryTrap(true);
}
},
onAnyMaybeTrapPokemon(pokemon, source) {
if (!source) source = this.effectState.target;
if (!source || !pokemon.isAdjacent(source)) return;
if (!pokemon.knownType || pokemon.hasType('Steel')) {
pokemon.maybeTrapped = true;
}
},
flags: { breakable: 1 },
name: "Lightning Rod",
rating: 0,
num: 32,
},
minus: {
inherit: true,
@ -196,7 +181,9 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
const target = pokemon.side.randomFoe();
if (!target || target.fainted) return;
const ability = target.getAbility();
pokemon.setAbility(ability, target);
if (pokemon.setAbility(ability)) {
this.add('-ability', pokemon, ability, '[from] ability: Trace', `[of] ${target}`);
}
},
flags: {},
},

View File

@ -3,7 +3,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
ivysaur: {
tier: "ZU",
tier: "PU",
},
venusaur: {
tier: "UUBL",
@ -21,7 +21,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
wartortle: {
tier: "PU",
tier: "ZU",
},
blastoise: {
tier: "UU",
@ -63,7 +63,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
fearow: {
tier: "RUBL",
tier: "UU",
},
ekans: {
tier: "LC",
@ -312,7 +312,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "ZU",
},
hypno: {
tier: "RU",
tier: "UU",
},
krabby: {
tier: "LC",
@ -762,7 +762,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
grovyle: {
tier: "ZU",
tier: "PU",
},
sceptile: {
tier: "UUBL",
@ -879,7 +879,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "RUBL",
},
shedinja: {
tier: "PU",
tier: "ZUBL",
},
whismur: {
tier: "LC",
@ -924,13 +924,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "ZU",
},
medicham: {
tier: "OU",
tier: "UUBL",
},
electrike: {
tier: "LC",
},
manectric: {
tier: "RU",
tier: "UU",
},
plusle: {
tier: "NU",
@ -1056,10 +1056,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "ZU",
},
castformsunny: {
tier: "ZU",
},
castformrainy: {
tier: "ZU",
},
castformsnowy: {
tier: "ZU",
},
kecleon: {
tier: "NU",
@ -1089,7 +1092,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
glalie: {
tier: "NUBL",
tier: "NU",
},
spheal: {
tier: "LC",
@ -1101,7 +1104,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "UU",
},
clamperl: {
tier: "PU",
tier: "ZU",
},
huntail: {
tier: "NU",

View File

@ -82,7 +82,6 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
num: 208,
gen: 3,
isNonstandard: "Unobtainable",
// No competitive use
},
fastball: {
inherit: true,
@ -139,8 +138,8 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
inherit: true,
onModifyMove(move) {
const affectedByKingsRock = [
'aerialace', 'aeroblast', 'aircutter', 'armthrust', 'barrage', 'beatup', 'bide', 'bind', 'blastburn', 'bonerush', 'bonemerang', 'bounce', 'brickbreak', 'bulletseed', 'clamp', 'cometpunch', 'crabhammer', 'crosschop', 'cut', 'dig', 'dive', 'doublekick', 'doubleslap', 'doubleedge', 'dragonbreath', 'dragonclaw', 'dragonrage', 'drillpeck', 'earthquake', 'eggbomb', 'endeavor', 'eruption', 'explosion', 'extremespeed', 'falseswipe', 'feintattack', 'firespin', 'flail', 'fly', 'frenzyplant', 'frustration', 'furyattack', 'furycutter', 'furyswipes', 'gust', 'hiddenpower', 'highjumpkick', 'hornattack', 'hydrocannon', 'hydropump', 'hyperbeam', 'iceball', 'iciclespear', 'jumpkick', 'karatechop', 'leafblade', 'lowkick', 'machpunch', 'magicalleaf', 'magnitude', 'megakick', 'megapunch', 'megahorn', 'meteormash', 'mudshot', 'muddywater', 'nightshade', 'outrage', 'overheat', 'payday', 'peck', 'petaldance', 'pinmissile', 'poisontail', 'pound', 'psychoboost', 'psywave', 'quickattack', 'rage', 'rapidspin', 'razorleaf', 'razorwind', 'return', 'revenge', 'reversal', 'rockblast', 'rockthrow', 'rollingkick', 'rollout', 'sandtomb', 'scratch', 'seismictoss', 'selfdestruct', 'shadowpunch', 'shockwave', 'signalbeam', 'silverwind', 'skullbash', 'skyattack', 'skyuppercut', 'slam', 'slash', 'snore', 'solarbeam', 'sonicboom', 'spikecannon', 'spitup', 'steelwing', 'strength', 'struggle', 'submission', 'surf', 'swift', 'tackle', 'takedown', 'thrash', 'triplekick', 'twister', 'uproar', 'visegrip', 'vinewhip', 'vitalthrow', 'volttackle', 'watergun', 'waterpulse', 'waterfall', 'weatherball', 'whirlpool', 'wingattack', 'wrap',
]; // Tickle also has the move flag, but can never flinch because King's Rock requires damage to trigger
'aerialace', 'aeroblast', 'aircutter', 'armthrust', 'barrage', 'beatup', 'bide', 'bind', 'blastburn', 'bonerush', 'bonemerang', 'bounce', 'brickbreak', 'bulletseed', 'clamp', 'cometpunch', 'crabhammer', 'crosschop', 'cut', 'dig', 'dive', 'doublekick', 'doubleslap', 'doubleedge', 'dragonbreath', 'dragonclaw', 'dragonrage', 'drillpeck', 'earthquake', 'eggbomb', 'endeavor', 'eruption', 'explosion', 'extremespeed', 'falseswipe', 'feintattack', 'firespin', 'flail', 'fly', 'frenzyplant', 'frustration', 'furyattack', 'furycutter', 'furyswipes', 'gust', 'hiddenpower', 'highjumpkick', 'hornattack', 'hydrocannon', 'hydropump', 'hyperbeam', 'iceball', 'iciclespear', 'jumpkick', 'karatechop', 'leafblade', 'lowkick', 'machpunch', 'magicalleaf', 'magnitude', 'megakick', 'megapunch', 'megahorn', 'meteormash', 'mudshot', 'muddywater', 'nightshade', 'outrage', 'overheat', 'payday', 'peck', 'petaldance', 'pinmissile', 'poisontail', 'pound', 'psychoboost', 'psywave', 'quickattack', 'rage', 'rapidspin', 'razorleaf', 'razorwind', 'return', 'revenge', 'reversal', 'rockblast', 'rockthrow', 'rollingkick', 'rollout', 'sandtomb', 'scratch', 'seismictoss', 'selfdestruct', 'shadowpunch', 'shockwave', 'signalbeam', 'silverwind', 'skullbash', 'skyattack', 'skyuppercut', 'slam', 'slash', 'snore', 'solarbeam', 'sonicboom', 'spikecannon', 'spitup', 'steelwing', 'strength', 'struggle', 'submission', 'surf', 'swift', 'tackle', 'takedown', 'thrash', 'tickle', 'triplekick', 'twister', 'uproar', 'visegrip', 'vinewhip', 'vitalthrow', 'volttackle', 'watergun', 'waterpulse', 'waterfall', 'weatherball', 'whirlpool', 'wingattack', 'wrap',
];
if (affectedByKingsRock.includes(move.id)) {
if (!move.secondaries) move.secondaries = [];
move.secondaries.push({

View File

@ -26,7 +26,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
astonish: {
inherit: true,
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1, minimize: 1 },
basePowerCallback(pokemon, target) {
if (target.volatiles['minimize']) return 60;
return 30;
},
},
beatup: {
inherit: true,
@ -41,16 +44,15 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
duration: 1,
onModifySpAPriority: -101,
onModifySpA(atk, pokemon, defender, move) {
if (!this.ruleTable.has('beatupnicknamesmod')) {
this.add('-activate', pokemon, 'move: Beat Up', '[of] ' + move.allies![0].name);
}
// https://www.smogon.com/forums/posts/8992145/
// this.add('-activate', pokemon, 'move: Beat Up', '[of] ' + move.allies![0].name);
this.event.modifier = 1;
return this.dex.species.get(move.allies!.shift()!.set.species).baseStats.atk;
return move.allies!.shift()!.species.baseStats.atk;
},
onFoeModifySpDPriority: -101,
onFoeModifySpD(def, pokemon) {
this.event.modifier = 1;
return this.dex.species.get(pokemon.set.species).baseStats.def;
return pokemon.species.baseStats.def;
},
},
},
@ -59,8 +61,18 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
accuracy: 100,
priority: 0,
condition: {
inherit: true,
onAfterSetStatus() {},
duration: 3,
onLockMove: 'bide',
onStart(pokemon) {
this.effectState.totalDamage = 0;
this.add('-start', pokemon, 'move: Bide');
},
onDamagePriority: -101,
onDamage(damage, target, source, move) {
if (!move || move.effectType !== 'Move' || !source) return;
this.effectState.totalDamage += damage;
this.effectState.lastDamageSource = source;
},
onBeforeMove(pokemon, target, move) {
if (this.effectState.duration === 1) {
this.add('-end', pokemon, 'move: Bide');
@ -98,6 +110,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
this.add('-activate', pokemon, 'move: Bide');
},
onMoveAborted(pokemon) {
pokemon.removeVolatile('bide');
},
onEnd(pokemon) {
this.add('-end', pokemon, 'move: Bide', '[silent]');
},
},
},
blizzard: {
@ -136,39 +154,20 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.add('-start', target, 'typechange', type);
},
},
conversion2: {
inherit: true,
onHit(target, source) {
if (!target.lastMoveUsed) {
return false;
}
const possibleTypes = [];
const lastMoveUsed = target.lastMoveUsed;
const attackType = lastMoveUsed.id === 'struggle' ? 'Normal' : lastMoveUsed.type;
for (const typeName of this.dex.types.names()) {
const typeCheck = this.dex.types.get(typeName).damageTaken[attackType];
if (typeCheck === 2 || typeCheck === 3) {
possibleTypes.push(typeName);
}
}
if (!possibleTypes.length) {
return false;
}
const randomType = this.sample(possibleTypes);
if (!source.setType(randomType)) return false;
this.add('-start', source, 'typechange', randomType);
},
},
counter: {
inherit: true,
condition: {
inherit: true,
duration: 1,
noCopy: true,
onStart(target, source, move) {
this.effectState.slot = null;
this.effectState.damage = 0;
},
onRedirectTargetPriority: -1,
onRedirectTarget(target, source, source2) {
if (source !== this.effectState.target || !this.effectState.slot) return;
return this.getAtSlot(this.effectState.slot);
},
onDamagingHit() {},
onDamagePriority: -101,
onDamage(damage, target, source, effect) {
if (
@ -202,13 +201,48 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
accuracy: 55,
flags: { protect: 1, mirror: 1, bypasssub: 1, metronome: 1 },
volatileStatus: 'disable',
condition: {
inherit: true,
durationCallback() {
return this.random(2, 6);
},
"onResidualOrder": undefined,
"onResidualSubOrder": undefined,
noCopy: true,
onStart(pokemon) {
if (!this.queue.willMove(pokemon)) {
this.effectState.duration!++;
}
if (!pokemon.lastMove) {
return false;
}
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id === pokemon.lastMove.id) {
if (!moveSlot.pp) {
return false;
} else {
this.add('-start', pokemon, 'Disable', moveSlot.move);
this.effectState.move = pokemon.lastMove.id;
return;
}
}
}
return false;
},
onEnd(pokemon) {
this.add('-end', pokemon, 'move: Disable');
},
onBeforeMove(attacker, defender, move) {
if (move.id === this.effectState.move) {
this.add('cant', attacker, 'Disable', move);
return false;
}
},
onDisableMove(pokemon) {
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id === this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
}
},
},
},
dive: {
@ -252,15 +286,56 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
volatileStatus: 'encore',
condition: {
inherit: true,
durationCallback() {
return this.random(3, 7);
},
onStart(target, source) {
const moveIndex = target.lastMove ? target.moves.indexOf(target.lastMove.id) : -1;
if (
!target.lastMove || target.lastMove.flags['failencore'] ||
!target.moveSlots[moveIndex] || target.moveSlots[moveIndex].pp <= 0
) {
// it failed
return false;
}
this.effectState.move = target.lastMove.id;
this.add('-start', target, 'Encore');
},
onOverrideAction(pokemon) {
return this.effectState.move;
},
onResidualOrder: 10,
onResidualSubOrder: 14,
onResidual(target) {
if (
target.moves.includes(this.effectState.move) &&
target.moveSlots[target.moves.indexOf(this.effectState.move)].pp <= 0
) {
// early termination if you run out of PP
target.removeVolatile('encore');
}
},
onEnd(target) {
this.add('-end', target, 'Encore');
},
onDisableMove(pokemon) {
if (!this.effectState.move || !pokemon.hasMove(this.effectState.move)) {
return;
}
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id !== this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
}
},
},
},
extrasensory: {
inherit: true,
flags: { protect: 1, mirror: 1, metronome: 1, minimize: 1 },
basePowerCallback(pokemon, target) {
if (target.volatiles['minimize']) return 160;
return 80;
},
},
fakeout: {
inherit: true,
@ -305,11 +380,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
volatileStatus: undefined,
slotCondition: 'followme',
condition: {
inherit: true,
duration: 1,
onStart(target, source, effect) {
this.add('-singleturn', target, 'move: Follow Me');
this.effectState.slot = target.getSlot();
},
onFoeRedirectTargetPriority: 1,
onFoeRedirectTarget(target, source, source2, move) {
const userSlot = this.getAtSlot(this.effectState.slot);
if (this.validTarget(userSlot, source, move.target)) {
@ -336,15 +412,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
ignoreImmunity: false,
},
haze: {
inherit: true,
onHitField() {
this.add('-clearallboost');
for (const pokemon of this.getAllActive()) {
pokemon.clearBoosts();
}
},
},
hiddenpower: {
inherit: true,
category: "Physical",
@ -407,12 +474,17 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
mirrorcoat: {
inherit: true,
condition: {
inherit: true,
duration: 1,
noCopy: true,
onStart(target, source, move) {
this.effectState.slot = null;
this.effectState.damage = 0;
},
onRedirectTargetPriority: -1,
onRedirectTarget(target, source, source2) {
if (source !== this.effectState.target || !this.effectState.slot) return;
return this.getAtSlot(this.effectState.slot);
},
onDamagingHit() {},
onDamagePriority: -101,
onDamage(damage, target, source, effect) {
if (
@ -453,7 +525,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
needlearm: {
inherit: true,
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1, minimize: 1 },
basePowerCallback(pokemon, target) {
if (target.volatiles['minimize']) return 120;
return 60;
},
},
nightmare: {
inherit: true,
@ -475,20 +550,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
basePower: 70,
},
pursuit: {
inherit: true,
beforeTurnCallback(pokemon, target) {
if (['frz', 'slp'].includes(pokemon.status) ||
(pokemon.hasAbility('truant') && pokemon.truantTurn)) return;
if (pokemon.isAlly(target)) return;
target.addVolatile('pursuit');
const data = target.volatiles['pursuit'];
if (!data.sources) {
data.sources = [];
}
data.sources.push(pokemon);
},
},
recover: {
inherit: true,
pp: 20,
@ -592,13 +653,28 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
flags: { protect: 1, bypasssub: 1, metronome: 1 },
condition: {
inherit: true,
duration: 2,
durationCallback: undefined,
onStart(target) {
this.add('-start', target, 'move: Taunt');
},
onResidualOrder: 10,
onResidualSubOrder: 15,
onEnd(target) {
this.add('-end', target, 'move: Taunt', '[silent]');
},
onBeforeMovePriority: undefined,
onDisableMove(pokemon) {
for (const moveSlot of pokemon.moveSlots) {
if (this.dex.moves.get(moveSlot.move).category === 'Status') {
pokemon.disableMove(moveSlot.id);
}
}
},
onBeforeMove(attacker, defender, move) {
if (move.category === 'Status') {
this.add('cant', attacker, 'move: Taunt', move);
return false;
}
},
},
},
teeterdance: {
@ -612,9 +688,37 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
uproar: {
inherit: true,
condition: {
inherit: true,
durationCallback() {
return this.random(2, 6);
onStart(target) {
this.add('-start', target, 'Uproar');
// 2-5 turns
this.effectState.duration = this.random(2, 6);
},
onResidual(target) {
if (target.volatiles['throatchop']) {
target.removeVolatile('uproar');
return;
}
if (target.lastMove && target.lastMove.id === 'struggle') {
// don't lock
delete target.volatiles['uproar'];
}
this.add('-start', target, 'Uproar', '[upkeep]');
},
onResidualOrder: 10,
onResidualSubOrder: 11,
onEnd(target) {
this.add('-end', target, 'Uproar');
},
onLockMove: 'uproar',
onAnySetStatus(status, pokemon) {
if (status.id === 'slp') {
if (pokemon === this.effectState.target) {
this.add('-fail', pokemon, 'slp', '[from] Uproar', '[msg]');
} else {
this.add('-fail', pokemon, 'slp', '[from] Uproar');
}
return null;
}
},
},
},

View File

@ -2,23 +2,7 @@ export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable
standard: {
effectType: 'ValidatorRule',
name: 'Standard',
desc: "The standard ruleset for all official Smogon singles tiers (Ubers, OU, etc.)",
ruleset: [
'Standard AG',
'Sleep Clause Mod', 'Switch Priority Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Items Clause', 'Evasion Moves Clause',
],
},
standarddraft: {
effectType: 'ValidatorRule',
name: 'Standard Draft',
desc: "The custom Draft League ruleset",
ruleset: [
'Obtainable', 'Nickname Clause', 'Beat Up Nicknames Mod', '+Unreleased', 'Sleep Clause Mod', 'OHKO Clause', 'Evasion Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod',
'One Boost Passer Clause', 'Freeze Clause Mod', 'Accuracy Moves Clause', 'Baton Pass Trap Clause',
],
banlist: [
'Uber', 'Smeargle + Ingrain', 'Swagger', 'Focus Band', 'King\'s Rock', 'Quick Claw', 'Baton Pass + Ancient Power', 'Baton Pass + Silver Wind',
],
// timer: {starting: 60 * 60, grace: 0, addPerTurn: 10, maxPerTurn: 100, timeoutAutoChoose: true},
desc: "The standard ruleset for all offical Smogon singles tiers (Ubers, OU, etc.)",
ruleset: ['Obtainable', 'Sleep Clause Mod', 'Switch Priority Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Items Clause', 'Evasion Moves Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod'],
},
};

View File

@ -49,7 +49,7 @@ export const Scripts: ModdedBattleScriptsData = {
// In Generation 3, the spread move modifier is 0.5x instead of 0.75x. Moves that hit both foes
// and the user's ally, like Earthquake and Explosion, don't get affected by spread modifiers
if (move.spreadHit && move.target === 'allAdjacentFoes') {
const spreadModifier = 0.5;
const spreadModifier = move.spreadModifier || 0.5;
this.battle.debug(`Spread modifier: ${spreadModifier}`);
baseDamage = this.battle.modify(baseDamage, spreadModifier);
}
@ -162,7 +162,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).name}`;
if (sourceEffect) attrs += `|[from]${this.dex.conditions.get(sourceEffect)}`;
this.battle.addMove('move', pokemon, movename, `${target}${attrs}`);
if (!target) {
@ -256,7 +256,7 @@ export const Scripts: ModdedBattleScriptsData = {
return false;
}
if (!(move.hasSheerForce && pokemon.hasAbility('sheerforce'))) {
if (!move.negateSecondary && !(move.hasSheerForce && pokemon.hasAbility('sheerforce'))) {
this.battle.singleEvent('AfterMoveSecondarySelf', move, null, pokemon, target, move);
this.battle.runEvent('AfterMoveSecondarySelf', pokemon, target, move);
}
@ -308,7 +308,10 @@ export const Scripts: ModdedBattleScriptsData = {
move.ignoreImmunity = (move.category === 'Status');
}
if (!target.runImmunity(move)) {
if (
(!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) &&
!target.runImmunity(move.type)
) {
naturalImmunity = true;
} else {
hitResult = this.battle.singleEvent('TryImmunity', move, {}, target, pokemon, move);
@ -468,7 +471,7 @@ export const Scripts: ModdedBattleScriptsData = {
this.battle.eachEvent('Update');
if (target) {
if (target && !move.negateSecondary) {
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
}

View File

@ -1,25 +0,0 @@
/**
* Gen 3 colosseum modifications (perish song should fail if it effects all remaining pokemon)
*/
export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
perishsong: {
inherit: true,
onTryMove(attacker, defender, move) {
if (attacker.side.pokemonLeft === 1) {
this.add('-fail', attacker, 'move: Perish Song');
this.hint("Self KO Clause: The last pokemon on a team cannot use moves that force fainting");
return false;
}
},
},
destinybond: {
inherit: true,
onTryMove(attacker, defender, move) {
if (attacker.side.pokemonLeft === 1) {
this.add('-fail', attacker, 'move: Perish Song');
this.hint("Self KO Clause: The last pokemon on a team cannot use moves that force fainting");
return false;
}
},
},
};

View File

@ -1,27 +0,0 @@
export const Scripts: ModdedBattleScriptsData = {
inherit: 'gen3',
gen: 3,
checkWin(faintData?: Battle['faintQueue'][0]) {
if (this.sides.every(side => !side.pokemonLeft)) {
let isSelfKo = false;
if (faintData?.effect) {
isSelfKo = isSelfKo || this.dex.moves.getByID(faintData?.effect?.id).selfdestruct !== undefined;
isSelfKo = isSelfKo || this.dex.moves.getByID(faintData?.effect?.id).recoil !== undefined;
}
if (isSelfKo) {
this.win(faintData ? faintData.target.side : null);
return true;
} else {
this.win(undefined);
return true;
}
}
for (const side of this.sides) {
if (!side.foePokemonLeft()) {
this.win(side);
return true;
}
}
},
};

File diff suppressed because it is too large Load Diff

View File

@ -1,58 +0,0 @@
export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
apicotberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
berryjuice: {
inherit: true,
isNonstandard: "Unobtainable",
},
fastball: {
inherit: true,
isNonstandard: "Unobtainable",
},
ganlonberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
heavyball: {
inherit: true,
isNonstandard: "Unobtainable",
},
lansatberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
levelball: {
inherit: true,
isNonstandard: "Unobtainable",
},
loveball: {
inherit: true,
isNonstandard: "Unobtainable",
},
lureball: {
inherit: true,
isNonstandard: "Unobtainable",
},
moonball: {
inherit: true,
isNonstandard: "Unobtainable",
},
petayaberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
salacberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
sportball: {
inherit: true,
isNonstandard: "Unobtainable",
},
starfberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
};

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +0,0 @@
export const Scripts: ModdedBattleScriptsData = {
inherit: 'gen3',
};

View File

@ -23,9 +23,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
onResidualSubOrder: 10,
},
blaze: {
inherit: true,
onModifyAtk() {},
onModifySpA() {},
onBasePowerPriority: 2,
onBasePower(basePower, attacker, defender, move) {
if (move.type === 'Fire' && attacker.hp <= attacker.maxhp / 3) {
@ -33,6 +30,9 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
return this.chainModify(1.5);
}
},
name: "Blaze",
rating: 2,
num: 66,
},
cloudnine: {
inherit: true,
@ -58,7 +58,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
onSourceModifyAccuracy(accuracy) {
if (typeof accuracy !== 'number') return;
this.debug('compoundeyes - enhancing accuracy');
return this.chainModify(1.3);
return accuracy * 1.3;
},
inherit: true,
},
@ -128,15 +128,19 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
}
},
condition: {
inherit: true,
onModifyAtk() {},
onModifySpA() {},
noCopy: true, // doesn't get copied by Baton Pass
onStart(target) {
this.add('-start', target, 'ability: Flash Fire');
},
onModifyDamagePhase1(atk, attacker, defender, move) {
if (move.type === 'Fire') {
this.debug('Flash Fire boost');
return this.chainModify(1.5);
}
},
onEnd(target) {
this.add('-end', target, 'ability: Flash Fire', '[silent]');
},
},
},
flowergift: {
@ -186,7 +190,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
inherit: true,
onStart(pokemon) {
const target = pokemon.side.randomFoe();
if (target?.item) {
if (target?.item && !target.itemState.knockedOff) {
this.add('-item', '', target.getItem().name, '[from] ability: Frisk', `[of] ${pokemon}`);
}
},
@ -196,19 +200,20 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
onSourceModifyAccuracyPriority: 7,
onSourceModifyAccuracy(accuracy, target, source, move) {
if (move.category === 'Physical' && typeof accuracy === 'number') {
return this.chainModify(0.8);
return accuracy * 0.8;
}
},
},
hydration: {
inherit: true,
onResidual() {},
onWeather(target, source, effect) {
if (effect.id === 'raindance' && target.status) {
this.add('-activate', target, 'ability: Hydration');
target.cureStatus();
}
},
name: "Hydration",
rating: 1.5,
num: 93,
},
insomnia: {
inherit: true,
@ -265,24 +270,31 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
},
},
magicguard: {
inherit: true,
onDamage(damage, target, source, effect) {
if (effect.effectType !== 'Move') {
return false;
}
},
onSetStatus(status, target, source, effect) {
if (effect && effect.id === 'toxicspikes') {
return false;
}
},
name: "Magic Guard",
rating: 4.5,
num: 98,
},
minus: {
inherit: true,
onModifySpAPriority: undefined,
onModifySpA(spa, pokemon) {
for (const allyActive of pokemon.allies()) {
if (allyActive.hasAbility('plus')) {
return this.chainModify(1.5);
for (const ally of pokemon.allies()) {
if (ally.ability === 'plus') {
return spa * 1.5;
}
}
},
name: "Minus",
rating: 0,
num: 58,
},
naturalcure: {
inherit: true,
@ -306,9 +318,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
},
},
overgrow: {
inherit: true,
onModifyAtk() {},
onModifySpA() {},
onBasePowerPriority: 2,
onBasePower(basePower, attacker, defender, move) {
if (move.type === 'Grass' && attacker.hp <= attacker.maxhp / 3) {
@ -316,23 +325,26 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
return this.chainModify(1.5);
}
},
name: "Overgrow",
rating: 2,
num: 65,
},
pickup: {
inherit: true,
onResidual() {},
name: "Pickup",
rating: 0,
// No competitive use
num: 53,
},
plus: {
inherit: true,
onModifySpAPriority: undefined,
onModifySpA(spa, pokemon) {
for (const allyActive of pokemon.allies()) {
if (allyActive.hasAbility('minus')) {
return this.chainModify(1.5);
for (const ally of pokemon.allies()) {
if (ally.ability === 'minus') {
return spa * 1.5;
}
}
},
name: "Plus",
rating: 0,
num: 57,
},
poisonpoint: {
inherit: true,
@ -345,12 +357,16 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
},
},
pressure: {
inherit: true,
onStart(pokemon) {
this.add('-ability', pokemon, 'Pressure');
},
onDeductPP(target, source) {
if (target === source) return;
return 1;
},
name: "Pressure",
rating: 1.5,
num: 46,
},
roughskin: {
inherit: true,
@ -367,14 +383,14 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
if (typeof accuracy !== 'number') return;
if (this.field.isWeather('sandstorm')) {
this.debug('Sand Veil - decreasing accuracy');
return this.chainModify(0.8);
return accuracy * 0.8;
}
},
},
serenegrace: {
inherit: true,
onModifyMove(move) {
if (move.secondaries && move.id !== 'chatter') {
if (move.secondaries) {
this.debug('doubling secondary chance');
for (const secondary of move.secondaries) {
if (secondary.chance) secondary.chance *= 2;
@ -388,14 +404,16 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
onResidualSubOrder: 3,
},
simple: {
inherit: true,
onChangeBoost() {},
onModifyBoost(boosts) {
let key: BoostID;
for (key in boosts) {
boosts[key]! *= 2;
}
},
flags: { breakable: 1 },
name: "Simple",
rating: 4,
num: 86,
},
snowcloak: {
inherit: true,
@ -404,7 +422,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
if (typeof accuracy !== 'number') return;
if (this.field.isWeather('hail')) {
this.debug('Snow Cloak - decreasing accuracy');
return this.chainModify(0.8);
return accuracy * 0.8;
}
},
},
@ -424,10 +442,9 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
},
},
stench: {
inherit: true,
onModifyMove() {},
name: "Stench",
rating: 0,
// No competitive use
num: 1,
},
stickyhold: {
inherit: true,
@ -449,9 +466,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
rating: 0,
},
swarm: {
inherit: true,
onModifyAtk() {},
onModifySpA() {},
onBasePowerPriority: 2,
onBasePower(basePower, attacker, defender, move) {
if (move.type === 'Bug' && attacker.hp <= attacker.maxhp / 3) {
@ -459,6 +473,9 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
return this.chainModify(1.5);
}
},
name: "Swarm",
rating: 2,
num: 68,
},
synchronize: {
inherit: true,
@ -478,25 +495,23 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
if (typeof accuracy !== 'number') return;
if (target?.volatiles['confusion']) {
this.debug('Tangled Feet - decreasing accuracy');
return this.chainModify(0.5);
return accuracy * 0.5;
}
},
},
thickfat: {
inherit: true,
onSourceModifyAtk() {},
onSourceModifySpA() {},
onSourceBasePowerPriority: 1,
onSourceBasePower(basePower, attacker, defender, move) {
if (move.type === 'Ice' || move.type === 'Fire') {
return this.chainModify(0.5);
}
},
flags: { breakable: 1 },
name: "Thick Fat",
rating: 3.5,
num: 47,
},
torrent: {
inherit: true,
onModifyAtk() {},
onModifySpA() {},
onBasePowerPriority: 2,
onBasePower(basePower, attacker, defender, move) {
if (move.type === 'Water' && attacker.hp <= attacker.maxhp / 3) {
@ -504,6 +519,9 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
return this.chainModify(1.5);
}
},
name: "Torrent",
rating: 2,
num: 67,
},
trace: {
inherit: true,
@ -516,10 +534,22 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
if (bannedAbilities.includes(target.ability)) {
return;
}
pokemon.setAbility(ability, target);
if (pokemon.setAbility(ability)) {
this.add('-ability', pokemon, ability, '[from] ability: Trace', `[of] ${target}`);
}
},
flags: { notrace: 1 },
},
unburden: {
inherit: true,
condition: {
onModifySpe(spe, pokemon) {
if ((!pokemon.item || pokemon.itemState.knockedOff) && !pokemon.ignoringAbility()) {
return this.chainModify(2);
}
},
},
},
vitalspirit: {
inherit: true,
rating: 2.5,
@ -531,16 +561,12 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
this.hint("In Gen 4, Fire Fang is always able to hit through Wonder Guard.", true, target.side);
return;
}
if (target === source || move.category === 'Status' || move.type === '???') return;
if (target === source || move.category === 'Status' || move.type === '???' || move.id === 'struggle') return;
this.debug('Wonder Guard immunity: ' + move.id);
if (target.runEffectiveness(move) <= 0 || !target.runImmunity(move)) {
if (target.runEffectiveness(move) <= 0) {
this.add('-immune', target, '[from] ability: Wonder Guard');
return null;
}
},
},
rebound: {
inherit: true,
onTryHitSide() {},
},
};

View File

@ -116,10 +116,6 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
onResidualOrder: 10,
onResidualSubOrder: 9,
},
lockedmove: {
inherit: true,
onAfterMove() {},
},
choicelock: {
inherit: true,
onStart(pokemon) {

View File

@ -736,7 +736,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "NU",
},
weavile: {
tier: "(OU)",
tier: "OU",
},
teddiursa: {
tier: "LC",
@ -1137,12 +1137,9 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
castform: {
tier: "NU",
},
castformsunny: {
},
castformrainy: {
},
castformsnowy: {
},
castformsunny: {},
castformrainy: {},
castformsnowy: {},
kecleon: {
tier: "NU",
},

View File

@ -144,7 +144,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
focussash: {
inherit: true,
onDamage() {},
onDamage() { },
onTryHit(target, source, move) {
if (target !== source && target.hp === target.maxhp) {
target.addVolatile('focussash');
@ -306,7 +306,11 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
metronome: {
inherit: true,
condition: {
inherit: true,
onStart(pokemon) {
this.effectState.numConsecutive = 0;
this.effectState.lastMove = '';
},
onTryMovePriority: -2,
onTryMove(pokemon, target, move) {
if (!pokemon.hasItem('metronome')) {
pokemon.removeVolatile('metronome');
@ -319,7 +323,6 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
}
this.effectState.lastMove = move.id;
},
onModifyDamage() {},
onModifyDamagePhase2(damage, source, target, move) {
return damage * (1 + (this.effectState.numConsecutive / 10));
},
@ -328,7 +331,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
micleberry: {
inherit: true,
condition: {
inherit: true,
duration: 2,
onSourceModifyAccuracyPriority: 3,
onSourceModifyAccuracy(accuracy, target, source) {
this.add('-enditem', source, 'Micle Berry');

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +1,11 @@
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
standardag: {
inherit: true,
ruleset: [
'Obtainable', 'HP Percentage Mod', 'Cancel Mod', 'Beat Up Nicknames Mod', 'Endless Battle Clause',
],
},
standard: {
inherit: true,
ruleset: [
'Standard AG',
'Sleep Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Items Clause', 'Evasion Moves Clause',
],
ruleset: ['Obtainable', 'Sleep Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Items Clause', 'Evasion Moves Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod'],
},
flatrules: {
inherit: true,
ruleset: ['Obtainable', 'Species Clause', 'Nickname Clause', 'Beat Up Nicknames Mod', 'Item Clause = 1', 'Adjust Level Down = 50', 'Picked Team Size = Auto', 'Cancel Mod'],
ruleset: ['Obtainable', 'Species Clause', 'Nickname Clause', 'Item Clause = 1', 'Adjust Level Down = 50', 'Cancel Mod'],
},
teampreview: {
inherit: true,

View File

@ -55,6 +55,10 @@ export const Scripts: ModdedBattleScriptsData = {
// Weather
baseDamage = this.battle.runEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
if (this.battle.gen === 3 && move.category === 'Physical' && !Math.floor(baseDamage)) {
baseDamage = 1;
}
baseDamage += 2;
const isCrit = target.getMoveHitData(move).crit;

View File

@ -1475,6 +1475,7 @@ export const Learnsets: import('../../../sim/dex-species').ModdedLearnsetDataTab
hiddenpower: ["4M", "3M"],
irontail: ["4M", "4S21", "3M"],
knockoff: ["4T"],
lastresort: ["4S18"],
lightscreen: ["4M", "4L42", "4S11", "3M", "3L50", "3S0", "3S6", "3S7", "3S8"],
magnetrise: ["4T"],
megakick: ["3T"],
@ -2915,6 +2916,7 @@ export const Learnsets: import('../../../sim/dex-species').ModdedLearnsetDataTab
steelwing: ["4M", "3M"],
substitute: ["4M", "3T"],
sunnyday: ["4M", "3M"],
superfang: ["4S0"],
supersonic: ["4L1", "3L1"],
swagger: ["4M", "3T"],
swift: ["4T", "3T"],

View File

@ -43,7 +43,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
newMove.hasBounced = true;
newMove.pranksterBoosted = false;
this.actions.useMove(newMove, this.effectState.target, { target: source });
move.hasBounced = true; // only bounce once in free-for-all battles
return null;
},
},
@ -65,9 +64,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
},
overcoat: {
inherit: true,
onImmunity(type, pokemon) {
if (type === 'sandstorm' || type === 'hail') return false;
},
onTryHit() {},
flags: {},
rating: 0.5,
@ -91,20 +87,4 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
inherit: true,
onAllyTryHitSide() {},
},
rebound: {
inherit: true,
onAllyTryHitSide(target, source, move) {
if (this.effectState.target.activeTurns) return;
if (target.isAlly(source) || move.hasBounced || !move.flags['reflectable']) {
return;
}
const newMove = this.dex.getActiveMove(move.id);
newMove.hasBounced = true;
newMove.pranksterBoosted = false;
this.actions.useMove(newMove, this.effectState.target, { target: source });
move.hasBounced = true; // only bounce once in free-for-all battles
return null;
},
},
};

View File

@ -15,7 +15,6 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
const trapper = this.effectState.source;
if (trapper && (!trapper.isActive || trapper.hp <= 0 || !trapper.activeTurns)) {
delete pokemon.volatiles['partiallytrapped'];
this.add('-end', pokemon, this.effectState.sourceEffect, '[partiallytrapped]', '[silent]');
return;
}
this.damage(pokemon.baseMaxhp / this.effectState.boundDivisor);

View File

@ -1347,8 +1347,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
},
castformrainy: {
},
castformsnowy: {
},
castformsnowy: {},
kecleon: {
tier: "PU",
doublesTier: "DUU",
@ -1626,7 +1625,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
gastrodon: {
tier: "(OU)",
tier: "OU",
doublesTier: "DOU",
},
drifloon: {

View File

@ -36,7 +36,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
autotomize: {
inherit: true,
volatileStatus: 'autotomize',
onHit() {},
onHit(pokemon) {
},
condition: {
noCopy: true, // doesn't get copied by Baton Pass
onStart(pokemon) {
@ -77,10 +78,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
flags: { protect: 1, reflectable: 1, mirror: 1, metronome: 1 },
},
bodyslam: {
inherit: true,
flags: { contact: 1, protect: 1, mirror: 1, nonsky: 1, metronome: 1 },
},
bounce: {
inherit: true,
flags: { contact: 1, charge: 1, protect: 1, mirror: 1, gravity: 1, distance: 1, metronome: 1, nosleeptalk: 1 },
@ -108,10 +105,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
basePower: 60,
onModifyMove(move, pokemon) {
if (pokemon.species.name !== 'Chatot') {
const confusion = move.secondaries?.find(secondary => secondary.volatileStatus === 'confusion');
if (confusion) confusion.chance = 0; // boosted by Sheer Force
}
if (pokemon.species.name !== 'Chatot') delete move.secondaries;
},
secondary: {
chance: 10,
@ -195,10 +189,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
flags: { contact: 1, protect: 1, mirror: 1, punch: 1, metronome: 1 },
},
dragonrush: {
inherit: true,
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
},
dreameater: {
inherit: true,
flags: { protect: 1, mirror: 1, metronome: 1 },
@ -267,7 +257,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
basePower: 20,
condition: {
inherit: true,
duration: 2,
onStart() {
this.effectState.multiplier = 1;
},
onRestart() {
if (this.effectState.multiplier < 8) {
this.effectState.multiplier <<= 1;
@ -359,17 +352,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
healpulse: {
inherit: true,
onHit(target, source) {
const success = !!this.heal(Math.ceil(target.baseMaxhp * 0.5));
if (success && !target.isAlly(source)) {
target.staleness = 'external';
}
return success;
},
},
heatcrash: {
inherit: true,
flags: { contact: 1, protect: 1, mirror: 1, nonsky: 1, metronome: 1 },
heal: [1, 2],
onHit() {},
},
heatwave: {
inherit: true,
@ -502,7 +486,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
lightscreen: {
inherit: true,
condition: {
inherit: true,
duration: 5,
durationCallback(target, source, effect) {
if (source?.hasItem('lightclay')) {
return 8;
}
return 5;
},
onAnyModifyDamage(damage, source, target, move) {
if (target !== source && this.effectState.target.hasAlly(target) && this.getCategory(move) === 'Special') {
if (!target.getMoveHitData(move).crit && !move.infiltrates) {
@ -512,6 +502,14 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
}
},
onSideStart(side) {
this.add('-sidestart', side, 'move: Light Screen');
},
onSideResidualOrder: 26,
onSideResidualSubOrder: 2,
onSideEnd(side) {
this.add('-sideend', side, 'move: Light Screen');
},
},
},
lowsweep: {
@ -521,7 +519,24 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
magiccoat: {
inherit: true,
condition: {
inherit: true,
duration: 1,
onStart(target, source, effect) {
this.add('-singleturn', target, 'move: Magic Coat');
if (effect?.effectType === 'Move') {
this.effectState.pranksterBoosted = effect.pranksterBoosted;
}
},
onTryHitPriority: 2,
onTryHit(target, source, move) {
if (target === source || move.hasBounced || !move.flags['reflectable'] || target.isSemiInvulnerable()) {
return;
}
const newMove = this.dex.getActiveMove(move.id);
newMove.hasBounced = true;
newMove.pranksterBoosted = this.effectState.pranksterBoosted;
this.actions.useMove(newMove, target, { target: source });
return null;
},
onAllyTryHitSide(target, source, move) {
if (target.isAlly(source) || move.hasBounced || !move.flags['reflectable']) {
return;
@ -530,7 +545,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
newMove.hasBounced = true;
newMove.pranksterBoosted = false;
this.actions.useMove(newMove, this.effectState.target, { target: source });
move.hasBounced = true; // only bounce once in free-for-all battles
return null;
},
},
@ -564,18 +578,18 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
pp: 20,
condition: {
inherit: true,
onAccuracy() {},
noCopy: true,
onSourceModifyDamage(damage, source, target, move) {
if (['stomp', 'steamroller'].includes(move.id)) {
return this.chainModify(2);
}
},
},
},
moonlight: {
inherit: true,
type: "Normal",
},
muddywater: {
inherit: true,
basePower: 95,
},
mudsport: {
inherit: true,
pseudoWeather: undefined,
@ -594,6 +608,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
},
},
muddywater: {
inherit: true,
basePower: 95,
},
naturepower: {
inherit: true,
onTryHit() {},
@ -634,10 +652,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
basePower: 70,
},
psychoshift: {
inherit: true,
accuracy: 90,
},
psychup: {
inherit: true,
onHit(target, source) {
@ -648,6 +662,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.add('-copyboost', source, target, '[from] move: Psych Up');
},
},
psychoshift: {
inherit: true,
accuracy: 90,
},
psywave: {
inherit: true,
accuracy: 80,
@ -662,7 +680,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
source.addVolatile('stall');
},
condition: {
inherit: true,
duration: 1,
onSideStart(target, source) {
this.add('-singleturn', source, 'Quick Guard');
},
onTryHitPriority: 4,
onTryHit(target, source, effect) {
// Quick Guard only blocks moves with a natural positive priority
// (e.g. it doesn't block 0 priority moves boosted by Prankster)
@ -689,7 +711,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
reflect: {
inherit: true,
condition: {
inherit: true,
duration: 5,
durationCallback(target, source, effect) {
if (source?.hasItem('lightclay')) {
return 8;
}
return 5;
},
onAnyModifyDamage(damage, source, target, move) {
if (target !== source && this.effectState.target.hasAlly(target) && this.getCategory(move) === 'Physical') {
if (!target.getMoveHitData(move).crit && !move.infiltrates) {
@ -699,6 +727,14 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
}
},
onSideStart(side) {
this.add('-sidestart', side, 'Reflect');
},
onSideResidualOrder: 26,
onSideResidualSubOrder: 1,
onSideEnd(side) {
this.add('-sideend', side, 'Reflect');
},
},
},
relicsong: {
@ -749,6 +785,19 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
flags: { protect: 1, reflectable: 1, mirror: 1, sound: 1, metronome: 1 },
},
skillswap: {
inherit: true,
onHit(target, source) {
const targetAbility = target.ability;
const sourceAbility = source.ability;
if (targetAbility === sourceAbility) {
return false;
}
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);
},
},
skullbash: {
inherit: true,
basePower: 100,
@ -836,7 +885,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
substitute: {
inherit: true,
condition: {
inherit: true,
onStart(target) {
this.add('-start', target, 'Substitute');
this.effectState.hp = Math.floor(target.maxhp / 4);
delete target.volatiles['partiallytrapped'];
},
onTryPrimaryHitPriority: -1,
onTryPrimaryHit(target, source, move) {
if (target === source || move.flags['bypasssub']) {
return;
@ -847,6 +901,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.attrLastMove('[still]');
return null;
}
damage = this.runEvent('SubDamage', target, source, move, damage);
if (!damage) {
return damage;
}
if (damage > target.volatiles['substitute'].hp) {
damage = target.volatiles['substitute'].hp as number;
}
@ -868,6 +926,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.runEvent('AfterSubDamage', target, source, move, damage);
return this.HIT_SUBSTITUTE;
},
onEnd(target) {
this.add('-end', target, 'Substitute');
},
},
},
submission: {

View File

@ -2,8 +2,7 @@ export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable
standard: {
inherit: true,
ruleset: [
'Standard AG',
'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Items Clause', 'Evasion Moves Clause',
'Obtainable', 'Team Preview', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Moody Clause', 'Evasion Items Clause', 'Evasion Moves Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod',
],
},
obtainablemoves: {

View File

@ -2,108 +2,39 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
venusaur: {
tier: "OU",
},
raichu: {
tier: "PU",
},
golbat: {
tier: "NFE",
},
vileplume: {
tier: "NU",
},
dugtrio: {
tier: "OU",
},
primeape: {
tier: "RU",
},
cloyster: {
tier: "OU",
},
electrode: {
tier: "PU",
},
marowak: {
tier: "NU",
},
chansey: {
tier: "OU",
},
kangaskhan: {
tier: "PU",
},
electabuzz: {
tier: "PU",
},
lapras: {
tier: "PU",
},
ditto: {
tier: "PU",
},
vaporeon: {
tier: "OU",
},
jolteon: {
tier: "OU",
},
flareon: {
tier: "NU",
},
ampharos: {
tier: "PU",
},
quagsire: {
tier: "NU",
},
espeon: {
tier: "OU",
},
donphan: {
tier: "OU",
},
linoone: {
tier: "PU",
},
vigoroth: {
tier: "NFE",
},
roselia: {
tier: "RU",
},
zangoose: {
tier: "PU",
},
cradily: {
tier: "PU",
},
absol: {
tier: "NU",
},
froslass: {
tier: "UU",
},
metagross: {
tier: "OU",
},
regice: {
tier: "PU",
},
deoxysdefense: {
tier: "UUBL",
},
torterra: {
tier: "NU",
},
infernape: {
tier: "OU",
},
luxray: {
tier: "NU",
},
garchomp: {
tier: "Uber",
},
lucario: {
tier: "OU",
},
@ -119,96 +50,27 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
abomasnow: {
tier: "UUBL",
},
magmortar: {
tier: "NU",
},
leafeon: {
tier: "NU",
},
porygonz: {
tier: "RUBL",
},
rotomfrost: {
tier: "PU",
},
emboar: {
tier: "NU",
},
stoutland: {
tier: "UU",
},
liepard: {
tier: "PU",
},
simipour: {
tier: "PU",
},
gigalith: {
tier: "PU",
garchomp: {
tier: "Uber",
},
excadrill: {
tier: "Uber",
},
seismitoad: {
tier: "PU",
},
throh: {
tier: "PU",
},
scolipede: {
tier: "RU",
},
basculin: {
tier: "NU",
},
scrafty: {
tier: "OU",
},
cofagrigus: {
tier: "RU",
},
carracosta: {
tier: "PU",
},
cinccino: {
tier: "NU",
},
gothorita: {
tier: "NFE",
},
gothitelle: {
tier: "PU",
},
swanna: {
tier: "PU",
},
escavalier: {
tier: "UU",
},
amoongus: {
tier: "NU",
},
chandelure: {
tier: "UU",
},
haxorus: {
tier: "OU",
},
cryogonal: {
tier: "NU",
},
mienshao: {
tier: "OU",
},
golurk: {
tier: "RU",
},
mandibuzz: {
tier: "RU",
},
durant: {
tier: "RUBL",
},
hydreigon: {
tier: "OU",
},

View File

@ -1585,7 +1585,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
huntail: {
tier: "ZUBL",
tier: "ZU",
doublesTier: "(DUU)",
},
gorebyss: {
@ -1678,7 +1678,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
doublesTier: "DUber",
},
jirachi: {
tier: "(OU)",
tier: "OU",
doublesTier: "DUber",
},
deoxys: {

View File

@ -34,6 +34,51 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
},
},
encore: {
inherit: true,
condition: {
duration: 3,
onStart(target) {
const moveIndex = target.lastMove ? target.moves.indexOf(target.lastMove.id) : -1;
if (
!target.lastMove || target.lastMove.flags['failencore'] ||
!target.moveSlots[moveIndex] || target.moveSlots[moveIndex].pp <= 0
) {
// it failed
return false;
}
this.effectState.move = target.lastMove.id;
this.add('-start', target, 'Encore');
if (!this.queue.willMove(target)) {
this.effectState.duration!++;
}
},
onOverrideAction(pokemon, target, move) {
if (move.id !== this.effectState.move) return this.effectState.move;
},
onResidualOrder: 16,
onResidual(target) {
const lockedMoveIndex = target.moves.indexOf(this.effectState.move);
if (lockedMoveIndex >= 0 && target.moveSlots[lockedMoveIndex].pp <= 0) {
// Encore ends early if you run out of PP
target.removeVolatile('encore');
}
},
onEnd(target) {
this.add('-end', target, 'Encore');
},
onDisableMove(pokemon) {
if (!this.effectState.move || !pokemon.hasMove(this.effectState.move)) {
return;
}
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id !== this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
}
},
},
},
fellstinger: {
inherit: true,
basePower: 30,
@ -45,10 +90,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
basePower: 80,
},
heavyslam: {
inherit: true,
flags: { contact: 1, protect: 1, mirror: 1, nonsky: 1, metronome: 1 },
},
leechlife: {
inherit: true,
basePower: 20,
@ -58,6 +99,29 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
flags: { protect: 1, bypasssub: 1, noassist: 1, failcopycat: 1, failmefirst: 1, nosleeptalk: 1 },
},
minimize: {
inherit: true,
condition: {
noCopy: true,
onSourceModifyDamage(damage, source, target, move) {
const boostedMoves = [
'stomp', 'steamroller', 'bodyslam', 'flyingpress', 'dragonrush', 'phantomforce', 'heatcrash', 'shadowforce',
];
if (boostedMoves.includes(move.id)) {
return this.chainModify(2);
}
},
onAccuracy(accuracy, target, source, move) {
const boostedMoves = [
'stomp', 'steamroller', 'bodyslam', 'flyingpress', 'dragonrush', 'phantomforce', 'heatcrash', 'shadowforce',
];
if (boostedMoves.includes(move.id)) {
return true;
}
return accuracy;
},
},
},
metronome: {
inherit: true,
flags: { noassist: 1, failcopycat: 1, nosleeptalk: 1 },
@ -65,8 +129,38 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
mistyterrain: {
inherit: true,
condition: {
inherit: true,
onTryAddVolatile() {},
duration: 5,
durationCallback(source, effect) {
if (source?.hasItem('terrainextender')) {
return 8;
}
return 5;
},
onSetStatus(status, target, source, effect) {
if (!target.isGrounded() || target.isSemiInvulnerable()) return;
if (effect && ((effect as Move).status || effect.id === 'yawn')) {
this.add('-activate', target, 'move: Misty Terrain');
}
return false;
},
onBasePower(basePower, attacker, defender, move) {
if (move.type === 'Dragon' && defender.isGrounded() && !defender.isSemiInvulnerable()) {
this.debug('misty terrain weaken');
return this.chainModify(0.5);
}
},
onFieldStart(field, source, effect) {
if (effect?.effectType === 'Ability') {
this.add('-fieldstart', 'move: Misty Terrain', `[from] ability: ${effect}`, `[of] ${source}`);
} else {
this.add('-fieldstart', 'move: Misty Terrain');
}
},
onFieldResidualOrder: 27,
onFieldResidualSubOrder: 7,
onFieldEnd() {
this.add('-fieldend', 'Misty Terrain');
},
},
},
mysticalfire: {
@ -87,25 +181,28 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.boost({ atk: -1, spa: -1 }, target, source);
},
},
phantomforce: {
inherit: true,
flags: { contact: 1, charge: 1, mirror: 1, metronome: 1, nosleeptalk: 1, noassist: 1, failinstruct: 1, minimize: 1 },
},
powder: {
inherit: true,
condition: {
inherit: true,
duration: 1,
onStart(target) {
this.add('-singleturn', target, 'Powder');
},
onTryMovePriority: 1,
onTryMove(pokemon, target, move) {
if (move.type === 'Fire') {
this.add('-activate', pokemon, 'move: Powder');
this.damage(this.clampIntRange(Math.round(pokemon.maxhp / 4), 1));
this.attrLastMove('[still]');
return false;
}
},
},
},
rockblast: {
inherit: true,
flags: { protect: 1, mirror: 1, metronome: 1 },
},
shadowforce: {
inherit: true,
flags: { contact: 1, charge: 1, mirror: 1, metronome: 1, nosleeptalk: 1, noassist: 1, failinstruct: 1, minimize: 1 },
},
sheercold: {
inherit: true,
ohko: true,
@ -168,7 +265,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
wideguard: {
inherit: true,
condition: {
inherit: true,
duration: 1,
onSideStart(target, source) {
this.add('-singleturn', source, 'Wide Guard');
},
onTryHitPriority: 4,
onTryHit(target, source, effect) {
// Wide Guard blocks damaging spread moves
if (

View File

@ -148,14 +148,6 @@ export const Pokedex: import('../../../sim/dex-species').ModdedSpeciesDataTable
inherit: true,
color: "Gray",
},
burmysandy: {
inherit: true,
color: "Gray",
},
burmytrash: {
inherit: true,
color: "Gray",
},
wormadam: {
inherit: true,
color: "Gray",
@ -172,14 +164,6 @@ export const Pokedex: import('../../../sim/dex-species').ModdedSpeciesDataTable
inherit: true,
color: "Pink",
},
shelloseast: {
inherit: true,
color: "Purple",
},
gastrodoneast: {
inherit: true,
color: "Purple",
},
arceus: {
inherit: true,
color: "Gray",
@ -313,18 +297,6 @@ export const Pokedex: import('../../../sim/dex-species').ModdedSpeciesDataTable
inherit: true,
color: "Yellow",
},
deerlingsummer: {
inherit: true,
color: "Yellow",
},
deerlingautumn: {
inherit: true,
color: "Yellow",
},
deerlingwinter: {
inherit: true,
color: "Yellow",
},
cubchoo: {
inherit: true,
abilities: { 0: "Snow Cloak", H: "Rattled" },
@ -346,82 +318,6 @@ export const Pokedex: import('../../../sim/dex-species').ModdedSpeciesDataTable
inherit: true,
color: "Black",
},
vivillonicysnow: {
inherit: true,
color: "Black",
},
vivillonpolar: {
inherit: true,
color: "Black",
},
vivillontundra: {
inherit: true,
color: "Black",
},
vivilloncontinental: {
inherit: true,
color: "Black",
},
vivillongarden: {
inherit: true,
color: "Black",
},
vivillonelegant: {
inherit: true,
color: "Black",
},
vivillonmodern: {
inherit: true,
color: "Black",
},
vivillonmarine: {
inherit: true,
color: "Black",
},
vivillonarchipelago: {
inherit: true,
color: "Black",
},
vivillonhighplains: {
inherit: true,
color: "Black",
},
vivillonsandstorm: {
inherit: true,
color: "Black",
},
vivillonriver: {
inherit: true,
color: "Black",
},
vivillonmonsoon: {
inherit: true,
color: "Black",
},
vivillonsavanna: {
inherit: true,
color: "Black",
},
vivillonsun: {
inherit: true,
color: "Black",
},
vivillonocean: {
inherit: true,
color: "Black",
},
vivillonjungle: {
inherit: true,
color: "Black",
},
vivillonfancy: {
inherit: true,
color: "Black",
},
vivillonpokeball: {
inherit: true,
color: "Black",
},
meowstic: {
inherit: true,
color: "White",

View File

@ -1,369 +0,0 @@
export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTable = {
merciless: {
shortDesc: "This Pokemon's attacks are critical hits if the target is statused.",
onModifyCritRatio(critRatio, source, target) {
if (target?.status) return 5;
},
name: "Merciless",
rating: 1.5,
num: 196,
gen: 6,
},
pocketdimension: {
shortDesc: "This Pokemon switches out after using a status move.",
onModifyMove(move, pokemon) {
if (move.category === 'Status') {
move.selfSwitch = true;
this.add('-ability', pokemon, 'Pocket Dimension');
this.add('-message', `${pokemon.name} will switch out if this moves lands!`);
}
},
name: "Pocket Dimension",
rating: 4.5,
},
grassysurge: {
inherit: true,
gen: 6,
},
mistysurge: {
inherit: true,
gen: 6,
},
neutralizinggas: {
inherit: true,
// Ability suppression cancelled in scripts.ts
// new Ability suppression implemented in scripts.ts
onSwitchIn(pokemon) {},
onEnd(source) {},
onStart(pokemon) {
this.add('-ability', pokemon, 'Neutralizing Gas');
},
// onModifyPriority implemented in relevant abilities
onFoeBeforeMovePriority: 13,
onFoeBeforeMove(attacker, defender, move) {
attacker.addVolatile('neutralizinggas');
},
condition: {
onAfterMove(pokemon) {
pokemon.removeVolatile('neutralizinggas');
},
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, notransform: 1 },
desc: "While this Pokemon is active, opposing Pokemon's moves and their effects ignore its own Ability. Does not affect the As One, Battle Bond, Comatose, Disguise, Gulp Missile, Ice Face, Multitype, Power Construct, RKS System, Schooling, Shields Down, Stance Change, or Zen Mode Abilities.",
shortDesc: "While this Pokemon is active, opposing Pokemon's Ability has no effect when it uses moves.",
gen: 6,
},
nostalgiatrip: {
shortDesc: "This Pokemon's moves have the damage categories they would have in Gen 3. Fairy-type moves are Special.",
onStart(pokemon) {
this.add('-ability', pokemon, 'Nostalgia Trip');
this.add('-message', `This Pokemon is experiencing a nostalgia trip!`);
},
onModifyMovePriority: 8,
onModifyMove(move, pokemon) {
if (move.category === "Status") return;
if (['Fire', 'Water', 'Grass', 'Electric', 'Dark', 'Psychic', 'Dragon', 'Fairy', 'Ice'].includes(move.type)) {
move.category = "Special";
} else {
move.category = "Physical";
}
},
name: "Nostalgia Trip",
rating: 4,
gen: 6,
},
weatherreport: {
onBeforeMovePriority: 0.5,
onBeforeMove(target, source, move) {
if (move.type === 'Fire') {
this.field.setWeather('sunnyday');
} else if (move.type === 'Water') {
this.field.setWeather('raindance');
}
},
name: "Weather Report",
shortDesc: "Before using a Water or Fire-type move, this Pokemon sets Rain Dance or Sunny Day respectively.",
rating: 4,
gen: 6,
},
armortail: {
inherit: true,
gen: 6,
},
brainpower: {
onModifySpAPriority: 5,
onModifySpA(spa) {
return this.chainModify(2);
},
name: "Brain Power",
shortDesc: "This Pokemon's Special Attack is doubled.",
rating: 5,
},
neuroforce: {
inherit: true,
gen: 6,
},
bugzapper: {
onTryHit(target, source, move) {
if (target !== source && move.type === 'Bug') {
if (!source.addVolatile('trapped', target, move, 'trapper')) {
this.add('-immune', target, '[from] ability: Bug Zapper');
}
return null;
}
},
name: "Bug Zapper",
shortDesc: "This Pokemon is immune to Bug-type moves and traps the foe if hit by one.",
rating: 5,
},
exoskeleton: {
onSourceModifyDamage(damage, source, target, move) {
if (move.category === 'Physical') {
return this.chainModify(0.5);
}
},
name: "Exoskeleton",
shortDesc: "This Pokemon receives 1/2 damage from physical attacks; Hazard immunity.",
rating: 4,
},
icescales: {
inherit: true,
onModifyAtkPriority: 5,
onModifyAtk(atk, attacker, defender, move) {
if (move.type === 'Ice') {
this.debug('Ice Scales boost');
return this.chainModify(1.5);
}
},
onModifySpAPriority: 5,
onModifySpA(atk, attacker, defender, move) {
if (move.type === 'Ice') {
this.debug('Ice Scales boost');
return this.chainModify(1.5);
}
},
onImmunity(type, pokemon) {
if (type === 'hail') return false;
},
shortDesc: "This Pokemon receives 1/2 damage from special attacks. Ice moves have 1.5x power. Hail immunity.",
gen: 6,
},
eartheater: {
inherit: true,
onDamage(damage, target, source, effect) {
if (effect && (effect.id === 'stealthrock' || effect.id === 'spikes')) {
this.heal(damage);
return false;
}
},
shortDesc: "Heals 1/4 of its max HP when hit by Ground; Ground immunity. Healed by Spikes and Stealth Rock.",
gen: 6,
},
toxicchain: {
inherit: true,
gen: 6,
},
shellejection: {
onModifyMovePriority: -1,
onModifyMove(move, attacker) {
if (move.category === 'Special') {
attacker.addVolatile('shellejection');
this.add('-ability', attacker, 'Shell Ejection');
this.add('-message', `${attacker.name} is getting ready to leave the battlefield!`);
this.add('-message', `${attacker.name} can no longer use status moves!`);
}
},
condition: {
duration: 2,
onDisableMove(pokemon) {
for (const moveSlot of pokemon.moveSlots) {
const move = this.dex.moves.get(moveSlot.id);
if (move.category === 'Status' && move.id !== 'mefirst') {
pokemon.disableMove(moveSlot.id);
}
}
},
onSwitchOut(pokemon) {
pokemon.heal(pokemon.baseMaxhp / 3);
},
onEnd(pokemon) {
this.add('-ability', pokemon, 'Shell Ejection');
this.add('-message', `${pokemon.name} ejected itself from its shell!`);
pokemon.heal(pokemon.baseMaxhp / 3);
pokemon.switchFlag = true;
},
},
name: "Shell Ejection",
rating: 3.5,
gen: 6,
shortDesc: "On using Special move: switching heals 1/3, can't use status, switches out at end of next turn.",
},
sharpness: {
inherit: true,
gen: 6,
},
dauntlessshield: {
onStart(pokemon) {
this.boost({ def: 1 }, pokemon);
pokemon.addVolatile('dauntlessshield');
},
onResidualOrder: 6,
onResidual(pokemon) {
if (pokemon.positiveBoosts()) {
this.heal(pokemon.baseMaxhp / 16);
this.add('-message', `${pokemon.name}'s shield gives it strength!`);
}
},
name: "Dauntless Shield",
rating: 5,
num: 235,
shortDesc: "+1 Defense on switch-in. Heals 1/16 of max HP if it has a positive boost.",
gen: 6,
},
confidence: {
onSourceAfterFaint(length, target, source, effect) {
if (effect && effect.effectType === 'Move') {
this.boost({ spa: length }, source);
}
},
name: "Confidence",
rating: 3,
shortDesc: "This Pokemon's Sp. Atk is raised by 1 stage if it attacks and KOes another Pokemon.",
gen: 6,
},
electricsurge: {
inherit: true,
gen: 6,
},
goodasgold: {
inherit: true,
gen: 6,
},
opportunist: {
inherit: true,
onUpdate(pokemon) {
let activate = false;
const boosts: SparseBoostsTable = {};
let i: BoostID;
for (i in pokemon.boosts) {
if (pokemon.boosts[i] < 0) {
activate = true;
boosts[i] = 0;
}
}
if (this.effectState.herb) return;
if (activate) {
pokemon.setBoost(boosts);
this.effectState.herb = true;
this.add('-ability', pokemon, 'Opportunist');
this.add('-clearnegativeboost', pokemon, '[silent]');
}
},
onSwitchIn(pokemon) {
delete this.effectState.herb;
},
shortDesc: "Copies foe's stat gains as they happen. Resets negative stat changes once per switch-in.",
gen: 6,
},
intoxicate: {
onModifyTypePriority: -1,
onModifyType(move, pokemon) {
const noModifyType = [
'judgment', 'multiattack', 'naturalgift', 'revelationdance', 'technoblast', 'terrainpulse', 'weatherball',
];
if (move.type === 'Normal' && !noModifyType.includes(move.id) &&
!(move.isZ && move.category !== 'Status') && !(move.name === 'Tera Blast' && pokemon.terastallized)) {
move.type = 'Poison';
move.typeChangerBoosted = this.effect;
}
},
onBasePowerPriority: 23,
onBasePower(basePower, pokemon, target, move) {
if (move.typeChangerBoosted) return this.chainModify([5325, 4096]);
},
name: "Intoxicate",
rating: 4,
shortDesc: "This Pokemon's Normal-type moves become Poison-type and have 1.3x power.",
},
dragonsgale: {
onStart(source) {
this.field.setWeather('deltastream');
},
onAnySetWeather(target, source, weather) {
const strongWeathers = ['desolateland', 'primordialsea', 'deltastream'];
if (this.field.getWeather().id === 'deltastream' && !strongWeathers.includes(weather.id)) return false;
},
onEnd(pokemon) {
if (this.field.weatherState.source !== pokemon) return;
for (const target of this.getAllActive()) {
if (target === pokemon) continue;
if (target.hasAbility('dragonsgale')) {
this.field.weatherState.source = target;
return;
}
}
this.field.clearWeather();
},
onDamage(damage, target, source, effect) {
if (effect && (effect.id === 'stealthrock' || effect.id === 'spikes')) {
return damage / 2;
}
},
flags: {},
name: "Dragon's Gale",
shortDesc: "On switch-in, sets Delta Stream. User takes halved damage from hazards.",
rating: 5,
},
parentalbond: {
onPrepareHit(source, target, move) {
if (move.category === 'Status' || move.selfdestruct || move.multihit) return;
if ([
'endeavor', 'seismictoss', 'psywave', 'nightshade', 'sonicboom', 'dragonrage',
'superfang', 'naturesmadness', 'bide', 'counter', 'mirrorcoat', 'metalburst',
].includes(move.id)) return;
if (!move.spreadHit && !move.isZ && !move.isMax) {
move.multihit = 2;
move.multihitType = 'parentalbond';
}
},
onSourceModifySecondaries(secondaries, target, source, move) {
if (move.multihitType === 'parentalbond' && move.id === 'secretpower' && move.hit < 2) {
// hack to prevent accidentally suppressing King's Rock/Razor Fang
return secondaries.filter(effect => effect.volatileStatus === 'flinch');
}
},
name: "Parental Bond",
rating: 4.5,
shortDesc: "This Pokemon's damaging moves hit twice. The second hit has its damage quartered.",
num: 184,
},
// for ngas
galewings: {
// for ngas
inherit: true,
onModifyPriority(priority, pokemon, target, move) {
for (const poke of this.getAllActive()) {
if (poke.hasAbility('neutralizinggas') && poke.side.id !== pokemon.side.id && !poke.abilityState.ending) {
return;
}
}
if (move && move.type === 'Flying') return priority + 1;
},
},
prankster: {
// for ngas
inherit: true,
onModifyPriority(priority, pokemon, target, move) {
for (const poke of this.getAllActive()) {
if (poke.hasAbility('neutralizinggas') && poke.side.id !== pokemon.side.id && !poke.abilityState.ending) {
return;
}
}
if (move?.category === 'Status') {
move.pranksterBoosted = true;
return priority + 1;
}
},
},
};

View File

@ -1,26 +0,0 @@
export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormatsDataTable = {
blaziken: {
tier: "OU",
},
blazikenmega: {
tier: "OU",
},
gengarmega: {
tier: "OU",
},
kangaskhanmega: {
tier: "OU",
},
lucariomega: {
tier: "OU",
},
mawilemega: {
tier: "OU",
},
sableyemega: {
tier: "OU",
},
salamencemega: {
tier: "OU",
},
};

View File

@ -1,12 +0,0 @@
export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
meteorite: {
name: "Meteorite",
spritenum: 615,
megaStone: { "Rayquaza": "Rayquaza-Mega" },
itemUser: ["Rayquaza"],
onTakeItem(item, source) {
return !item.megaStone?.[source.baseSpecies.baseSpecies];
},
desc: "If held by a Rayquaza, this item allows it to Mega Evolve in battle.",
},
};

View File

@ -1,77 +0,0 @@
export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
stealthrock: {
inherit: true,
condition: {
// this is a side condition
onSideStart(side) {
this.add('-sidestart', side, 'move: Stealth Rock');
},
onSwitchIn(pokemon) {
if (pokemon.hasItem('heavydutyboots') || pokemon.hasAbility('exoskeleton')) return;
const typeMod = this.clampIntRange(pokemon.runEffectiveness(this.dex.getActiveMove('stealthrock')), -6, 6);
this.damage(pokemon.maxhp * (2 ** typeMod) / 8);
},
},
},
toxicspikes: {
inherit: true,
condition: {
// this is a side condition
onSideStart(side) {
this.add('-sidestart', side, 'move: Toxic Spikes');
this.effectState.layers = 1;
},
onSideRestart(side) {
if (this.effectState.layers >= 2) return false;
this.add('-sidestart', side, 'move: Toxic Spikes');
this.effectState.layers++;
},
onSwitchIn(pokemon) {
if (!pokemon.isGrounded()) return;
if (pokemon.hasType('Poison')) {
this.add('-sideend', pokemon.side, 'move: Toxic Spikes', `[of] ${pokemon}`);
pokemon.side.removeSideCondition('toxicspikes');
} else if (pokemon.hasType('Steel') || pokemon.hasItem('heavydutyboots') || pokemon.hasAbility('exoskeleton')) {
// do nothing
} else if (this.effectState.layers >= 2) {
pokemon.trySetStatus('tox', pokemon.side.foe.active[0]);
} else {
pokemon.trySetStatus('psn', pokemon.side.foe.active[0]);
}
},
},
},
spikes: {
inherit: true,
condition: {
// this is a side condition
onSideStart(side) {
this.add('-sidestart', side, 'Spikes');
this.effectState.layers = 1;
},
onSideRestart(side) {
if (this.effectState.layers >= 3) return false;
this.add('-sidestart', side, 'Spikes');
this.effectState.layers++;
},
onSwitchIn(pokemon) {
if (!pokemon.isGrounded() || pokemon.hasItem('heavydutyboots') || pokemon.hasAbility('exoskeleton')) return;
const damageAmounts = [0, 3, 4, 6]; // 1/8, 1/6, 1/4
this.damage(damageAmounts[this.effectState.layers] * pokemon.maxhp / 24);
},
},
},
stickyweb: {
inherit: true,
condition: {
onSideStart(side) {
this.add('-sidestart', side, 'move: Sticky Web');
},
onSwitchIn(pokemon) {
if (!pokemon.isGrounded() || pokemon.hasItem('heavydutyboots') || pokemon.hasAbility('exoskeleton')) return;
this.add('-activate', pokemon, 'move: Sticky Web');
this.boost({ spe: -1 }, pokemon, pokemon.side.foe.active[0], this.dex.getActiveMove('stickyweb'));
},
},
},
};

View File

@ -1,249 +0,0 @@
export const Pokedex: import('../../../sim/dex-species').ModdedSpeciesDataTable = {
audinomega: {
inherit: true,
types: ["Normal", "Electric"],
baseStats: { hp: 103, atk: 60, def: 120, spa: 110, spd: 97, spe: 55 },
abilities: { 0: "Regenerator" },
},
houndoommega: {
inherit: true,
types: ["Dark", "Fire"],
baseStats: { hp: 75, atk: 90, def: 90, spa: 140, spd: 90, spe: 115 },
abilities: { 0: "Merciless" },
},
lucariomega: {
inherit: true,
types: ["Fighting", "Steel"],
baseStats: { hp: 70, atk: 125, def: 70, spa: 140, spd: 94, spe: 126 },
abilities: { 0: "Lightning Rod" },
},
banettemega: {
inherit: true,
types: ["Ghost", "Steel"],
baseStats: { hp: 64, atk: 149, def: 75, spa: 83, spd: 83, spe: 101 },
abilities: { 0: "Pocket Dimension" },
},
glaliemega: {
inherit: true,
types: ["Ice", "Steel"],
baseStats: { hp: 80, atk: 160, def: 70, spa: 95, spd: 70, spe: 105 },
abilities: { 0: "Refrigerate" },
},
venusaurmega: {
inherit: true,
types: ["Grass", "Poison"],
baseStats: { hp: 80, atk: 82, def: 123, spa: 120, spd: 120, spe: 100 },
abilities: { 0: "Grassy Surge" },
},
blastoisemega: {
inherit: true,
types: ["Water", "Fairy"],
baseStats: { hp: 79, atk: 83, def: 130, spa: 135, spd: 105, spe: 98 },
abilities: { 0: "Misty Surge" },
},
charizardmegay: {
inherit: true,
types: ["Fire", "Flying"],
baseStats: { hp: 78, atk: 94, def: 93, spa: 159, spd: 110, spe: 100 },
abilities: { 0: "Dragon's Gale" },
},
alakazammega: {
inherit: true,
types: ["Psychic", "Ice"],
baseStats: { hp: 55, atk: 50, def: 75, spa: 155, spd: 125, spe: 140 },
abilities: { 0: "Magic Guard" },
},
pinsirmega: {
inherit: true,
types: ["Bug", "Ice"],
baseStats: { hp: 65, atk: 150, def: 110, spa: 80, spd: 85, spe: 110 },
abilities: { 0: "Mountaineer" },
},
gengarmega: {
inherit: true,
types: ["Ghost", "Poison"],
baseStats: { hp: 60, atk: 65, def: 105, spa: 155, spd: 105, spe: 110 },
abilities: { 0: "Neutralizing Gas" },
},
aerodactylmega: {
inherit: true,
types: ["Rock", "Flying"],
baseStats: { hp: 80, atk: 140, def: 65, spa: 85, spd: 100, spe: 145 },
abilities: { 0: "Nostalgia Trip" },
},
steelixmega: {
inherit: true,
types: ["Steel", "Ground"],
baseStats: { hp: 75, atk: 135, def: 210, spa: 55, spd: 105, spe: 30 },
abilities: { 0: "Flash Fire" },
weightkg: 999.9,
},
altariamega: {
inherit: true,
types: ["Dragon", "Fairy"],
baseStats: { hp: 75, atk: 90, def: 90, spa: 140, spd: 115, spe: 80 },
abilities: { 0: "Weather Report" },
},
sceptilemega: {
inherit: true,
types: ["Grass", "Dragon"],
baseStats: { hp: 70, atk: 95, def: 79, spa: 145, spd: 99, spe: 142 },
abilities: { 0: "Armor Tail" },
},
swampertmega: {
inherit: true,
types: ["Water", "Poison"],
baseStats: { hp: 100, atk: 145, def: 110, spa: 85, spd: 110, spe: 85 },
abilities: { 0: "Toxic Chain" },
},
manectricmega: {
inherit: true,
types: ["Electric"],
baseStats: { hp: 70, atk: 75, def: 80, spa: 135, spd: 85, spe: 130 },
abilities: { 0: "Bug Zapper" },
},
absolmega: {
inherit: true,
types: ["Dark", "Fairy"],
baseStats: { hp: 65, atk: 130, def: 60, spa: 135, spd: 60, spe: 115 },
abilities: { 0: "Neuroforce" },
},
medichammega: {
inherit: true,
types: ["Fighting", "Psychic"],
baseStats: { hp: 60, atk: 60, def: 100, spa: 90, spd: 100, spe: 100 },
abilities: { 0: "Brain Power" },
},
sableyemega: {
inherit: true,
types: ["Dark", "Ghost"],
baseStats: { hp: 50, atk: 95, def: 115, spa: 85, spd: 115, spe: 20 },
},
beedrillmega: {
inherit: true,
types: ["Bug", "Rock"],
baseStats: { hp: 65, atk: 140, def: 85, spa: 45, spd: 85, spe: 75 },
abilities: { 0: "Exoskeleton" },
},
mawilemega: {
inherit: true,
types: ["Steel", "Fairy"],
baseStats: { hp: 50, atk: 90, def: 125, spa: 70, spd: 95, spe: 50 },
abilities: { 0: "Huge Power" },
},
abomasnowmega: {
inherit: true,
types: ["Grass"],
abilities: { 0: "Ice Scales" },
},
cameruptmega: {
inherit: true,
types: ["Fire", "Ground"],
baseStats: { hp: 70, atk: 80, def: 140, spa: 135, spd: 115, spe: 20 },
abilities: { 0: "Earth Eater" },
},
slowbromega: {
inherit: true,
types: ["Water", "Psychic"],
baseStats: { hp: 95, atk: 75, def: 150, spa: 120, spd: 120, spe: 30 },
abilities: { 0: "Shell Ejection" },
},
gallademega: {
inherit: true,
types: ["Psychic", "Fighting"],
baseStats: { hp: 68, atk: 150, def: 100, spa: 75, spd: 127, spe: 98 },
abilities: { 0: "Sharpness" },
},
ampharosmega: {
inherit: true,
types: ["Electric", "Dragon"],
baseStats: { hp: 90, atk: 95, def: 95, spa: 165, spd: 110, spe: 55 },
abilities: { 0: "Mega Launcher" },
},
gyaradosmega: {
inherit: true,
types: ["Water", "Flying"],
baseStats: { hp: 95, atk: 130, def: 109, spa: 85, spd: 130, spe: 91 },
abilities: { 0: "Aerilate" },
},
heracrossmega: {
inherit: true,
types: ["Bug", "Fighting"],
baseStats: { hp: 80, atk: 150, def: 150, spa: 40, spd: 110, spe: 70 },
abilities: { 0: "Iron Barbs" },
},
sharpedomega: {
inherit: true,
types: ["Water", "Electric"],
baseStats: { hp: 70, atk: 130, def: 55, spa: 145, spd: 55, spe: 105 },
abilities: { 0: "No Guard" },
},
gardevoirmega: {
inherit: true,
types: ["Psychic", "Fairy"],
baseStats: { hp: 68, atk: 65, def: 100, spa: 150, spd: 127, spe: 108 },
},
aggronmega: {
inherit: true,
types: ["Steel"],
baseStats: { hp: 70, atk: 145, def: 185, spa: 85, spd: 85, spe: 60 },
abilities: { 0: "Dauntless Shield" },
},
kangaskhanmega: {
inherit: true,
types: ["Normal", "Ground"],
baseStats: { hp: 105, atk: 125, def: 105, spa: 50, spd: 105, spe: 100 },
},
salamencemega: {
inherit: true,
types: ["Dragon", "Flying"],
baseStats: { hp: 95, atk: 135, def: 105, spa: 155, spd: 105, spe: 105 },
abilities: { 0: "Confidence" },
},
garchompmega: {
inherit: true,
types: ["Dragon", "Ground"],
baseStats: { hp: 108, atk: 150, def: 115, spa: 140, spd: 85, spe: 102 },
abilities: { 0: "Water Absorb" },
},
tyranitarmega: {
inherit: true,
types: ["Rock", "Electric"],
baseStats: { hp: 100, atk: 144, def: 120, spa: 110, spd: 144, spe: 82 },
abilities: { 0: "Electric Surge" },
},
latiasmega: {
inherit: true,
abilities: { 0: "Trace" },
},
latiosmega: {
inherit: true,
baseStats: { hp: 80, atk: 140, def: 100, spa: 150, spd: 120, spe: 110 },
abilities: { 0: "Opportunist" },
},
dianciemega: {
inherit: true,
abilities: { 0: "Good As Gold" },
},
blazikenmega: {
inherit: true,
baseStats: { hp: 80, atk: 150, def: 80, spa: 120, spd: 90, spe: 110 },
abilities: { 0: "Regenerator" },
},
mewtwomegax: {
inherit: true,
types: ["Psychic", "Poison"],
baseStats: { hp: 106, atk: 140, def: 130, spa: 154, spd: 120, spe: 130 },
abilities: { 0: "Intoxicate" },
},
mewtwomegay: {
inherit: true,
types: ["Psychic", "Water"],
baseStats: { hp: 106, atk: 120, def: 110, spa: 194, spd: 130, spe: 120 },
abilities: { 0: "Levitate" },
},
rayquazamega: {
inherit: true,
requiredItem: "Meteorite",
},
};

View File

@ -1,33 +0,0 @@
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
megadatamod: {
effectType: 'Rule',
name: 'Mega Data Mod',
desc: 'Gives data on stats, Ability and types when a Pokémon Mega Evolves or undergoes Ultra Burst.',
onSwitchIn(pokemon) {
if (pokemon.species.forme.startsWith('Mega') || pokemon.species.forme.startsWith('Ultra')) {
this.add('-start', pokemon, 'typechange', pokemon.getTypes(true).join('/'), '[silent]');
}
},
onAfterMega(pokemon) {
this.add('-start', pokemon, 'typechange', pokemon.getTypes(true).join('/'), '[silent]');
const species = pokemon.species;
let buf = `<span class="col pokemonnamecol" style="white-space: nowrap">${species.name}</span> `;
buf += `<span class="col typecol">`;
buf += `<img src="https://${Config.routes.client}/sprites/types/${species.types[0]}.png" alt="${species.types[0]}" height="14" width="32">`;
if (species.types[1]) {
buf += `<img src="https://${Config.routes.client}/sprites/types/${species.types[1]}.png" alt="${species.types[1]}" height="14" width="32">`;
}
buf += `</span> `;
buf += `<span style="float: left ; min-height: 26px"><span class="col abilitycol">${species.abilities[0]}</span><span class="col abilitycol"></span></span>`;
const stats = [];
let stat: StatID;
for (stat in species.baseStats) {
const statNames: { [k in StatID]: string } = { hp: "HP", atk: "Atk", def: "Def", spa: "SpA", spd: "SpD", spe: "Spe" };
stats.push(`<span class="col statcol"><em>${statNames[stat]}</em><br>${species.baseStats[stat]}</span>`);
}
buf += `<span style="float: left ; min-height: 26px">${stats.join(' ')}</span>`;
buf += `</span>`;
this.add(`raw|<ul class="utilichart"><li class="result">${buf}</li><li style="clear: both"></li></ul>`);
},
},
};

View File

@ -1,237 +0,0 @@
export const Scripts: ModdedBattleScriptsData = {
gen: 6,
inherit: 'gen6',
actions: {
// for parental bond
modifyDamage(
baseDamage: number, pokemon: Pokemon, target: Pokemon, move: ActiveMove, suppressMessages = false
) {
const tr = this.battle.trunc;
if (!move.type) move.type = '???';
const type = move.type;
baseDamage += 2;
if (move.spreadHit) {
// multi-target modifier (doubles only)
const spreadModifier = this.battle.gameType === 'freeforall' ? 0.5 : 0.75;
this.battle.debug(`Spread modifier: ${spreadModifier}`);
baseDamage = this.battle.modify(baseDamage, spreadModifier);
} else if (move.multihitType === 'parentalbond' && move.hit > 1) {
// Parental Bond modifier
const bondModifier = 0.25;
this.battle.debug(`Parental Bond modifier: ${bondModifier}`);
baseDamage = this.battle.modify(baseDamage, bondModifier);
}
baseDamage = this.battle.runEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
const isCrit = target.getMoveHitData(move).crit;
if (isCrit) {
baseDamage = tr(baseDamage * (move.critModifier || (this.battle.gen >= 6 ? 1.5 : 2)));
}
baseDamage = this.battle.randomizer(baseDamage);
if (type !== '???') {
let stab: number | [number, number] = 1;
const isSTAB = move.forceSTAB || pokemon.hasType(type) || pokemon.getTypes(false, true).includes(type);
if (isSTAB) {
stab = 1.5;
}
if (pokemon.terastallized === 'Stellar') {
if (!pokemon.stellarBoostedTypes.includes(type) || move.stellarBoosted) {
stab = isSTAB ? 2 : [4915, 4096];
move.stellarBoosted = true;
if (pokemon.species.name !== 'Terapagos-Stellar') {
pokemon.stellarBoostedTypes.push(type);
}
}
} else {
if (pokemon.terastallized === type && pokemon.getTypes(false, true).includes(type)) {
stab = 2;
}
stab = this.battle.runEvent('ModifySTAB', pokemon, target, move, stab);
}
baseDamage = this.battle.modify(baseDamage, stab);
}
let typeMod = target.runEffectiveness(move);
typeMod = this.battle.clampIntRange(typeMod, -6, 6);
target.getMoveHitData(move).typeMod = typeMod;
if (typeMod > 0) {
if (!suppressMessages) this.battle.add('-supereffective', target);
for (let i = 0; i < typeMod; i++) {
baseDamage *= 2;
}
}
if (typeMod < 0) {
if (!suppressMessages) this.battle.add('-resisted', target);
for (let i = 0; i > typeMod; i--) {
baseDamage = tr(baseDamage / 2);
}
}
if (isCrit && !suppressMessages) this.battle.add('-crit', target);
if (pokemon.status === 'brn' && move.category === 'Physical' && !pokemon.hasAbility('guts')) {
if (this.battle.gen < 6 || move.id !== 'facade') {
baseDamage = this.battle.modify(baseDamage, 0.5);
}
}
// Generation 5, but nothing later, sets damage to 1 before the final damage modifiers
if (this.battle.gen === 5 && !baseDamage) baseDamage = 1;
// Final modifier. Modifiers that modify damage after min damage check, such as Life Orb.
baseDamage = this.battle.runEvent('ModifyDamage', pokemon, target, move, baseDamage);
if (move.isZOrMaxPowered && target.getMoveHitData(move).zBrokeProtect) {
baseDamage = this.battle.modify(baseDamage, 0.25);
this.battle.add('-zbroken', target);
}
// Generation 6-7 moves the check for minimum 1 damage after the final modifier...
if (this.battle.gen !== 5 && !baseDamage) return 1;
// ...but 16-bit truncation happens even later, and can truncate to 0
return tr(baseDamage, 16);
},
},
pokemon: {
// for neutralizing gas
ignoringAbility() {
if (this.battle.gen >= 5 && !this.isActive) return true;
if (this.getAbility().flags['notransform'] && this.transformed) return true;
if (this.getAbility().flags['cantsuppress']) return false;
if (this.volatiles['gastroacid']) return true;
if (this.ability === ('neutralizinggas' as ID)) return false;
if (this.volatiles['neutralizinggas']) return true;
return false;
},
},
init() {
this.modData("Learnsets", "lucario").learnset.meteormash = ["6L1"];
this.modData("Learnsets", "lucario").learnset.machpunch = ["6L1"];
this.modData("Learnsets", "houndoom").learnset.toxicspikes = ["6L1"];
this.modData("Learnsets", "houndoom").learnset.venoshock = ["6L1"];
this.modData("Learnsets", "houndoom").learnset.hex = ["6L1"];
this.modData("Learnsets", "audino").learnset.discharge = ["6L1"];
this.modData("Learnsets", "audino").learnset.voltswitch = ["6L1"];
this.modData("Learnsets", "audino").learnset.chargebeam = ["6L1"];
this.modData("Learnsets", "audino").learnset.charge = ["6L1"];
this.modData("Learnsets", "audino").learnset.zapcannon = ["6L1"];
this.modData("Learnsets", "glalie").learnset.thunderfang = ["6L1"];
this.modData("Learnsets", "glalie").learnset.partingshot = ["6L1"];
this.modData("Learnsets", "glalie").learnset.boomburst = ["6L1"];
this.modData("Learnsets", "banette").learnset.ironhead = ["6L1"];
this.modData("Learnsets", "banette").learnset.metalsound = ["6L1"];
this.modData("Learnsets", "banette").learnset.powder = ["6L1"];
this.modData("Learnsets", "banette").learnset.stealthrock = ["6L1"];
this.modData("Learnsets", "banette").learnset.defog = ["6L1"];
this.modData("Learnsets", "venusaur").learnset.psychic = ["6L1"];
this.modData("Learnsets", "venusaur").learnset.calmmind = ["6L1"];
this.modData("Learnsets", "blastoise").learnset.moonblast = ["6L1"];
this.modData("Learnsets", "blastoise").learnset.mistyterrain = ["6L1"];
this.modData("Learnsets", "blastoise").learnset.taunt = ["6L1"];
this.modData("Learnsets", "blastoise").learnset.drainingkiss = ["6L1"];
this.modData("Learnsets", "blastoise").learnset.dazzlinggleam = ["6L1"];
this.modData("Learnsets", "charizard").learnset.calmmind = ["6L1"];
this.modData("Learnsets", "charizard").learnset.hurricane = ["6L1"];
this.modData("Learnsets", "charizard").learnset.lavaplume = ["6L1"];
this.modData("Learnsets", "gengar").learnset.reflecttype = ["6L1"];
this.modData("Learnsets", "gengar").learnset.calmmind = ["6L1"];
this.modData("Learnsets", "alakazam").learnset.blizzard = ["6L1"];
this.modData("Learnsets", "alakazam").learnset.flashcannon = ["6L1"];
this.modData("Learnsets", "alakazam").learnset.icebeam = ["6L1"];
this.modData("Learnsets", "alakazam").learnset.hail = ["6L1"];
this.modData("Learnsets", "pinsir").learnset.hail = ["6L1"];
this.modData("Learnsets", "pinsir").learnset.megahorn = ["6L1"];
this.modData("Learnsets", "pinsir").learnset.uturn = ["6L1"];
this.modData("Learnsets", "pinsir").learnset.iceshard = ["6L1"];
this.modData("Learnsets", "pinsir").learnset.iciclecrash = ["6L1"];
this.modData("Learnsets", "pinsir").learnset.icebeam = ["6L1"];
this.modData("Learnsets", "pinsir").learnset.blizzard = ["6L1"];
this.modData("Learnsets", "pinsir").learnset.roost = ["6L1"];
this.modData("Learnsets", "pinsir").learnset.iciclespear = ["6L1"];
this.modData("Learnsets", "aerodactyl").learnset.powergem = ["6L1"];
this.modData("Learnsets", "aerodactyl").learnset.shadowball = ["6L1"];
this.modData("Learnsets", "aerodactyl").learnset.hurricane = ["6L1"];
this.modData("Learnsets", "steelix").learnset.heatcrash = ["6L1"];
this.modData("Learnsets", "steelix").learnset.rapidspin = ["6L1"];
this.modData("Learnsets", "steelix").learnset.smackdown = ["6L1"];
this.modData("Learnsets", "altaria").learnset.scald = ["6L1"];
this.modData("Learnsets", "altaria").learnset.hydropump = ["6L1"];
this.modData("Learnsets", "altaria").learnset.thunder = ["6L1"];
this.modData("Learnsets", "sceptile").learnset.calmmind = ["6L1"];
this.modData("Learnsets", "sceptile").learnset.sludgewave = ["6L1"];
this.modData("Learnsets", "swampert").learnset.sludgebomb = ["6L1"];
this.modData("Learnsets", "swampert").learnset.bulkup = ["6L1"];
this.modData("Learnsets", "swampert").learnset.toxicspikes = ["6L1"];
this.modData("Learnsets", "swampert").learnset.aquajet = ["6L1"];
this.modData("Learnsets", "swampert").learnset.gunkshot = ["6L1"];
this.modData("Learnsets", "swampert").learnset.poisonjab = ["6L1"];
this.modData("Learnsets", "pidgeot").learnset.focusblast = ["6L1"];
this.modData("Learnsets", "absol").learnset.closecombat = ["6L1"];
this.modData("Learnsets", "absol").learnset.moonblast = ["6L1"];
this.modData("Learnsets", "absol").learnset.moonlight = ["6L1"];
this.modData("Learnsets", "medicham").learnset.aurasphere = ["6L1"];
this.modData("Learnsets", "medicham").learnset.thunderbolt = ["6L1"];
this.modData("Learnsets", "medicham").learnset.closecombat = ["6L1"];
this.modData("Learnsets", "medicham").learnset.gunkshot = ["6L1"];
this.modData("Learnsets", "medicham").learnset.healingwish = ["6L1"];
this.modData("Learnsets", "beedrill").learnset.earthquake = ["6L1"];
this.modData("Learnsets", "beedrill").learnset.stoneedge = ["6L1"];
this.modData("Learnsets", "beedrill").learnset.rockslide = ["6L1"];
this.modData("Learnsets", "beedrill").learnset.smackdown = ["6L1"];
this.modData("Learnsets", "beedrill").learnset.stealthrock = ["6L1"];
this.modData("Learnsets", "beedrill").learnset.diamondstorm = ["6L1"];
this.modData("Learnsets", "mawile").learnset.firepunch = ["6L1"];
this.modData("Learnsets", "mawile").learnset.rockslide = ["6L1"];
this.modData("Learnsets", "mawile").learnset.slackoff = ["6L1"];
this.modData("Learnsets", "camerupt").learnset.morningsun = ["6L1"];
this.modData("Learnsets", "abomasnow").learnset.spikyshield = ["6L1"];
this.modData("Learnsets", "abomasnow").learnset.earthpower = ["6L1"];
this.modData("Learnsets", "abomasnow").learnset.hornleech = ["6L1"];
this.modData("Learnsets", "gallade").learnset.sacredsword = ["6L1"];
this.modData("Learnsets", "gallade").learnset.machpunch = ["6L1"];
this.modData('Moves', 'aerialace').flags.slicing = 1;
this.modData('Moves', 'aircutter').flags.slicing = 1;
this.modData('Moves', 'airslash').flags.slicing = 1;
this.modData('Moves', 'behemothblade').flags.slicing = 1;
this.modData('Moves', 'crosspoison').flags.slicing = 1;
this.modData('Moves', 'cut').flags.slicing = 1;
this.modData('Moves', 'furycutter').flags.slicing = 1;
this.modData('Moves', 'nightslash').flags.slicing = 1;
this.modData('Moves', 'psychocut').flags.slicing = 1;
this.modData('Moves', 'razorleaf').flags.slicing = 1;
this.modData('Moves', 'razorshell').flags.slicing = 1;
this.modData('Moves', 'sacredsword').flags.slicing = 1;
this.modData('Moves', 'slash').flags.slicing = 1;
this.modData('Moves', 'solarblade').flags.slicing = 1;
this.modData('Moves', 'xscissor').flags.slicing = 1;
this.modData("Learnsets", "ampharos").learnset.waterpulse = ["6L1"];
this.modData("Learnsets", "ampharos").learnset.aurasphere = ["6L1"];
this.modData("Learnsets", "ampharos").learnset.darkpulse = ["6L1"];
this.modData("Learnsets", "ampharos").learnset.defog = ["6L1"];
this.modData("Learnsets", "ampharos").learnset.slackoff = ["6L1"];
this.modData("Learnsets", "heracross").learnset.healorder = ["6L1"];
this.modData("Learnsets", "heracross").learnset.circlethrow = ["6L1"];
this.modData("Learnsets", "heracross").learnset.spikes = ["6L1"];
this.modData("Learnsets", "heracross").learnset.icepunch = ["6L1"];
this.modData("Learnsets", "sharpedo").learnset.thunder = ["6L1"];
this.modData("Learnsets", "gardevoir").learnset.rapidspin = ["6L1"];
this.modData("Learnsets", "gardevoir").learnset.mysticalfire = ["6L1"];
this.modData("Learnsets", "aggron").learnset.voltswitch = ["6L1"];
this.modData("Learnsets", "kangaskhan").learnset.milkdrink = ["6L1"];
this.modData("Learnsets", "salamence").learnset.hurricane = ["6L1"];
this.modData("Learnsets", "salamence").learnset.airslash = ["6L1"];
this.modData("Learnsets", "salamence").learnset.ironhead = ["6L1"];
this.modData("Learnsets", "tyranitar").learnset.wildcharge = ["6L1"];
this.modData("Learnsets", "tyranitar").learnset.waterfall = ["6L1"];
this.modData("Learnsets", "diancie").learnset.spikyshield = ["6L1"];
this.modData("Learnsets", "blaziken").learnset.uturn = ["6L1"];
this.modData("Learnsets", "blaziken").learnset.spikes = ["6L1"];
this.modData("Learnsets", "blaziken").learnset.roost = ["6L1"];
this.modData("Learnsets", "blaziken").learnset.closecombat = ["6L1"];
this.modData("Learnsets", "mewtwo").learnset.extremespeed = ["6L1"];
this.modData("Learnsets", "mewtwo").learnset.sludgewave = ["6L1"];
this.modData("Learnsets", "mewtwo").learnset.swordsdance = ["6L1"];
this.modData("Learnsets", "mewtwo").learnset.uturn = ["6L1"];
this.modData("Learnsets", "mewtwo").learnset.closecombat = ["6L1"];
this.modData("Learnsets", "mewtwo").learnset.drainpunch = ["6L1"];
this.modData("Learnsets", "mewtwo").learnset.machpunch = ["6L1"];
this.modData("Learnsets", "mewtwo").learnset.scald = ["6L1"];
this.modData("Learnsets", "mewtwo").learnset.surf = ["6L1"];
this.modData("Learnsets", "mewtwo").learnset.hydropump = ["6L1"];
this.modData("Learnsets", "rayquaza").learnset.coil = ["6L1"];
this.modData("Learnsets", "rayquaza").learnset.defog = ["6L1"];
},
};

View File

@ -1,46 +0,0 @@
export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
blueorb: {
inherit: true,
onSwitchIn(pokemon) {
if (pokemon.isActive && !pokemon.species.isPrimal && !pokemon.transformed) {
// @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);
} else {
pokemon.formeChange(species, this.effect, true);
pokemon.baseSpecies = species;
this.add('-start', pokemon, 'Blue Orb', '[silent]');
}
}
},
onTakeItem: false,
},
redorb: {
inherit: true,
onSwitchIn(pokemon) {
if (pokemon.isActive && !pokemon.species.isPrimal && !pokemon.transformed) {
// @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);
} else {
pokemon.formeChange(species, this.effect, true);
pokemon.baseSpecies = species;
this.add('-start', pokemon, 'Red Orb', '[silent]');
const apparentSpecies = pokemon.illusion ? pokemon.illusion.species.name : pokemon.m.originalSpecies;
const oSpecies = this.dex.species.get(apparentSpecies);
if (pokemon.illusion) {
const types = oSpecies.types;
if (types.length > 1 || types[types.length - 1] !== 'Fire') {
this.add('-start', pokemon, 'typechange', (types[0] !== 'Fire' ? types[0] + '/' : '') + 'Fire', '[silent]');
}
} else if (oSpecies.types.length !== pokemon.species.types.length || oSpecies.types[1] !== pokemon.species.types[1]) {
this.add('-start', pokemon, 'typechange', pokemon.species.types.join('/'), '[silent]');
}
}
}
},
onTakeItem: false,
},
};

View File

@ -1,117 +0,0 @@
export const Scripts: ModdedBattleScriptsData = {
gen: 6,
inherit: 'gen6',
init() {
for (const i in this.data.Items) {
if (!this.data.Items[i].megaStone) continue;
this.modData('Items', i).onTakeItem = false;
}
},
actions: {
canMegaEvo(pokemon) {
if (pokemon.species.isMega || pokemon.species.isPrimal) return null;
const item = pokemon.getItem();
if (item.megaStone) {
const values = Object.values(item.megaStone);
if (values.includes(pokemon.name)) return null;
return values[0];
} else if (pokemon.baseMoves.includes('dragonascent')) {
return 'Rayquaza-Mega';
} else {
return null;
}
},
runMegaEvo(pokemon) {
if (pokemon.species.isMega || pokemon.species.isPrimal) return false;
const species: Species = (this as any).getMixedSpecies(pokemon.m.originalSpecies, pokemon.canMegaEvo, pokemon);
// Do we have a proper sprite for it? Code for when megas actually exist
if (this.dex.species.get(pokemon.canMegaEvo as any).baseSpecies === pokemon.m.originalSpecies) {
pokemon.formeChange(species, pokemon.getItem(), true);
} else {
const oSpecies = this.dex.species.get(pokemon.m.originalSpecies);
const oMegaSpecies = this.dex.species.get((species as any).originalSpecies);
pokemon.formeChange(species, pokemon.getItem(), true);
this.battle.add('-start', pokemon, oMegaSpecies.requiredItem, '[silent]');
if (oSpecies.types.join('/') !== pokemon.species.types.join('/')) {
this.battle.add('-start', pokemon, 'typechange', pokemon.species.types.join('/'), '[silent]');
}
}
pokemon.canMegaEvo = false;
return true;
},
getMixedSpecies(originalForme, formeChange, pokemon) {
const originalSpecies = this.dex.species.get(originalForme);
const formeChangeSpecies = this.dex.species.get(formeChange);
if (originalSpecies.baseSpecies === formeChangeSpecies.baseSpecies) {
return formeChangeSpecies;
}
const deltas = (this as any).getFormeChangeDeltas(formeChangeSpecies, pokemon);
const species = (this as any).mutateOriginalSpecies(originalSpecies, deltas);
return species;
},
getFormeChangeDeltas(formeChangeSpecies, pokemon) {
// Should be fine as long as Necrozma-U doesn't get added or Game Freak makes me sad with some convoluted forme change
const baseSpecies = this.dex.species.get(formeChangeSpecies.isMega ?
formeChangeSpecies.battleOnly as string : formeChangeSpecies.baseSpecies);
const deltas: {
ability: string,
baseStats: SparseStatsTable,
weighthg: number,
heightm: number,
originalSpecies: string,
requiredItem: string | undefined,
type?: string,
formeType?: string,
isMega?: boolean,
} = {
ability: formeChangeSpecies.abilities['0'],
baseStats: {},
weighthg: formeChangeSpecies.weighthg - baseSpecies.weighthg,
heightm: ((formeChangeSpecies.heightm * 10) - (baseSpecies.heightm * 10)) / 10,
originalSpecies: formeChangeSpecies.name,
requiredItem: formeChangeSpecies.requiredItem,
};
let statId: StatID;
for (statId in formeChangeSpecies.baseStats) {
deltas.baseStats[statId] = formeChangeSpecies.baseStats[statId] - baseSpecies.baseStats[statId];
}
let formeType: string | null = null;
if (formeChangeSpecies.types.length > baseSpecies.types.length) {
deltas.type = formeChangeSpecies.types[1];
} else if (formeChangeSpecies.types.length < baseSpecies.types.length) {
deltas.type = baseSpecies.types[0];
} else if (formeChangeSpecies.types[1] !== baseSpecies.types[1]) {
deltas.type = formeChangeSpecies.types[1];
}
if (formeChangeSpecies.isMega && !formeType) formeType = 'Mega';
if (formeChangeSpecies.isPrimal) formeType = 'Primal';
if (formeType) deltas.formeType = formeType;
return deltas;
},
mutateOriginalSpecies(speciesOrForme, deltas) {
if (!deltas) throw new TypeError("Must specify deltas!");
const species = this.dex.deepClone(this.dex.species.get(speciesOrForme));
species.abilities = { '0': deltas.ability };
if (species.types[0] === deltas.type) {
species.types = [deltas.type];
} else if (deltas.type) {
species.types = [species.types[0], deltas.type];
}
const baseStats = species.baseStats;
for (const statName in baseStats) {
baseStats[statName] = this.battle.clampIntRange(baseStats[statName] + deltas.baseStats[statName], 1, 255);
}
species.weighthg = Math.max(1, species.weighthg + deltas.weighthg);
species.heightm = Math.max(0.1, ((species.heightm * 10) + (deltas.heightm * 10)) / 10);
species.originalSpecies = deltas.originalSpecies;
species.requiredItem = deltas.requiredItem;
if (deltas.formeType === 'Mega' || deltas.isMega) species.isMega = true;
if (deltas.formeType === 'Primal') species.isPrimal = true;
return species;
},
},
};

View File

@ -19,7 +19,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
if (['mimikyu', 'mimikyutotem'].includes(pokemon.species.id) && this.effectState.busted) {
const speciesid = pokemon.species.id === 'mimikyutotem' ? 'Mimikyu-Busted-Totem' : 'Mimikyu-Busted';
pokemon.formeChange(speciesid, this.effect, true);
pokemon.formeRegression = true;
}
},
},
@ -72,8 +71,14 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
onTryBoost() {},
},
rattled: {
inherit: true,
onAfterBoost() {},
onDamagingHit(damage, target, source, move) {
if (['Dark', 'Bug', 'Ghost'].includes(move.type)) {
this.boost({ spe: 1 });
}
},
name: "Rattled",
rating: 1.5,
num: 155,
},
scrappy: {
inherit: true,
@ -81,18 +86,33 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
},
slowstart: {
inherit: true,
onModifyAtk(atk, pokemon, target, move) {
// This is because the game checks the move's category in data, rather than what it is currently, unlike e.g. Huge Power
if (this.effectState.counter && this.dex.moves.get(move.id).category === 'Physical') {
condition: {
duration: 5,
onResidualOrder: 28,
onResidualSubOrder: 2,
onStart(target) {
this.add('-start', target, 'ability: Slow Start');
},
onModifyAtkPriority: 5,
onModifyAtk(atk, pokemon, target, move) {
// This is because the game checks the move's category in data, rather than what it is currently, unlike e.g. Huge Power
if (this.dex.moves.get(move.id).category === 'Physical') {
return this.chainModify(0.5);
}
},
onModifySpAPriority: 5,
onModifySpA(spa, pokemon, target, move) {
// Ordinary Z-moves like Breakneck Blitz will halve the user's Special Attack as well
if (this.dex.moves.get(move.id).category === 'Physical') {
return this.chainModify(0.5);
}
},
onModifySpe(spe, pokemon) {
return this.chainModify(0.5);
}
},
onModifySpAPriority: 5,
onModifySpA(spa, pokemon, target, move) {
// Ordinary Z-moves like Breakneck Blitz will halve the user's Special Attack as well
if (this.effectState.counter && this.dex.moves.get(move.id).category === 'Physical') {
return this.chainModify(0.5);
}
},
onEnd(target) {
this.add('-end', target, 'Slow Start');
},
},
},
soundproof: {

View File

@ -207,7 +207,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "NFE",
},
vulpixalola: {
tier: "NFE",
tier: "LC",
},
ninetales: {
tier: "RU",
@ -592,7 +592,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
doublesTier: "NFE",
},
tangrowth: {
tier: "(OU)",
tier: "OU",
doublesTier: "(DUU)",
},
kangaskhan: {
@ -916,7 +916,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "NFE",
},
azumarill: {
tier: "(OU)",
tier: "OU",
doublesTier: "DUU",
},
bonsly: {

View File

@ -127,8 +127,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
onHit(target, source, move) {
let success = false;
if (!target.volatiles['substitute'] || move.infiltrates) success = !!this.boost({ evasion: -1 });
const removeTarget = [
'reflect', 'lightscreen', 'auroraveil', 'safeguard', 'mist', 'spikes', 'toxicspikes', 'stealthrock', 'stickyweb',
];
const removeAll = ['spikes', 'toxicspikes', 'stealthrock', 'stickyweb'];
const removeTarget = ['reflect', 'lightscreen', 'auroraveil', 'safeguard', 'mist', ...removeAll];
for (const targetCondition of removeTarget) {
if (target.side.removeSideCondition(targetCondition)) {
if (!removeAll.includes(targetCondition)) continue;
@ -182,13 +184,46 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
electricterrain: {
inherit: true,
condition: {
inherit: true,
duration: 5,
durationCallback(source, effect) {
if (source?.hasItem('terrainextender')) {
return 8;
}
return 5;
},
onSetStatus(status, target, source, effect) {
if (status.id === 'slp' && target.isGrounded() && !target.isSemiInvulnerable()) {
if (effect.id === 'yawn' || (effect.effectType === 'Move' && !effect.secondaries)) {
this.add('-activate', target, 'move: Electric Terrain');
}
return false;
}
},
onTryAddVolatile(status, target) {
if (!target.isGrounded() || target.isSemiInvulnerable()) return;
if (status.id === 'yawn') {
this.add('-activate', target, 'move: Electric Terrain');
return null;
}
},
onBasePower(basePower, attacker, defender, move) {
if (move.type === 'Electric' && attacker.isGrounded() && !attacker.isSemiInvulnerable()) {
this.debug('electric terrain boost');
return this.chainModify(1.5);
}
},
onFieldStart(field, source, effect) {
if (effect && effect.effectType === 'Ability') {
this.add('-fieldstart', 'move: Electric Terrain', `[from] ability: ${effect}`, `[of] ${source}`);
} else {
this.add('-fieldstart', 'move: Electric Terrain');
}
},
onFieldResidualOrder: 27,
onFieldResidualSubOrder: 7,
onFieldEnd() {
this.add('-fieldend', 'move: Electric Terrain');
},
},
},
embargo: {
@ -282,7 +317,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
grassyterrain: {
inherit: true,
condition: {
inherit: true,
duration: 5,
durationCallback(source, effect) {
if (source?.hasItem('terrainextender')) {
return 8;
}
return 5;
},
onBasePower(basePower, attacker, defender, move) {
const weakenedMoves = ['earthquake', 'bulldoze', 'magnitude'];
if (weakenedMoves.includes(move.id) && defender.isGrounded() && !defender.isSemiInvulnerable()) {
@ -294,6 +335,27 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
return this.chainModify(1.5);
}
},
onFieldStart(field, source, effect) {
if (effect && effect.effectType === 'Ability') {
this.add('-fieldstart', 'move: Grassy Terrain', `[from] ability: ${effect}`, `[of] ${source}`);
} else {
this.add('-fieldstart', 'move: Grassy Terrain');
}
},
onResidualOrder: 5,
onResidualSubOrder: 2,
onResidual(pokemon) {
if (pokemon.isGrounded() && !pokemon.isSemiInvulnerable()) {
this.heal(pokemon.baseMaxhp / 16, pokemon, pokemon);
} else {
this.debug(`Pokemon semi-invuln or not grounded; Grassy Terrain skipped`);
}
},
onFieldResidualOrder: 27,
onFieldResidualSubOrder: 7,
onFieldEnd() {
this.add('-fieldend', 'move: Grassy Terrain');
},
},
},
guardianofalola: {
@ -324,6 +386,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
condition: {
duration: 2,
onSwitchInPriority: 1,
onSwitchIn(target) {
if (!target.fainted) {
target.heal(target.maxhp);
@ -496,7 +559,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
kingsshield: {
inherit: true,
condition: {
inherit: true,
duration: 1,
onStart(target) {
this.add('-singleturn', target, 'Protect');
},
onTryHitPriority: 3,
onTryHit(target, source, move) {
if (!move.flags['protect'] || move.category === 'Status') {
if (move.isZ || move.isMax) target.getMoveHitData(move).zBrokeProtect = true;
@ -546,6 +613,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
condition: {
duration: 2,
onSwitchInPriority: 1,
onSwitchIn(target) {
if (!target.fainted) {
target.heal(target.maxhp);
@ -714,13 +782,47 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
psychicterrain: {
inherit: true,
condition: {
inherit: true,
duration: 5,
durationCallback(source, effect) {
if (source?.hasItem('terrainextender')) {
return 8;
}
return 5;
},
onTryHitPriority: 4,
onTryHit(target, source, effect) {
if (effect && (effect.priority <= 0.1 || effect.target === 'self')) {
return;
}
if (target.isSemiInvulnerable() || target.isAlly(source)) return;
if (!target.isGrounded()) {
const baseMove = this.dex.moves.get(effect.id);
if (baseMove.priority > 0) {
this.hint("Psychic Terrain doesn't affect Pokémon immune to Ground.");
}
return;
}
this.add('-activate', target, 'move: Psychic Terrain');
return null;
},
onBasePower(basePower, attacker, defender, move) {
if (move.type === 'Psychic' && attacker.isGrounded() && !attacker.isSemiInvulnerable()) {
this.debug('psychic terrain boost');
return this.chainModify(1.5);
}
},
onFieldStart(field, source, effect) {
if (effect && effect.effectType === 'Ability') {
this.add('-fieldstart', 'move: Psychic Terrain', `[from] ability: ${effect}`, `[of] ${source}`);
} else {
this.add('-fieldstart', 'move: Psychic Terrain');
}
},
onFieldResidualOrder: 27,
onFieldResidualSubOrder: 7,
onFieldEnd() {
this.add('-fieldend', 'move: Psychic Terrain');
},
},
},
psychoboost: {
@ -1052,6 +1154,39 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
isNonstandard: null,
},
trick: {
inherit: true,
onHit(target, source, move) {
const yourItem = target.takeItem(source);
const myItem = source.takeItem();
if (target.item || source.item || (!yourItem && !myItem)) {
if (yourItem) target.item = yourItem.id;
if (myItem) source.item = myItem.id;
return false;
}
if (
(myItem && !this.singleEvent('TakeItem', myItem, source.itemState, target, source, move, myItem)) ||
(yourItem && !this.singleEvent('TakeItem', yourItem, target.itemState, source, target, move, yourItem))
) {
if (yourItem) target.item = yourItem.id;
if (myItem) source.item = myItem.id;
return false;
}
this.add('-activate', source, 'move: Trick', `[of] ${target}`);
if (myItem) {
target.setItem(myItem);
this.add('-item', target, myItem, '[from] move: Trick');
} else {
this.add('-enditem', target, yourItem, '[silent]', '[from] move: Trick');
}
if (yourItem) {
source.setItem(yourItem);
this.add('-item', source, yourItem, '[from] move: Trick');
} else {
this.add('-enditem', source, myItem, '[silent]', '[from] move: Trick');
}
},
},
trumpcard: {
inherit: true,
isNonstandard: null,

View File

@ -59,14 +59,6 @@ export const Pokedex: import('../../../sim/dex-species').ModdedSpeciesDataTable
inherit: true,
eggGroups: ["Bug"],
},
burmysandy: {
inherit: true,
color: "Green",
},
burmytrash: {
inherit: true,
color: "Green",
},
magnezone: {
inherit: true,
evoType: "levelExtra",
@ -91,94 +83,6 @@ export const Pokedex: import('../../../sim/dex-species').ModdedSpeciesDataTable
abilities: { 0: "Flash Fire", H: "Flame Body" },
unreleasedHidden: true,
},
deerlingsummer: {
inherit: true,
color: "Pink",
},
deerlingautumn: {
inherit: true,
color: "Pink",
},
deerlingwinter: {
inherit: true,
color: "Pink",
},
vivillonicysnow: {
inherit: true,
color: "White",
},
vivillonpolar: {
inherit: true,
color: "White",
},
vivillontundra: {
inherit: true,
color: "White",
},
vivilloncontinental: {
inherit: true,
color: "White",
},
vivillongarden: {
inherit: true,
color: "White",
},
vivillonelegant: {
inherit: true,
color: "White",
},
vivillonmodern: {
inherit: true,
color: "White",
},
vivillonmarine: {
inherit: true,
color: "White",
},
vivillonarchipelago: {
inherit: true,
color: "White",
},
vivillonhighplains: {
inherit: true,
color: "White",
},
vivillonsandstorm: {
inherit: true,
color: "White",
},
vivillonriver: {
inherit: true,
color: "White",
},
vivillonmonsoon: {
inherit: true,
color: "White",
},
vivillonsavanna: {
inherit: true,
color: "White",
},
vivillonsun: {
inherit: true,
color: "White",
},
vivillonocean: {
inherit: true,
color: "White",
},
vivillonjungle: {
inherit: true,
color: "White",
},
vivillonfancy: {
inherit: true,
color: "White",
},
vivillonpokeball: {
inherit: true,
color: "White",
},
aegislash: {
inherit: true,
baseStats: { hp: 60, atk: 50, def: 150, spa: 50, spd: 150, spe: 60 },

View File

@ -1,19 +1,11 @@
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
standard: {
inherit: true,
ruleset: [
'Standard AG',
'Sleep Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Items Clause', 'Evasion Moves Clause',
],
banlist: ['Moody'],
ruleset: ['Obtainable', 'Team Preview', 'Sleep Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Moody Clause', 'Evasion Items Clause', 'Evasion Moves Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod'],
},
standarddoubles: {
inherit: true,
ruleset: [
'Standard AG',
'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Abilities Clause', 'Evasion Moves Clause', 'Gravity Sleep Clause',
],
banlist: ['Moody'],
ruleset: ['Obtainable', 'Team Preview', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Moody Clause', 'Evasion Abilities Clause', 'Evasion Moves Clause', 'Gravity Sleep Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod'],
},
obtainablemoves: {
inherit: true,

View File

@ -1,4 +1,4 @@
export const Scripts: ModdedBattleScriptsData = {
gen: 8,
inherit: 'gen8',
inherit: 'gen7',
gen: 7,
};

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