mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-06-02 22:08:36 -05:00
Merge branch 'master' into psychoshift
This commit is contained in:
commit
8dddfb0352
10
.github/workflows/test.yml
vendored
10
.github/workflows/test.yml
vendored
|
|
@ -17,7 +17,15 @@ jobs:
|
|||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [18.x]
|
||||
# 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']
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
|
|
|||
19
.github/workflows/update_version.yml
vendored
19
.github/workflows/update_version.yml
vendored
|
|
@ -3,12 +3,12 @@ name: Update the npm package version
|
|||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
required: true
|
||||
type: choice
|
||||
description: Version type
|
||||
default: patch
|
||||
options:
|
||||
version:
|
||||
required: true
|
||||
type: choice
|
||||
description: Version type
|
||||
default: patch
|
||||
options:
|
||||
- major
|
||||
- minor
|
||||
- patch
|
||||
|
|
@ -16,15 +16,18 @@ on:
|
|||
- preminor
|
||||
- prepatch
|
||||
- prerelease
|
||||
|
||||
jobs:
|
||||
update_version:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
cache: 'npm'
|
||||
|
||||
- id: bump_version
|
||||
run: |
|
||||
echo "old_version=$(jq -r .version package.json)" >> "$GITHUB_OUTPUT"
|
||||
|
|
@ -33,10 +36,10 @@ jobs:
|
|||
|
||||
- uses: peter-evans/create-pull-request@v7
|
||||
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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
config/formats.ts @KrisXV @Marty-D
|
||||
data/mods/gen9ssb/ @HoeenCoder @HisuianZoroark @KrisXV
|
||||
data/random-battles/ @AnnikaCodes @KrisXV @MathyFurret @ACakeWearingAHat @livid-washed @adrivrie
|
||||
data/random-battles/ @KrisXV @MathyFurret @ACakeWearingAHat @livid-washed @adrivrie
|
||||
data/text/ @Marty-D
|
||||
data/cg-team*.ts @KrisXV @pyuk
|
||||
databases/ @monsanto
|
||||
lib/sql.ts @mia-pi-git
|
||||
server/artemis/* @mia-pi-git
|
||||
|
|
|
|||
|
|
@ -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 any 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 either 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: 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.
|
||||
- Default Properties: Use.
|
||||
|
||||
|
||||
Dependencies
|
||||
|
|
|
|||
17
build
17
build
|
|
@ -2,10 +2,12 @@
|
|||
"use strict";
|
||||
|
||||
try {
|
||||
// technically this was introduced in Node 17, but we'll ask for the most recent LTS with it to be safe
|
||||
structuredClone({});
|
||||
// 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;
|
||||
} catch (e) {
|
||||
console.log("We require Node.js version 18 or later; you're using " + process.version);
|
||||
console.error("We require Node.js version 22 or later; you're using " + process.version);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
|
@ -22,13 +24,10 @@ function shell(cmd) {
|
|||
|
||||
// Check to make sure the most recently added or updated dependency is installed at the correct version
|
||||
try {
|
||||
var version = require('esbuild').version.split('.');
|
||||
if (parseInt(version[1]) < 16) {
|
||||
throw new Error("esbuild version too old");
|
||||
}
|
||||
require.resolve('ts-chacha20');
|
||||
} catch (e) {
|
||||
console.log('Installing dependencies...');
|
||||
shell('npm install');
|
||||
shell('npm ci');
|
||||
}
|
||||
|
||||
// Make sure config.js exists. If not, copy it over synchronously from
|
||||
|
|
@ -48,7 +47,5 @@ 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);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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` - ban made-up things other than CAP (such as Magikarp's Revenge, or Staff Bros moves)
|
||||
`- Custom` - (DEPRECATED) ban miscellaneous other things
|
||||
|
||||
`- Nonexistent` - catch-all to ban all nonexistent Pokémon, items, etc. Includes: `- CAP, - Past, - Future, - LGPE`
|
||||
|
||||
|
|
|
|||
|
|
@ -15,23 +15,6 @@ 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.
|
||||
|
|
@ -92,6 +75,50 @@ 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
|
||||
*
|
||||
|
|
@ -401,15 +428,6 @@ 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.
|
||||
|
|
|
|||
1260
config/formats.ts
1260
config/formats.ts
File diff suppressed because it is too large
Load Diff
|
|
@ -127,6 +127,7 @@ 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
|
||||
|
|
|
|||
|
|
@ -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) &&
|
||||
if (move.type === 'Normal' && (!noModifyType.includes(move.id) || this.activeMove?.isMax) &&
|
||||
!(move.isZ && move.category !== 'Status') && !(move.name === 'Tera Blast' && pokemon.terastallized)) {
|
||||
move.type = 'Flying';
|
||||
move.typeChangerBoosted = this.effect;
|
||||
|
|
@ -740,33 +740,29 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
num: 238,
|
||||
},
|
||||
cudchew: {
|
||||
onEatItem(item, pokemon) {
|
||||
if (item.isBerry && pokemon.addVolatile('cudchew')) {
|
||||
pokemon.volatiles['cudchew'].berry = item;
|
||||
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--;
|
||||
}
|
||||
},
|
||||
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;
|
||||
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);
|
||||
}
|
||||
},
|
||||
if (item.onEat) pokemon.ateBerry = true;
|
||||
delete this.effectState.berry;
|
||||
delete this.effectState.counter;
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Cud Chew",
|
||||
|
|
@ -1166,8 +1162,8 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
embodyaspectcornerstone: {
|
||||
onStart(pokemon) {
|
||||
if (pokemon.baseSpecies.name === 'Ogerpon-Cornerstone-Tera' && pokemon.terastallized &&
|
||||
this.effectState.embodied !== pokemon.previouslySwitchedIn) {
|
||||
this.effectState.embodied = pokemon.previouslySwitchedIn;
|
||||
!this.effectState.embodied) {
|
||||
this.effectState.embodied = true;
|
||||
this.boost({ def: 1 }, pokemon);
|
||||
}
|
||||
},
|
||||
|
|
@ -1179,8 +1175,8 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
embodyaspecthearthflame: {
|
||||
onStart(pokemon) {
|
||||
if (pokemon.baseSpecies.name === 'Ogerpon-Hearthflame-Tera' && pokemon.terastallized &&
|
||||
this.effectState.embodied !== pokemon.previouslySwitchedIn) {
|
||||
this.effectState.embodied = pokemon.previouslySwitchedIn;
|
||||
!this.effectState.embodied) {
|
||||
this.effectState.embodied = true;
|
||||
this.boost({ atk: 1 }, pokemon);
|
||||
}
|
||||
},
|
||||
|
|
@ -1192,8 +1188,8 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
embodyaspectteal: {
|
||||
onStart(pokemon) {
|
||||
if (pokemon.baseSpecies.name === 'Ogerpon-Teal-Tera' && pokemon.terastallized &&
|
||||
this.effectState.embodied !== pokemon.previouslySwitchedIn) {
|
||||
this.effectState.embodied = pokemon.previouslySwitchedIn;
|
||||
!this.effectState.embodied) {
|
||||
this.effectState.embodied = true;
|
||||
this.boost({ spe: 1 }, pokemon);
|
||||
}
|
||||
},
|
||||
|
|
@ -1205,8 +1201,8 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
embodyaspectwellspring: {
|
||||
onStart(pokemon) {
|
||||
if (pokemon.baseSpecies.name === 'Ogerpon-Wellspring-Tera' && pokemon.terastallized &&
|
||||
this.effectState.embodied !== pokemon.previouslySwitchedIn) {
|
||||
this.effectState.embodied = pokemon.previouslySwitchedIn;
|
||||
!this.effectState.embodied) {
|
||||
this.effectState.embodied = true;
|
||||
this.boost({ spd: 1 }, pokemon);
|
||||
}
|
||||
},
|
||||
|
|
@ -1547,7 +1543,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) &&
|
||||
if (move.type === 'Normal' && (!noModifyType.includes(move.id) || this.activeMove?.isMax) &&
|
||||
!(move.isZ && move.category !== 'Status') && !(move.name === 'Tera Blast' && pokemon.terastallized)) {
|
||||
move.type = 'Electric';
|
||||
move.typeChangerBoosted = this.effect;
|
||||
|
|
@ -2263,12 +2259,12 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
},
|
||||
libero: {
|
||||
onPrepareHit(source, target, move) {
|
||||
if (this.effectState.libero === source.previouslySwitchedIn) return;
|
||||
if (this.effectState.libero) 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 = source.previouslySwitchedIn;
|
||||
this.effectState.libero = true;
|
||||
this.add('-start', source, 'typechange', type, '[from] ability: Libero');
|
||||
}
|
||||
},
|
||||
|
|
@ -2406,9 +2402,6 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
move.hasBounced = true; // only bounce once in free-for-all battles
|
||||
return null;
|
||||
},
|
||||
condition: {
|
||||
duration: 1,
|
||||
},
|
||||
flags: { breakable: 1 },
|
||||
name: "Magic Bounce",
|
||||
rating: 4,
|
||||
|
|
@ -2930,9 +2923,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') && !noModifyType.includes(move.id) &&
|
||||
if (!(move.isZ && move.category !== 'Status') &&
|
||||
// TODO: Figure out actual interaction
|
||||
!(move.name === 'Tera Blast' && pokemon.terastallized)) {
|
||||
(!noModifyType.includes(move.id) || this.activeMove?.isMax) && !(move.name === 'Tera Blast' && pokemon.terastallized)) {
|
||||
move.type = 'Normal';
|
||||
move.typeChangerBoosted = this.effect;
|
||||
}
|
||||
|
|
@ -3226,7 +3219,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) &&
|
||||
if (move.type === 'Normal' && (!noModifyType.includes(move.id) || this.activeMove?.isMax) &&
|
||||
!(move.isZ && move.category !== 'Status') && !(move.name === 'Tera Blast' && pokemon.terastallized)) {
|
||||
move.type = 'Fairy';
|
||||
move.typeChangerBoosted = this.effect;
|
||||
|
|
@ -3316,14 +3309,8 @@ 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",
|
||||
|
|
@ -3335,9 +3322,7 @@ 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;
|
||||
if (this.effectState.target.setAbility(ability)) {
|
||||
this.add('-ability', this.effectState.target, ability, '[from] ability: Power of Alchemy', `[of] ${target}`);
|
||||
}
|
||||
this.effectState.target.setAbility(ability, target);
|
||||
},
|
||||
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1 },
|
||||
name: "Power of Alchemy",
|
||||
|
|
@ -3431,12 +3416,12 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
},
|
||||
protean: {
|
||||
onPrepareHit(source, target, move) {
|
||||
if (this.effectState.protean === source.previouslySwitchedIn) return;
|
||||
if (this.effectState.protean) 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 = source.previouslySwitchedIn;
|
||||
this.effectState.protean = true;
|
||||
this.add('-start', source, 'typechange', type, '[from] ability: Protean');
|
||||
}
|
||||
},
|
||||
|
|
@ -3724,9 +3709,7 @@ 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;
|
||||
if (this.effectState.target.setAbility(ability)) {
|
||||
this.add('-ability', this.effectState.target, ability, '[from] ability: Receiver', `[of] ${target}`);
|
||||
}
|
||||
this.effectState.target.setAbility(ability, target);
|
||||
},
|
||||
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1 },
|
||||
name: "Receiver",
|
||||
|
|
@ -3752,7 +3735,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) &&
|
||||
if (move.type === 'Normal' && (!noModifyType.includes(move.id) || this.activeMove?.isMax) &&
|
||||
!(move.isZ && move.category !== 'Status') && !(move.name === 'Tera Blast' && pokemon.terastallized)) {
|
||||
move.type = 'Ice';
|
||||
move.typeChangerBoosted = this.effect;
|
||||
|
|
@ -4247,34 +4230,30 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
},
|
||||
slowstart: {
|
||||
onStart(pokemon) {
|
||||
pokemon.addVolatile('slowstart');
|
||||
this.add('-start', pokemon, 'ability: Slow Start');
|
||||
this.effectState.counter = 5;
|
||||
},
|
||||
onEnd(pokemon) {
|
||||
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;
|
||||
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) {
|
||||
}
|
||||
},
|
||||
onModifyAtkPriority: 5,
|
||||
onModifyAtk(atk, pokemon) {
|
||||
if (this.effectState.counter) {
|
||||
return this.chainModify(0.5);
|
||||
},
|
||||
onModifySpe(spe, pokemon) {
|
||||
}
|
||||
},
|
||||
onModifySpe(spe, pokemon) {
|
||||
if (this.effectState.counter) {
|
||||
return this.chainModify(0.5);
|
||||
},
|
||||
onEnd(target) {
|
||||
this.add('-end', target, 'Slow Start');
|
||||
},
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Slow Start",
|
||||
|
|
@ -4743,6 +4722,24 @@ 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;
|
||||
|
|
@ -4778,24 +4775,6 @@ 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;
|
||||
|
|
@ -4902,13 +4881,6 @@ 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.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 },
|
||||
|
|
@ -5083,9 +5055,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
|
||||
const target = this.sample(possibleTargets);
|
||||
const ability = target.getAbility();
|
||||
if (pokemon.setAbility(ability)) {
|
||||
this.add('-ability', pokemon, ability, '[from] ability: Trace', `[of] ${target}`);
|
||||
}
|
||||
pokemon.setAbility(ability, target);
|
||||
},
|
||||
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1 },
|
||||
name: "Trace",
|
||||
|
|
@ -5508,7 +5478,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
},
|
||||
wonderguard: {
|
||||
onTryHit(target, source, move) {
|
||||
if (target === source || move.category === 'Status' || move.type === '???' || move.id === 'struggle') return;
|
||||
if (target === source || move.category === 'Status' || 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)) {
|
||||
|
|
@ -5583,13 +5553,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;
|
||||
}
|
||||
},
|
||||
onSwitchIn(pokemon) {
|
||||
if (pokemon.baseSpecies.baseSpecies !== 'Palafin') return;
|
||||
if (!this.effectState.heroMessageDisplayed && pokemon.species.forme === 'Hero') {
|
||||
if (!pokemon.heroMessageDisplayed && pokemon.species.forme === 'Hero') {
|
||||
this.add('-activate', pokemon, 'ability: Zero to Hero');
|
||||
this.effectState.heroMessageDisplayed = true;
|
||||
pokemon.heroMessageDisplayed = true;
|
||||
}
|
||||
},
|
||||
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, cantsuppress: 1, notransform: 1 },
|
||||
|
|
@ -5615,7 +5586,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
flags: { breakable: 1 },
|
||||
name: "Mountaineer",
|
||||
rating: 3,
|
||||
num: -2,
|
||||
num: -1,
|
||||
},
|
||||
rebound: {
|
||||
isNonstandard: "CAP",
|
||||
|
|
@ -5623,32 +5594,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']) {
|
||||
if (target === source || move.hasBounced || !move.flags['reflectable'] || target.isSemiInvulnerable()) {
|
||||
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']) {
|
||||
if (target.isAlly(source) || move.hasBounced || !move.flags['reflectable'] || target.isSemiInvulnerable()) {
|
||||
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: -3,
|
||||
num: -2,
|
||||
},
|
||||
persistent: {
|
||||
isNonstandard: "CAP",
|
||||
|
|
@ -5656,6 +5627,6 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
flags: {},
|
||||
name: "Persistent",
|
||||
rating: 3,
|
||||
num: -4,
|
||||
num: -3,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ export const Aliases: import('../sim/dex').AliasesTable = {
|
|||
zeroused: "[Gen 9] ZU",
|
||||
mono: "[Gen 9] Monotype",
|
||||
ag: "[Gen 9] Anything Goes",
|
||||
bss: "[Gen 9] BSS Reg I",
|
||||
vgc: "[Gen 9] VGC 2025 Reg I",
|
||||
bsd: "[Gen 9] VGC 2025 Reg I",
|
||||
bss: "[Gen 9] BSS Reg J",
|
||||
vgc: "[Gen 9] VGC 2026 Reg F",
|
||||
bsd: "[Gen 9] VGC 2026 Reg F",
|
||||
randdubs: "[Gen 9] Random Doubles Battle",
|
||||
doubles: "[Gen 9] Doubles OU",
|
||||
dou: "[Gen 9] Doubles OU",
|
||||
|
|
@ -62,8 +62,6 @@ export const Aliases: import('../sim/dex').AliasesTable = {
|
|||
gen6hackmons: "[Gen 6] Pure Hackmons",
|
||||
cc1v1: "[Gen 9] Challenge Cup 1v1",
|
||||
cc2v2: "[Gen 9] Challenge Cup 2v2",
|
||||
cgt: "[Gen 9] Computer-Generated Teams",
|
||||
compgen: "[Gen 9] Computer-Generated Teams",
|
||||
hc: "[Gen 9] Hackmons Cup",
|
||||
bf: "[Gen 8] Battle Factory",
|
||||
bssf: "[Gen 9] BSS Factory",
|
||||
|
|
@ -90,8 +88,11 @@ export const Aliases: import('../sim/dex').AliasesTable = {
|
|||
gen6ag: "[Gen 6] Anything Goes",
|
||||
crossevo: "[Gen 9] Cross Evolution",
|
||||
mayhem: "[Gen 9] Random Battle Mayhem",
|
||||
omotm: "[Gen 9] Tier Shift",
|
||||
lcotm: "[Gen 9] Pure Hackmons",
|
||||
zaou: "[Gen 9] Legends Z-A OU",
|
||||
legendsou: "[Gen 9] Legends Z-A OU",
|
||||
plzaou: "[Gen 9] Legends Z-A OU",
|
||||
omotm: "[Gen 9] Pokebilities",
|
||||
lcotm: "[Gen 9] Tera Override",
|
||||
|
||||
// mega evos --- 1st ordered alphabetically by species, 2nd by alias
|
||||
megasnow: "Abomasnow-Mega",
|
||||
|
|
@ -107,7 +108,10 @@ export const Aliases: import('../sim/dex').AliasesTable = {
|
|||
megacharizardy: "Charizard-Mega-Y",
|
||||
yard: "Charizard-Mega-Y",
|
||||
zardy: "Charizard-Mega-Y",
|
||||
megacruci: "Crucibelle-Mega",
|
||||
mdia: "Diancie-Mega",
|
||||
floetteeternalmega: "Floette-Mega",
|
||||
megafloetteeternal: "Floette-Mega",
|
||||
megagard: "Gardevoir-Mega",
|
||||
megacross: "Heracross-Mega",
|
||||
megadoom: "Houndoom-Mega",
|
||||
|
|
@ -123,6 +127,7 @@ export const Aliases: import('../sim/dex').AliasesTable = {
|
|||
megamaw: "Mawile-Mega",
|
||||
mmedi: "Medicham-Mega",
|
||||
megamedi: "Medicham-Mega",
|
||||
meowsticmega: "Meowstic-M-Mega",
|
||||
mmx: "Mewtwo-Mega-X",
|
||||
megamewtwox: "Mewtwo-Mega-X",
|
||||
mewtwox: "Mewtwo-Mega-X",
|
||||
|
|
@ -133,7 +138,10 @@ export const Aliases: import('../sim/dex').AliasesTable = {
|
|||
megashark: "Sharpedo-Mega",
|
||||
mbro: "Slowbro-Mega",
|
||||
megabro: "Slowbro-Mega",
|
||||
tatsugirimega: "Tatsugiri-Curly-Mega",
|
||||
megasaur: "Venusaur-Mega",
|
||||
megazygardecomplete: "Zygarde-Mega",
|
||||
zygardecompletemega: "Zygarde-Mega",
|
||||
|
||||
// Pokéstar Studios --- 1st ordered alphabetically by species, 2nd by alias
|
||||
blackdoor: "Pokestar Black Door",
|
||||
|
|
@ -328,8 +336,10 @@ export const Aliases: import('../sim/dex').AliasesTable = {
|
|||
gourgeistxl: "Gourgeist-Super",
|
||||
gourgeisth: "Gourgeist-Super",
|
||||
gourgeisthuge: "Gourgeist-Super",
|
||||
gourgeistjumbo: "Gourgeist-Super",
|
||||
ashgreninja: "Greninja-Ash",
|
||||
greninjabattlebond: "Greninja-Bond",
|
||||
pdon: "Groudon-Primal",
|
||||
growlh: "Growlithe-Hisui",
|
||||
hoopau: "Hoopa-Unbound",
|
||||
nddf: "Indeedee-F",
|
||||
|
|
@ -412,7 +422,12 @@ export const Aliases: import('../sim/dex').AliasesTable = {
|
|||
horsepalkia: "Palkia-Origin",
|
||||
alosian: "Persian-Alola",
|
||||
ponyg: "Ponyta-Galar",
|
||||
pumpkaboos: "Pumpkaboo-Small",
|
||||
pumpkabool: "Pumpkaboo-Large",
|
||||
pumpkabooxl: "Pumpkaboo-Super",
|
||||
pumpkabooh: "Pumpkaboo-Super",
|
||||
pumpkaboohuge: "Pumpkaboo-Super",
|
||||
pumpkaboojumbo: "Pumpkaboo-Super",
|
||||
hqwil: "Qwilfish-Hisui",
|
||||
gorse: "Rapidash-Galar",
|
||||
galardash: "Rapidash-Galar",
|
||||
|
|
@ -512,6 +527,8 @@ export const Aliases: import('../sim/dex').AliasesTable = {
|
|||
giratinaa: "Giratina",
|
||||
giratinaaltered: "Giratina",
|
||||
gourgeistaverage: "Gourgeist",
|
||||
gourgeistm: "Gourgeist",
|
||||
gourgeistmedium: "Gourgeist",
|
||||
hoopac: "Hoopa",
|
||||
hoopaconfined: "Hoopa",
|
||||
indeedeem: "Indeedee",
|
||||
|
|
@ -542,6 +559,8 @@ export const Aliases: import('../sim/dex').AliasesTable = {
|
|||
poltchageistcounterfeit: "Poltchageist",
|
||||
polteageistphony: "Polteageist",
|
||||
pumpkabooaverage: "Pumpkaboo",
|
||||
pumpkaboom: "Pumpkaboo",
|
||||
pumpkaboomedium: "Pumpkaboo",
|
||||
rockruffmidday: "Rockruff",
|
||||
shayminl: "Shaymin",
|
||||
shayminland: "Shaymin",
|
||||
|
|
@ -707,8 +726,6 @@ export const Aliases: import('../sim/dex').AliasesTable = {
|
|||
sawsbuckautumn: "Sawsbuck",
|
||||
sawsbuckwinter: "Sawsbuck",
|
||||
tatsugiricurly: "Tatsugiri",
|
||||
tatsugiridroopy: "Tatsugiri",
|
||||
tatsugiristretchy: "Tatsugiri",
|
||||
unowna: "Unown",
|
||||
unownb: "Unown",
|
||||
unownc: "Unown",
|
||||
|
|
@ -2541,12 +2558,12 @@ export const Aliases: import('../sim/dex').AliasesTable = {
|
|||
krilo: "Krilowatt",
|
||||
libra: "Equilibra",
|
||||
mala: "Malaconda",
|
||||
megacruci: "Crucibelle-Mega",
|
||||
navi: "Naviathan",
|
||||
nect: "Necturna",
|
||||
ohmagod: "Plasmanta",
|
||||
plas: "Plasmanta",
|
||||
raja: "Saharaja",
|
||||
ramnarokdormant: "Ramnarok",
|
||||
reve: "Revenankh",
|
||||
roak: "Pyroak",
|
||||
smoko: "Smokomodo",
|
||||
|
|
|
|||
|
|
@ -1,78 +0,0 @@
|
|||
// 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
1098
data/cg-teams.ts
File diff suppressed because it is too large
Load Diff
|
|
@ -95,7 +95,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
},
|
||||
onBeforeMovePriority: 10,
|
||||
onBeforeMove(pokemon, target, move) {
|
||||
if (move.flags['defrost']) return;
|
||||
if (move.flags['defrost'] && !(move.id === 'burnup' && !pokemon.hasType('Fire'))) return;
|
||||
if (this.randomChance(1, 5)) {
|
||||
pokemon.cureStatus();
|
||||
return;
|
||||
|
|
@ -115,7 +115,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
}
|
||||
},
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (move.type === 'Fire' && move.category !== 'Status') {
|
||||
if (move.type === 'Fire' && move.category !== 'Status' && move.id !== 'polarflare') {
|
||||
target.cureStatus();
|
||||
}
|
||||
},
|
||||
|
|
@ -270,6 +270,11 @@ 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');
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
972
data/items.ts
972
data/items.ts
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
206
data/mods/biomechmons/abilities.ts
Normal file
206
data/mods/biomechmons/abilities.ts
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
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);
|
||||
},
|
||||
},
|
||||
};
|
||||
44
data/mods/biomechmons/conditions.ts
Normal file
44
data/mods/biomechmons/conditions.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
41
data/mods/biomechmons/items.ts
Normal file
41
data/mods/biomechmons/items.ts
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
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'));
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
401
data/mods/biomechmons/moves.ts
Normal file
401
data/mods/biomechmons/moves.ts
Normal file
|
|
@ -0,0 +1,401 @@
|
|||
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,
|
||||
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}`);
|
||||
},
|
||||
},
|
||||
};
|
||||
546
data/mods/biomechmons/scripts.ts
Normal file
546
data/mods/biomechmons/scripts.ts
Normal file
|
|
@ -0,0 +1,546 @@
|
|||
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) {
|
||||
let isBMMAbil = false;
|
||||
let isOldBMMAbil = false;
|
||||
if (!this.hp) return false;
|
||||
if (!this.battle.dex.abilities.get(ability).exists) isBMMAbil = true;
|
||||
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 (!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);
|
||||
oldAbility = {
|
||||
id: this.ability,
|
||||
name: abil.name || this.ability,
|
||||
flags: {},
|
||||
effectType: "Ability",
|
||||
toString() {
|
||||
return abil.name || this.id;
|
||||
},
|
||||
} as Ability;
|
||||
isOldBMMAbil = true;
|
||||
}
|
||||
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') return false;
|
||||
if (this.battle.toID(source.ability) === 'multitype') 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) {
|
||||
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) {
|
||||
let isBMMItem = false;
|
||||
let isOldBMMItem = false;
|
||||
if (!this.hp || !this.isActive) return false;
|
||||
if (!this.battle.dex.items.get(item).exists) isBMMItem = true;
|
||||
if (typeof item === 'string') {
|
||||
if (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);
|
||||
item = {
|
||||
id: newData.id || itemString,
|
||||
name: newData.name || itemString,
|
||||
effectType: "Item",
|
||||
toString() {
|
||||
return newData.name || itemString;
|
||||
},
|
||||
} as Item;
|
||||
}
|
||||
}
|
||||
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) {
|
||||
this.removeVolatile(item.id);
|
||||
this.m.scrambled.items.splice((this.m.scrambled.items as { thing: string, inSlot: string }[]).findIndex(e =>
|
||||
e.thing === this.battle.toID(item.name) && e.inSlot === isBMM), 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) {
|
||||
this.removeVolatile(item.id);
|
||||
this.m.scrambled.items.splice((this.m.scrambled.items as { thing: string, inSlot: string }[]).findIndex(e =>
|
||||
e.thing === this.battle.toID(item.name) && e.inSlot === isBMM), 1);
|
||||
if (isBMM === 'Ability') this.setAbility('No Ability');
|
||||
} else {
|
||||
this.lastItem = this.item;
|
||||
this.item = '';
|
||||
}
|
||||
this.battle.clearEffectState(this.itemState);
|
||||
this.usedItemThisTurn = true;
|
||||
this.battle.runEvent('AfterUseItem', this, null, null, item);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
transformInto(pokemon, effect) {
|
||||
const species = pokemon.species;
|
||||
if (
|
||||
pokemon.fainted || this.illusion || pokemon.illusion || (pokemon.volatiles['substitute'] && this.battle.gen >= 5) ||
|
||||
(pokemon.transformed && this.battle.gen >= 2) || (this.transformed && this.battle.gen >= 5) ||
|
||||
species.name === 'Eternatus-Eternamax' ||
|
||||
(['Ogerpon', 'Terapagos'].includes(species.baseSpecies) && (this.terastallized || pokemon.terastallized)) ||
|
||||
this.terastallized === 'Stellar'
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.battle.dex.currentMod === 'gen1stadium' && (
|
||||
species.name === 'Ditto' ||
|
||||
(this.species.name === 'Ditto' && pokemon.moves.includes('transform'))
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.setSpecies(species, effect, true)) return false;
|
||||
|
||||
this.transformed = true;
|
||||
this.weighthg = pokemon.weighthg;
|
||||
|
||||
const types = pokemon.getTypes(true, true);
|
||||
this.setType(pokemon.volatiles['roost'] ? pokemon.volatiles['roost'].typeWas : types, true);
|
||||
this.addedType = pokemon.addedType;
|
||||
this.knownType = this.isAlly(pokemon) && pokemon.knownType;
|
||||
this.apparentType = pokemon.apparentType;
|
||||
|
||||
let statName: StatIDExceptHP;
|
||||
for (statName in this.storedStats) {
|
||||
this.storedStats[statName] = pokemon.storedStats[statName];
|
||||
if (this.modifiedStats) this.modifiedStats[statName] = pokemon.modifiedStats![statName]; // Gen 1: Copy modified stats.
|
||||
}
|
||||
this.moveSlots = [];
|
||||
this.hpType = (this.battle.gen >= 5 ? this.hpType : pokemon.hpType);
|
||||
this.hpPower = (this.battle.gen >= 5 ? this.hpPower : pokemon.hpPower);
|
||||
this.timesAttacked = pokemon.timesAttacked;
|
||||
for (const moveSlot of pokemon.moveSlots) {
|
||||
let moveName = moveSlot.move;
|
||||
if (moveSlot.id === 'hiddenpower') {
|
||||
moveName = 'Hidden Power ' + this.hpType;
|
||||
}
|
||||
this.moveSlots.push({
|
||||
move: moveName,
|
||||
id: moveSlot.id,
|
||||
pp: moveSlot.maxpp === 1 ? 1 : 5,
|
||||
maxpp: this.battle.gen >= 5 ? (moveSlot.maxpp === 1 ? 1 : 5) : moveSlot.maxpp,
|
||||
target: moveSlot.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
virtual: true,
|
||||
});
|
||||
}
|
||||
let boostName: BoostID;
|
||||
for (boostName in pokemon.boosts) {
|
||||
this.boosts[boostName] = pokemon.boosts[boostName];
|
||||
}
|
||||
if (this.battle.gen >= 6) {
|
||||
// we need to remove all of the overlapping crit volatiles before adding any of them
|
||||
const volatilesToCopy = ['dragoncheer', 'focusenergy', 'gmaxchistrike', 'laserfocus'];
|
||||
for (const volatile of volatilesToCopy) this.removeVolatile(volatile);
|
||||
for (const volatile of volatilesToCopy) {
|
||||
if (pokemon.volatiles[volatile]) {
|
||||
this.addVolatile(volatile);
|
||||
if (volatile === 'gmaxchistrike') this.volatiles[volatile].layers = pokemon.volatiles[volatile].layers;
|
||||
if (volatile === 'dragoncheer') this.volatiles[volatile].hasDragonType = pokemon.volatiles[volatile].hasDragonType;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (effect) {
|
||||
this.battle.add('-transform', this, pokemon, '[from] ' + effect.fullname);
|
||||
} else {
|
||||
this.battle.add('-transform', this, pokemon);
|
||||
}
|
||||
if (this.terastallized) {
|
||||
this.knownType = true;
|
||||
this.apparentType = this.terastallized;
|
||||
}
|
||||
if (this.battle.gen > 2) this.setAbility(pokemon.ability, this, null, true, true);
|
||||
|
||||
// Change formes based on held items (for Transform)
|
||||
// Only ever relevant in Generation 4 since Generation 3 didn't have item-based forme changes
|
||||
if (this.battle.gen === 4) {
|
||||
if (this.species.num === 487) {
|
||||
// Giratina formes
|
||||
if (this.species.name === 'Giratina' && this.item === 'griseousorb') {
|
||||
this.formeChange('Giratina-Origin');
|
||||
} else if (this.species.name === 'Giratina-Origin' && this.item !== 'griseousorb') {
|
||||
this.formeChange('Giratina');
|
||||
}
|
||||
}
|
||||
if (this.species.num === 493) {
|
||||
// Arceus formes
|
||||
const item = this.getItem();
|
||||
const targetForme = (item?.onPlate ? 'Arceus-' + item.onPlate : 'Arceus');
|
||||
if (this.species.name !== targetForme) {
|
||||
this.formeChange(targetForme);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pokemon transformed into Ogerpon cannot Terastallize
|
||||
// restoring their ability to tera after they untransform is handled ELSEWHERE
|
||||
if (['Ogerpon', 'Terapagos'].includes(this.species.baseSpecies) && this.canTerastallize) this.canTerastallize = false;
|
||||
|
||||
for (const volatile in this.volatiles) {
|
||||
if (this.volatiles[volatile].inSlot && this.volatiles[volatile].inSlot === 'Move') {
|
||||
this.removeVolatile(volatile);
|
||||
}
|
||||
}
|
||||
|
||||
for (const volatile in pokemon.volatiles) {
|
||||
if (pokemon.volatiles[volatile].inSlot && pokemon.volatiles[volatile].inSlot === 'Move') {
|
||||
this.addVolatile(volatile);
|
||||
this.volatiles[volatile].inSlot = 'Move';
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
},
|
||||
field: {
|
||||
suppressingWeather() {
|
||||
for (const pokemon of this.battle.getAllActive()) {
|
||||
const innates = Object.keys(pokemon.volatiles).filter(x => x.startsWith('ability:'));
|
||||
if (pokemon && !pokemon.ignoringAbility() &&
|
||||
(pokemon.getAbility().suppressWeather || innates.some(x => (
|
||||
this.battle.dex.abilities.get(x.replace('ability:', '')).suppressWeather
|
||||
)))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -1,970 +0,0 @@
|
|||
export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTable = {
|
||||
absorber: {
|
||||
name: "Absorber",
|
||||
rating: 3,
|
||||
shortDesc: "This Pokemon heals 3/16 max HP after being targeted by a NVE/immune move.",
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (target.getMoveHitData(move).typeMod < 0)
|
||||
this.heal(target.baseMaxhp * 0.18);
|
||||
},
|
||||
onImmunity(type, pokemon) {
|
||||
if (this.dex.types.isName(type)) {
|
||||
this.heal(pokemon.baseMaxhp * 0.18);
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
},
|
||||
antimatter: {
|
||||
onEffectiveness(typeMod) {
|
||||
return typeMod * -1;
|
||||
},
|
||||
flags: {},
|
||||
name: "Antimatter",
|
||||
shortDesc: "This Pokemon's defending effectiveness is reversed.",
|
||||
},
|
||||
asymmetry: {
|
||||
onStart(pokemon) {
|
||||
let activated = false;
|
||||
for (const target of pokemon.adjacentFoes()) {
|
||||
if (!activated) {
|
||||
this.add('-ability', pokemon, 'Asymmetry');
|
||||
activated = true;
|
||||
}
|
||||
target.addVolatile('asymmetry');
|
||||
const createArray = (x: number) => Array.from({ length: x }, (_, i) => i);
|
||||
const pokemonArray = createArray(pokemon.moves.length);
|
||||
const targetArray = createArray(target.moves.length);
|
||||
|
||||
const pickNum1 = this.sample(pokemonArray);
|
||||
pokemonArray.splice(pokemonArray.indexOf(pickNum1), 1);
|
||||
let pickNum2;
|
||||
if (pokemonArray.length === 0) pickNum2 = -1;
|
||||
else pickNum2 = this.sample(pokemonArray);
|
||||
|
||||
const pickNum3 = this.sample(targetArray);
|
||||
targetArray.splice(targetArray.indexOf(pickNum3), 1);
|
||||
let pickNum4;
|
||||
if (targetArray.length === 0) pickNum4 = -1;
|
||||
else pickNum4 = this.sample(targetArray);
|
||||
|
||||
const pokemonMove1 = this.dex.moves.get(pokemon.moves[pickNum1]);
|
||||
const realPokemonMove1 = {
|
||||
move: pokemonMove1.name,
|
||||
id: pokemonMove1.id,
|
||||
pp: pokemonMove1.pp * 1.6,
|
||||
maxpp: pokemonMove1.pp * 1.6,
|
||||
target: pokemonMove1.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
virtual: true,
|
||||
};
|
||||
const targetMove1 = this.dex.moves.get(target.moves[pickNum3]);
|
||||
const realTargetMove1 = {
|
||||
move: targetMove1.name,
|
||||
id: targetMove1.id,
|
||||
pp: targetMove1.pp * 1.6,
|
||||
maxpp: targetMove1.pp * 1.6,
|
||||
target: targetMove1.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
virtual: true,
|
||||
};
|
||||
|
||||
pokemon.moveSlots[pickNum1] = realTargetMove1;
|
||||
pokemon.baseMoveSlots[pickNum1] = realTargetMove1;
|
||||
target.moveSlots[pickNum3] = realPokemonMove1;
|
||||
target.baseMoveSlots[pickNum3] = realPokemonMove1;
|
||||
|
||||
if (pickNum2 === -1 || pickNum4 === -1) return;
|
||||
const pokemonMove2 = this.dex.moves.get(pokemon.moves[pickNum2]);
|
||||
const realPokemonMove2 = {
|
||||
move: pokemonMove2.name,
|
||||
id: pokemonMove2.id,
|
||||
pp: pokemonMove2.pp * 1.6,
|
||||
maxpp: pokemonMove2.pp * 1.6,
|
||||
target: pokemonMove2.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
virtual: true,
|
||||
};
|
||||
const targetMove2 = this.dex.moves.get(target.moves[pickNum4]);
|
||||
const realTargetMove2 = {
|
||||
move: targetMove2.name,
|
||||
id: targetMove2.id,
|
||||
pp: targetMove2.pp * 1.6,
|
||||
maxpp: targetMove2.pp * 1.6,
|
||||
target: targetMove2.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
virtual: true,
|
||||
};
|
||||
|
||||
pokemon.moveSlots[pickNum2] = realTargetMove2;
|
||||
pokemon.baseMoveSlots[pickNum2] = realTargetMove2;
|
||||
target.moveSlots[pickNum4] = realPokemonMove2;
|
||||
target.baseMoveSlots[pickNum4] = realPokemonMove2;
|
||||
}
|
||||
},
|
||||
condition: {
|
||||
duration: 1,
|
||||
noCopy: true,
|
||||
onBeforeMovePriority: 6,
|
||||
onBeforeMove(pokemon, target, move) {
|
||||
if (pokemon.moveSlots.filter(m => m.id === move.id).length === 0) {
|
||||
const newMove = this.dex.moves.get(move);
|
||||
this.actions.useMove(newMove, pokemon);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
},
|
||||
flags: {},
|
||||
name: "Asymmetry",
|
||||
shortDesc: "On switch-in, this Pokemon randomly swaps two of its moves with the opponent's.",
|
||||
},
|
||||
backatya: {
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
this.damage(target.getUndynamaxedHP(damage * 2), source, target);
|
||||
},
|
||||
flags: {},
|
||||
name: "Back at Ya!",
|
||||
shortDesc: "This Pokemon deals double damage to the opponent when damaged by a move.",
|
||||
},
|
||||
badpacing: {
|
||||
onResidualOrder: 28,
|
||||
onResidualSubOrder: 2,
|
||||
onResidual(pokemon) {
|
||||
pokemon.addVolatile('badpacing');
|
||||
},
|
||||
condition: {
|
||||
noCopy: true,
|
||||
onStart(target) {
|
||||
this.add('-start', target, 'ability: Bad Pacing');
|
||||
this.effectState.badpacing = 1;
|
||||
},
|
||||
onRestart() {
|
||||
this.effectState.badpacing++;
|
||||
},
|
||||
onModifyAtkPriority: 5,
|
||||
onModifyAtk(atk, pokemon) {
|
||||
return this.chainModify(1 - 0.05 * this.effectState.badpacing);
|
||||
},
|
||||
onModifyDefPriority: 5,
|
||||
onModifyDef(def, pokemon) {
|
||||
return this.chainModify(1 - 0.05 * this.effectState.badpacing);
|
||||
},
|
||||
onModifySpAPriority: 5,
|
||||
onModifySpA(spa, pokemon) {
|
||||
return this.chainModify(1 - 0.05 * this.effectState.badpacing);
|
||||
},
|
||||
onModifySpDPriority: 5,
|
||||
onModifySpD(spd, pokemon) {
|
||||
return this.chainModify(1 - 0.05 * this.effectState.badpacing);
|
||||
},
|
||||
onModifySpePriority: 5,
|
||||
onModifySpe(spe, pokemon) {
|
||||
return this.chainModify(1 - 0.05 * this.effectState.badpacing);
|
||||
},
|
||||
},
|
||||
flags: {},
|
||||
name: "Bad Pacing",
|
||||
shortDesc: "This Pokemon's non-HP stats are reduced by 5% each turn.",
|
||||
},
|
||||
bathroombreak: {
|
||||
onAfterMove(target, source, move) {
|
||||
if (move.type === 'Water') {
|
||||
this.add('-activate', target, 'ability: Bathroom Break');
|
||||
target.switchFlag = true;
|
||||
}
|
||||
},
|
||||
onDamagingHitOrder: 1,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (move.type === 'Water') target.switchFlag = true;
|
||||
},
|
||||
name: "Bathroom Break",
|
||||
shortDesc: "This Pokemon switches out when using or hit by a Water move.",
|
||||
},
|
||||
bigstick: {
|
||||
onResidual(pokemon) {
|
||||
if (pokemon.adjacentFoes().length === 0) return;
|
||||
const branchpoke = this.dex.getActiveMove('branchpoke');
|
||||
this.actions.useMove(branchpoke, pokemon);
|
||||
},
|
||||
flags: {},
|
||||
name: "big stick",
|
||||
shortDesc: "This Pokemon uses Branch Poke at the end of each turn.",
|
||||
},
|
||||
bloodsucking: {
|
||||
onStart(pokemon) {
|
||||
let activated = false;
|
||||
if (!activated) {
|
||||
activated = true;
|
||||
pokemon.addVolatile('bloodsucking');
|
||||
const leechlife = this.dex.getActiveMove('leechlife');
|
||||
this.actions.useMove(leechlife, pokemon);
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Bloodsucking",
|
||||
shortDesc: "On switchin, this Pokemon uses a 20 BP Bug move and heals equal to the damage dealt.",
|
||||
},
|
||||
braceforimpact: {
|
||||
name: "Brace for Impact",
|
||||
shortDesc: "This Pokemon takes half damage from attacks when switching in.",
|
||||
onSourceModifyDamage(damage, source, target, move) {
|
||||
if (!target.activeTurns) {
|
||||
this.debug('Brace For Impact weaken');
|
||||
return this.chainModify(0.5);
|
||||
}
|
||||
},
|
||||
},
|
||||
brokenwand: {
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move.category === 'Special') {
|
||||
return this.chainModify(1.3);
|
||||
}
|
||||
},
|
||||
onModifyMove(move, pokemon) {
|
||||
if (move.category === 'Special') {
|
||||
move.recoil = [1, 3];
|
||||
}
|
||||
},
|
||||
name: "Broken Wand",
|
||||
shortDesc: "This Pokemon's special moves have 1.3x more power but 33% recoil.",
|
||||
},
|
||||
capricious: {
|
||||
onBasePower(basePower, pokemon) {
|
||||
if (this.randomChance(3, 10)) {
|
||||
this.attrLastMove('[anim] Fickle Beam All Out');
|
||||
this.add('-activate', pokemon, 'move: Fickle Beam');
|
||||
return this.chainModify(2);
|
||||
}
|
||||
},
|
||||
name: "Capricious",
|
||||
shortDesc: "This Pokemon's attacks have a 30% chance of dealing double damage.",
|
||||
},
|
||||
clinch: {
|
||||
onBeforeTurn(pokemon) {
|
||||
for (const side of this.sides) {
|
||||
if (side.hasAlly(pokemon)) continue;
|
||||
side.addSideCondition('clinch', pokemon);
|
||||
const data = side.getSideConditionData('clinch');
|
||||
if (!data.sources) {
|
||||
data.sources = [];
|
||||
}
|
||||
data.sources.push(pokemon);
|
||||
}
|
||||
},
|
||||
onBeforeMove(source, target, move) {
|
||||
if (move.volatileStatus === "twoturnmove") {
|
||||
delete move.volatileStatus;
|
||||
move.accuracy = true;
|
||||
}
|
||||
},
|
||||
onTryHit(source, target) {
|
||||
target.side.removeSideCondition('clinch');
|
||||
},
|
||||
condition: {
|
||||
duration: 1,
|
||||
onBeforeSwitchOut(pokemon) {
|
||||
const move = this.queue.willMove(pokemon.foes()[0]);
|
||||
const moveName = move && move.moveid ? this.dex.getActiveMove(move.moveid.toString()) : "";
|
||||
if (!moveName || !moveName.flags['charge']) return;
|
||||
delete moveName.onTryMove;
|
||||
this.debug('Clinch start');
|
||||
let alreadyAdded = false;
|
||||
pokemon.removeVolatile('destinybond');
|
||||
for (const source of this.effectState.sources) {
|
||||
if (!source.isAdjacent(pokemon) || !this.queue.cancelMove(source) || !source.hp) continue;
|
||||
if (!alreadyAdded) {
|
||||
this.add('-activate', pokemon.foes()[0], 'ability: Clinch');
|
||||
alreadyAdded = true;
|
||||
}
|
||||
this.actions.runMove(moveName, source, source.getLocOf(pokemon));
|
||||
}
|
||||
},
|
||||
},
|
||||
flags: {},
|
||||
name: "Clinch",
|
||||
shortDesc: "This Pokemon's charge moves fully charge and hit a target switching out.",
|
||||
},
|
||||
colorwheel: {
|
||||
onResidual(pokemon) {
|
||||
this.add('-ability', pokemon, 'ability: Color Wheel');
|
||||
const types = ['Bug', 'Dark', 'Dragon', 'Electric', 'Fairy', 'Fighting',
|
||||
'Fire', 'Flying', 'Ghost', 'Grass', 'Ground', 'Ice',
|
||||
'Normal', 'Poison', 'Psychic', 'Rock', 'Steel', 'Water'];
|
||||
const newType1 = types[(types.indexOf(pokemon.types[0]) + 1) % 18];
|
||||
let newTypes = [newType1];
|
||||
if (pokemon.types.length > 1) {
|
||||
const newType2 = types[(types.indexOf(pokemon.types[1]) + 1) % 18];
|
||||
newTypes = [newType1, newType2];
|
||||
}
|
||||
if (pokemon.setType(newTypes)) this.add('-start', pokemon, 'typechange', newTypes.join('/'));
|
||||
},
|
||||
flags: {},
|
||||
name: "Color Wheel",
|
||||
shortDesc: "This Pokemon changes type(s) to the next one(s) alphabetically at the end of each turn.",
|
||||
},
|
||||
comeback: {
|
||||
onBasePowerPriority: 23,
|
||||
onBasePower(basePower, pokemon, target, move) {
|
||||
if (pokemon.activeMoveActions <= 1) return this.chainModify(1.3);
|
||||
},
|
||||
flags: {},
|
||||
name: "Comeback",
|
||||
shortDesc: "For the first turn after this Pokemon is active, its attacks have 1.3x power.",
|
||||
},
|
||||
contagious: {
|
||||
onDamagingHitOrder: 1,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (target.status && !source.status && this.checkMoveMakesContact(move, source, target, true)) {
|
||||
source.setStatus(target.status);
|
||||
target.cureStatus();
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Contagious",
|
||||
shortDesc: "This Pokemon's non-volatile statuses transfer to Pokemon making contact with it.",
|
||||
},
|
||||
countermeasures: {
|
||||
// coded in scripts/actions/secondaries
|
||||
flags: {},
|
||||
name: "Countermeasures",
|
||||
shortDesc: "When an attacker's secondary activates, it loses HP equal to 100 - secondary chance.",
|
||||
},
|
||||
crumble: {
|
||||
onFaint(pokemon) {
|
||||
const side = pokemon.side.foe;
|
||||
const stealthrock = side.sideConditions['stealthrock'];
|
||||
if (!stealthrock) {
|
||||
this.add('-activate', pokemon, 'ability: Crumble');
|
||||
side.addSideCondition('stealthrock', pokemon);
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Crumble",
|
||||
shortDesc: "This Pokemon sets Stealth Rock upon fainting.",
|
||||
},
|
||||
dewdrop: {
|
||||
onBasePowerPriority: 15,
|
||||
onBasePower(basePower, user, target, move) {
|
||||
if (move && ['Grass', 'Water', 'Fairy'].includes(move.type)) {
|
||||
return this.chainModify([4915, 4096]);
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Dewdrop",
|
||||
shortDesc: "This Pokemon's Grass/Water/Fairy moves have 1.2x power.",
|
||||
},
|
||||
diceroller: {
|
||||
onSourceDamagingHit(damage, target, source, move) {
|
||||
if (!move.flags['bullet']) return;
|
||||
const stats: BoostID[] = [];
|
||||
let stat: BoostID;
|
||||
for (stat in target.boosts) {
|
||||
if (source.boosts[stat] < 6) {
|
||||
if (stat === 'evasion') continue;
|
||||
stats.push(stat);
|
||||
}
|
||||
}
|
||||
if (stats.length) {
|
||||
let randomStat = this.sample(stats);
|
||||
const boost: SparseBoostsTable = {};
|
||||
boost[randomStat] = 1;
|
||||
randomStat = this.sample(stats);
|
||||
boost[randomStat] = 1;
|
||||
this.boost(boost, source, source);
|
||||
} else return;
|
||||
},
|
||||
flags: {},
|
||||
name: "Dice Roller",
|
||||
shortDesc: "This Pokemon boosts random stats (not eva) by 1 twice after using a bullet move.",
|
||||
},
|
||||
diseased: {
|
||||
onResidualOrder: 28,
|
||||
onResidualSubOrder: 2,
|
||||
onResidual(pokemon) {
|
||||
this.damage(pokemon.baseMaxhp / 8, pokemon, pokemon);
|
||||
},
|
||||
onSourceDamagingHit(damage, target, source, move) {
|
||||
// Despite not being a secondary, Shield Dust / Covert Cloak block Toxic Chain's effect
|
||||
if (target.hasAbility('shielddust') || target.hasItem('covertcloak')) return;
|
||||
|
||||
if (this.randomChance(3, 10)) {
|
||||
target.trySetStatus('psn', source);
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Diseased",
|
||||
shortDesc: "This Pokemon's moves have a 30% chance to poison, but it loses 1/8 max HP every turn.",
|
||||
},
|
||||
drawfour: {
|
||||
shortDesc: "After knocking out target, if user knows less than 12 moves, it learns target's moves.",
|
||||
onSourceAfterFaint(length, source, target, effect) {
|
||||
if (effect && effect.effectType === 'Move') {
|
||||
for (const moveSlot of source.moveSlots) {
|
||||
if (moveSlot === null) return;
|
||||
if (target.moveSlots.length < 12) {
|
||||
this.attrLastMove('[still]');
|
||||
if (target.moveSlots.length < 0) return false;
|
||||
target.moveSlots[target.moveSlots.length] = moveSlot;
|
||||
target.baseMoveSlots[target.moveSlots.length - 1] = moveSlot;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
name: "Draw Four",
|
||||
},
|
||||
electromagneticmanipulation: {
|
||||
onUpdate(pokemon) {
|
||||
if (pokemon.adjacentFoes().length === 0) return;
|
||||
const target = this.sample(pokemon.adjacentFoes());
|
||||
if (!target || target.types[0] === 'Electric') return;
|
||||
target.addVolatile('electromagneticmanipulation');
|
||||
},
|
||||
condition: {
|
||||
onStart(pokemon) {
|
||||
const types = pokemon.types.length === 2 ? ['Electric', pokemon.types[1]] : ['Electric'];
|
||||
pokemon.setType(types);
|
||||
this.add('-start', pokemon, 'typechange', types.join('/'));
|
||||
},
|
||||
onUpdate(pokemon) {
|
||||
if (pokemon.adjacentFoes().length === 0) pokemon.removeVolatile('electromagneticmanipulation');
|
||||
else {
|
||||
const target = this.sample(pokemon.adjacentFoes());
|
||||
if (!target.hasAbility('electromagneticmanipulation')) pokemon.removeVolatile('electromagneticmanipulation');
|
||||
}
|
||||
},
|
||||
onEnd(pokemon) {
|
||||
const types = pokemon.baseSpecies.types;
|
||||
console.log(types);
|
||||
pokemon.setType(types);
|
||||
this.add('-start', pokemon, 'typechange', types.join('/'));
|
||||
},
|
||||
},
|
||||
flags: {},
|
||||
name: "Electromagnetic Manipulation",
|
||||
shortDesc: "While this Pokemon is active, the foe's primary type is Electric.",
|
||||
},
|
||||
exhaust: {
|
||||
onFoeSwitchOut(pokemon) {
|
||||
if (!pokemon.lastMoveUsed) return;
|
||||
const moveUsed = pokemon.lastMoveUsed;
|
||||
const moveIndex = pokemon.moves.indexOf(moveUsed.id);
|
||||
if (moveIndex === -1) return;
|
||||
console.log(pokemon.moveSlots[moveIndex]);
|
||||
pokemon.moveSlots[moveIndex].pp -= 5;
|
||||
},
|
||||
flags: {},
|
||||
name: "Exhaust",
|
||||
shortDesc: "While this Pokemon is active, opponents switching out lose 5 PP on the last move they used.",
|
||||
},
|
||||
firstclassticket: {
|
||||
onAfterMove(target, source, move) {
|
||||
if (move.type === 'Flying') {
|
||||
this.heal(target.baseMaxhp / 4);
|
||||
}
|
||||
},
|
||||
name: "First-Class Ticket",
|
||||
shortDesc: "This Pokemon's Flying-type moves heal it for 1/4 max HP.",
|
||||
},
|
||||
fumigation: {
|
||||
onDamagingHitOrder: 1,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
const poisongas = this.dex.getActiveMove('poisongas');
|
||||
this.actions.useMove(poisongas, target);
|
||||
},
|
||||
flags: {},
|
||||
name: "Fumigation",
|
||||
shortDesc: "When this Pokemon is damaged by a move, it uses Poison Gas against the attacker.",
|
||||
},
|
||||
gangster: {
|
||||
onFractionalPriorityPriority: -1,
|
||||
onFractionalPriority(priority, pokemon, target, move) {
|
||||
if (move.type === 'Dark' || move.type === 'Fighting') {
|
||||
return 0.1;
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Gangster",
|
||||
shortDesc: "This Pokemon's Dark/Fighting moves go first in its priority bracket.",
|
||||
},
|
||||
hibernation: {
|
||||
onResidualOrder: 28,
|
||||
onResidualSubOrder: 2,
|
||||
onResidual(pokemon) {
|
||||
if (pokemon.status === 'slp') this.boost({ def: 1, spd: 1 });
|
||||
},
|
||||
flags: {},
|
||||
name: "Hibernation",
|
||||
shortDesc: "This Pokemon's Def/SpD are raised by 1 each turn while asleep.",
|
||||
},
|
||||
ironfistening: {
|
||||
onStart(source) {
|
||||
this.actions.useMove("Fishing Tokens", source);
|
||||
},
|
||||
flags: {},
|
||||
name: "Iron Fistening",
|
||||
shortDesc: "On switchin, this Pokemon's side gains a Fishing Token.",
|
||||
},
|
||||
magicmissile: {
|
||||
name: "Magic Missile",
|
||||
shortDesc: "Magician + when damaged, fling item for 25% max HP.",
|
||||
onSourceHit(target, source, move) {
|
||||
if (!move || !target) 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: Magic Missile', target);
|
||||
}
|
||||
},
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (target.isSemiInvulnerable()) return;
|
||||
if (target.ignoringItem()) return false;
|
||||
const item = target.getItem();
|
||||
if (!this.singleEvent('TakeItem', item, target.itemState, target, target, move, item)) return false;
|
||||
if (item.id && !item.megaStone) {
|
||||
this.damage(source.baseMaxhp / 4, source, target);
|
||||
target.addVolatile('fling');
|
||||
if (item.isBerry
|
||||
) {
|
||||
if (this.singleEvent('Eat', item, null, source, null, null)) {
|
||||
this.runEvent('EatItem', source, null, null, item);
|
||||
if (item.id === 'leppaberry') source.staleness = 'external';
|
||||
}
|
||||
if (item.onEat) source.ateBerry = true;
|
||||
} else if (item.id === 'mentalherb') {
|
||||
const conditions = ['attract', 'taunt', 'encore', 'torment', 'disable', 'healblock'];
|
||||
for (const firstCondition of conditions) {
|
||||
if (source.volatiles[firstCondition]) {
|
||||
for (const secondCondition of conditions) {
|
||||
source.removeVolatile(secondCondition);
|
||||
if (firstCondition === 'attract' && secondCondition === 'attract') {
|
||||
this.add('-end', source, 'move: Attract', '[from] item: Mental Herb');
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (item.id === 'whiteherb') {
|
||||
let activate = false;
|
||||
const boosts: SparseBoostsTable = {};
|
||||
let boostName: BoostID;
|
||||
for (boostName in source.boosts) {
|
||||
if (source.boosts[boostName] < 0) {
|
||||
activate = true;
|
||||
boosts[boostName] = 0;
|
||||
}
|
||||
}
|
||||
if (activate) {
|
||||
source.setBoost(boosts);
|
||||
this.add('-clearnegativeboost', source, '[silent]');
|
||||
}
|
||||
} else {
|
||||
if (item.fling?.status) {
|
||||
source.trySetStatus(item.fling.status, target);
|
||||
} else if (item.fling?.volatileStatus) {
|
||||
source.addVolatile(item.fling.volatileStatus, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
medic: {
|
||||
onSwitchOut(pokemon) {
|
||||
pokemon.side.addSideCondition('medic');
|
||||
},
|
||||
condition: {
|
||||
// this is a side condition
|
||||
onSideStart(side) {
|
||||
this.add('-sidestart', side, 'medic', '[silent]');
|
||||
},
|
||||
onSwitchIn(pokemon) {
|
||||
this.heal(pokemon.maxhp / 6);
|
||||
if (pokemon.status) pokemon.cureStatus();
|
||||
pokemon.side.removeSideCondition('medic');
|
||||
this.add('-sideend', pokemon.side, 'move: Medic', '[silent]');
|
||||
},
|
||||
},
|
||||
flags: {},
|
||||
name: "Medic",
|
||||
shortDesc: "Upon switching out, the replacement heals 1/6 max HP and has its status cured.",
|
||||
},
|
||||
mindbloom: {
|
||||
onModifyMove(move, pokemon) {
|
||||
if (move.category === 'Status' && move.target === 'normal') {
|
||||
move.boosts = {
|
||||
spd: -1,
|
||||
};
|
||||
}
|
||||
},
|
||||
onAfterMove(pokemon, source, move) {
|
||||
if (move.category === 'Status') {
|
||||
if (pokemon.adjacentFoes().length === 0) return;
|
||||
const target = this.sample(pokemon.adjacentFoes());
|
||||
this.boost({ spd: -1 }, target, pokemon, null, true);
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Mind Bloom",
|
||||
shortDesc: "This Pokemon's status moves lower the opponent's Sp. Def by 1.",
|
||||
},
|
||||
momentum: {
|
||||
name: "Momentum",
|
||||
shortDesc: "Damage of moves used on consecutive turns is increased. Max 2x after 5 turns.",
|
||||
flags: {},
|
||||
onStart(pokemon) {
|
||||
pokemon.addVolatile('momentum');
|
||||
},
|
||||
condition: {
|
||||
onStart(pokemon) {
|
||||
this.effectState.lastMove = '';
|
||||
this.effectState.numConsecutive = 0;
|
||||
},
|
||||
onTryMovePriority: -2,
|
||||
onTryMove(pokemon, target, move) {
|
||||
if (!pokemon.hasItem('momentum')) {
|
||||
pokemon.removeVolatile('momentum');
|
||||
return;
|
||||
}
|
||||
if (move.callsMove) return;
|
||||
if (this.effectState.lastMove === move.id && pokemon.moveLastTurnResult) {
|
||||
this.effectState.numConsecutive++;
|
||||
} else if (pokemon.volatiles['twoturnmove']) {
|
||||
if (this.effectState.lastMove !== move.id) {
|
||||
this.effectState.numConsecutive = 1;
|
||||
} else {
|
||||
this.effectState.numConsecutive++;
|
||||
}
|
||||
} else {
|
||||
this.effectState.numConsecutive = 0;
|
||||
}
|
||||
this.effectState.lastMove = move.id;
|
||||
},
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
const dmgMod = [4096, 4915, 5734, 6553, 7372, 8192];
|
||||
const numConsecutive = this.effectState.numConsecutive > 5 ? 5 : this.effectState.numConsecutive;
|
||||
this.debug(`Current Metronome boost: ${dmgMod[numConsecutive]}/4096`);
|
||||
return this.chainModify([dmgMod[numConsecutive], 4096]);
|
||||
},
|
||||
},
|
||||
},
|
||||
nightlight: {
|
||||
onSourceModifyAtkPriority: 6,
|
||||
onSourceModifyAtk(atk, attacker, defender, move) {
|
||||
if (move.type === 'Dark' || move.type === 'Ghost') {
|
||||
this.debug('Night Light weaken');
|
||||
return this.chainModify(0.5);
|
||||
}
|
||||
},
|
||||
onSourceModifySpAPriority: 5,
|
||||
onSourceModifySpA(atk, attacker, defender, move) {
|
||||
if (move.type === 'Dark' || move.type === 'Ghost') {
|
||||
this.debug('Night Light weaken');
|
||||
return this.chainModify(0.5);
|
||||
}
|
||||
},
|
||||
flags: { breakable: 1 },
|
||||
name: "Night Light",
|
||||
shortDesc: "This Pokemon takes halved damage from Dark and Ghost-type moves.",
|
||||
},
|
||||
nightmarch: {
|
||||
onBasePower(basePower, pokemon, target, move) {
|
||||
for (const ally of pokemon.side.pokemon)
|
||||
if (ally !== pokemon && ally.set.moves.includes(move.name))
|
||||
basePower += 20;
|
||||
return;
|
||||
},
|
||||
name: "Night March",
|
||||
shortDesc: "This Pokemon's attacks gain +20 power for each ally that also has that move.",
|
||||
},
|
||||
nocturnal: {
|
||||
onTryHit(target, source, move) {
|
||||
if (target !== source && move.type === 'Dark') {
|
||||
if (!this.heal(target.baseMaxhp / 4)) {
|
||||
this.add('-immune', target, '[from] ability: Nocturnal');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
},
|
||||
flags: { breakable: 1 },
|
||||
name: "Nocturnal",
|
||||
shortDesc: "This Pokemon heals 1/4 of its max HP when hit by Dark moves; Dark immunity.",
|
||||
},
|
||||
outclass: {
|
||||
onSourceHit(target, source, move) {
|
||||
if (!move || !target) return;
|
||||
const targetType = target.types[0];
|
||||
let sourceSecondaryType = '???';
|
||||
if (source.types[1]) sourceSecondaryType = source.types[1];
|
||||
if (target !== source && move.category !== 'Status' &&
|
||||
!source.hasType(targetType) && targetType !== '???' &&
|
||||
!(source.volatiles['outclass'] && !source.side.removeSideCondition('fishingtokens'))) {
|
||||
source.setType([source.types[0]]);
|
||||
if (source.addType(targetType)) {
|
||||
target.setType(target.getTypes(true).map(type => type === targetType ? "???" : type));
|
||||
this.add('-start', target, 'typechange', target.types.join('/'));
|
||||
this.add('-start', source, 'typeadd', targetType, '[from] ability: Outclass');
|
||||
source.addVolatile('outclass');
|
||||
} else {
|
||||
this.debug('Failed to take target type.');
|
||||
if (sourceSecondaryType !== '???') source.setType([source.types[0], sourceSecondaryType]);
|
||||
}
|
||||
}
|
||||
},
|
||||
condition: {},
|
||||
flags: {},
|
||||
name: "Outclass",
|
||||
shortDesc: "Fishing token or first hit: steals target primary type and replaces its own secondary type.",
|
||||
},
|
||||
peckingorder: {
|
||||
name: "Pecking Order",
|
||||
shortDesc: "On switch-in, this Pokemon lowers the Defense of adjacent opponents by 1 stage.",
|
||||
flags: {},
|
||||
onStart(pokemon) {
|
||||
let activated = false;
|
||||
for (const target of pokemon.adjacentFoes()) {
|
||||
if (!activated) {
|
||||
this.add('-ability', pokemon, 'Pecking Order', 'boost');
|
||||
activated = true;
|
||||
}
|
||||
if (target.volatiles['substitute']) {
|
||||
this.add('-immune', target);
|
||||
} else {
|
||||
this.boost({ def: -1 }, target, pokemon, null, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
polychrome: {
|
||||
onBasePower(basePower, pokemon, target, move) {
|
||||
if (!pokemon.hasType(move.type)) return this.chainModify(1.25);
|
||||
},
|
||||
name: "Polychrome",
|
||||
shortDesc: "This Pokemon's non-STAB moves have 1.25x power.",
|
||||
},
|
||||
precognition: {
|
||||
onBeforeTurn(pokemon) {
|
||||
if (pokemon.adjacentFoes().length === 0) return;
|
||||
const target = this.sample(pokemon.adjacentFoes());
|
||||
const targetAction = this.queue.willMove(target);
|
||||
if (!targetAction) return;
|
||||
const pokemonAction = this.queue.willMove(pokemon);
|
||||
if (!pokemonAction) return;
|
||||
const targetMove = this.dex.getActiveMove(targetAction.move.id);
|
||||
const pokemonMove = this.dex.getActiveMove(pokemonAction.move.id);
|
||||
if (!pokemon.volatiles['substitute'] && targetMove.type === pokemonMove.type) {
|
||||
const substitute = this.dex.getActiveMove('substitute');
|
||||
this.actions.useMove(substitute, pokemon);
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Precognition",
|
||||
shortDesc: "If a foe selects the same type move as the user, the user uses Substitute at the beginning of the turn.",
|
||||
},
|
||||
preeminence: {
|
||||
onModifyPriority(priority, pokemon, target, move) {
|
||||
const basePowerAfterMultiplier = this.modify(move.basePower, this.event.modifier);
|
||||
this.debug(`Base Power: ${basePowerAfterMultiplier}`);
|
||||
if (basePowerAfterMultiplier <= 60) {
|
||||
this.debug('Preeminence boost');
|
||||
return priority + 1;
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Preeminence",
|
||||
shortDesc: "This Pokemon's moves of 60 power or less have +1 priority, including Struggle.",
|
||||
},
|
||||
preparation: {
|
||||
onAfterMove(source, target, move) {
|
||||
if (move.category === 'Status' && move.name !== 'Substitute' && !move.stallingMove) {
|
||||
source.addVolatile('preparation');
|
||||
}
|
||||
},
|
||||
condition: {
|
||||
duration: 2,
|
||||
onBasePower(basePower, attacker, defender, move) {
|
||||
return this.chainModify(2);
|
||||
},
|
||||
},
|
||||
name: "Preparation",
|
||||
shortDesc: "Deals 2x damage the turn after using a status move.",
|
||||
},
|
||||
puppetmaster: {
|
||||
onSwitchIn(pokemon) {
|
||||
this.effectState.puppetmaster = pokemon;
|
||||
},
|
||||
onAnyPrepareHitPriority: -1,
|
||||
onAnyPrepareHit(source, target, move) {
|
||||
const puppetmaster = this.effectState.puppetmaster;
|
||||
if (!move || move.name !== 'Substitute' || move.isZ || move.isMax || move.sourceEffect === 'puppetmaster') return;
|
||||
this.actions.useMove(move.id, puppetmaster);
|
||||
return null;
|
||||
},
|
||||
onResidualOrder: 28,
|
||||
onResidualSubOrder: 2,
|
||||
onResidual(pokemon) {
|
||||
if (pokemon.adjacentFoes().length === 0) return;
|
||||
const target = this.sample(pokemon.adjacentFoes());
|
||||
if (target.volatiles['substitute']) this.damage(target.baseMaxhp / 8, target, pokemon);
|
||||
},
|
||||
onDamagingHitOrder: 1,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (this.checkMoveMakesContact(move, source, target, true) && this.randomChance(1, 1000)) {
|
||||
source.formeChange('Cradily');
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Puppet Master",
|
||||
shortDesc: "This Pokemon steals foes' Substitute. Foes under Substitute lose 1/5 max HP per turn.",
|
||||
},
|
||||
quickthinking: {
|
||||
onBasePowerPriority: 21,
|
||||
onBasePower(basePower, pokemon) {
|
||||
for (const target of this.getAllActive()) {
|
||||
if (target === pokemon) continue;
|
||||
if (target.newlySwitched || this.queue.willMove(target)) {
|
||||
return this.chainModify(1.3);
|
||||
}
|
||||
}
|
||||
},
|
||||
onSourceModifyDamage(damage, source, target, move) {
|
||||
if (this.queue.willMove(target)) {
|
||||
this.debug('Slow and Steady neutralize');
|
||||
return this.chainModify(0.7);
|
||||
}
|
||||
},
|
||||
flags: { breakable: 1 },
|
||||
name: "Quick Thinking",
|
||||
shortDesc: "This Pokemon deals 1.3x damage when moving first and takes 0.7x damage when moving last.",
|
||||
},
|
||||
refraction: {
|
||||
onStart(pokemon) {
|
||||
this.add('-activate', pokemon, 'ability: Refraction');
|
||||
pokemon.side.addSideCondition('waterpledge');
|
||||
},
|
||||
flags: {},
|
||||
name: "Refraction",
|
||||
shortDesc: "On switchin, this Pokemon sets Rainbow on its side.",
|
||||
},
|
||||
royalguard: {
|
||||
onStart(pokemon) {
|
||||
if (this.effectState.royalguard) return;
|
||||
this.effectState.royalguard = true;
|
||||
this.actions.useMove("substitute", pokemon);
|
||||
},
|
||||
name: "Royal Guard",
|
||||
shortDesc: "On switchin, this Pokemon uses Substitute. Once per battle.",
|
||||
},
|
||||
sealedoff: {
|
||||
onStart(pokemon) {
|
||||
this.add('-activate', pokemon, 'ability: Sealed Off');
|
||||
this.actions.useMove("imprison", pokemon);
|
||||
},
|
||||
name: "Sealed Off",
|
||||
shortDesc: "On switchin, this Pokemon uses Imprison.",
|
||||
},
|
||||
searingremark: {
|
||||
onSourceDamagingHit(damage, target, source, move) {
|
||||
if (move.flags['sound'] && this.randomChance(3, 10)) {
|
||||
if (!target.hasAbility('shielddust') && !target.hasItem('covertcloak')) target.trySetStatus('brn', source);
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Searing Remark",
|
||||
shortDesc: "This Pokemon's sound moves have a 30% of burning the target.",
|
||||
},
|
||||
selfrepair: {
|
||||
onAfterMove(target, source, move) {
|
||||
if (move.category === 'Status') {
|
||||
this.heal(target.baseMaxhp / 4);
|
||||
}
|
||||
},
|
||||
name: "Self-Repair",
|
||||
shortDesc: "This Pokemon heals 25% its max HP after using a Status move.",
|
||||
},
|
||||
snowhazard: {
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
this.field.setWeather('snowscape');
|
||||
},
|
||||
flags: {},
|
||||
name: "Snowhazard",
|
||||
shortDesc: "When this Pokemon is hit by an attack, the effect of Snow begins.",
|
||||
},
|
||||
spinthewheel: {
|
||||
onResidual(pokemon) {
|
||||
const metronome = this.dex.getActiveMove('metronome');
|
||||
this.actions.useMove(metronome, pokemon);
|
||||
},
|
||||
flags: {},
|
||||
name: "Spin the Wheel",
|
||||
shortDesc: "This Pokemon uses Metronome at the end of each turn.",
|
||||
},
|
||||
statleeching: {
|
||||
onFoeAfterBoost(boost, target, source, effect) {
|
||||
if (effect?.name === 'Opportunist' || effect?.name === 'Stat Leeching' || effect?.name === 'Mirror Herb') return;
|
||||
const pokemon = this.effectState.target;
|
||||
const boosts: Partial<BoostsTable> = {};
|
||||
let i: BoostID;
|
||||
for (i in boost) {
|
||||
boost[i]! *= -1;
|
||||
boosts[i] = boost[i];
|
||||
}
|
||||
if (Object.keys(boosts).length < 1) return;
|
||||
this.boost(boosts, pokemon);
|
||||
},
|
||||
flags: {},
|
||||
name: "Stat Leeching",
|
||||
shortDesc: "This Pokemon gains the opposite stat change as opposing Pokemon.",
|
||||
},
|
||||
strongbreeze: {
|
||||
onStart(pokemon) {
|
||||
if (this.effectState.strongbreeze) return;
|
||||
this.effectState.strongbreeze = true;
|
||||
this.add('-activate', pokemon, 'ability: Strong Breeze');
|
||||
pokemon.side.addSideCondition('tailwind');
|
||||
},
|
||||
name: "Strong Breeze",
|
||||
shortDesc: "On switchin, this Pokemon sets Tailwind. Once per battle.",
|
||||
},
|
||||
superrod: {
|
||||
onAfterMove(target, source, move) {
|
||||
if (!source.side.sideConditions['fishingTokens']) return;
|
||||
if (move.type === 'Water') {
|
||||
this.heal(source.baseMaxhp / 16 * source.side.sideConditions['fishingTokens'].layers);
|
||||
}
|
||||
},
|
||||
name: "Super Rod",
|
||||
shortDesc: "This Pokemon's Water-type moves heal it for 1/16 max HP for each Fishing Token.",
|
||||
},
|
||||
treasurecraze: {
|
||||
onAfterUseItem(item, pokemon) {
|
||||
if (pokemon !== this.effectState.target) return;
|
||||
this.boost({ atk: 2 }, pokemon, pokemon, null, false, true);
|
||||
},
|
||||
onTakeItem(item, pokemon) {
|
||||
this.boost({ atk: 2 }, pokemon, pokemon, null, false, true);
|
||||
},
|
||||
flags: {},
|
||||
name: "Treasure Craze",
|
||||
shortDesc: "When this Pokemon loses its held item, its Attack is raised by 2.",
|
||||
},
|
||||
troubled: {
|
||||
onStart(source) {
|
||||
source.addVolatile('troubled');
|
||||
},
|
||||
condition: {
|
||||
noCopy: true,
|
||||
onDisableMove(pokemon) {
|
||||
if (pokemon.lastMove && pokemon.lastMove.id !== 'struggle') pokemon.disableMove(pokemon.lastMove.id);
|
||||
},
|
||||
},
|
||||
name: "Troubled",
|
||||
shortDesc: "This Pokemon cannot use the same move twice in a row.",
|
||||
},
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,44 +0,0 @@
|
|||
export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
||||
leechlife: {
|
||||
inherit: true,
|
||||
onModifyMove(move, pokemon) {
|
||||
if (!pokemon.volatiles['bloodsucking']) return;
|
||||
move.basePower = 20;
|
||||
move.drain = [1, 1];
|
||||
if (pokemon.getStat('atk', false, true) > pokemon.getStat('spa', false, true)) move.category = 'Physical';
|
||||
pokemon.removeVolatile('bloodsucking');
|
||||
},
|
||||
},
|
||||
|
||||
// fake moves
|
||||
fishingtokens: {
|
||||
accuracy: true,
|
||||
basePower: 0,
|
||||
category: "Status",
|
||||
name: "Fishing Tokens",
|
||||
pp: 30,
|
||||
priority: 0,
|
||||
flags: { snatch: 1 },
|
||||
sideCondition: 'fishingtokens',
|
||||
condition: {
|
||||
onSideStart(side) {
|
||||
this.add('-sidestart', side, 'Fishing Tokens');
|
||||
this.effectState.layers = 1;
|
||||
},
|
||||
onSideRestart(side) {
|
||||
this.add('-sidestart', side, 'Fishing Tokens');
|
||||
this.effectState.layers++;
|
||||
},
|
||||
onSideResidualOrder: 26,
|
||||
onSideResidualSubOrder: 2,
|
||||
onSideEnd(side) {
|
||||
this.add('-sideend', side, 'move: Fishing Tokens');
|
||||
},
|
||||
},
|
||||
secondary: null,
|
||||
target: "allySide",
|
||||
type: "Water",
|
||||
zMove: { boost: { spd: 1 } },
|
||||
contestType: "Beautiful", // they sure are
|
||||
},
|
||||
};
|
||||
|
|
@ -1,571 +0,0 @@
|
|||
export const Pokedex: import('../../../sim/dex-species').ModdedSpeciesDataTable = {
|
||||
spreetah: {
|
||||
num: 2001,
|
||||
name: "Spreetah",
|
||||
types: ["Electric", "Fire"],
|
||||
baseStats: { hp: 64, atk: 90, def: 54, spa: 90, spd: 54, spe: 150 },
|
||||
abilities: { 0: "Momentum" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
raintoad: {
|
||||
num: 2002,
|
||||
name: "Raintoad",
|
||||
types: ["Normal"],
|
||||
baseStats: { hp: 110, atk: 90, def: 70, spa: 70, spd: 80, spe: 90 },
|
||||
abilities: { 0: "Color Wheel" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
pomegrenade: {
|
||||
num: 2003,
|
||||
name: "Pomegrenade",
|
||||
types: ["Fire", "Fairy"],
|
||||
baseStats: { hp: 120, atk: 50, def: 85, spa: 105, spd: 70, spe: 85 },
|
||||
abilities: { 0: "Mind Bloom" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
surfsurge: {
|
||||
num: 2004,
|
||||
name: "Surfsurge",
|
||||
types: ["Water", "Electric"],
|
||||
baseStats: { hp: 86, atk: 74, def: 110, spa: 128, spd: 74, spe: 68 },
|
||||
abilities: { 0: "Strong Breeze" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
anxiousoil: {
|
||||
num: 2005,
|
||||
name: "Anxiousoil",
|
||||
types: ["Ground", "Ghost"],
|
||||
baseStats: { hp: 80, atk: 130, def: 65, spa: 130, spd: 65, spe: 115 },
|
||||
abilities: { 0: "Troubled" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
depresloth: {
|
||||
num: 2006,
|
||||
name: "Depresloth",
|
||||
types: ["Electric", "Ghost"],
|
||||
baseStats: { hp: 111, atk: 105, def: 65, spa: 115, spd: 75, spe: 74 },
|
||||
abilities: { 0: "Exhaust" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
obsallas: {
|
||||
num: 2007,
|
||||
name: "Obsallas",
|
||||
types: ["Rock", "Normal"],
|
||||
baseStats: { hp: 102, atk: 92, def: 69, spa: 52, spd: 70, spe: 112 },
|
||||
abilities: { 0: "Crumble" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
nharboard: {
|
||||
num: 2008,
|
||||
name: "Nharboard",
|
||||
types: ["Water", "Steel"],
|
||||
baseStats: { hp: 120, atk: 90, def: 70, spa: 100, spd: 50, spe: 60 },
|
||||
abilities: { 0: "First-Class Ticket" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
lampyre: {
|
||||
num: 2009,
|
||||
name: "Lampyre",
|
||||
types: ["Steel", "Fire"],
|
||||
baseStats: { hp: 50, atk: 45, def: 100, spa: 145, spd: 100, spe: 80 },
|
||||
abilities: { 0: "Night Light" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
noyew: {
|
||||
num: 2010,
|
||||
name: "Noyew",
|
||||
types: ["Grass", "Steel"],
|
||||
baseStats: { hp: 64, atk: 51, def: 116, spa: 51, spd: 116, spe: 42 },
|
||||
abilities: { 0: "Back at Ya!" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
underhazard: {
|
||||
num: 2011,
|
||||
name: "Underhazard",
|
||||
types: ["Dark", "Poison"],
|
||||
baseStats: { hp: 140, atk: 95, def: 75, spa: 100, spd: 80, spe: 40 },
|
||||
abilities: { 0: "Countermeasures" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
bleyabat: {
|
||||
num: 2012,
|
||||
name: "Bleyabat",
|
||||
types: ["Ghost", "Flying"],
|
||||
baseStats: { hp: 125, atk: 95, def: 110, spa: 55, spd: 100, spe: 55 },
|
||||
abilities: { 0: "Night Light" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
nectaregal: {
|
||||
num: 2013,
|
||||
name: "Nectaregal",
|
||||
types: ["Grass", "Electric"],
|
||||
baseStats: { hp: 80, atk: 45, def: 80, spa: 90, spd: 100, spe: 70 },
|
||||
abilities: { 0: "Electromagnetic Manipulation" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
nummanutts: {
|
||||
num: 2014,
|
||||
name: "Nummanutts",
|
||||
types: ["Poison", "Dark"],
|
||||
baseStats: { hp: 80, atk: 80, def: 100, spa: 100, spd: 120, spe: 40 },
|
||||
abilities: { 0: "Dice Roller" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
mosstrosity: {
|
||||
num: 2015,
|
||||
name: "Mosstrosity",
|
||||
types: ["Dark", "Grass"],
|
||||
baseStats: { hp: 70, atk: 110, def: 50, spa: 100, spd: 70, spe: 130 },
|
||||
abilities: { 0: "Clinch" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
faellen: {
|
||||
num: 2016,
|
||||
name: "Faellen",
|
||||
types: ["Fairy", "Dark"],
|
||||
baseStats: { hp: 80, atk: 60, def: 65, spa: 130, spd: 100, spe: 115 },
|
||||
abilities: { 0: "Broken Wand" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
nucleophage: {
|
||||
num: 2017,
|
||||
name: "Nucleophage",
|
||||
types: ["Poison", "Psychic"],
|
||||
baseStats: { hp: 60, atk: 100, def: 50, spa: 130, spd: 60, spe: 125 },
|
||||
abilities: { 0: "Diseased" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
tardeblade: {
|
||||
num: 2018,
|
||||
name: "Tardeblade",
|
||||
types: ["Steel", "Psychic"],
|
||||
baseStats: { hp: 130, atk: 90, def: 90, spa: 80, spd: 80, spe: 50 },
|
||||
abilities: { 0: "Hibernation" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
bugsome: {
|
||||
num: 2019,
|
||||
name: "Bugsome",
|
||||
types: ["Bug"],
|
||||
baseStats: { hp: 89, atk: 110, def: 90, spa: 60, spd: 70, spe: 136 },
|
||||
abilities: { 0: "Stat Leeching" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
pestifer: {
|
||||
num: 2020,
|
||||
name: "Pestifer",
|
||||
types: ["Poison", "Ground"],
|
||||
baseStats: { hp: 110, atk: 50, def: 100, spa: 130, spd: 55, spe: 96 },
|
||||
abilities: { 0: "Contagious" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
fungemory: {
|
||||
num: 2021,
|
||||
name: "Fungemory",
|
||||
types: ["Psychic", "Ghost"],
|
||||
baseStats: { hp: 66, atk: 106, def: 66, spa: 116, spd: 166, spe: 46 },
|
||||
abilities: { 0: "Sealed Off" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
guarden: {
|
||||
num: 2022,
|
||||
name: "Guarden",
|
||||
types: ["Steel", "Grass"],
|
||||
baseStats: { hp: 94, atk: 119, def: 120, spa: 42, spd: 52, spe: 73 },
|
||||
abilities: { 0: "Royal Guard" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
hawksectiff: {
|
||||
num: 2023,
|
||||
name: "Hawksectiff",
|
||||
types: ["Dark", "Flying"],
|
||||
baseStats: { hp: 110, atk: 125, def: 90, spa: 65, spd: 80, spe: 75 },
|
||||
abilities: { 0: "Pecking Order" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
boogeymancer: {
|
||||
num: 2024,
|
||||
name: "Boogeymancer",
|
||||
types: ["Ghost", "Fire"],
|
||||
baseStats: { hp: 65, atk: 118, def: 63, spa: 112, spd: 65, spe: 122 },
|
||||
abilities: { 0: "Broken Wand" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
cliffilisk: {
|
||||
num: 2025,
|
||||
name: "Cliffilisk",
|
||||
types: ["Rock", "Dragon"],
|
||||
baseStats: { hp: 140, atk: 148, def: 132, spa: 40, spd: 62, spe: 28 },
|
||||
abilities: { 0: "Crumble" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
aesap: {
|
||||
num: 2026,
|
||||
name: "Aesap",
|
||||
types: ["Dark", "Fairy"],
|
||||
baseStats: { hp: 75, atk: 115, def: 100, spa: 70, spd: 120, spe: 120 },
|
||||
abilities: { 0: "Exhaust" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
delirirak: {
|
||||
num: 2027,
|
||||
name: "Delirirak",
|
||||
types: ["Ice", "Ghost"],
|
||||
baseStats: { hp: 75, atk: 115, def: 55, spa: 130, spd: 100, spe: 115 },
|
||||
abilities: { 0: "Fumigation" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
lazahrusk: {
|
||||
num: 2028,
|
||||
name: "Lazahrusk",
|
||||
types: ["Bug", "Ghost"],
|
||||
baseStats: { hp: 89, atk: 105, def: 140, spa: 105, spd: 106, spe: 20 },
|
||||
abilities: { 0: "Diseased" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
cogwyld: {
|
||||
num: 2029,
|
||||
name: "Cogwyld",
|
||||
types: ["Dark", "Steel"],
|
||||
baseStats: { hp: 97, atk: 102, def: 87, spa: 72, spd: 87, spe: 97 },
|
||||
abilities: { 0: "Self-Repair" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
folibower: {
|
||||
num: 2030,
|
||||
name: "Folibower",
|
||||
types: ["Flying", "Grass"],
|
||||
baseStats: { hp: 90, atk: 101, def: 83, spa: 85, spd: 70, spe: 106 },
|
||||
abilities: { 0: "Treasure Craze" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
araquisis: {
|
||||
num: 2031,
|
||||
name: "Araquisis",
|
||||
types: ["Psychic", "Dark"],
|
||||
baseStats: { hp: 109, atk: 117, def: 92, spa: 80, spd: 88, spe: 38 },
|
||||
abilities: { 0: "Precognition" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
liwyzard: {
|
||||
num: 2032,
|
||||
name: "Liwyzard",
|
||||
types: ["Dragon", "Fairy"],
|
||||
baseStats: { hp: 75, atk: 75, def: 75, spa: 100, spd: 100, spe: 100 },
|
||||
abilities: { 0: "Magic Missile" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
shail: {
|
||||
num: 2033,
|
||||
name: "Shail",
|
||||
types: ["Ice", "Ground"],
|
||||
baseStats: { hp: 55, atk: 65, def: 113, spa: 101, spd: 124, spe: 41 },
|
||||
abilities: { 0: "Snowhazard" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
fightinfly: {
|
||||
num: 2034,
|
||||
name: "Fightinfly",
|
||||
types: ["Bug", "Fighting"],
|
||||
baseStats: { hp: 60, atk: 110, def: 70, spa: 105, spd: 70, spe: 115 },
|
||||
abilities: { 0: "Nocturnal" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
arthrostrike: {
|
||||
num: 2035,
|
||||
name: "Arthrostrike",
|
||||
types: ["Bug", "Fighting"],
|
||||
baseStats: { hp: 80, atk: 120, def: 85, spa: 50, spd: 65, spe: 60 },
|
||||
abilities: { 0: "Preeminence" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
magmouth: {
|
||||
num: 2036,
|
||||
name: "Magmouth",
|
||||
types: ["Ground", "Normal"],
|
||||
baseStats: { hp: 144, atk: 60, def: 100, spa: 90, spd: 53, spe: 20 },
|
||||
abilities: { 0: "Searing Remark" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
orchidauntless: {
|
||||
num: 2037,
|
||||
name: "Orchidauntless",
|
||||
types: ["Grass", "Psychic"],
|
||||
baseStats: { hp: 84, atk: 121, def: 76, spa: 118, spd: 79, spe: 121 },
|
||||
abilities: { 0: "Dewdrop" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
boillusk: {
|
||||
num: 2038,
|
||||
name: "Boillusk",
|
||||
types: ["Water", "Fire"],
|
||||
baseStats: { hp: 88, atk: 86, def: 132, spa: 96, spd: 118, spe: 20 },
|
||||
abilities: { 0: "Absorber" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
minkai: {
|
||||
num: 2039,
|
||||
name: "Minkai",
|
||||
types: ["Fighting", "Ice"],
|
||||
baseStats: { hp: 80, atk: 60, def: 110, spa: 120, spd: 60, spe: 110 },
|
||||
abilities: { 0: "Nocturnal" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
shurifluri: {
|
||||
num: 2040,
|
||||
name: "Shurifluri",
|
||||
types: ["Ice", "Steel"],
|
||||
baseStats: { hp: 66, atk: 128, def: 54, spa: 78, spd: 78, spe: 108 },
|
||||
abilities: { 0: "Snowhazard" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
roolette: {
|
||||
num: 2041,
|
||||
name: "Roolette",
|
||||
types: ["Normal", "Fighting"],
|
||||
baseStats: { hp: 100, atk: 120, def: 75, spa: 100, spd: 75, spe: 100 },
|
||||
abilities: { 0: "Spin the Wheel" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
frenzaiai: {
|
||||
num: 2042,
|
||||
name: "Frenzaiai",
|
||||
types: ["Normal", "Poison"],
|
||||
baseStats: { hp: 83, atk: 95, def: 85, spa: 80, spd: 92, spe: 110 },
|
||||
abilities: { 0: "Asymmetry" },
|
||||
weightkg: 50,
|
||||
prevo: "Grafaiai",
|
||||
evoType: "levelFriendship",
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
buffball: {
|
||||
num: 2043,
|
||||
name: "Buffball",
|
||||
types: ["Fighting", "Bug"],
|
||||
baseStats: { hp: 101, atk: 127, def: 71, spa: 103, spd: 71, spe: 97 },
|
||||
abilities: { 0: "Preparation" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
rootfraction: {
|
||||
num: 2044,
|
||||
name: "Rootfraction",
|
||||
types: ["Grass", "Poison"],
|
||||
baseStats: { hp: 95, atk: 60, def: 94, spa: 121, spd: 94, spe: 66 },
|
||||
abilities: { 0: "Refraction" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
remnant: {
|
||||
num: 2045,
|
||||
name: "Remnant",
|
||||
types: ["Ghost"],
|
||||
baseStats: { hp: 75, atk: 75, def: 145, spa: 75, spd: 155, spe: 75 },
|
||||
abilities: { 0: "Night March" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
marlord: {
|
||||
num: 2046,
|
||||
name: "Marlord",
|
||||
types: ["Steel", "Fighting"],
|
||||
baseStats: { hp: 91, atk: 124, def: 67, spa: 67, spd: 118, spe: 74 },
|
||||
abilities: { 0: "Polychrome" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
marsonmallow: {
|
||||
num: 2047,
|
||||
name: "Marsonmallow",
|
||||
types: ["Fairy", "Fire"],
|
||||
baseStats: { hp: 72, atk: 107, def: 96, spa: 91, spd: 136, spe: 23 },
|
||||
abilities: { 0: "big stick" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
trawlutre: {
|
||||
num: 2048,
|
||||
name: "Trawlutre",
|
||||
types: ["Water", "Fighting"],
|
||||
baseStats: { hp: 72, atk: 104, def: 75, spa: 94, spd: 75, spe: 120 },
|
||||
abilities: { 0: "Super Rod" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
manticrash: {
|
||||
num: 2049,
|
||||
name: "Manticrash",
|
||||
types: ["Normal", "Ground"],
|
||||
baseStats: { hp: 105, atk: 108, def: 86, spa: 71, spd: 89, spe: 42 },
|
||||
abilities: { 0: "Comeback" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
ichthyocorn: {
|
||||
num: 2050,
|
||||
name: "Ichthyocorn",
|
||||
types: ["Water", "Fairy"],
|
||||
baseStats: { hp: 85, atk: 60, def: 85, spa: 80, spd: 105, spe: 105 },
|
||||
abilities: { 0: "Capricious" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
cryobser: {
|
||||
num: 2051,
|
||||
name: "Cryobser",
|
||||
types: ["Normal", "Ice"],
|
||||
baseStats: { hp: 113, atk: 70, def: 91, spa: 70, spd: 111, spe: 50 },
|
||||
abilities: { 0: "Medic" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
skibidragon: {
|
||||
num: 2052,
|
||||
name: "Skibidragon",
|
||||
types: ["Dragon"],
|
||||
baseStats: { hp: 90, atk: 90, def: 98, spa: 105, spd: 92, spe: 125 },
|
||||
abilities: { 0: "Bathroom Break" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
tuxquito: {
|
||||
num: 2053,
|
||||
name: "Tuxquito",
|
||||
types: ["Bug", "Flying"],
|
||||
baseStats: { hp: 95, atk: 100, def: 75, spa: 110, spd: 75, spe: 145 },
|
||||
abilities: { 0: "Bloodsucking" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
cosmole: {
|
||||
num: 2054,
|
||||
name: "Cosmole",
|
||||
types: ["Ground", "Psychic"],
|
||||
baseStats: { hp: 124, atk: 108, def: 79, spa: 61, spd: 79, spe: 89 },
|
||||
abilities: { 0: "Quick Thinking" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
suragon: {
|
||||
num: 2055,
|
||||
name: "Suragon",
|
||||
types: ["Psychic", "Dragon"],
|
||||
baseStats: { hp: 80, atk: 70, def: 70, spa: 122, spd: 122, spe: 86 },
|
||||
abilities: { 0: "Antimatter" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
shufflux: {
|
||||
num: 2056,
|
||||
name: "Shufflux",
|
||||
types: ["Fairy", "Normal"],
|
||||
baseStats: { hp: 92, atk: 60, def: 60, spa: 114, spd: 124, spe: 84 },
|
||||
abilities: { 0: "Draw Four" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
mindwyrm: {
|
||||
num: 2057,
|
||||
name: "Mindwyrm",
|
||||
types: ["Bug", "Dragon"],
|
||||
baseStats: { hp: 120, atk: 120, def: 90, spa: 60, spd: 90, spe: 90 },
|
||||
abilities: { 0: "Quick Thinking" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
crashtank: {
|
||||
num: 2058,
|
||||
name: "Crashtank",
|
||||
types: ["Normal"],
|
||||
baseStats: { hp: 60, atk: 100, def: 140, spa: 50, spd: 120, spe: 70 },
|
||||
abilities: { 0: "Brace for Impact" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
leviadon: {
|
||||
num: 2059,
|
||||
name: "Leviadon",
|
||||
types: ["Dragon"],
|
||||
baseStats: { hp: 131, atk: 91, def: 66, spa: 140, spd: 61, spe: 61 },
|
||||
abilities: { 0: "Gangster" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
oonoonsi: {
|
||||
num: 2060,
|
||||
name: "Oonoonsi",
|
||||
types: ["Bug", "Psychic"],
|
||||
baseStats: { hp: 73, atk: 65, def: 85, spa: 125, spd: 135, spe: 80 },
|
||||
abilities: { 0: "Puppet Master" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
contradox: {
|
||||
num: 2061,
|
||||
name: "Contradox",
|
||||
types: ["Ice", "Psychic"],
|
||||
baseStats: { hp: 85, atk: 120, def: 85, spa: 100, spd: 70, spe: 106 },
|
||||
abilities: { 0: "Antimatter" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
roddammit: {
|
||||
num: 2062,
|
||||
name: "Roddammit",
|
||||
types: ["Dark", "Grass"],
|
||||
baseStats: { hp: 75, atk: 130, def: 134, spa: 95, spd: 86, spe: 45 },
|
||||
abilities: { 0: "Outclass" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
rizzquaza: {
|
||||
num: 2063,
|
||||
name: "Rizzquaza",
|
||||
types: ["Dragon", "Water"],
|
||||
baseStats: { hp: 110, atk: 80, def: 95, spa: 75, spd: 90, spe: 90 },
|
||||
abilities: { 0: "Iron Fistening" },
|
||||
weightkg: 50,
|
||||
eggGroups: ["Undiscovered"],
|
||||
},
|
||||
};
|
||||
|
|
@ -1,517 +0,0 @@
|
|||
import RandomTeams from '../../random-battles/gen9/teams';
|
||||
|
||||
export interface CPMSet {
|
||||
species: string;
|
||||
ability: string | string[];
|
||||
item: string | string[];
|
||||
gender: GenderName | GenderName[];
|
||||
moves: (string | string[])[];
|
||||
signatureMove: string;
|
||||
evs?: { hp?: number, atk?: number, def?: number, spa?: number, spd?: number, spe?: number };
|
||||
ivs?: { hp?: number, atk?: number, def?: number, spa?: number, spd?: number, spe?: number };
|
||||
nature?: string | string[];
|
||||
shiny?: number | boolean;
|
||||
level?: number;
|
||||
happiness?: number;
|
||||
skip?: string;
|
||||
teraType?: string | string[];
|
||||
}
|
||||
interface CPMSets { [k: string]: CPMSet }
|
||||
|
||||
export const cpmSets: CPMSets = {
|
||||
Aesap: {
|
||||
species: 'Aesap', ability: 'Exhaust', item: 'Leppa Berry', gender: '',
|
||||
moves: ['Knock Off', 'U-turn', 'Strength Sap'],
|
||||
signatureMove: 'Let\'s Snuggle Forever',
|
||||
evs: { hp: 4, atk: 252, spe: 252 }, nature: 'Jolly', teraType: 'Flying',
|
||||
},
|
||||
Anxiousoil: {
|
||||
species: 'Anxiousoil', ability: 'Troubled', item: 'Leftovers', gender: '',
|
||||
moves: [['Earthquake', 'Earth Power'], ['Shadow Ball', 'Poltergeist'], ['Ice Beam', 'Spikes', 'Moonblast']],
|
||||
signatureMove: 'Taunt',
|
||||
evs: { hp: 252, spa: 4, spe: 252 }, nature: 'Naive', teraType: 'Steel',
|
||||
},
|
||||
Araquisis: {
|
||||
species: 'Araquisis', ability: 'Precognition', item: 'Leftovers', gender: '',
|
||||
moves: ['Zen Headbutt', ['Sticky Web', 'Trick Room'], ['Moonlight', 'Pursuit']],
|
||||
signatureMove: 'Knock Off',
|
||||
evs: { hp: 252, atk: 252, spd: 4 }, ivs: { spe: 0 }, nature: 'Adamant', teraType: 'Dark',
|
||||
},
|
||||
Arthrostrike: {
|
||||
species: 'Arthrostrike', ability: 'Preeminence', item: 'Loaded Dice', gender: '',
|
||||
moves: ['Pin Missile', 'Earthquake', ['Fell Stinger', 'U-turn']],
|
||||
signatureMove: 'Arm Thrust',
|
||||
evs: { hp: 248, atk: 252, spe: 8 }, nature: 'Adamant', teraType: 'Fairy',
|
||||
},
|
||||
Bleyabat: {
|
||||
species: 'Bleyabat', ability: 'Night Light', item: 'Heavy-Duty Boots', gender: '',
|
||||
moves: ['Dual Wingbeat', 'Shadow Claw', 'Roost'],
|
||||
signatureMove: 'Bulk Up',
|
||||
evs: { hp: 252, def: 4, spd: 252 }, nature: 'Careful', teraType: 'Water',
|
||||
},
|
||||
Boillusk: {
|
||||
species: 'Boillusk', ability: 'Absorber', item: 'Heavy-Duty Boots', gender: '',
|
||||
moves: ['Steam Eruption', 'Earth Power', ['Scald', 'Stealth Rock', 'Overheat']],
|
||||
signatureMove: 'Fire Blast',
|
||||
evs: { hp: 252, spa: 252, spe: 4 }, nature: 'Modest', teraType: 'Fire',
|
||||
},
|
||||
Boogeymancer: {
|
||||
species: 'Boogeymancer', ability: 'Broken Wand', item: 'Heavy-Duty Boots', gender: '',
|
||||
moves: ['Shadow Ball', 'Energy Ball', ['Parting Shot', 'Calm Mind']],
|
||||
signatureMove: 'Lava Plume',
|
||||
evs: { atk: 4, spa: 252, spd: 252 }, nature: 'Timid', teraType: 'Dragon',
|
||||
},
|
||||
Buffball: {
|
||||
species: 'Buffball', ability: 'Preparation', item: 'Leftovers', gender: '',
|
||||
moves: ['Leech Life', 'Knock Off', ['Bulk Up', 'Agility']],
|
||||
signatureMove: "Close Combat",
|
||||
evs: { hp: 4, atk: 252, spe: 252 }, nature: 'Adamant', teraType: 'Ground',
|
||||
},
|
||||
Bugsome: {
|
||||
species: 'Bugsome', ability: 'Stat Leeching', item: 'Heavy-Duty Boots', gender: '',
|
||||
moves: ['Lunge', ['Crunch', 'Psychic Fangs'], 'Close Combat'],
|
||||
signatureMove: "U-turn",
|
||||
evs: { atk: 252, def: 4, spe: 252 }, nature: 'Jolly', teraType: 'Fire',
|
||||
},
|
||||
Cliffilisk: {
|
||||
species: 'Cliffilisk', ability: 'Crumble', item: 'Leftovers', gender: '',
|
||||
moves: ['Dragon Claw', ['Knock Off', 'Earthquake'], ['Stone Edge', 'Head Smash']],
|
||||
signatureMove: "Collision Course",
|
||||
evs: { hp: 252, atk: 252, spd: 4 }, nature: 'Adamant', teraType: 'Fighting',
|
||||
},
|
||||
Cogwyld: {
|
||||
species: 'Cogwyld', ability: 'Self-Repair', item: 'Heavy-Duty Boots', gender: '',
|
||||
moves: ['Knock Off', 'Gear Grind', ['Heal Bell', 'Thunder Wave', 'Stealth Rock']],
|
||||
signatureMove: 'Parting Shot',
|
||||
evs: { hp: 252, def: 4, spe: 252 }, nature: 'Jolly', teraType: 'Water',
|
||||
},
|
||||
Contradox: {
|
||||
species: 'Contradox', ability: 'Antimatter', item: 'Life Orb', gender: '',
|
||||
moves: ['Psychic Fangs', ['Earthquake', 'Fire Punch', 'Ice Shard'], 'U-turn'],
|
||||
signatureMove: 'Triple Axel',
|
||||
evs: { atk: 252, def: 4, spe: 252 }, nature: 'Jolly', teraType: 'Poison',
|
||||
},
|
||||
Cosmole: {
|
||||
species: 'Cosmole', ability: 'Quick Thinking', item: 'Life Orb', gender: '',
|
||||
moves: [['Swords Dance', 'Rapid Spin', 'Close Combat'], 'Earthquake', 'Psychic Fangs'],
|
||||
signatureMove: 'Extreme Speed',
|
||||
evs: { atk: 252, spd: 4, spe: 252 }, nature: 'Adamant', teraType: 'Ground',
|
||||
},
|
||||
Crashtank: {
|
||||
species: 'Crashtank', ability: 'Brace for Impact', item: 'Heavy-Duty Boots', gender: 'N',
|
||||
moves: ['Knock Off', 'Body Press', ['Rapid Spin', 'Spikes', 'U-turn']],
|
||||
signatureMove: 'Body Slam',
|
||||
evs: { hp: 248, def: 252, spd: 8 }, nature: 'Impish', teraType: 'Fairy',
|
||||
},
|
||||
Cryobser: {
|
||||
species: 'Cryobser', ability: 'Medic', item: 'Heavy-Duty Boots', gender: '',
|
||||
moves: ['Ice Beam', 'Heal Bell', ['Discharge', 'Body Slam']],
|
||||
signatureMove: 'Revival Blessing',
|
||||
evs: { hp: 252, spd: 252, spe: 4 }, nature: 'Calm', teraType: 'Fairy',
|
||||
},
|
||||
Delirirak: {
|
||||
species: 'Delirirak', ability: 'Fumigation', item: 'Heavy-Duty Boots', gender: '',
|
||||
moves: ['Recover', 'Ice Beam', ['Earth Power', 'Toxic', 'Will-O-Wisp']],
|
||||
signatureMove: 'Hex',
|
||||
evs: { hp: 4, spa: 252, spd: 252 }, nature: 'Modest', teraType: 'Stellar',
|
||||
},
|
||||
Depresloth: {
|
||||
species: 'Depresloth', ability: 'Exhaust', item: 'Leftovers', gender: '',
|
||||
moves: ['Thunderbolt', 'Shadow Ball', 'Volt Switch'],
|
||||
signatureMove: 'Signal Beam',
|
||||
evs: { hp: 252, def: 252, spa: 4 }, nature: 'Timid', teraType: 'Bug',
|
||||
},
|
||||
Faellen: {
|
||||
species: 'Faellen', ability: 'Broken Wand', item: 'Choice Specs', gender: '',
|
||||
moves: [['U-turn', 'Trick'], 'Dark Pulse', ['Flamethrower', 'Moonblast']],
|
||||
signatureMove: 'Light of Ruin',
|
||||
evs: { spa: 252, spd: 4, spe: 252 }, nature: 'Timid', teraType: 'Ghost',
|
||||
},
|
||||
Fightinfly: {
|
||||
species: 'Fightinfly', ability: 'Nocturnal', item: 'Choice Band', gender: '',
|
||||
moves: ['Close Combat', ['Knock Off', 'Stone Edge'], ['Earthquake', 'Flare Blitz']],
|
||||
signatureMove: 'U-turn',
|
||||
evs: { hp: 4, atk: 252, spe: 252 }, nature: 'Jolly', teraType: 'Fairy',
|
||||
},
|
||||
Folibower: {
|
||||
species: 'Folibower', ability: 'Treasure Craze', item: 'Salac Berry', gender: '',
|
||||
moves: ['Seed Bomb', 'Acrobatics', 'Recycle'],
|
||||
signatureMove: 'Stuff Cheeks',
|
||||
evs: { atk: 252, def: 4, spe: 252 }, nature: 'Jolly', teraType: 'Fairy',
|
||||
},
|
||||
Frenzaiai: {
|
||||
species: 'Frenzaiai', ability: 'Asymmetry', item: 'Black Sludge', gender: '',
|
||||
moves: ['Toxic', 'U-turn', 'Knock Off'],
|
||||
signatureMove: 'Encore',
|
||||
evs: { hp: 252, spd: 4, spe: 252 }, nature: 'Jolly', teraType: 'Fairy',
|
||||
},
|
||||
Fungemory: {
|
||||
species: 'Fungemory', ability: 'Sealed Off', item: 'Leftovers', gender: 'M',
|
||||
moves: ['Psychic Noise', 'Scald', ['Tidy Up', 'Teleport']],
|
||||
signatureMove: 'Shadow Ball',
|
||||
evs: { hp: 252, spa: 4, spd: 252 }, nature: 'Calm', teraType: 'Psychic',
|
||||
},
|
||||
Guarden: {
|
||||
species: 'Guarden', ability: 'Royal Guard', item: 'Leftovers', gender: '',
|
||||
moves: ['Bulk Up', 'Leaf Blade', ['Body Press', 'Bitter Blade', 'Iron Head']],
|
||||
signatureMove: 'Spiky Shield',
|
||||
evs: { hp: 252, spd: 252, spe: 4 }, nature: 'Careful', teraType: 'Steel',
|
||||
},
|
||||
Hawksectiff: {
|
||||
species: 'Hawksectiff', ability: 'Pecking Order', item: 'Heavy-Duty Boots', gender: '',
|
||||
moves: ['Dual Wingbeat', 'Knock Off', ['Roost', 'Sucker Punch']],
|
||||
signatureMove: 'Pursuit',
|
||||
evs: { hp: 4, atk: 252, spe: 252 }, nature: 'Jolly', teraType: 'Steel',
|
||||
},
|
||||
Ichthyocorn: {
|
||||
species: 'Ichthyocorn', ability: 'Capricious', item: 'Leftovers', gender: '',
|
||||
moves: [['Recover', 'Ice Beam'], 'Moonblast', ['Hydro Pump', 'Scald']],
|
||||
signatureMove: 'Flip Turn',
|
||||
evs: { spa: 252, spd: 4, spe: 252 }, nature: 'Timid', teraType: 'Rock',
|
||||
},
|
||||
Lampyre: {
|
||||
species: 'Lampyre', ability: 'Night Light', item: ['Air Balloon', 'Choice Specs'], gender: '',
|
||||
moves: ['Flash Cannon', 'Scald', ['Calm Mind', 'Overheat']],
|
||||
signatureMove: 'Fire Blast',
|
||||
evs: { hp: 252, def: 28, spd: 224 }, ivs: { atk: 0, spe: 0 }, nature: 'Relaxed',
|
||||
},
|
||||
Lazahrusk: {
|
||||
species: 'Lazahrusk', ability: 'Diseased', item: 'Heavy-Duty Boots', gender: '',
|
||||
moves: [['Leech Life', 'Shadow Ball'], 'Strength Sap', 'Revival Blessing'],
|
||||
signatureMove: 'Mortal Spin',
|
||||
evs: { hp: 252, def: 252, spd: 4 }, nature: 'Relaxed', teraType: 'Fairy',
|
||||
},
|
||||
Leviadon: {
|
||||
species: 'Leviadon', ability: 'Gangster', item: 'Leftovers', gender: '',
|
||||
moves: ['Close Combat', ['Glare', 'Flash Cannon', 'Fire Blast'], ['Dragon Tail', 'Stealth Rock']],
|
||||
signatureMove: 'Core Enforcer',
|
||||
evs: { hp: 252, spa: 252, spd: 4 }, nature: 'Modest', teraType: 'Water',
|
||||
},
|
||||
Liwyzard: {
|
||||
species: 'Liwyzard', ability: 'Magic Missile', item: 'Light Ball', gender: '',
|
||||
moves: ['Calm Mind', 'Mystical Fire', 'Moonlight'],
|
||||
signatureMove: 'Strange Steam',
|
||||
evs: { hp: 252, spa: 4, spe: 252 }, nature: 'Timid', teraType: 'Steel',
|
||||
},
|
||||
Magmouth: {
|
||||
species: 'Magmouth', ability: 'Searing Remark', item: 'Leftovers', gender: '',
|
||||
moves: ['Boomburst', 'Sandsear Storm', ['Parting Shot', 'Torch Song']],
|
||||
signatureMove: 'Burning Bulwark',
|
||||
evs: { hp: 252, def: 252, spd: 4 }, nature: 'Bold', teraType: ['Steel', 'Flying', 'Electric', 'Dark'],
|
||||
},
|
||||
Manticrash: {
|
||||
species: 'Manticrash', ability: 'Comeback', item: 'Assault Vest', gender: '',
|
||||
moves: ['Hyper Drill', ['Fake Out', 'First Impression'], ['Wild Charge', 'U-turn']],
|
||||
signatureMove: 'Headlong Rush',
|
||||
evs: { hp: 252, atk: 252, spd: 4 }, nature: 'Adamant', teraType: 'Grass',
|
||||
},
|
||||
Marlord: {
|
||||
species: 'Marlord', ability: 'Polychrome', item: 'Assault Vest', gender: '',
|
||||
moves: ['Close Combat', ['Head Smash', 'Knock Off'], 'Earthquake'],
|
||||
signatureMove: 'Iron Head',
|
||||
evs: { hp: 148, atk: 156, spd: 204 }, nature: 'Adamant', teraType: 'Steel',
|
||||
},
|
||||
Marsonmallow: {
|
||||
species: 'Marsonmallow', ability: 'big stick', item: 'Heavy-Duty Boots', gender: '',
|
||||
moves: ['Play Rough', ['Recover', 'Leaf Blade'], ['Trick Room', 'Sticky Web']],
|
||||
signatureMove: 'Flare Blitz',
|
||||
evs: { hp: 252, atk: 252, def: 4 }, nature: 'Brave', teraType: 'Poison',
|
||||
},
|
||||
Mindwyrm: {
|
||||
species: 'Mindwyrm', ability: 'Quick Thinking', item: 'Sitrus Berry', gender: '',
|
||||
moves: ['Leech Life', ['Knock Off', 'Temper Flare'], 'Dragon Hammer'],
|
||||
signatureMove: 'Clangorous Soul',
|
||||
evs: { atk: 252, def: 4, spe: 252 }, nature: 'Jolly', teraType: 'Any',
|
||||
},
|
||||
Minkai: {
|
||||
species: 'Minkai', ability: 'Nocturnal', item: ['Life Orb', 'Choice Specs'], gender: '',
|
||||
moves: ['Focus Blast', 'Earth Power', ['Calm Mind', 'Shadow Ball']],
|
||||
signatureMove: 'Ice Beam',
|
||||
evs: { spa: 252, spd: 4, spe: 252 }, nature: 'Timid', teraType: 'Any',
|
||||
},
|
||||
Mosstrosity: {
|
||||
species: 'Mosstrosity', ability: 'Clinch', item: 'Power Herb', gender: '',
|
||||
moves: ['Meteor Beam', 'Surf', 'Thunderbolt'],
|
||||
signatureMove: 'Solar Beam',
|
||||
evs: { spa: 252, spd: 4, spe: 252 }, nature: 'Timid', teraType: 'Any',
|
||||
},
|
||||
Nectaregal: {
|
||||
species: 'Nectaregal', ability: 'Electromagnetic Manipulation', item: 'Leftovers', gender: '',
|
||||
moves: ['Giga Drain', ['Volt Switch', 'Discharge', 'Mud Shot'], ['Spikes', 'Calm Mind']],
|
||||
signatureMove: 'Synthesis',
|
||||
evs: { hp: 252, def: 252, spd: 4 }, nature: 'Bold', teraType: 'Flying',
|
||||
},
|
||||
Nharboard: {
|
||||
species: 'Nharboard', ability: 'First-Class Ticket', item: 'Leftovers', gender: '',
|
||||
moves: ['Flash Cannon', 'Flip Turn', ['Hurricane', 'Defog']],
|
||||
signatureMove: 'Scald',
|
||||
evs: { hp: 252, def: 4, spa: 252 }, nature: 'Modest', teraType: 'Fairy',
|
||||
},
|
||||
Noyew: {
|
||||
species: 'Noyew', ability: 'Back at Ya!', item: 'Leftovers', gender: '',
|
||||
moves: ['Spikes', 'Toxic', 'Grass Knot'],
|
||||
signatureMove: 'Leech Seed',
|
||||
evs: { hp: 252, def: 128, spd: 128 }, nature: 'Careful', teraType: 'Fairy',
|
||||
},
|
||||
Nucleophage: {
|
||||
species: 'Nucleophage', ability: 'Diseased', item: 'Black Sludge', gender: '',
|
||||
moves: ['Psychic', 'Sludge Wave', 'Lava Plume'],
|
||||
signatureMove: 'Nasty Plot',
|
||||
evs: { spa: 252, spd: 4, spe: 252 }, nature: 'Timid', teraType: 'Psychic',
|
||||
},
|
||||
Nummanutts: {
|
||||
species: 'Nummanutts', ability: 'Dice Roller', item: 'Black Sludge', gender: '',
|
||||
moves: ['Knock Off', 'Recover', ['Mortal Spin', 'U-turn']],
|
||||
signatureMove: 'Sludge Bomb',
|
||||
evs: { hp: 252, spa: 4, spd: 252 }, nature: 'Sassy', teraType: 'Poison',
|
||||
},
|
||||
Obsallas: {
|
||||
species: 'Obsallas', ability: 'Crumble', item: 'Life Orb', gender: '',
|
||||
moves: [['Fire Fang', 'Explosion', 'Taunt'], 'Icicle Crash', 'Extreme Speed'],
|
||||
signatureMove: 'Head Smash',
|
||||
evs: { atk: 252, def: 4, spe: 252 }, nature: 'Jolly', teraType: 'Fairy',
|
||||
},
|
||||
Oonoonsi: {
|
||||
species: 'Oonoonsi', ability: 'Puppet Master', item: 'Heavy-Duty Boots', gender: '',
|
||||
moves: ['Psychic Noise', 'Bug Buzz', 'Focus Blast'],
|
||||
signatureMove: 'Tail Glow',
|
||||
evs: { spa: 252, spd: 4, spe: 252 }, nature: 'Timid', teraType: 'Poison',
|
||||
},
|
||||
Orchidauntless: {
|
||||
species: 'Orchidauntless', ability: 'Dewdrop', item: 'Choice Band', gender: '',
|
||||
moves: ['Zen Headbutt', ['Play Rough', 'Sacred Sword'], 'Flip Turn'],
|
||||
signatureMove: 'Horn Leech',
|
||||
evs: { atk: 252, def: 4, spe: 252 }, nature: 'Jolly', teraType: 'Ghost',
|
||||
},
|
||||
Pestifer: {
|
||||
species: 'Pestifer', ability: 'Contagious', item: 'Flame Orb', gender: '',
|
||||
moves: ['Nasty Plot', 'Sludge Wave', ['Thunderbolt', 'Flamethrower', 'Rapid Spin']],
|
||||
signatureMove: 'Sandsear Storm',
|
||||
evs: { spa: 252, spd: 4, spe: 252 }, nature: 'Timid', teraType: 'Ghost',
|
||||
},
|
||||
Pomegrenade: {
|
||||
species: 'Pomegrenade', ability: 'Mind Bloom', item: 'Heavy-Duty Boots', gender: '',
|
||||
moves: ['Moonblast', 'Synthesis', ['Calm Mind', 'Aromatherapy']],
|
||||
signatureMove: 'Lava Plume',
|
||||
evs: { hp: 252, spa: 4, spe: 252 }, nature: 'Timid', teraType: 'Ghost',
|
||||
},
|
||||
Raintoad: {
|
||||
species: 'Raintoad', ability: 'Color Wheel', item: 'Leftovers', gender: '',
|
||||
moves: ['Body Slam', ['U-turn', 'Zen Headbutt'], 'Toxic'],
|
||||
signatureMove: 'Protect',
|
||||
evs: { hp: 252, atk: 4, spe: 252 }, nature: 'Jolly', teraType: 'Ghost',
|
||||
},
|
||||
Remnant: {
|
||||
species: 'Remnant', ability: 'Night March', item: 'Leftovers', gender: '',
|
||||
moves: ['Circle Throw', 'Toxic', 'Protect'],
|
||||
signatureMove: 'Poltergeist',
|
||||
evs: { hp: 252, def: 128, spd: 128 }, nature: 'Impish', teraType: 'Ground',
|
||||
},
|
||||
Rizzquaza: {
|
||||
species: 'Rizzquaza', ability: 'Iron Fistening', item: 'Mystic Water', gender: '',
|
||||
moves: ['Dragon Dance', 'Ice Spinner', 'Outrage'],
|
||||
signatureMove: 'Fishious Rend',
|
||||
evs: { hp: 4, atk: 252, spe: 252 }, nature: 'Jolly', teraType: 'Ghost',
|
||||
},
|
||||
Roddammit: {
|
||||
species: 'Roddammit', ability: 'Outclass', item: 'Leftovers', gender: '',
|
||||
moves: [['Wicked Blow', 'Knock Off'], ['Gunk Shot', 'Synthesis', 'Spikes'], 'Chilly Reception'],
|
||||
signatureMove: 'Flower Trick',
|
||||
evs: { hp: 252, atk: 252, spd: 4 }, nature: 'Adamant', teraType: 'Fire',
|
||||
},
|
||||
Roolette: {
|
||||
species: 'Roolette', ability: 'Spin the Wheel', item: 'Leftovers', gender: '',
|
||||
moves: ['Close Combat', 'Knock Off', ['Rapid Spin', 'Protect', 'Triple Axel']],
|
||||
signatureMove: 'Double-Edge',
|
||||
evs: { atk: 252, def: 4, spe: 252 }, nature: 'Jolly', teraType: 'Fire',
|
||||
},
|
||||
Rootfraction: {
|
||||
species: 'Rootfraction', ability: 'Refraction', item: 'Black Sludge', gender: '',
|
||||
moves: ['Giga Drain', 'Synthesis', ['Flamethrower', 'U-turn']],
|
||||
signatureMove: 'Malignant Chain',
|
||||
evs: { hp: 252, spa: 252, spe: 4 }, nature: 'Modest', teraType: 'Dark',
|
||||
},
|
||||
Shail: {
|
||||
species: 'Shail', ability: 'Snowhazard', item: 'White Herb', gender: '',
|
||||
moves: ['Blizzard', 'Earth Power', 'Power Gem'],
|
||||
signatureMove: 'Shell Smash',
|
||||
evs: { spa: 252, spd: 4, spe: 252 }, nature: 'Timid', teraType: ['Dark', 'Poison', 'Ghost', 'Steel'],
|
||||
},
|
||||
Shufflux: {
|
||||
species: 'Shufflux', ability: 'Draw Four', item: ['Choice Specs', 'Choice Scarf'], gender: '',
|
||||
moves: ['Trick', 'Dazzling Gleam', 'Extrasensory'],
|
||||
signatureMove: 'Tri Attack',
|
||||
evs: { spa: 252, spd: 4, spe: 252 }, nature: 'Timid', teraType: 'Any',
|
||||
},
|
||||
Shurifluri: {
|
||||
species: 'Shurifluri', ability: 'Snowhazard', item: 'Never-Melt Ice', gender: '',
|
||||
moves: ['Ice Spinner', 'Ice Shard', 'Iron Head'],
|
||||
signatureMove: 'Bulk Up',
|
||||
evs: { atk: 252, def: 4, spe: 252 }, nature: 'Jolly', teraType: 'Fire',
|
||||
},
|
||||
Skibidragon: {
|
||||
species: 'Skibidragon', ability: 'Bathroom Break', item: 'Choice Specs', gender: '',
|
||||
moves: ['Hydro Pump', 'Searing Shot', ['Defog', 'Thunderbolt', 'Sludge Wave']],
|
||||
signatureMove: 'Draco Meteor',
|
||||
evs: { spa: 252, spd: 4, spe: 252 }, nature: 'Timid', teraType: 'Dark',
|
||||
},
|
||||
Spreetah: {
|
||||
species: 'Spreetah', ability: 'Momentum', item: 'Metronome', gender: '',
|
||||
moves: ['Swords Dance', 'Flare Blitz', 'Volt Tackle'],
|
||||
signatureMove: 'Bonemerang',
|
||||
evs: { atk: 252, spd: 4, spe: 252 }, nature: 'Jolly', teraType: 'Ghost',
|
||||
},
|
||||
Suragon: {
|
||||
species: 'Suragon', ability: 'Antimatter', item: 'Leftovers', gender: '',
|
||||
moves: ['Draco Meteor', ['Knock Off', 'Thunder Wave'], 'Psychic Noise'],
|
||||
signatureMove: 'Topsy-Turvy',
|
||||
evs: { hp: 252, def: 252, spa: 4 }, nature: 'Bold', teraType: 'Bug',
|
||||
},
|
||||
Surfsurge: {
|
||||
species: 'Surfsurge', ability: 'Strong Breeze', item: 'Heavy-Duty Boots', gender: '',
|
||||
moves: ['Volt Switch', ['Thunderbolt', 'Rapid Spin'], ['Ice Beam', 'Thunder Wave']],
|
||||
signatureMove: 'Surf',
|
||||
evs: { spa: 252, spd: 4, spe: 252 }, nature: 'Timid', teraType: 'Fairy',
|
||||
},
|
||||
Tardeblade: {
|
||||
species: 'Tardeblade', ability: 'Hibernation', item: 'Leftovers', gender: '',
|
||||
moves: ['Body Press', 'Rest', 'Sleep Talk'],
|
||||
signatureMove: 'Stored Power',
|
||||
evs: { hp: 252, def: 128, spd: 128 }, nature: 'Bold', teraType: 'Water',
|
||||
},
|
||||
Trawlutre: {
|
||||
species: 'Trawlutre', ability: 'Super Rod', item: 'Leftovers', gender: '',
|
||||
moves: ['Close Combat', 'Knock Off', ['U-turn', 'Bulk Up', 'Aqua Jet']],
|
||||
signatureMove: 'Liquidation',
|
||||
evs: { atk: 252, def: 4, spe: 252 }, nature: 'Jolly', teraType: 'Flying',
|
||||
},
|
||||
Tuxquito: {
|
||||
species: 'Tuxquito', ability: 'Bloodsucking', item: 'Heavy-Duty Boots', gender: '',
|
||||
moves: ['Hurricane', 'Fire Blast', 'Bug Buzz'],
|
||||
signatureMove: 'Quiver Dance',
|
||||
evs: { def: 4, spa: 252, spe: 252 }, nature: 'Modest', teraType: 'Normal',
|
||||
},
|
||||
Underhazard: {
|
||||
species: 'Underhazard', ability: 'Countermeasures', item: 'Black Sludge', gender: '',
|
||||
moves: ['Recover', 'Dark Pulse', 'Sludge Bomb'],
|
||||
signatureMove: 'Toxic Spikes',
|
||||
evs: { hp: 252, def: 4, spd: 252 }, nature: 'Careful', teraType: 'Water',
|
||||
},
|
||||
};
|
||||
|
||||
export class RandomCPMTeams extends RandomTeams {
|
||||
randomCPMTeam(options: { inBattle?: boolean } = {}) {
|
||||
this.enforceNoDirectCustomBanlistChanges();
|
||||
|
||||
const team: PokemonSet[] = [];
|
||||
const debug: string[] = []; // Set this to a list of CPM sets to override the normal pool for debugging.
|
||||
const ruleTable = this.dex.formats.getRuleTable(this.format);
|
||||
const monotype = this.forceMonotype || (ruleTable.has('sametypeclause') ?
|
||||
this.sample(this.dex.types.names().filter(x => x !== 'Stellar')) : false);
|
||||
|
||||
let pool = Object.keys(cpmSets);
|
||||
if (debug.length) {
|
||||
while (debug.length < 6) {
|
||||
const fakemon = this.sampleNoReplace(pool);
|
||||
if (debug.includes(fakemon) || cpmSets[fakemon].skip) continue;
|
||||
debug.push(fakemon);
|
||||
}
|
||||
pool = debug;
|
||||
}
|
||||
if (monotype && !debug.length) {
|
||||
pool = pool.filter(x => this.dex.species.get(cpmSets[x].species).types.includes(monotype));
|
||||
}
|
||||
if (global.Config?.disabledssbsets?.length) {
|
||||
pool = pool.filter(x => !global.Config.disabledssbsets.includes(this.dex.toID(x)));
|
||||
}
|
||||
const typePool: { [k: string]: number } = {};
|
||||
let depth = 0;
|
||||
while (pool.length && team.length < this.maxTeamSize) {
|
||||
if (depth >= 200) throw new Error(`Infinite loop in CPM team generation.`);
|
||||
depth++;
|
||||
const name = this.sampleNoReplace(pool);
|
||||
const cpmSet: CPMSet = this.dex.deepClone(cpmSets[name]);
|
||||
if (cpmSet.skip) continue;
|
||||
|
||||
// Enforce typing limits
|
||||
if (!(debug.length || monotype)) { // Type limits are ignored for debugging and monotype
|
||||
const species = this.dex.species.get(cpmSet.species);
|
||||
|
||||
const weaknesses = [];
|
||||
for (const type of this.dex.types.names()) {
|
||||
const typeMod = this.dex.getEffectiveness(type, species.types);
|
||||
if (typeMod > 0) weaknesses.push(type);
|
||||
}
|
||||
let rejected = false;
|
||||
for (const type of weaknesses) {
|
||||
if (typePool[type] === undefined) typePool[type] = 0;
|
||||
if (typePool[type] >= 3) {
|
||||
// Reject
|
||||
rejected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cpmSet.ability === 'Wonder Guard') {
|
||||
if (!typePool['wonderguard']) {
|
||||
typePool['wonderguard'] = 1;
|
||||
} else {
|
||||
rejected = true;
|
||||
}
|
||||
}
|
||||
if (rejected) continue;
|
||||
// Update type counts
|
||||
for (const type of weaknesses) {
|
||||
typePool[type]++;
|
||||
}
|
||||
}
|
||||
|
||||
let teraType: string | undefined;
|
||||
if (cpmSet.teraType) {
|
||||
teraType = cpmSet.teraType === 'Any' ?
|
||||
this.sample(this.dex.types.names()) :
|
||||
this.sampleIfArray(cpmSet.teraType);
|
||||
}
|
||||
const moves: string[] = [];
|
||||
while (moves.length < 3 && cpmSet.moves.length > 0) {
|
||||
let move = this.sampleNoReplace(cpmSet.moves);
|
||||
if (Array.isArray(move)) move = this.sampleNoReplace(move);
|
||||
moves.push(this.dex.moves.get(move).name);
|
||||
}
|
||||
moves.push(this.dex.moves.get(cpmSet.signatureMove).name);
|
||||
const ivs = { hp: 31, atk: 31, def: 31, spa: 31, spd: 31, spe: 31, ...cpmSet.ivs };
|
||||
|
||||
if (!moves.map(x => this.dex.moves.get(x)).some(x => x.category === 'Physical')) {
|
||||
ivs.atk = 0;
|
||||
}
|
||||
|
||||
const set: PokemonSet = {
|
||||
name,
|
||||
species: cpmSet.species,
|
||||
item: this.sampleIfArray(cpmSet.item),
|
||||
ability: this.sampleIfArray(cpmSet.ability),
|
||||
moves,
|
||||
nature: cpmSet.nature ? Array.isArray(cpmSet.nature) ? this.sampleNoReplace(cpmSet.nature) : cpmSet.nature : 'Serious',
|
||||
gender: cpmSet.gender ? this.sampleIfArray(cpmSet.gender) : this.sample(['M', 'F', 'N']),
|
||||
evs: cpmSet.evs ? { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0, ...cpmSet.evs } :
|
||||
|
||||
{ hp: 84, atk: 84, def: 84, spa: 84, spd: 84, spe: 84 },
|
||||
ivs,
|
||||
level: this.adjustLevel || cpmSet.level || 100,
|
||||
happiness: typeof cpmSet.happiness === 'number' ? cpmSet.happiness : 255,
|
||||
shiny: typeof cpmSet.shiny === 'number' ? this.randomChance(1, cpmSet.shiny) : !!cpmSet.shiny,
|
||||
};
|
||||
|
||||
if (teraType) set.teraType = teraType;
|
||||
|
||||
team.push(set);
|
||||
|
||||
if (team.length === this.maxTeamSize && (set.ability === 'Illusion')) {
|
||||
team[this.maxTeamSize - 1] = team[this.maxTeamSize - 2];
|
||||
team[this.maxTeamSize - 2] = set;
|
||||
}
|
||||
}
|
||||
return team;
|
||||
}
|
||||
}
|
||||
|
||||
export default RandomCPMTeams;
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
import type Dex from "../../../sim/dex";
|
||||
|
||||
export const Scripts: ModdedBattleScriptsData = {
|
||||
gen: 9,
|
||||
actions: {
|
||||
secondaries(targets: SpreadMoveTargets, source: Pokemon, move: ActiveMove, moveData: ActiveMove, isSelf?: boolean) {
|
||||
if (!moveData.secondaries) return;
|
||||
for (const foe of targets) {
|
||||
if (foe === false) continue;
|
||||
const secondaries: Dex.SecondaryEffect[] =
|
||||
this.battle.runEvent('ModifySecondaries', foe, source, moveData, moveData.secondaries.slice());
|
||||
for (const secondary of secondaries) {
|
||||
const secondaryRoll = this.battle.random(100);
|
||||
// User stat boosts or foe stat drops can possibly overflow if it goes beyond 256 in Gen 8 or prior
|
||||
const secondaryOverflow = (secondary.boosts || secondary.self) && this.battle.gen <= 8;
|
||||
if (typeof secondary.chance === 'undefined' ||
|
||||
secondaryRoll < (secondaryOverflow ? secondary.chance % 256 : secondary.chance)) {
|
||||
let flag = true;
|
||||
if (moveData.secondary?.status && foe) flag = foe.setStatus(moveData.secondary.status, source);
|
||||
if (moveData.secondary?.volatileStatus && foe) flag = !(moveData.secondary.volatileStatus in foe.volatiles);
|
||||
if (moveData.secondary?.volatileStatus === 'flinch' && foe) flag = flag && foe.activeTurns >= 1 && !foe.moveThisTurn;
|
||||
this.moveHit(foe, source, move, secondary, true, isSelf);
|
||||
if (moveData.secondary?.self?.boosts) {
|
||||
Object.entries(moveData.secondary.self.boosts).forEach(([stat, boost]) => {
|
||||
if (source.boosts[stat as BoostID] === 6) flag = false;
|
||||
});
|
||||
} else {
|
||||
if (foe) flag = flag && !(foe.hp === undefined || foe.hp <= 0);
|
||||
}
|
||||
if (moveData.target !== 'self' && moveData.secondary?.boosts && foe) {
|
||||
const cantLower = {
|
||||
'atk': ['clearbody', 'fullmetalbody', 'hypercutter', 'whitesmoke'],
|
||||
'def': ['bigpecks', 'clearbody', 'fullmetalbody', 'whitesmoke'],
|
||||
'spa': ['clearbody', 'fullmetalbody', 'whitesmoke'],
|
||||
'spd': ['clearbody', 'fullmetalbody', 'whitesmoke'],
|
||||
'spe': ['clearbody', 'fullmetalbody', 'whitesmoke'],
|
||||
'accuracy': ['clearbody', 'fullmetalbody', 'keeneye', 'whitesmoke'],
|
||||
'evasion': [] };
|
||||
for (const k in moveData.secondary.boosts) {
|
||||
if (foe.boosts[k as BoostID] === -6) {
|
||||
flag = false;
|
||||
continue;
|
||||
}
|
||||
if (foe.hasAbility(cantLower[k as BoostID]) && !move.ignoreAbility) {
|
||||
flag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (source.hasAbility('sheerforce')) flag = false;
|
||||
if (foe && foe.hasAbility('shielddust') && !move.ignoreAbility &&
|
||||
move.secondary && !move.secondary.self?.boosts) {
|
||||
flag = false;
|
||||
}
|
||||
if (flag && foe && foe.hasAbility('countermeasures') && secondary.chance) {
|
||||
this.battle.add('-activate', foe, 'ability: Countermeasures');
|
||||
this.battle.damage(source.baseMaxhp * (100 - secondary.chance) / 100, source, foe);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
956
data/mods/chatbats/abilities.ts
Normal file
956
data/mods/chatbats/abilities.ts
Normal file
|
|
@ -0,0 +1,956 @@
|
|||
export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTable = {
|
||||
thickfat: {
|
||||
// prevents burning
|
||||
inherit: true,
|
||||
onUpdate(pokemon) {
|
||||
if (pokemon.status === 'brn') {
|
||||
this.add('-activate', pokemon, 'ability: Thick Fat');
|
||||
pokemon.cureStatus();
|
||||
}
|
||||
},
|
||||
onSetStatus(status, target, source, effect) {
|
||||
if (status.id !== 'brn') return;
|
||||
if ((effect as Move)?.status) {
|
||||
this.add('-immune', target, '[from] ability: Thick Fat');
|
||||
}
|
||||
return false;
|
||||
},
|
||||
shortDesc: "-50% damage from Fire and Ice. Burn immune.",
|
||||
},
|
||||
callillumise: {
|
||||
onDamagePriority: -30,
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (damage >= target.hp) {
|
||||
this.add('-ability', target, 'Call Illumise');
|
||||
this.effectState.callillumise = true;
|
||||
return target.hp - 1;
|
||||
}
|
||||
},
|
||||
onUpdate(pokemon) {
|
||||
if (!this.effectState.callillumise) return;
|
||||
|
||||
this.add('-message', `Volbeat calls upon Illumise for aid!`);
|
||||
// Define new moves
|
||||
const newMoves = ['bugbuzz', 'icebeam', 'thunderbolt', 'quiverdance'];
|
||||
// Update move slots
|
||||
pokemon.moveSlots = newMoves.map(move => {
|
||||
const moveData = this.dex.moves.get(move);
|
||||
return {
|
||||
move: moveData.name,
|
||||
id: moveData.id,
|
||||
pp: moveData.pp,
|
||||
maxpp: moveData.pp,
|
||||
target: moveData.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
});
|
||||
// this forces the UI to update move slots visually
|
||||
(pokemon as any).baseMoveSlots = pokemon.moveSlots.slice();
|
||||
// removes status/boosts
|
||||
pokemon.cureStatus();
|
||||
pokemon.clearBoosts();
|
||||
// forces the UI to update part II
|
||||
this.add('-clearboost', pokemon, '[from] ability: Call Illumise', '[silent]');
|
||||
for (const volatile in pokemon.volatiles) {
|
||||
this.add('-end', pokemon, volatile);
|
||||
}
|
||||
pokemon.clearVolatile(true);
|
||||
// form change + heal
|
||||
pokemon.formeChange('Illumise', null, true);
|
||||
this.heal(pokemon.maxhp);
|
||||
// sets new ability
|
||||
pokemon.setAbility('Tinted Lens', null, null, true);
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
this.add('-ability', pokemon, 'Tinted Lens');
|
||||
},
|
||||
flags: {
|
||||
breakable: 1, failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, notransform: 1,
|
||||
},
|
||||
name: "Call Illumise",
|
||||
rating: 5,
|
||||
num: -100,
|
||||
shortDesc: "When Volbeat gets low on HP, it calls Illumise for aid.",
|
||||
},
|
||||
callvolbeat: {
|
||||
onDamagePriority: -30,
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (damage >= target.hp) {
|
||||
this.add('-ability', target, 'Call Volbeat');
|
||||
this.effectState.callvolbeat = true;
|
||||
return target.hp - 1;
|
||||
}
|
||||
},
|
||||
onUpdate(pokemon) {
|
||||
if (!this.effectState.callvolbeat) return;
|
||||
|
||||
this.add('-message', `Illumise calls upon Volbeat for aid!`);
|
||||
// Define new moves
|
||||
const newMoves = ['victorydance', 'lunge', 'mightycleave', 'earthquake'];
|
||||
// Update move slots
|
||||
pokemon.moveSlots = newMoves.map(move => {
|
||||
const moveData = this.dex.moves.get(move);
|
||||
return {
|
||||
move: moveData.name,
|
||||
id: moveData.id,
|
||||
pp: moveData.pp,
|
||||
maxpp: moveData.pp,
|
||||
target: moveData.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
});
|
||||
// this forces the UI to update move slots visually
|
||||
(pokemon as any).baseMoveSlots = pokemon.moveSlots.slice();
|
||||
// removes status/boosts
|
||||
pokemon.cureStatus();
|
||||
pokemon.clearBoosts();
|
||||
// forces the UI to update part II
|
||||
this.add('-clearboost', pokemon, '[from] ability: Call Volbeat', '[silent]');
|
||||
for (const volatile in pokemon.volatiles) {
|
||||
this.add('-end', pokemon, volatile);
|
||||
}
|
||||
pokemon.clearVolatile(true);
|
||||
// form change + heal
|
||||
pokemon.formeChange('Volbeat', null, true);
|
||||
this.heal(pokemon.maxhp);
|
||||
// sets new ability
|
||||
pokemon.setAbility('Dancer', null, null, true);
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
this.add('-ability', pokemon, 'Dancer');
|
||||
},
|
||||
flags: {
|
||||
breakable: 1, failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, notransform: 1,
|
||||
},
|
||||
name: "Call Volbeat",
|
||||
rating: 5,
|
||||
num: -101,
|
||||
shortDesc: "When Illumise gets low on HP, it calls Volbeat for aid.",
|
||||
},
|
||||
shortfuse: {
|
||||
onDamagePriority: -30,
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (damage >= target.hp) {
|
||||
this.add('-ability', target, 'Short Fuse');
|
||||
this.effectState.shortfuse = true;
|
||||
return target.hp - 1;
|
||||
}
|
||||
},
|
||||
onUpdate(pokemon) {
|
||||
if (this.effectState.shortfuse) {
|
||||
delete this.effectState.shortfuse;
|
||||
this.actions.useMove('explosion', pokemon);
|
||||
}
|
||||
this.checkFainted();
|
||||
},
|
||||
flags: {
|
||||
breakable: 1, failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1,
|
||||
},
|
||||
name: "Short Fuse",
|
||||
rating: 5,
|
||||
num: -102,
|
||||
shortDesc: "If KO'd, use Explosion instead.",
|
||||
},
|
||||
hydroelectricdam: {
|
||||
// Copied from the code for Sand Spit
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
this.field.setWeather('raindance');
|
||||
},
|
||||
flags: {},
|
||||
name: "Hydroelectric Dam",
|
||||
rating: 5,
|
||||
num: -103,
|
||||
shortDesc: "Starts Rain Dance when hit by an attack.",
|
||||
},
|
||||
frozenarmor: {
|
||||
onTryHit(target, source, move) {
|
||||
if (move.category !== 'Status') {
|
||||
this.add('-ability', target, 'Frozen Armor');
|
||||
// reduces base power of incoming moves by 20 (math.max prevents base power from reducing below 0)
|
||||
move.basePower = Math.max(move.basePower - 20, 0);
|
||||
}
|
||||
},
|
||||
onSwitchInPriority: -1,
|
||||
onUpdate(pokemon) {
|
||||
// checks if Glastrier is below 50% HP, if so transforms into Caly-Ice and sets ability to As One
|
||||
if (pokemon.species.id !== 'glastrier' || !pokemon.hp) return;
|
||||
if (pokemon.hp < pokemon.maxhp / 2) {
|
||||
if (pokemon.species.id !== 'calyrexice' && pokemon.ability === 'frozenarmor') {
|
||||
pokemon.formeChange('Calyrex-Ice', null, true);
|
||||
this.add('-message', `Glastrier's Frozen Armor has shattered!`);
|
||||
// pokemon.setAbility('As One (Glastrier)');
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
// this.add('-ability', pokemon, 'As One');
|
||||
}
|
||||
}
|
||||
},
|
||||
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1 },
|
||||
name: "Frozen Armor",
|
||||
rating: 5,
|
||||
num: -105,
|
||||
shortDesc: "-20 BP on attacks targeting Glastrier, at 50% HP become Calyrex-Ice.",
|
||||
},
|
||||
flipflop: {
|
||||
onDamagingHitOrder: 1,
|
||||
onTryHit(target, source, move) {
|
||||
if (move.flags['contact']) {
|
||||
let flipFlopBoosts = false;
|
||||
const invertedBoosts: SparseBoostsTable = {};
|
||||
for (const stat in source.boosts) {
|
||||
if (source.boosts[stat as BoostID] > 0) {
|
||||
// checks for boosts on source of move, inverts boosts and adds them to invertedBoosts table
|
||||
invertedBoosts[stat as BoostID] = -2 * source.boosts[stat as BoostID];
|
||||
if (!flipFlopBoosts) {
|
||||
this.add('-ability', target, 'Flip Flop');
|
||||
flipFlopBoosts = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// applies boosts
|
||||
this.boost(invertedBoosts, source, target);
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Flip Flop",
|
||||
rating: 5,
|
||||
num: -104,
|
||||
shortDesc: "When hit by contact move, invert attacker’s stat boosts.",
|
||||
},
|
||||
|
||||
grasspelt: {
|
||||
inherit: true,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
this.field.setTerrain('grassyterrain');
|
||||
},
|
||||
shortDesc: "Starts Grassy Terrain on hit. 1.5x Def in Grassy Terrain.",
|
||||
},
|
||||
aquaveil: {
|
||||
onSwitchInPriority: -1,
|
||||
// fakes the effect of aqua ring volatile lel
|
||||
onStart(pokemon) {
|
||||
this.add('-start', pokemon, 'Aqua Ring');
|
||||
},
|
||||
// provides effects of Water Bubble because Aqua Ring is modified to provide Water Bubble.
|
||||
onResidualOrder: 6,
|
||||
onResidual(pokemon) {
|
||||
this.heal(pokemon.baseMaxhp / 16);
|
||||
},
|
||||
onSourceModifyAtkPriority: 5,
|
||||
onSourceModifyAtk(atk, attacker, defender, move) {
|
||||
if (move.type === 'Fire') {
|
||||
return this.chainModify(0.5);
|
||||
}
|
||||
},
|
||||
onSourceModifySpAPriority: 5,
|
||||
onSourceModifySpA(atk, attacker, defender, move) {
|
||||
if (move.type === 'Fire') {
|
||||
return this.chainModify(0.5);
|
||||
}
|
||||
},
|
||||
onModifyAtk(atk, attacker, defender, move) {
|
||||
if (move.type === 'Water') {
|
||||
return this.chainModify(2);
|
||||
}
|
||||
},
|
||||
onModifySpA(atk, attacker, defender, move) {
|
||||
if (move.type === 'Water') {
|
||||
return this.chainModify(2);
|
||||
}
|
||||
},
|
||||
// this ability is supposed to just add Aqua Ring (the volatile) to the Pokemon on switch in
|
||||
flags: { cantsuppress: 1 },
|
||||
name: "Aqua Veil",
|
||||
rating: 5,
|
||||
num: -106,
|
||||
shortDesc: "Starts Aqua Ring on switch in.",
|
||||
},
|
||||
// unaware + water absorb
|
||||
stillwater: {
|
||||
onAnyModifyBoost(boosts, pokemon) {
|
||||
const unawareUser = this.effectState.target;
|
||||
if (unawareUser === pokemon) return;
|
||||
if (unawareUser === this.activePokemon && pokemon === this.activeTarget) {
|
||||
boosts['def'] = 0;
|
||||
boosts['spd'] = 0;
|
||||
boosts['evasion'] = 0;
|
||||
}
|
||||
if (pokemon === this.activePokemon && unawareUser === this.activeTarget) {
|
||||
boosts['atk'] = 0;
|
||||
boosts['def'] = 0;
|
||||
boosts['spa'] = 0;
|
||||
boosts['accuracy'] = 0;
|
||||
}
|
||||
},
|
||||
onTryHit(target, source, move) {
|
||||
if (target !== source && move.type === 'Water') {
|
||||
if (!this.heal(target.baseMaxhp / 4)) {
|
||||
this.add('-immune', target, '[from] ability: Still Water');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
},
|
||||
flags: { breakable: 1 },
|
||||
name: "Still Water",
|
||||
rating: 5,
|
||||
num: -107,
|
||||
shortDesc: "Unaware + Water Absorb",
|
||||
},
|
||||
kingofthehill: {
|
||||
// sharpness + mountaineer + prevents hazard immunity
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (effect && effect.id === 'stealthrock') {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onTryHit(target, source, move) {
|
||||
if (move.type === 'Rock' && !target.activeTurns) {
|
||||
this.add('-immune', target, '[from] ability: King of the Hill');
|
||||
return null;
|
||||
}
|
||||
},
|
||||
// sharpness
|
||||
onBasePowerPriority: 19,
|
||||
onBasePower(basePower, attacker, defender, move) {
|
||||
if (move.flags['slicing']) {
|
||||
this.debug('Sharpness boost');
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
},
|
||||
// starts side condition for foes, side condition interacts with hazard effects
|
||||
onStart(pokemon) {
|
||||
this.add('-ability', pokemon, 'King of the Hill');
|
||||
for (const side of pokemon.side.foeSidesWithConditions()) {
|
||||
side.addSideCondition('kingofthehill');
|
||||
}
|
||||
},
|
||||
onEnd(pokemon) {
|
||||
for (const side of pokemon.side.foeSidesWithConditions()) {
|
||||
if (side.getSideCondition('kingofthehill')) {
|
||||
side.removeSideCondition('kingofthehill');
|
||||
}
|
||||
}
|
||||
},
|
||||
condition: {},
|
||||
flags: { breakable: 1 },
|
||||
name: "King of the Hill",
|
||||
rating: 5,
|
||||
num: -108,
|
||||
shortDesc: "Mountaineer + Sharpness. Opponent cannot ignore hazard damage.",
|
||||
},
|
||||
// stockpile on hit
|
||||
omnivore: {
|
||||
onDamagingHitOrder: 1,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (!target.hp) return;
|
||||
this.add('-activate', target, 'ability: Omnivore');
|
||||
target.addVolatile('stockpile');
|
||||
},
|
||||
flags: {},
|
||||
name: "Omnivore",
|
||||
rating: 5,
|
||||
num: -109,
|
||||
shortDesc: "Gain Stockpile charge when hit by attack.",
|
||||
},
|
||||
// disguise clone
|
||||
pseudowoodo: {
|
||||
onDamagePriority: 1,
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (effect?.effectType === 'Move' && ['sudowoodo'].includes(target.species.id)) {
|
||||
this.add('-activate', target, 'ability: Pseudowoodo');
|
||||
this.effectState.rock = true;
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
onCriticalHit(target, source, move) {
|
||||
if (!target) return;
|
||||
if (!['sudowoodo'].includes(target.species.id)) {
|
||||
return;
|
||||
}
|
||||
const hitSub = target.volatiles['substitute'] && !move.flags['bypasssub'] && !(move.infiltrates && this.gen >= 6);
|
||||
if (hitSub) return;
|
||||
|
||||
if (!target.runImmunity(move.type)) return;
|
||||
return false;
|
||||
},
|
||||
onEffectiveness(typeMod, target, type, move) {
|
||||
if (!target || move.category === 'Status') return;
|
||||
if (!['sudowoodo'].includes(target.species.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const hitSub = target.volatiles['substitute'] && !move.flags['bypasssub'] && !(move.infiltrates && this.gen >= 6);
|
||||
if (hitSub) return;
|
||||
|
||||
if (!target.runImmunity(move.type)) return;
|
||||
return 0;
|
||||
},
|
||||
onUpdate(pokemon) {
|
||||
if (['sudowoodo'].includes(pokemon.species.id) && this.effectState.rock) {
|
||||
const speciesid = 'Sudowoodo-Rock';
|
||||
pokemon.formeChange(speciesid, this.effect, true);
|
||||
this.damage(pokemon.baseMaxhp / 8, pokemon, pokemon, this.dex.species.get(speciesid));
|
||||
}
|
||||
},
|
||||
flags: {
|
||||
failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1,
|
||||
breakable: 1, notransform: 1,
|
||||
},
|
||||
name: "Pseudowoodo",
|
||||
rating: 5,
|
||||
num: -110,
|
||||
shortDesc: "Disguise. Becomes Rock type when it breaks.",
|
||||
},
|
||||
magicguard: {
|
||||
onDamage(damage, target, source, effect) {
|
||||
// prevents magic guard from blocking hazard damage while King of the Hill is active
|
||||
if (target.side.getSideCondition('kingofthehill')) {
|
||||
const hazards = ['stealthrock', 'spikes', 'toxicspikes', 'stickyweb'];
|
||||
if (effect && hazards.includes(effect.id)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (effect.effectType !== 'Move') {
|
||||
if (effect.effectType === 'Ability') this.add('-activate', source, 'ability: ' + effect.name);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Magic Guard",
|
||||
rating: 4,
|
||||
num: 98,
|
||||
},
|
||||
disguise: {
|
||||
onDamagePriority: 1,
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (effect?.effectType === 'Move' && ['mimikyu', 'mimikyutotem'].includes(target.species.id)) {
|
||||
this.add('-activate', target, 'ability: Disguise');
|
||||
this.effectState.busted = true;
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
onCriticalHit(target, source, move) {
|
||||
if (!target) return;
|
||||
if (!['mimikyu', 'mimikyutotem'].includes(target.species.id)) {
|
||||
return;
|
||||
}
|
||||
const hitSub = target.volatiles['substitute'] && !move.flags['bypasssub'] && !(move.infiltrates && this.gen >= 6);
|
||||
if (hitSub) return;
|
||||
|
||||
if (!target.runImmunity(move.type)) return;
|
||||
return false;
|
||||
},
|
||||
onEffectiveness(typeMod, target, type, move) {
|
||||
if (!target || move.category === 'Status') return;
|
||||
if (!['mimikyu', 'mimikyutotem'].includes(target.species.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const hitSub = target.volatiles['substitute'] && !move.flags['bypasssub'] && !(move.infiltrates && this.gen >= 6);
|
||||
if (hitSub) return;
|
||||
|
||||
if (!target.runImmunity(move.type)) return;
|
||||
return 0;
|
||||
},
|
||||
onUpdate(pokemon) {
|
||||
if (['mimikyu', 'mimikyutotem'].includes(pokemon.species.id) && this.effectState.busted) {
|
||||
const speciesid = pokemon.species.id === 'mimikyutotem' ? 'Mimikyu-Busted-Totem' : 'Mimikyu-Busted';
|
||||
pokemon.formeChange(speciesid, this.effect, true);
|
||||
this.damage(pokemon.baseMaxhp / 8, pokemon, pokemon, this.dex.species.get(speciesid));
|
||||
}
|
||||
// sets ability to perish body
|
||||
if (pokemon.species.id === 'mimikyubusted' && pokemon.ability === 'disguise') {
|
||||
pokemon.setAbility("Perish Body");
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
}
|
||||
},
|
||||
// cantsuppress flag removed to allow for ability change
|
||||
flags: {
|
||||
failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1,
|
||||
breakable: 1, notransform: 1,
|
||||
},
|
||||
name: "Disguise",
|
||||
rating: 3.5,
|
||||
num: 209,
|
||||
},
|
||||
gulpmissile: {
|
||||
inherit: true,
|
||||
onTryHit(target, source, move) {
|
||||
// Storm Drain effect while cramorant-gulping
|
||||
if (target !== source && move.type === 'Water' && target.species.id === 'cramorantgulping') {
|
||||
if (!this.boost({ spa: 1 })) {
|
||||
this.add('-immune', target, '[from] ability: Gulp Missile');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// Lightning Rod effect while cramorant-gorging
|
||||
if (target !== source && move.type === 'Electric' && target.species.id === 'cramorantgorging') {
|
||||
if (!this.boost({ spa: 1 })) {
|
||||
this.add('-immune', target, '[from] ability: Gulp Missile');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return;
|
||||
},
|
||||
},
|
||||
asoneglastrier: {
|
||||
inherit: true,
|
||||
// removing these flags allows Frozen Armor to correctly set Caly-Ice ability as As One
|
||||
flags: {},
|
||||
},
|
||||
protean: {
|
||||
inherit: true,
|
||||
onPrepareHit(source, target, move) {
|
||||
if (move.hasBounced || move.flags['futuremove'] || move.sourceEffect === 'snatch' || move.callsMove) return;
|
||||
const type = move.type;
|
||||
if (type && type !== '???' && source.getTypes().join() !== type) {
|
||||
if (!source.setType(type)) return;
|
||||
this.add('-start', source, 'typechange', type, '[from] ability: Protean');
|
||||
}
|
||||
},
|
||||
rating: 4.5,
|
||||
shortDesc: "Gen 8 Protean.",
|
||||
},
|
||||
berserk: {
|
||||
onUpdate(pokemon) {
|
||||
if (pokemon.species.id !== 'infernape' || !pokemon.hp || pokemon.m.triggeredBerserk) return;
|
||||
if (pokemon.hp < pokemon.maxhp / 2) {
|
||||
this.boost({ spa: 1 }, pokemon, pokemon);
|
||||
pokemon.m.triggeredBerserk = true;
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Berserk",
|
||||
rating: 2,
|
||||
num: 201,
|
||||
},
|
||||
bloodsoakedcrescent: {
|
||||
// modifies atk
|
||||
onStart(pokemon) {
|
||||
this.add('-ability', pokemon, 'Blood-Soaked Crescent');
|
||||
},
|
||||
onModifyAtkPriority: 1,
|
||||
onModifyAtk(atk, pokemon) {
|
||||
if (pokemon.volatiles['dynamax']) return;
|
||||
this.debug('bsc Attack boost');
|
||||
return this.chainModify(1.5);
|
||||
},
|
||||
// ends move lock properly
|
||||
onAfterMove(pokemon) {
|
||||
if (pokemon.volatiles['bloodsoakedcrescent']?.duration === 1) {
|
||||
pokemon.removeVolatile('bloodsoakedcrescent');
|
||||
this.add('-end', pokemon, 'Blood-Soaked Rage');
|
||||
}
|
||||
},
|
||||
// applies move lock
|
||||
onAfterMoveSecondarySelf(pokemon, source, move) {
|
||||
if (move.id === 'dragondance') return;
|
||||
if (!pokemon.volatiles['bloodsoakedcrescent']) {
|
||||
this.add('-start', pokemon, 'Blood-Soaked Rage');
|
||||
}
|
||||
pokemon.addVolatile('bloodsoakedcrescent');
|
||||
},
|
||||
// condition is just lockedmove with some changes
|
||||
condition: {
|
||||
// Outrage, Thrash, Petal Dance...
|
||||
duration: 2,
|
||||
onResidual(target) {
|
||||
if (target.status === 'slp') {
|
||||
// don't lock, and bypass confusion for calming
|
||||
delete target.volatiles['bloodsoakedcrescent'];
|
||||
}
|
||||
this.effectState.trueDuration--;
|
||||
},
|
||||
onStart(target, source, effect) {
|
||||
this.effectState.trueDuration = this.random(2, 4);
|
||||
this.effectState.move = this.activeMove;
|
||||
},
|
||||
onRestart() {
|
||||
if (this.effectState.trueDuration >= 2) {
|
||||
this.effectState.duration = 2;
|
||||
}
|
||||
},
|
||||
onEnd(target) {
|
||||
if (this.effectState.trueDuration > 1) return;
|
||||
target.addVolatile('confusion');
|
||||
},
|
||||
onLockMove(pokemon) {
|
||||
if (pokemon.volatiles['dynamax']) return;
|
||||
return this.effectState.move;
|
||||
},
|
||||
},
|
||||
flags: {},
|
||||
name: "Blood-Soaked Crescent",
|
||||
rating: 5,
|
||||
num: -111,
|
||||
shortDesc: "1.5x Attack, but attacks have the Outrage effect.",
|
||||
},
|
||||
powerspot: {
|
||||
onChargeMove(pokemon, target, move) {
|
||||
this.debug('power spot - remove charge turn for ' + move.id);
|
||||
this.attrLastMove('[still]');
|
||||
this.addMove('-anim', pokemon, move.name, target);
|
||||
return false; // skip charge turn
|
||||
},
|
||||
onAfterMoveSecondarySelf(pokemon, target, move) {
|
||||
if (pokemon.getVolatile('mustrecharge')) {
|
||||
pokemon.removeVolatile('mustrecharge');
|
||||
this.add('-end', pokemon, 'mustrecharge');
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Power Spot",
|
||||
rating: 5,
|
||||
num: 249,
|
||||
shortDesc: "Moves ignore charge/recharge turns.",
|
||||
},
|
||||
biogenesis: {
|
||||
onSwitchInPriority: -1,
|
||||
onBeforeSwitchIn(pokemon) {
|
||||
if (pokemon.m.didRandomMoves) return;
|
||||
const moves = this.dex.moves.all();
|
||||
const newMoves = [];
|
||||
while (newMoves.length < 8) {
|
||||
const newMove = this.sample(moves);
|
||||
if (newMove.basePower === 1) continue;
|
||||
if (newMove.isMax === true) continue;
|
||||
if (newMove.isNonstandard === "Gigantamax") continue;
|
||||
if (newMoves.map(x => x.id).includes(newMove.id)) continue;
|
||||
newMoves.push(newMove);
|
||||
}
|
||||
// Update move slots
|
||||
pokemon.moveSlots = newMoves.map(move => {
|
||||
const moveData = this.dex.moves.get(move);
|
||||
return {
|
||||
move: moveData.name,
|
||||
id: moveData.id,
|
||||
pp: moveData.pp,
|
||||
maxpp: moveData.pp,
|
||||
target: moveData.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
});
|
||||
// this forces the UI to update move slots visually
|
||||
(pokemon as any).baseMoveSlots = pokemon.moveSlots.slice();
|
||||
pokemon.m.didRandomMoves = true;
|
||||
},
|
||||
onSwitchIn(pokemon) {
|
||||
if (!pokemon) return; // Chat command
|
||||
if (!pokemon.m.hasTypeChanged) {
|
||||
this.add('-ability', pokemon, 'Biogenesis');
|
||||
this.add('-anim', pokemon, 'Growth', pokemon);
|
||||
this.add('-message', `Mew evolves into a new form with its Biogenesis!`);
|
||||
}
|
||||
const attackingMoves = pokemon.baseMoveSlots
|
||||
.map(slot => this.dex.moves.get(slot.id))
|
||||
.filter(move => move.category !== "Status");
|
||||
|
||||
// pick types of first 2 attacking moves (failsafe if there are none)
|
||||
const types = attackingMoves.length ?
|
||||
[...new Set(attackingMoves.slice(0, 2).map(move => move.type))] :
|
||||
pokemon.types;
|
||||
pokemon.setType(types);
|
||||
pokemon.baseTypes = pokemon.types;
|
||||
pokemon.m.hasTypeChanged = true;
|
||||
this.add('-start', pokemon, 'typechange', (pokemon.illusion || pokemon).getTypes(true).join('/'), '[silent]');
|
||||
},
|
||||
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1,
|
||||
breakable: 1, notransform: 1, cantsuppress: 1 },
|
||||
name: "Biogenesis",
|
||||
rating: 5,
|
||||
num: -112,
|
||||
shortDesc: "This Pokemon receives 8 completely random moves at the start of the game.",
|
||||
},
|
||||
orichalcumpulse: {
|
||||
onStart(pokemon) {
|
||||
pokemon.updateMaxHp();
|
||||
if (this.field.setWeather('sunnyday')) {
|
||||
this.add('-activate', pokemon, 'Orichalcum Pulse', '[source]');
|
||||
} else if (this.field.isWeather('sunnyday')) {
|
||||
this.add('-activate', pokemon, 'ability: Orichalcum Pulse');
|
||||
}
|
||||
},
|
||||
onModifyAtkPriority: 5,
|
||||
onModifyAtk(atk, pokemon) {
|
||||
if (['sunnyday', 'desolateland'].includes(pokemon.effectiveWeather())) {
|
||||
this.debug('Orichalcum boost');
|
||||
return this.chainModify([5461, 4096]);
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Orichalcum Pulse",
|
||||
rating: 4.5,
|
||||
num: 288,
|
||||
},
|
||||
hailmary: {
|
||||
onStart(pokemon) {
|
||||
this.add('-activate', pokemon, 'ability: Hail Mary');
|
||||
},
|
||||
onModifySpe(spe, pokemon) {
|
||||
if (this.field.isWeather(['hail', 'snowscape'])) {
|
||||
this.debug('hail mary spe boost');
|
||||
return this.chainModify(2);
|
||||
}
|
||||
},
|
||||
onModifyAtkPriority: 5,
|
||||
onModifyAtk(atk, pokemon) {
|
||||
if (this.field.isWeather(['hail', 'snowscape'])) {
|
||||
this.debug('hail mary atk boost');
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
},
|
||||
onSourceModifyAccuracyPriority: -1,
|
||||
onSourceModifyAccuracy(accuracy, target, source, move) {
|
||||
if (this.field.isWeather(['hail', 'snowscape'])) {
|
||||
if (move.category === 'Physical' && typeof accuracy === 'number') {
|
||||
return this.chainModify([3277, 4096]);
|
||||
}
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Hail Mary",
|
||||
rating: 5,
|
||||
num: -113,
|
||||
shortDesc: "In Snowscape: 2x Speed, 1.5x Attack, 0.8x accuracy.",
|
||||
},
|
||||
brainfreeze: {
|
||||
onModifyCritRatio(critRatio, source, target) {
|
||||
if (target && (target.status === 'frostbite' || this.field.isWeather('snowscape'))) return 5;
|
||||
},
|
||||
flags: {},
|
||||
name: "Brain Freeze",
|
||||
rating: 5,
|
||||
num: -114,
|
||||
shortDesc: "If Snowscape or target is Frostbitten, attacks auto Crit.",
|
||||
},
|
||||
neutralizinggas: {
|
||||
inherit: true,
|
||||
onStart(pokemon) {
|
||||
// this makes Neutralizing Gas properly show as activated in the client when Typhlosion Mega evolves
|
||||
this.add('-ability', pokemon, 'Neutralizing Gas');
|
||||
},
|
||||
},
|
||||
terawheel: {
|
||||
onStart(pokemon) {
|
||||
pokemon.canTerastallize = null;
|
||||
},
|
||||
// copied from SSB High Performance Computing
|
||||
onResidualOrder: 6,
|
||||
onResidual(source) {
|
||||
const type = this.sample(this.dex.types.names().filter(i => i !== source.getTypes()[0]));
|
||||
if (source.setType(type)) {
|
||||
this.add('-start', source, 'typechange', type, '[from] ability: Tera Wheel');
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Tera Wheel",
|
||||
rating: 5,
|
||||
num: -115,
|
||||
shortDesc: "End of turn: this Pokemon switches to a random type (including Stellar).",
|
||||
},
|
||||
download: {
|
||||
inherit: true,
|
||||
onUpdate(pokemon) {
|
||||
if (pokemon.species.name === 'Genesect-Burn' && pokemon.terastallized) {
|
||||
pokemon.setAbility('Drought', null, null, true);
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
this.add('-ability', pokemon, 'Drought');
|
||||
}
|
||||
if (pokemon.species.name === 'Genesect-Chill' && pokemon.terastallized) {
|
||||
pokemon.setAbility('Snow Warning', null, null, true);
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
this.add('-ability', pokemon, 'Snow Warning');
|
||||
}
|
||||
if (pokemon.species.name === 'Genesect-Douse' && pokemon.terastallized) {
|
||||
pokemon.setAbility('Drizzle', null, null, true);
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
this.add('-ability', pokemon, 'Drizzle');
|
||||
}
|
||||
if (pokemon.species.name === 'Genesect-Shock' && pokemon.terastallized) {
|
||||
pokemon.setAbility('Electric Surge', null, null, true);
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
this.add('-ability', pokemon, 'Electric Surge');
|
||||
}
|
||||
},
|
||||
shortDesc: "Download + Gets weather setting move when Tera.",
|
||||
},
|
||||
battlerage: {
|
||||
onDamagingHit(damage, target, source, effect) {
|
||||
this.boost({ atk: 1 });
|
||||
},
|
||||
flags: {},
|
||||
name: "Battle Rage",
|
||||
rating: 5,
|
||||
num: -116,
|
||||
shortDesc: "+1 Atk when hit by an attack.",
|
||||
},
|
||||
terrainshift: {
|
||||
onStart(source) {
|
||||
if (source.hp >= source.maxhp) {
|
||||
source.setType("Electric");
|
||||
this.field.setTerrain('electricterrain');
|
||||
this.add('-start', source, 'typechange', 'Electric', '[silent]');
|
||||
} else if (source.hp >= (2 * source.maxhp) / 3) {
|
||||
source.setType("Fairy");
|
||||
this.field.setTerrain('mistyterrain');
|
||||
this.add('-start', source, 'typechange', 'Fairy', '[silent]');
|
||||
} else if (source.hp >= source.maxhp / 3) {
|
||||
source.setType("Grass");
|
||||
this.field.setTerrain('grassyterrain');
|
||||
this.add('-start', source, 'typechange', 'Grass', '[silent]');
|
||||
} else {
|
||||
source.setType("Psychic");
|
||||
this.field.setTerrain('psychicterrain');
|
||||
this.add('-start', source, 'typechange', 'Psychic', '[silent]');
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Terrain Shift",
|
||||
rating: 5,
|
||||
num: -117,
|
||||
shortDesc: "Sets terrain depending on HP value.",
|
||||
},
|
||||
dragonsjaw: {
|
||||
onBasePower(basePower, attacker, defender, move) {
|
||||
if (defender.hasType('Dragon') && defender.hasType('Steel')) {
|
||||
return this.chainModify(1.5);
|
||||
} else if (defender.hasType('Dragon')) {
|
||||
return this.chainModify(2.25);
|
||||
} else if (defender.hasType('Steel')) {
|
||||
return;
|
||||
} else return this.chainModify(1.5);
|
||||
},
|
||||
onTryHit(target, source, move) {
|
||||
if (target.hasType('Fairy')) {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
onModifyMovePriority: -2,
|
||||
onModifyMove(move) {
|
||||
if (move.secondaries) {
|
||||
this.debug('doubling secondary chance');
|
||||
for (const secondary of move.secondaries) {
|
||||
if (secondary.chance) secondary.chance *= 2;
|
||||
}
|
||||
}
|
||||
if (move.self?.chance) move.self.chance *= 2;
|
||||
},
|
||||
flags: {},
|
||||
name: "Dragon's Jaw",
|
||||
rating: 5,
|
||||
num: -118,
|
||||
shortDesc: "Serene Grace + Bite attacks are Dragon type.",
|
||||
},
|
||||
corrosivesoul: {
|
||||
onStart(source) {
|
||||
this.field.setTerrain('corrosivesoul');
|
||||
},
|
||||
condition: {
|
||||
effectType: 'Terrain',
|
||||
duration: 5,
|
||||
durationCallback(source, effect) {
|
||||
if (source?.hasItem('terrainextender')) {
|
||||
return 8;
|
||||
}
|
||||
return 5;
|
||||
},
|
||||
onFieldStart(field, source, effect) {
|
||||
if (effect?.effectType === 'Ability') {
|
||||
this.add('-fieldstart', 'move: Corrosive Soul', '[from] ability: ' + effect.name, `[of] ${source}`);
|
||||
} else {
|
||||
this.add('-fieldstart', 'move: Corrosive Soul');
|
||||
}
|
||||
},
|
||||
onResidualOrder: 5,
|
||||
onResidualSubOrder: 2,
|
||||
onResidual(pokemon) {
|
||||
const move = this.dex.getActiveMove('smog');
|
||||
move.accuracy = 100;
|
||||
const target = pokemon.foes()[0];
|
||||
if (target && !target.fainted) {
|
||||
this.actions.useMove(move, pokemon, { target });
|
||||
}
|
||||
},
|
||||
onFieldResidualOrder: 27,
|
||||
onFieldResidualSubOrder: 7,
|
||||
onFieldEnd() {
|
||||
this.add('-fieldend', 'move: Corrosive Soul');
|
||||
},
|
||||
},
|
||||
flags: {},
|
||||
name: "Corrosive Soul",
|
||||
rating: 5,
|
||||
num: -119,
|
||||
shortDesc: "Sets Corrosive Terrian: active Pokemon hit each other with Smog.",
|
||||
},
|
||||
oceanicblessing: {
|
||||
onSwitchInPriority: -2,
|
||||
onStart(pokemon) {
|
||||
this.singleEvent('WeatherChange', this.effect, this.effectState, pokemon);
|
||||
},
|
||||
onWeatherChange(pokemon) {
|
||||
if (!pokemon.isActive || pokemon.baseSpecies.baseSpecies !== 'Kyogre' || pokemon.transformed) return;
|
||||
if (!pokemon.hp) return;
|
||||
if (['raindance', 'primordialsea'].includes(pokemon.effectiveWeather())) {
|
||||
if (pokemon.species.id !== 'kyogreprimal') {
|
||||
pokemon.formeChange('Kyogre-Primal', this.effect, false);
|
||||
}
|
||||
} else {
|
||||
if (pokemon.species.id === 'kyogreprimal') {
|
||||
pokemon.formeChange('kyogre', this.effect, false);
|
||||
}
|
||||
}
|
||||
},
|
||||
onAllyModifyAtkPriority: 3,
|
||||
onAllyModifyAtk(atk, pokemon) {
|
||||
if (this.effectState.target.baseSpecies.baseSpecies !== 'Kyogre') return;
|
||||
if (['raindance', 'primordialsea'].includes(pokemon.effectiveWeather())) {
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
},
|
||||
onAllyModifySpDPriority: 4,
|
||||
onAllyModifySpD(spd, pokemon) {
|
||||
if (this.effectState.target.baseSpecies.baseSpecies !== 'Kyogre') return;
|
||||
if (['raindance', 'primordialsea'].includes(pokemon.effectiveWeather())) {
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
},
|
||||
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, breakable: 1 },
|
||||
name: "Oceanic Blessing",
|
||||
rating: 5,
|
||||
num: -120,
|
||||
shortDesc: "Flower Gift but Kyogre",
|
||||
},
|
||||
autospin: {
|
||||
onResidual(pokemon, s, effect) {
|
||||
const move = this.dex.getActiveMove('metronome');
|
||||
const target = pokemon.foes()[0];
|
||||
if (target && !target.fainted && (pokemon.hp >= pokemon.maxhp / 2)) {
|
||||
this.actions.useMove(move, pokemon, { target, sourceEffect: effect });
|
||||
} else if (target && !target.fainted && (pokemon.hp <= pokemon.maxhp / 10)) {
|
||||
this.actions.useMove(move, pokemon, { target, sourceEffect: effect });
|
||||
this.actions.useMove(move, pokemon, { target, sourceEffect: effect });
|
||||
this.actions.useMove(move, pokemon, { target, sourceEffect: effect });
|
||||
} else if (target && !target.fainted) {
|
||||
this.actions.useMove(move, pokemon, { target, sourceEffect: effect });
|
||||
this.actions.useMove(move, pokemon, { target, sourceEffect: effect });
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Auto Spin",
|
||||
rating: 5,
|
||||
num: -121,
|
||||
shortDesc: "Use Metronome at end of turn.",
|
||||
},
|
||||
corrosion: {
|
||||
inherit: true,
|
||||
onModifyMovePriority: -5,
|
||||
onModifyMove(move) {
|
||||
if (!move.ignoreImmunity) move.ignoreImmunity = {};
|
||||
if (move.ignoreImmunity !== true) {
|
||||
move.ignoreImmunity['Poison'] = true;
|
||||
}
|
||||
},
|
||||
shortDesc: "This Pokemon can poison a Pokemon regardless of its typing and hit them with Poison moves.",
|
||||
},
|
||||
};
|
||||
20
data/mods/chatbats/conditions.ts
Normal file
20
data/mods/chatbats/conditions.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
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;
|
||||
},
|
||||
},
|
||||
};
|
||||
140
data/mods/chatbats/items.ts
Normal file
140
data/mods/chatbats/items.ts
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
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-Mega",
|
||||
megaEvolves: "Masquerain",
|
||||
itemUser: ["Masquerain"],
|
||||
onTakeItem(item, source) {
|
||||
if (item.megaEvolves === source.baseSpecies.baseSpecies) return false;
|
||||
return true;
|
||||
},
|
||||
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-Mega",
|
||||
megaEvolves: "Typhlosion",
|
||||
itemUser: ["Typhlosion"],
|
||||
onTakeItem(item, source) {
|
||||
if (item.megaEvolves === source.baseSpecies.baseSpecies) return false;
|
||||
return true;
|
||||
},
|
||||
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(target.hp / target.maxhp), 10);
|
||||
if (this.randomChance(chance, 100) && damage >= target.hp && effect && effect.effectType === 'Move') {
|
||||
this.add("-activate", target, "item: Focus Band");
|
||||
return target.hp - 1;
|
||||
}
|
||||
},
|
||||
num: 230,
|
||||
gen: 2,
|
||||
desc: "Chance to survive attack equal to percentage of remaining HP, minimum 10%.",
|
||||
},
|
||||
};
|
||||
1720
data/mods/chatbats/moves.ts
Normal file
1720
data/mods/chatbats/moves.ts
Normal file
File diff suppressed because it is too large
Load Diff
491
data/mods/chatbats/pokedex.ts
Normal file
491
data/mods/chatbats/pokedex.ts
Normal file
|
|
@ -0,0 +1,491 @@
|
|||
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" },
|
||||
types: ["Psychic", "Normal"],
|
||||
},
|
||||
glimmora: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Corrosion" },
|
||||
},
|
||||
};
|
||||
298
data/mods/chatbats/scripts.ts
Normal file
298
data/mods/chatbats/scripts.ts
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
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'];
|
||||
},
|
||||
};
|
||||
|
|
@ -191,7 +191,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
duration: 2,
|
||||
// defender still takes PSN damage, etc
|
||||
// TODO: research exact mechanics
|
||||
onBeforeMovePriority: 0,
|
||||
onBeforeMovePriority: 9,
|
||||
onBeforeMove(pokemon) {
|
||||
this.add('cant', pokemon, 'partiallytrapped');
|
||||
return false;
|
||||
|
|
@ -199,6 +199,9 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
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';
|
||||
|
|
@ -227,34 +230,33 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
|
||||
this.effectState.move = effect.id;
|
||||
this.effectState.totalDuration = this.effectState.duration!;
|
||||
this.effectState.damage = target.lastDamage;
|
||||
this.effectState.trapTarget = foe;
|
||||
this.effectState.damage = this.lastDamage;
|
||||
this.effectState.locked = foe;
|
||||
foe.addVolatile('partiallytrapped', target, effect);
|
||||
},
|
||||
onOverrideAction(pokemon, target, move) {
|
||||
return this.effectState.move;
|
||||
},
|
||||
// attacker still takes PSN damage, etc
|
||||
onBeforeMovePriority: 0,
|
||||
onBeforeMove(pokemon, target, move) {
|
||||
const foe = pokemon.foes()[0];
|
||||
if (!foe || foe !== this.effectState.trapTarget) {
|
||||
if (target !== this.effectState.locked) {
|
||||
pokemon.removeVolatile('partialtrappinglock');
|
||||
}
|
||||
},
|
||||
onAfterMove(pokemon, target, move) {
|
||||
if (target && target.hp <= 0) {
|
||||
delete pokemon.volatiles['partialtrappinglock'];
|
||||
return;
|
||||
}
|
||||
|
||||
const moveName = this.dex.moves.get(this.effectState.move).name;
|
||||
this.add('move', pokemon, moveName, foe, `[from] ${moveName}`);
|
||||
this.damage(this.effectState.damage, foe, pokemon, move);
|
||||
if (this.effectState.duration === 1) {
|
||||
if (this.effectState.totalDuration !== 5) {
|
||||
pokemon.addVolatile('fakepartiallytrapped');
|
||||
foe.addVolatile('fakepartiallytrapped');
|
||||
pokemon.volatiles['fakepartiallytrapped'].counterpart = target;
|
||||
target.addVolatile('fakepartiallytrapped');
|
||||
target.volatiles['fakepartiallytrapped'].counterpart = pokemon;
|
||||
}
|
||||
} else {
|
||||
foe.addVolatile('partiallytrapped', pokemon, move);
|
||||
target.addVolatile('partiallytrapped', pokemon, move);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
onLockMove() {
|
||||
return this.effectState.move;
|
||||
|
|
@ -268,6 +270,13 @@ 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.
|
||||
|
|
@ -287,6 +296,11 @@ 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, ...
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
pidgeot: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
rattata: {
|
||||
tier: "LC",
|
||||
|
|
@ -90,7 +90,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
nidoqueen: {
|
||||
tier: "PU",
|
||||
tier: "ZU",
|
||||
},
|
||||
nidoranm: {
|
||||
tier: "LC",
|
||||
|
|
@ -117,7 +117,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
wigglytuff: {
|
||||
tier: "PU",
|
||||
tier: "ZU",
|
||||
},
|
||||
zubat: {
|
||||
tier: "LC",
|
||||
|
|
@ -132,7 +132,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
vileplume: {
|
||||
tier: "PU",
|
||||
tier: "ZU",
|
||||
},
|
||||
paras: {
|
||||
tier: "LC",
|
||||
|
|
@ -168,7 +168,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
primeape: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
growlithe: {
|
||||
tier: "LC",
|
||||
|
|
@ -189,7 +189,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "PU",
|
||||
},
|
||||
kadabra: {
|
||||
tier: "UU",
|
||||
tier: "NU",
|
||||
},
|
||||
alakazam: {
|
||||
tier: "OU",
|
||||
|
|
@ -201,7 +201,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
machamp: {
|
||||
tier: "PU",
|
||||
tier: "ZU",
|
||||
},
|
||||
bellsprout: {
|
||||
tier: "LC",
|
||||
|
|
@ -210,13 +210,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
victreebel: {
|
||||
tier: "OU",
|
||||
tier: "NU",
|
||||
},
|
||||
tentacool: {
|
||||
tier: "ZU",
|
||||
},
|
||||
tentacruel: {
|
||||
tier: "UU",
|
||||
tier: "NU",
|
||||
},
|
||||
geodude: {
|
||||
tier: "LC",
|
||||
|
|
@ -225,19 +225,19 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "PU",
|
||||
},
|
||||
golem: {
|
||||
tier: "UU",
|
||||
tier: "NU",
|
||||
},
|
||||
ponyta: {
|
||||
tier: "LC",
|
||||
},
|
||||
rapidash: {
|
||||
tier: "PUBL",
|
||||
tier: "UU",
|
||||
},
|
||||
slowpoke: {
|
||||
tier: "ZU",
|
||||
},
|
||||
slowbro: {
|
||||
tier: "OU",
|
||||
tier: "UU",
|
||||
},
|
||||
magnemite: {
|
||||
tier: "LC",
|
||||
|
|
@ -258,7 +258,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
dewgong: {
|
||||
tier: "UU",
|
||||
tier: "NU",
|
||||
},
|
||||
grimer: {
|
||||
tier: "LC",
|
||||
|
|
@ -294,13 +294,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
kingler: {
|
||||
tier: "PU",
|
||||
tier: "ZU",
|
||||
},
|
||||
voltorb: {
|
||||
tier: "LC",
|
||||
},
|
||||
electrode: {
|
||||
tier: "UU",
|
||||
tier: "NU",
|
||||
},
|
||||
exeggcute: {
|
||||
tier: "PU",
|
||||
|
|
@ -339,7 +339,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "OU",
|
||||
},
|
||||
tangela: {
|
||||
tier: "UU",
|
||||
tier: "NU",
|
||||
},
|
||||
kangaskhan: {
|
||||
tier: "UU",
|
||||
|
|
@ -366,7 +366,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NU",
|
||||
},
|
||||
scyther: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
jynx: {
|
||||
tier: "OU",
|
||||
|
|
@ -375,10 +375,10 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
magmar: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
pinsir: {
|
||||
tier: "PU",
|
||||
tier: "ZU",
|
||||
},
|
||||
tauros: {
|
||||
tier: "OU",
|
||||
|
|
@ -399,7 +399,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
vaporeon: {
|
||||
tier: "UU",
|
||||
tier: "NU",
|
||||
},
|
||||
jolteon: {
|
||||
tier: "OU",
|
||||
|
|
@ -414,7 +414,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "ZU",
|
||||
},
|
||||
omastar: {
|
||||
tier: "UU",
|
||||
tier: "NU",
|
||||
},
|
||||
kabuto: {
|
||||
tier: "LC",
|
||||
|
|
@ -435,7 +435,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "OU",
|
||||
},
|
||||
moltres: {
|
||||
tier: "NU",
|
||||
tier: "UU",
|
||||
},
|
||||
dratini: {
|
||||
tier: "LC",
|
||||
|
|
|
|||
|
|
@ -129,6 +129,12 @@ 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.
|
||||
|
|
@ -153,21 +159,13 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
return;
|
||||
}
|
||||
|
||||
let ppMove: ID = pokemon.volatiles['twoturnmove']?.ppMove || '';
|
||||
if (pokemon.getLockedMove()) {
|
||||
// locked moves don't deduct PP
|
||||
sourceEffect = move;
|
||||
} else {
|
||||
ppMove ||= move.id;
|
||||
}
|
||||
const lockedMove = pokemon.getLockedMove();
|
||||
if (lockedMove) sourceEffect = move;
|
||||
|
||||
this.useMove(move, pokemon, { target, sourceEffect });
|
||||
|
||||
if (pokemon.volatiles['twoturnmove']) {
|
||||
// Deduct PP on the second turn, not first
|
||||
// If called from e.g. Metronome, remember to deduct Metronome PP
|
||||
pokemon.volatiles['twoturnmove'].ppMove = move.id;
|
||||
} else if (ppMove) {
|
||||
// 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) {
|
||||
|
|
@ -175,6 +173,13 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
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.");
|
||||
}
|
||||
}
|
||||
|
||||
this.useMove(move, pokemon, { target, sourceEffect });
|
||||
|
||||
if (pokemon.volatiles['twoturnmove']) {
|
||||
pokemon.deductPP(move, -1, target);
|
||||
pokemon.volatiles['twoturnmove'].ppMove = move.id;
|
||||
}
|
||||
},
|
||||
// This function deals with AfterMoveSelf events.
|
||||
// This leads with partial trapping moves shenanigans after the move has been used.
|
||||
|
|
@ -211,37 +216,9 @@ 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;
|
||||
|
||||
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.
|
||||
this.battle.runEvent('AfterMove', pokemon, target, move);
|
||||
if (!target || target.hp > 0) {
|
||||
this.battle.runEvent('AfterMoveSelf', pokemon, target, move);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -281,7 +258,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (sourceEffect) attrs += `|[from]${this.battle.dex.conditions.get(sourceEffect)}`;
|
||||
if (sourceEffect) attrs += `|[from] ${this.battle.dex.conditions.get(sourceEffect).name}`;
|
||||
this.battle.addMove('move', pokemon, move.name, `${target}${attrs}`);
|
||||
|
||||
if (!this.battle.singleEvent('Try', move, null, pokemon, target, move)) {
|
||||
|
|
@ -371,11 +348,6 @@ 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;
|
||||
|
|
@ -508,14 +480,6 @@ 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;
|
||||
|
|
@ -590,7 +554,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 correspoding stat penalties will be applied again to that Pokémon.
|
||||
// burned, the corresponding 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') {
|
||||
|
|
@ -681,11 +645,6 @@ 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) {
|
||||
|
|
@ -757,7 +716,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.volatileStatus === 'partiallytrapped' && move.type === 'Normal' && target.hasType('Ghost')) {
|
||||
if (move.self?.volatileStatus === 'partialtrappinglock' && move.type === 'Normal' && target.hasType('Ghost')) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
golem: {
|
||||
tier: "OU",
|
||||
tier: "UU",
|
||||
},
|
||||
ponyta: {
|
||||
tier: "LC",
|
||||
|
|
@ -270,7 +270,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
cloyster: {
|
||||
tier: "OU",
|
||||
tier: "UU",
|
||||
},
|
||||
gastly: {
|
||||
tier: "LC",
|
||||
|
|
@ -279,7 +279,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
gengar: {
|
||||
tier: "OU",
|
||||
tier: "UU",
|
||||
},
|
||||
onix: {
|
||||
tier: "UU",
|
||||
|
|
@ -342,7 +342,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
kangaskhan: {
|
||||
tier: "OU",
|
||||
tier: "UU",
|
||||
},
|
||||
horsea: {
|
||||
tier: "LC",
|
||||
|
|
@ -369,7 +369,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
jynx: {
|
||||
tier: "OU",
|
||||
tier: "UU",
|
||||
},
|
||||
electabuzz: {
|
||||
tier: "UU",
|
||||
|
|
@ -402,7 +402,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
jolteon: {
|
||||
tier: "OU",
|
||||
tier: "UU",
|
||||
},
|
||||
flareon: {
|
||||
tier: "UU",
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (sourceEffect) attrs += `|[from]${this.battle.dex.conditions.get(sourceEffect)}`;
|
||||
if (sourceEffect) attrs += `|[from] ${this.battle.dex.conditions.get(sourceEffect).name}`;
|
||||
this.battle.addMove('move', pokemon, move.name, `${target}${attrs}`);
|
||||
|
||||
if (!this.battle.singleEvent('Try', move, null, pokemon, target, move)) {
|
||||
|
|
|
|||
|
|
@ -177,6 +177,11 @@ 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'];
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "PU",
|
||||
},
|
||||
diglett: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
dugtrio: {
|
||||
tier: "NU",
|
||||
|
|
@ -195,7 +195,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "ZUBL",
|
||||
},
|
||||
poliwhirl: {
|
||||
tier: "PU",
|
||||
tier: "PUBL",
|
||||
},
|
||||
poliwrath: {
|
||||
tier: "NUBL",
|
||||
|
|
@ -252,7 +252,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NU",
|
||||
},
|
||||
slowpoke: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
slowbro: {
|
||||
tier: "UU",
|
||||
|
|
@ -534,7 +534,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "ZU",
|
||||
},
|
||||
feraligatr: {
|
||||
tier: "NUBL",
|
||||
tier: "UU",
|
||||
},
|
||||
sentret: {
|
||||
tier: "LC",
|
||||
|
|
@ -699,7 +699,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "PU",
|
||||
},
|
||||
mantine: {
|
||||
tier: "ZU",
|
||||
tier: "ZUBL",
|
||||
},
|
||||
skarmory: {
|
||||
tier: "OU",
|
||||
|
|
|
|||
|
|
@ -252,11 +252,11 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
}
|
||||
},
|
||||
},
|
||||
berserkgene: {
|
||||
berry: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
},
|
||||
berry: {
|
||||
berserkgene: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -527,11 +527,6 @@ 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,
|
||||
|
|
@ -557,11 +552,6 @@ 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,
|
||||
|
|
@ -914,11 +904,6 @@ 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,
|
||||
|
|
|
|||
|
|
@ -198,9 +198,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
const target = pokemon.side.randomFoe();
|
||||
if (!target || target.fainted) return;
|
||||
const ability = target.getAbility();
|
||||
if (pokemon.setAbility(ability)) {
|
||||
this.add('-ability', pokemon, ability, '[from] ability: Trace', `[of] ${target}`);
|
||||
}
|
||||
pokemon.setAbility(ability, target);
|
||||
},
|
||||
flags: {},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
ivysaur: {
|
||||
tier: "PU",
|
||||
tier: "ZU",
|
||||
},
|
||||
venusaur: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -21,7 +21,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
wartortle: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
blastoise: {
|
||||
tier: "UU",
|
||||
|
|
@ -762,7 +762,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
grovyle: {
|
||||
tier: "PU",
|
||||
tier: "ZU",
|
||||
},
|
||||
sceptile: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -879,7 +879,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "RUBL",
|
||||
},
|
||||
shedinja: {
|
||||
tier: "ZUBL",
|
||||
tier: "PU",
|
||||
},
|
||||
whismur: {
|
||||
tier: "LC",
|
||||
|
|
@ -1056,13 +1056,10 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "ZU",
|
||||
},
|
||||
castformsunny: {
|
||||
tier: "ZU",
|
||||
},
|
||||
castformrainy: {
|
||||
tier: "ZU",
|
||||
},
|
||||
castformsnowy: {
|
||||
tier: "ZU",
|
||||
},
|
||||
kecleon: {
|
||||
tier: "NU",
|
||||
|
|
@ -1092,7 +1089,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
glalie: {
|
||||
tier: "NU",
|
||||
tier: "NUBL",
|
||||
},
|
||||
spheal: {
|
||||
tier: "LC",
|
||||
|
|
@ -1104,7 +1101,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
clamperl: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
huntail: {
|
||||
tier: "NU",
|
||||
|
|
|
|||
|
|
@ -138,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', 'tickle', 'triplekick', 'twister', 'uproar', 'visegrip', 'vinewhip', 'vitalthrow', 'volttackle', 'watergun', 'waterpulse', 'waterfall', 'weatherball', 'whirlpool', 'wingattack', 'wrap',
|
||||
];
|
||||
'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
|
||||
if (affectedByKingsRock.includes(move.id)) {
|
||||
if (!move.secondaries) move.secondaries = [];
|
||||
move.secondaries.push({
|
||||
|
|
|
|||
|
|
@ -154,6 +154,30 @@ 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: {
|
||||
|
|
|
|||
|
|
@ -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)}`;
|
||||
if (sourceEffect) attrs += `|[from] ${this.dex.conditions.get(sourceEffect).name}`;
|
||||
this.battle.addMove('move', pokemon, movename, `${target}${attrs}`);
|
||||
|
||||
if (!target) {
|
||||
|
|
|
|||
|
|
@ -1240,13 +1240,10 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "ZU",
|
||||
},
|
||||
castformsunny: {
|
||||
tier: "ZU",
|
||||
},
|
||||
castformrainy: {
|
||||
tier: "ZU",
|
||||
},
|
||||
castformsnowy: {
|
||||
tier: "ZU",
|
||||
},
|
||||
kecleon: {
|
||||
tier: "NU",
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
inherit: true,
|
||||
onStart(pokemon) {
|
||||
const target = pokemon.side.randomFoe();
|
||||
if (target?.item && !target.itemState.knockedOff) {
|
||||
if (target?.item) {
|
||||
this.add('-item', '', target.getItem().name, '[from] ability: Frisk', `[of] ${pokemon}`);
|
||||
}
|
||||
},
|
||||
|
|
@ -534,22 +534,10 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
if (bannedAbilities.includes(target.ability)) {
|
||||
return;
|
||||
}
|
||||
if (pokemon.setAbility(ability)) {
|
||||
this.add('-ability', pokemon, ability, '[from] ability: Trace', `[of] ${target}`);
|
||||
}
|
||||
pokemon.setAbility(ability, 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,
|
||||
|
|
@ -561,7 +549,7 @@ 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 === '???' || move.id === 'struggle') return;
|
||||
if (target === source || move.category === 'Status' || move.type === '???') return;
|
||||
this.debug('Wonder Guard immunity: ' + move.id);
|
||||
if (target.runEffectiveness(move) <= 0 || !target.runImmunity(move)) {
|
||||
this.add('-immune', target, '[from] ability: Wonder Guard');
|
||||
|
|
@ -569,4 +557,8 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
}
|
||||
},
|
||||
},
|
||||
rebound: {
|
||||
inherit: true,
|
||||
onTryHitSide() {},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -116,6 +116,10 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 9,
|
||||
},
|
||||
lockedmove: {
|
||||
inherit: true,
|
||||
onAfterMove() {},
|
||||
},
|
||||
choicelock: {
|
||||
inherit: true,
|
||||
onStart(pokemon) {
|
||||
|
|
|
|||
|
|
@ -1137,9 +1137,12 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
castform: {
|
||||
tier: "NU",
|
||||
},
|
||||
castformsunny: {},
|
||||
castformrainy: {},
|
||||
castformsnowy: {},
|
||||
castformsunny: {
|
||||
},
|
||||
castformrainy: {
|
||||
},
|
||||
castformsnowy: {
|
||||
},
|
||||
kecleon: {
|
||||
tier: "NU",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -225,6 +225,31 @@ 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()) {
|
||||
if (source.hasType(typeName)) continue;
|
||||
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);
|
||||
},
|
||||
},
|
||||
copycat: {
|
||||
inherit: true,
|
||||
onHit(pokemon) {
|
||||
|
|
@ -550,8 +575,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
this.debug(`BP: ${move.basePower}`);
|
||||
if (item.isBerry) {
|
||||
move.onHit = function (foe) {
|
||||
if (this.singleEvent('Eat', item, null, foe, null, null)) {
|
||||
this.runEvent('EatItem', foe, null, null, item);
|
||||
if (this.singleEvent('Eat', item, source.itemState, foe, source, move)) {
|
||||
this.runEvent('EatItem', foe, source, move, item);
|
||||
if (item.id === 'leppaberry') foe.staleness = 'external';
|
||||
}
|
||||
if (item.onEat) foe.ateBerry = true;
|
||||
|
|
@ -880,11 +905,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
knockoff: {
|
||||
inherit: true,
|
||||
onAfterHit(target, source, move) {
|
||||
if (!target.item || target.itemState.knockedOff) return;
|
||||
if (!target.item) return;
|
||||
if (target.ability === 'multitype') return;
|
||||
const item = target.getItem();
|
||||
if (this.runEvent('TakeItem', target, source, move, item)) {
|
||||
target.itemState.knockedOff = true;
|
||||
target.item = '';
|
||||
target.itemKnockedOff = true;
|
||||
this.add('-enditem', target, item.name, '[from] move: Knock Off', `[of] ${source}`);
|
||||
this.hint("In Gens 3-4, Knock Off only makes the target's item unusable; it cannot obtain a new item.", true);
|
||||
}
|
||||
|
|
@ -1231,7 +1257,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
outrage: {
|
||||
inherit: true,
|
||||
pp: 15,
|
||||
onAfterMove() {},
|
||||
},
|
||||
payback: {
|
||||
inherit: true,
|
||||
|
|
@ -1268,7 +1293,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
basePower: 90,
|
||||
pp: 20,
|
||||
onAfterMove() {},
|
||||
},
|
||||
poisongas: {
|
||||
inherit: true,
|
||||
|
|
@ -1656,10 +1680,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
target.removeVolatile('substitute');
|
||||
target.addVolatile('substitutebroken');
|
||||
if (target.volatiles['substitutebroken']) target.volatiles['substitutebroken'].move = move.id;
|
||||
if (move.ohko) this.add('-ohko');
|
||||
} else {
|
||||
this.add('-activate', target, 'Substitute', '[damage]');
|
||||
}
|
||||
if (move.ohko) this.add('-ohko');
|
||||
if (move.recoil && damage) {
|
||||
this.damage(this.actions.calcRecoilDamage(damage, move, source), source, target, 'recoil');
|
||||
}
|
||||
|
|
@ -1693,6 +1717,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
switcheroo: {
|
||||
inherit: true,
|
||||
onTryHit(target, source, move) {
|
||||
if (target.itemKnockedOff || source.itemKnockedOff) return false;
|
||||
if (target.hasAbility('multitype') || source.hasAbility('multitype')) return false;
|
||||
},
|
||||
},
|
||||
|
|
@ -1781,7 +1806,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
basePower: 90,
|
||||
pp: 20,
|
||||
onAfterMove() {},
|
||||
},
|
||||
torment: {
|
||||
inherit: true,
|
||||
|
|
@ -1810,7 +1834,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
if (pokemon.hasType('Poison')) {
|
||||
this.add('-sideend', pokemon.side, 'move: Toxic Spikes', `[of] ${pokemon}`);
|
||||
pokemon.side.removeSideCondition('toxicspikes');
|
||||
} else if (pokemon.volatiles['substitute'] || pokemon.hasType('Steel')) {
|
||||
} else if (pokemon.volatiles['substitute'] || pokemon.hasType('Steel') || pokemon.hasAbility('magicguard')) {
|
||||
// do nothing
|
||||
} else if (this.effectState.layers >= 2) {
|
||||
pokemon.trySetStatus('tox', pokemon.side.foe.active[0]);
|
||||
|
|
@ -1827,6 +1851,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
trick: {
|
||||
inherit: true,
|
||||
onTryHit(target, source, move) {
|
||||
if (target.itemKnockedOff || source.itemKnockedOff) return false;
|
||||
if (target.hasAbility('multitype') || source.hasAbility('multitype')) return false;
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -65,6 +65,9 @@ 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,
|
||||
|
|
@ -88,4 +91,20 @@ 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;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1347,7 +1347,8 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
},
|
||||
castformrainy: {
|
||||
},
|
||||
castformsnowy: {},
|
||||
castformsnowy: {
|
||||
},
|
||||
kecleon: {
|
||||
tier: "PU",
|
||||
doublesTier: "DUU",
|
||||
|
|
|
|||
|
|
@ -553,6 +553,7 @@ 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;
|
||||
},
|
||||
},
|
||||
|
|
@ -598,6 +599,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
type: "Normal",
|
||||
},
|
||||
muddywater: {
|
||||
inherit: true,
|
||||
basePower: 95,
|
||||
},
|
||||
mudsport: {
|
||||
inherit: true,
|
||||
pseudoWeather: undefined,
|
||||
|
|
@ -616,10 +621,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
},
|
||||
},
|
||||
muddywater: {
|
||||
inherit: true,
|
||||
basePower: 95,
|
||||
},
|
||||
naturepower: {
|
||||
inherit: true,
|
||||
onTryHit() {},
|
||||
|
|
@ -660,6 +661,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
basePower: 70,
|
||||
},
|
||||
psychoshift: {
|
||||
inherit: true,
|
||||
accuracy: 90,
|
||||
},
|
||||
psychup: {
|
||||
inherit: true,
|
||||
onHit(target, source) {
|
||||
|
|
@ -670,10 +675,6 @@ 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,
|
||||
|
|
|
|||
117
data/mods/gen5pokebilities/abilities.ts
Normal file
117
data/mods/gen5pokebilities/abilities.ts
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTable = {
|
||||
mummy: {
|
||||
inherit: true,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (target.ability === 'mummy') {
|
||||
const sourceAbility = source.getAbility();
|
||||
if (sourceAbility.flags['cantsuppress'] || sourceAbility.id === 'mummy') {
|
||||
return;
|
||||
}
|
||||
if (this.checkMoveMakesContact(move, source, target, !source.isAlly(target))) {
|
||||
const oldAbility = source.setAbility('mummy', target);
|
||||
if (oldAbility) {
|
||||
this.add('-activate', target, 'ability: Mummy', this.dex.abilities.get(oldAbility).name, `[of] ${source}`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const possibleAbilities = [source.ability, ...(source.m.innates || [])]
|
||||
.filter(val => !this.dex.abilities.get(val).flags['cantsuppress'] && val !== 'mummy');
|
||||
if (!possibleAbilities.length) return;
|
||||
if (this.checkMoveMakesContact(move, source, target, !source.isAlly(target))) {
|
||||
const abil = this.sample(possibleAbilities);
|
||||
if (abil === source.ability) {
|
||||
const oldAbility = source.setAbility('mummy', target);
|
||||
if (oldAbility) {
|
||||
this.add('-activate', target, 'ability: Mummy', this.dex.abilities.get(oldAbility).name, `[of] ${source}`);
|
||||
}
|
||||
} else {
|
||||
source.removeVolatile('ability:' + abil);
|
||||
source.addVolatile('ability:mummy', source);
|
||||
if (abil) {
|
||||
this.add('-activate', target, 'ability: Mummy', this.dex.abilities.get(abil).name, `[of] ${source}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
powerofalchemy: {
|
||||
inherit: true,
|
||||
onAllyFaint(ally) {
|
||||
const pokemon = this.effectState.target;
|
||||
if (!pokemon.hp) return;
|
||||
const isAbility = pokemon.ability === 'powerofalchemy';
|
||||
let possibleAbilities = [ally.ability];
|
||||
if (ally.m.innates) possibleAbilities.push(...ally.m.innates);
|
||||
const additionalBannedAbilities = [pokemon.ability, ...(pokemon.m.innates || [])];
|
||||
possibleAbilities = possibleAbilities
|
||||
.filter(val => !this.dex.abilities.get(val).flags['noreceiver'] && !additionalBannedAbilities.includes(val));
|
||||
if (!possibleAbilities.length) return;
|
||||
const ability = this.dex.abilities.get(possibleAbilities[this.random(possibleAbilities.length)]);
|
||||
this.add('-ability', pokemon, ability, '[from] ability: Power of Alchemy', `[of] ${ally}`);
|
||||
if (isAbility) {
|
||||
pokemon.setAbility(ability);
|
||||
} else {
|
||||
pokemon.removeVolatile("ability:powerofalchemy");
|
||||
pokemon.addVolatile(`ability:${ability}`, pokemon);
|
||||
}
|
||||
},
|
||||
},
|
||||
receiver: {
|
||||
inherit: true,
|
||||
onAllyFaint(ally) {
|
||||
const pokemon = this.effectState.target;
|
||||
if (!pokemon.hp) return;
|
||||
const isAbility = pokemon.ability === 'receiver';
|
||||
let possibleAbilities = [ally.ability];
|
||||
if (ally.m.innates) possibleAbilities.push(...ally.m.innates);
|
||||
const additionalBannedAbilities = [pokemon.ability, ...(pokemon.m.innates || [])];
|
||||
possibleAbilities = possibleAbilities
|
||||
.filter(val => !this.dex.abilities.get(val).flags['noreceiver'] && !additionalBannedAbilities.includes(val));
|
||||
if (!possibleAbilities.length) return;
|
||||
const ability = this.dex.abilities.get(possibleAbilities[this.random(possibleAbilities.length)]);
|
||||
this.add('-ability', pokemon, ability, '[from] ability: Receiver', `[of] ${ally}`);
|
||||
if (isAbility) {
|
||||
pokemon.setAbility(ability);
|
||||
} else {
|
||||
pokemon.removeVolatile("ability:receiver");
|
||||
pokemon.addVolatile(`ability:${ability}`, pokemon);
|
||||
}
|
||||
},
|
||||
},
|
||||
trace: {
|
||||
inherit: true,
|
||||
onUpdate(pokemon) {
|
||||
if (!this.effectState.seek) return;
|
||||
const isAbility = pokemon.ability === 'trace';
|
||||
const possibleTargets: Pokemon[] = [];
|
||||
for (const target of pokemon.side.foe.active) {
|
||||
if (target && !target.fainted) {
|
||||
possibleTargets.push(target);
|
||||
}
|
||||
}
|
||||
while (possibleTargets.length) {
|
||||
const rand = this.random(possibleTargets.length);
|
||||
const target = possibleTargets[rand];
|
||||
let possibleAbilities = [target.ability];
|
||||
if (target.m.innates) possibleAbilities.push(...target.m.innates);
|
||||
const additionalBannedAbilities = [pokemon.ability, ...(pokemon.m.innates || [])];
|
||||
possibleAbilities = possibleAbilities
|
||||
.filter(val => !this.dex.abilities.get(val).flags['notrace'] && !additionalBannedAbilities.includes(val));
|
||||
if (!possibleAbilities.length) {
|
||||
possibleTargets.splice(rand, 1);
|
||||
continue;
|
||||
}
|
||||
const ability = this.dex.abilities.get(this.sample(possibleAbilities));
|
||||
this.add('-ability', pokemon, ability, '[from] ability: Trace', `[of] ${target}`);
|
||||
if (isAbility) {
|
||||
pokemon.setAbility(ability);
|
||||
} else {
|
||||
pokemon.removeVolatile("ability:trace");
|
||||
pokemon.addVolatile(`ability:${ability}`, pokemon);
|
||||
}
|
||||
return;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
17
data/mods/gen5pokebilities/moves.ts
Normal file
17
data/mods/gen5pokebilities/moves.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
||||
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 (pokemon.m.innates) {
|
||||
for (const innate of pokemon.m.innates) {
|
||||
pokemon.removeVolatile("ability" + innate);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
215
data/mods/gen5pokebilities/scripts.ts
Normal file
215
data/mods/gen5pokebilities/scripts.ts
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
export const Scripts: ModdedBattleScriptsData = {
|
||||
inherit: 'gen5',
|
||||
field: {
|
||||
suppressingWeather() {
|
||||
for (const pokemon of this.battle.getAllActive()) {
|
||||
if (pokemon && !pokemon.fainted && !pokemon.ignoringAbility() &&
|
||||
(pokemon.getAbility().suppressWeather ||
|
||||
pokemon.m.innates?.some((k: string) => this.battle.dex.abilities.get(k).suppressWeather))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
},
|
||||
pokemon: {
|
||||
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.innates?.some((k: string) => k === '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.innates?.some((k: string) => k === 'neutralizinggas'))
|
||||
)) && !this.getAbility().flags['cantsuppress']
|
||||
)
|
||||
);
|
||||
},
|
||||
hasAbility(ability) {
|
||||
if (this.ignoringAbility()) return false;
|
||||
if (Array.isArray(ability)) return ability.some(abil => this.hasAbility(abil));
|
||||
ability = this.battle.toID(ability);
|
||||
return this.ability === ability || !!this.volatiles['ability:' + ability];
|
||||
},
|
||||
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') {
|
||||
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.set.ivs = (this.battle.gen >= 5 ? this.set.ivs : pokemon.set.ivs);
|
||||
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 be sure to remove all the overlapping crit volatiles before trying to add 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.terastallized !== this.apparentType) {
|
||||
this.battle.add('-start', this, 'typechange', this.terastallized, '[silent]');
|
||||
this.apparentType = this.terastallized;
|
||||
}
|
||||
if (this.battle.gen > 2) {
|
||||
this.setAbility(pokemon.ability, this, null, true);
|
||||
if (this.m.innates) {
|
||||
for (const innate of this.m.innates) {
|
||||
this.removeVolatile('ability:' + innate);
|
||||
}
|
||||
}
|
||||
if (pokemon.m.innates) {
|
||||
for (const innate of pokemon.m.innates) {
|
||||
this.addVolatile('ability:' + innate, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
/**
|
||||
* Changes this Pokemon's forme to match the given speciesId (or species).
|
||||
* This function handles all changes to stats, ability, type, species, etc.
|
||||
* as well as sending all relevant messages sent to the client.
|
||||
*/
|
||||
formeChange(speciesId, source, isPermanent, message) {
|
||||
if (!source) source = this.battle.effect;
|
||||
|
||||
const rawSpecies = this.battle.dex.species.get(speciesId);
|
||||
|
||||
const species = this.setSpecies(rawSpecies, source);
|
||||
if (!species) return false;
|
||||
|
||||
if (this.battle.gen <= 2) return true;
|
||||
|
||||
// The species the opponent sees
|
||||
const apparentSpecies =
|
||||
this.illusion ? this.illusion.species.name : species.baseSpecies;
|
||||
if (isPermanent) {
|
||||
this.baseSpecies = rawSpecies;
|
||||
this.details = this.getUpdatedDetails();
|
||||
this.battle.add('detailschange', this, (this.illusion || this).details);
|
||||
if (source.effectType === 'Item') {
|
||||
this.canTerastallize = null; // National Dex behavior
|
||||
if (source.zMove) {
|
||||
this.battle.add('-burst', this, apparentSpecies, species.requiredItem);
|
||||
this.moveThisTurnResult = true; // Ultra Burst counts as an action for Truant
|
||||
} else if (source.isPrimalOrb) {
|
||||
if (this.illusion) {
|
||||
this.ability = '';
|
||||
this.battle.add('-primal', this.illusion);
|
||||
} else {
|
||||
this.battle.add('-primal', this);
|
||||
}
|
||||
} else {
|
||||
this.battle.add('-mega', this, apparentSpecies, species.requiredItem);
|
||||
this.moveThisTurnResult = true; // Mega Evolution counts as an action for Truant
|
||||
}
|
||||
} else if (source.effectType === 'Status') {
|
||||
// Shaymin-Sky -> Shaymin
|
||||
this.battle.add('-formechange', this, species.name, message);
|
||||
}
|
||||
} else {
|
||||
if (source.effectType === 'Ability') {
|
||||
this.battle.add('-formechange', this, species.name, message, `[from] ability: ${source.name}`);
|
||||
} else {
|
||||
this.battle.add('-formechange', this, this.illusion ? this.illusion.species.name : species.name, message);
|
||||
}
|
||||
}
|
||||
if (isPermanent && !['disguise', 'iceface', 'ability:disguise', 'ability:iceface'].includes(source.id)) {
|
||||
if (this.illusion) {
|
||||
this.ability = ''; // Don't allow Illusion to wear off
|
||||
}
|
||||
this.setAbility(species.abilities['0'], null, null, true);
|
||||
this.baseAbility = this.ability;
|
||||
}
|
||||
if (this.terastallized && this.terastallized !== this.apparentType) {
|
||||
this.battle.add('-start', this, 'typechange', this.terastallized, '[silent]');
|
||||
this.apparentType = this.terastallized;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -148,6 +148,14 @@ 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",
|
||||
|
|
@ -164,6 +172,14 @@ 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",
|
||||
|
|
@ -297,6 +313,18 @@ 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" },
|
||||
|
|
@ -318,6 +346,82 @@ 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",
|
||||
|
|
|
|||
|
|
@ -87,33 +87,18 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
},
|
||||
slowstart: {
|
||||
inherit: true,
|
||||
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) {
|
||||
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') {
|
||||
return this.chainModify(0.5);
|
||||
},
|
||||
onEnd(target) {
|
||||
this.add('-end', target, 'Slow Start');
|
||||
},
|
||||
}
|
||||
},
|
||||
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);
|
||||
}
|
||||
},
|
||||
},
|
||||
soundproof: {
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
vulpixalola: {
|
||||
tier: "LC",
|
||||
tier: "NFE",
|
||||
},
|
||||
ninetales: {
|
||||
tier: "RU",
|
||||
|
|
|
|||
|
|
@ -386,7 +386,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
condition: {
|
||||
duration: 2,
|
||||
onSwitchInPriority: 1,
|
||||
onSwitchIn(target) {
|
||||
if (!target.fainted) {
|
||||
target.heal(target.maxhp);
|
||||
|
|
@ -613,7 +612,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
condition: {
|
||||
duration: 2,
|
||||
onSwitchInPriority: 1,
|
||||
onSwitchIn(target) {
|
||||
if (!target.fainted) {
|
||||
target.heal(target.maxhp);
|
||||
|
|
@ -1155,39 +1153,6 @@ 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,
|
||||
|
|
|
|||
|
|
@ -59,6 +59,14 @@ 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",
|
||||
|
|
@ -83,6 +91,94 @@ 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 },
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
},
|
||||
pikachustarter: {
|
||||
isNonstandard: null,
|
||||
tier: "UU",
|
||||
tier: "RU",
|
||||
doublesTier: "DOU",
|
||||
},
|
||||
raichu: {
|
||||
|
|
@ -138,7 +138,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
doublesTier: "DOU",
|
||||
},
|
||||
sandslashalola: {
|
||||
tier: "UU",
|
||||
tier: "RU",
|
||||
doublesTier: "DOU",
|
||||
},
|
||||
nidoranf: {
|
||||
|
|
@ -186,7 +186,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
wigglytuff: {
|
||||
tier: "UU",
|
||||
tier: "RU",
|
||||
doublesTier: "DOU",
|
||||
},
|
||||
zubat: {
|
||||
|
|
@ -203,7 +203,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
vileplume: {
|
||||
tier: "UU",
|
||||
tier: "RU",
|
||||
doublesTier: "DOU",
|
||||
},
|
||||
paras: {
|
||||
|
|
@ -227,7 +227,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
dugtrio: {
|
||||
tier: "UU",
|
||||
tier: "RU",
|
||||
doublesTier: "DOU",
|
||||
},
|
||||
dugtrioalola: {
|
||||
|
|
@ -245,7 +245,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
doublesTier: "DOU",
|
||||
},
|
||||
persianalola: {
|
||||
tier: "UU",
|
||||
tier: "RU",
|
||||
doublesTier: "DOU",
|
||||
},
|
||||
psyduck: {
|
||||
|
|
@ -266,7 +266,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
arcanine: {
|
||||
tier: "UU",
|
||||
tier: "RU",
|
||||
doublesTier: "DOU",
|
||||
},
|
||||
poliwag: {
|
||||
|
|
@ -317,7 +317,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
tentacruel: {
|
||||
tier: "UU",
|
||||
tier: "RU",
|
||||
doublesTier: "DOU",
|
||||
},
|
||||
geodude: {
|
||||
|
|
@ -401,7 +401,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
cloyster: {
|
||||
tier: "UU",
|
||||
tier: "RU",
|
||||
doublesTier: "DOU",
|
||||
},
|
||||
gastly: {
|
||||
|
|
@ -433,7 +433,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
kingler: {
|
||||
tier: "RU",
|
||||
tier: "UU",
|
||||
doublesTier: "DOU",
|
||||
},
|
||||
voltorb: {
|
||||
|
|
@ -492,7 +492,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
doublesTier: "DOU",
|
||||
},
|
||||
chansey: {
|
||||
tier: "UU",
|
||||
tier: "RU",
|
||||
doublesTier: "DOU",
|
||||
},
|
||||
tangela: {
|
||||
|
|
@ -572,7 +572,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
doublesTier: "DOU",
|
||||
},
|
||||
lapras: {
|
||||
tier: "UU",
|
||||
tier: "RU",
|
||||
doublesTier: "DOU",
|
||||
},
|
||||
ditto: {
|
||||
|
|
@ -584,7 +584,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
},
|
||||
eeveestarter: {
|
||||
isNonstandard: null,
|
||||
tier: "UU",
|
||||
tier: "RU",
|
||||
doublesTier: "DOU",
|
||||
},
|
||||
vaporeon: {
|
||||
|
|
@ -607,14 +607,14 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
omastar: {
|
||||
tier: "UU",
|
||||
tier: "RU",
|
||||
doublesTier: "DOU",
|
||||
},
|
||||
kabuto: {
|
||||
tier: "LC",
|
||||
},
|
||||
kabutops: {
|
||||
tier: "UU",
|
||||
tier: "RU",
|
||||
doublesTier: "DOU",
|
||||
},
|
||||
aerodactyl: {
|
||||
|
|
@ -638,7 +638,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
doublesTier: "DOU",
|
||||
},
|
||||
moltres: {
|
||||
tier: "UU",
|
||||
tier: "RU",
|
||||
doublesTier: "DOU",
|
||||
},
|
||||
dratini: {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
standard: {
|
||||
inherit: true,
|
||||
ruleset: ['Adjust Level = 50', 'Obtainable', 'Team Preview', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'HP Percentage Mod', 'Cancel Mod', 'Sleep Clause Mod'],
|
||||
ruleset: ['LGPE Normal Rules', 'Obtainable', 'Team Preview', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'HP Percentage Mod', 'Cancel Mod', 'Sleep Clause Mod'],
|
||||
},
|
||||
standarddoubles: {
|
||||
inherit: true,
|
||||
ruleset: ['Adjust Level = 50', 'Obtainable', 'Team Preview', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'HP Percentage Mod', 'Cancel Mod'],
|
||||
ruleset: ['LGPE Normal Rules', 'Obtainable', 'Team Preview', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'HP Percentage Mod', 'Cancel Mod'],
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
function checkMegaForme(species: Species, forme: string, battle: Battle) {
|
||||
const baseSpecies = battle.dex.species.get(species.baseSpecies);
|
||||
const altForme = battle.dex.species.get(`${baseSpecies.name}-${forme}`);
|
||||
if (
|
||||
altForme.exists && !battle.ruleTable.isBannedSpecies(altForme) &&
|
||||
if (altForme.exists && altForme.gen <= 7 && !battle.ruleTable.isBannedSpecies(altForme) &&
|
||||
!battle.ruleTable.isBanned('pokemontag:mega')
|
||||
) {
|
||||
return altForme.name;
|
||||
|
|
@ -40,9 +39,9 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
|
||||
// Limit one mega evolution
|
||||
for (const ally of pokemon.side.pokemon) {
|
||||
ally.canMegaEvo = null;
|
||||
ally.canMegaEvoX = null;
|
||||
ally.canMegaEvoY = null;
|
||||
ally.canMegaEvo = false;
|
||||
ally.canMegaEvoX = false;
|
||||
ally.canMegaEvoY = false;
|
||||
}
|
||||
|
||||
this.battle.runEvent('AfterMega', pokemon);
|
||||
|
|
@ -50,50 +49,34 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
},
|
||||
runMegaEvoX(pokemon) {
|
||||
if (!pokemon.canMegaEvoX) return false;
|
||||
pokemon.canMegaEvoY = null;
|
||||
pokemon.canMegaEvoY = false;
|
||||
return this.runMegaEvo(pokemon);
|
||||
},
|
||||
runMegaEvoY(pokemon) {
|
||||
if (!pokemon.canMegaEvoY) return false;
|
||||
pokemon.canMegaEvoX = null;
|
||||
pokemon.canMegaEvoX = false;
|
||||
return this.runMegaEvo(pokemon);
|
||||
},
|
||||
},
|
||||
/**
|
||||
* Given a table of base stats and a pokemon set, return the actual stats.
|
||||
*/
|
||||
spreadModify(baseStats, set) {
|
||||
const modStats: StatsTable = { hp: 10, atk: 10, def: 10, spa: 10, spd: 10, spe: 10 };
|
||||
let statName: StatID;
|
||||
for (statName in modStats) {
|
||||
const stat = baseStats[statName];
|
||||
modStats[statName] = Math.floor((Math.floor(2 * stat + set.ivs[statName]) * set.level / 100 + 5));
|
||||
statModify(baseStats, set, statName) {
|
||||
const tr = this.trunc;
|
||||
let stat = baseStats[statName];
|
||||
if (statName === 'hp') {
|
||||
return tr(tr(2 * stat + set.ivs[statName] + 100) * set.level / 100 + 10) + set.evs[statName];
|
||||
}
|
||||
if ('hp' in baseStats) {
|
||||
const stat = baseStats['hp'];
|
||||
modStats['hp'] = Math.floor(Math.floor(2 * stat + set.ivs['hp'] + 100) * set.level / 100 + 10);
|
||||
}
|
||||
return this.natureModify(modStats, set);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {StatsTable} stats
|
||||
* @param {PokemonSet} set
|
||||
* @return {StatsTable}
|
||||
*/
|
||||
natureModify(stats, set) {
|
||||
stat = tr((tr(2 * stat + set.ivs[statName]) * set.level / 100 + 5));
|
||||
const nature = this.dex.natures.get(set.nature);
|
||||
if (nature.plus) stats[nature.plus] = Math.floor(stats[nature.plus] * 1.1);
|
||||
if (nature.minus) stats[nature.minus] = Math.floor(stats[nature.minus] * 0.9);
|
||||
set.happiness = 70;
|
||||
const friendshipValue = Math.floor((set.happiness / 255 / 10 + 1) * 100);
|
||||
let stat: StatID;
|
||||
for (stat in stats) {
|
||||
if (stat !== 'hp') {
|
||||
stats[stat] = Math.floor(stats[stat] * friendshipValue / 100);
|
||||
}
|
||||
stats[stat] += set.evs[stat];
|
||||
if (nature.plus === statName) {
|
||||
stat = tr(tr(stat * 110, 16) / 100);
|
||||
} else if (nature.minus === statName) {
|
||||
stat = tr(tr(stat * 90, 16) / 100);
|
||||
}
|
||||
return stats;
|
||||
set.happiness = 70;
|
||||
const friendshipValue = tr((set.happiness / 255 / 10 + 1) * 100);
|
||||
stat = tr(stat * friendshipValue / 100);
|
||||
return stat;
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
this.apparentType = this.terastallized;
|
||||
}
|
||||
if (this.battle.gen > 2) {
|
||||
this.setAbility(pokemon.ability, this, true);
|
||||
this.setAbility(pokemon.ability, this, null, true);
|
||||
if (this.m.innates) {
|
||||
for (const innate of this.m.innates) {
|
||||
this.removeVolatile('ability:' + innate);
|
||||
|
|
@ -202,7 +202,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
if (this.illusion) {
|
||||
this.ability = ''; // Don't allow Illusion to wear off
|
||||
}
|
||||
this.setAbility(species.abilities['0'], null, true);
|
||||
this.setAbility(species.abilities['0'], null, null, true);
|
||||
this.baseAbility = this.ability;
|
||||
}
|
||||
if (this.terastallized && this.terastallized !== this.apparentType) {
|
||||
|
|
|
|||
|
|
@ -283,9 +283,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
this.damage(pokemon.baseMaxhp / 8, pokemon, pokemon, this.dex.species.get(speciesid));
|
||||
}
|
||||
},
|
||||
onFaint(target) {
|
||||
delete this.effectState.busted;
|
||||
},
|
||||
rating: 3.5,
|
||||
},
|
||||
download: {
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
}
|
||||
|
||||
// In SwSh, Fly's animation leaks the initial target through a camera focus
|
||||
// The animation leak target itself isn't "accurate"; the target it reveals is as if Fly weren't a charge movee
|
||||
// The animation leak target itself isn't "accurate"; the target it reveals is as if Fly weren't a charge move
|
||||
// (Fly, like all other charge moves, will actually target slots on its charging turn, relevant for things like Follow Me)
|
||||
// We use a generic single-target move to represent this
|
||||
if (this.sides.length > 2) {
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable
|
|||
if (set.item && this.dex.items.get(set.item).megaStone) {
|
||||
const item = this.dex.items.get(set.item);
|
||||
if (item.megaEvolves === species.baseSpecies) {
|
||||
species = this.dex.species.get(item.megaStone);
|
||||
species = this.dex.species.get(Array.isArray(item.megaStone) ? item.megaStone[0] : item.megaStone);
|
||||
}
|
||||
}
|
||||
if (
|
||||
|
|
@ -123,7 +123,9 @@ export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable
|
|||
}
|
||||
if (set.item) {
|
||||
const item = this.dex.items.get(set.item);
|
||||
if (item.megaEvolves === set.species) godSpecies = this.dex.species.get(item.megaStone);
|
||||
if (item.megaEvolves === set.species) {
|
||||
godSpecies = this.dex.species.get(Array.isArray(item.megaStone) ? item.megaStone[0] : item.megaStone);
|
||||
}
|
||||
if (["Zacian", "Zamazenta"].includes(godSpecies.baseSpecies) && item.id.startsWith('rusted')) {
|
||||
godSpecies = this.dex.species.get(set.species + "-Crowned");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1341,6 +1341,12 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "PU",
|
||||
doublesTier: "DUU",
|
||||
},
|
||||
castformsunny: {
|
||||
},
|
||||
castformrainy: {
|
||||
},
|
||||
castformsnowy: {
|
||||
},
|
||||
kecleon: {
|
||||
tier: "PU",
|
||||
doublesTier: "DUU",
|
||||
|
|
@ -1374,7 +1380,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
doublesTier: "DUU",
|
||||
},
|
||||
absol: {
|
||||
tier: "RU",
|
||||
tier: "RUBL",
|
||||
doublesTier: "DUU",
|
||||
},
|
||||
snorunt: {
|
||||
|
|
@ -1622,7 +1628,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
drifblim: {
|
||||
tier: "PU",
|
||||
tier: "PUBL",
|
||||
doublesTier: "DUU",
|
||||
},
|
||||
buneary: {
|
||||
|
|
@ -1654,7 +1660,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
doublesTier: "DOU",
|
||||
},
|
||||
chatot: {
|
||||
tier: "PU",
|
||||
tier: "PUBL",
|
||||
doublesTier: "DUU",
|
||||
},
|
||||
spiritomb: {
|
||||
|
|
|
|||
|
|
@ -102,18 +102,6 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
ejectbutton: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
onAfterMoveSecondary(target, source, move) {
|
||||
if (source && source !== target && target.hp && move && move.category !== 'Status' && !move.flags['futuremove']) {
|
||||
if (!this.canSwitch(target.side) || target.forceSwitchFlag || target.beingCalledBack || target.isSkyDropped()) return;
|
||||
for (const pokemon of this.getAllActive()) {
|
||||
if (pokemon.switchFlag === true) return;
|
||||
}
|
||||
// TODO: Confirm mechanics
|
||||
this.add("-activate", target, "item: Eject Button");
|
||||
target.switchFlag = true;
|
||||
source.switchFlag = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
ejectpack: {
|
||||
inherit: true,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
2768
data/mods/gen8legends/formats-data.ts
Normal file
2768
data/mods/gen8legends/formats-data.ts
Normal file
File diff suppressed because it is too large
Load Diff
5627
data/mods/gen8legends/learnsets.ts
Normal file
5627
data/mods/gen8legends/learnsets.ts
Normal file
File diff suppressed because it is too large
Load Diff
42
data/mods/gen8legends/pokedex.ts
Normal file
42
data/mods/gen8legends/pokedex.ts
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
export const Pokedex: import('../../../sim/dex-species').ModdedSpeciesDataTable = {
|
||||
pikachu: {
|
||||
inherit: true,
|
||||
evos: ["Raichu"],
|
||||
},
|
||||
quilava: {
|
||||
inherit: true,
|
||||
evos: ["Typhlosion-Hisui"],
|
||||
},
|
||||
cherrimsunshine: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 70, atk: 90, def: 70, spa: 87, spd: 117, spe: 85 },
|
||||
},
|
||||
mimejr: {
|
||||
inherit: true,
|
||||
evos: ["Mr. Mime"],
|
||||
},
|
||||
dewott: {
|
||||
inherit: true,
|
||||
evos: ["Samurott-Hisui"],
|
||||
},
|
||||
petilil: {
|
||||
inherit: true,
|
||||
evos: ["Lilligant-Hisui"],
|
||||
},
|
||||
rufflet: {
|
||||
inherit: true,
|
||||
evos: ["Braviary-Hisui"],
|
||||
},
|
||||
goomy: {
|
||||
inherit: true,
|
||||
evos: ["Sliggoo-Hisui"],
|
||||
},
|
||||
bergmite: {
|
||||
inherit: true,
|
||||
evos: ["Avalugg-Hisui"],
|
||||
},
|
||||
dartrix: {
|
||||
inherit: true,
|
||||
evos: ["Decidueye-Hisui"],
|
||||
},
|
||||
};
|
||||
4
data/mods/gen8legends/scripts.ts
Normal file
4
data/mods/gen8legends/scripts.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
export const Scripts: ModdedBattleScriptsData = {
|
||||
gen: 8,
|
||||
inherit: 'gen8',
|
||||
};
|
||||
|
|
@ -83,7 +83,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
if (!species) continue;
|
||||
pokemon.baseSpecies = rawSpecies;
|
||||
pokemon.details = pokemon.getUpdatedDetails();
|
||||
// pokemon.setAbility(species.abilities['0'], null, true);
|
||||
// pokemon.setAbility(species.abilities['0'], null, null, true);
|
||||
// pokemon.baseAbility = pokemon.ability;
|
||||
|
||||
const behemothMove: { [k: string]: string } = {
|
||||
|
|
|
|||
|
|
@ -35,13 +35,6 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
if (pokemon.species.name === 'Terapagos-Terastal') {
|
||||
pokemon.formeChange('Terapagos-Stellar', null, 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.baseMaxhp;
|
||||
pokemon.hp = newMaxHP - (pokemon.maxhp - pokemon.hp);
|
||||
pokemon.maxhp = newMaxHP;
|
||||
this.battle.add('-heal', pokemon, pokemon.getHealth, '[silent]');
|
||||
}
|
||||
if (pokemon.species.baseSpecies === 'Morpeko' && !pokemon.transformed &&
|
||||
pokemon.baseSpecies.id !== pokemon.species.id
|
||||
|
|
@ -135,7 +128,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
this.knownType = true;
|
||||
this.apparentType = this.terastallized;
|
||||
}
|
||||
if (this.battle.gen > 2) this.setAbility(pokemon.ability, this, true, true);
|
||||
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
|
||||
|
|
|
|||
3302
data/mods/gen9legends/formats-data.ts
Normal file
3302
data/mods/gen9legends/formats-data.ts
Normal file
File diff suppressed because it is too large
Load Diff
16736
data/mods/gen9legends/learnsets.ts
Normal file
16736
data/mods/gen9legends/learnsets.ts
Normal file
File diff suppressed because it is too large
Load Diff
14
data/mods/gen9legends/pokedex.ts
Normal file
14
data/mods/gen9legends/pokedex.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
export const Pokedex: import('../../../sim/dex-species').ModdedSpeciesDataTable = {
|
||||
starmiemega: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 60, atk: 140, def: 105, spa: 130, spd: 105, spe: 120 },
|
||||
},
|
||||
mawilemega: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 50, atk: 147, def: 125, spa: 55, spd: 95, spe: 50 },
|
||||
},
|
||||
medichammega: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 60, atk: 140, def: 85, spa: 80, spd: 85, spe: 100 },
|
||||
},
|
||||
};
|
||||
4
data/mods/gen9legends/scripts.ts
Normal file
4
data/mods/gen9legends/scripts.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
export const Scripts: ModdedBattleScriptsData = {
|
||||
gen: 9,
|
||||
inherit: 'gen9',
|
||||
};
|
||||
1535
data/mods/gen9legendsou/formats-data.ts
Normal file
1535
data/mods/gen9legendsou/formats-data.ts
Normal file
File diff suppressed because it is too large
Load Diff
24
data/mods/gen9legendsou/items.ts
Normal file
24
data/mods/gen9legendsou/items.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
||||
slowbronite: {
|
||||
inherit: true,
|
||||
onTakeItem(item, source) {
|
||||
if (item.megaEvolves === source.baseSpecies.name || item.megaStone === source.baseSpecies.name) return false;
|
||||
return true;
|
||||
},
|
||||
},
|
||||
greninjite: {
|
||||
inherit: true,
|
||||
onTakeItem(item, source) {
|
||||
if (item.megaEvolves === source.baseSpecies.name || item.megaStone === source.baseSpecies.name) return false;
|
||||
return true;
|
||||
},
|
||||
},
|
||||
zygardite: {
|
||||
inherit: true,
|
||||
onTakeItem(item, source) {
|
||||
if ((source.baseSpecies.baseSpecies === 'Zygarde' && source.baseAbility === 'powerconstruct') ||
|
||||
source.baseSpecies.name === 'Zygarde-Mega') return false;
|
||||
return true;
|
||||
},
|
||||
},
|
||||
};
|
||||
99971
data/mods/gen9legendsou/learnsets.ts
Normal file
99971
data/mods/gen9legendsou/learnsets.ts
Normal file
File diff suppressed because it is too large
Load Diff
10
data/mods/gen9legendsou/moves.ts
Normal file
10
data/mods/gen9legendsou/moves.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
||||
volttackle: {
|
||||
inherit: true,
|
||||
onModifyMove(move, pokemon, target) {
|
||||
if (pokemon.baseSpecies.name === "Raichu-Mega-X") {
|
||||
move.self = { boosts: { atk: 1 } };
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
219
data/mods/gen9legendsou/pokedex.ts
Normal file
219
data/mods/gen9legendsou/pokedex.ts
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
export const Pokedex: import('../../../sim/dex-species').ModdedSpeciesDataTable = {
|
||||
clefablemega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Prankster" },
|
||||
},
|
||||
victreebelmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Triage" },
|
||||
},
|
||||
raichumegax: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Levitate" },
|
||||
},
|
||||
raichumegay: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Transistor" },
|
||||
},
|
||||
starmiemega: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 60, atk: 100, def: 105, spa: 130, spd: 105, spe: 120 },
|
||||
abilities: { 0: "Pure Power" },
|
||||
},
|
||||
dragonitemega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Sheer Force" },
|
||||
},
|
||||
meganiummega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Flower Veil" },
|
||||
},
|
||||
feraligatrmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Dragon's Maw" },
|
||||
},
|
||||
ampharosmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Fluffy" },
|
||||
},
|
||||
absolmegaz: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Technician" },
|
||||
},
|
||||
chimechomega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Levitate" },
|
||||
},
|
||||
skarmorymega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Tough Claws" },
|
||||
},
|
||||
mawilemega: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 50, atk: 105, def: 125, spa: 55, spd: 95, spe: 50 },
|
||||
},
|
||||
medichammega: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 60, atk: 100, def: 85, spa: 80, spd: 85, spe: 100 },
|
||||
},
|
||||
staraptormega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Tough Claws" },
|
||||
},
|
||||
gallademega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Sharpness" },
|
||||
},
|
||||
froslassmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Snow Warning" },
|
||||
},
|
||||
garchompmegaz: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Rough Skin" },
|
||||
},
|
||||
lucariomegaz: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Mind's Eye" },
|
||||
},
|
||||
heatranmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Filter" },
|
||||
},
|
||||
darkraimega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Dark Aura" },
|
||||
},
|
||||
emboarmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Supreme Overlord" },
|
||||
},
|
||||
excadrillmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Sand Rush" },
|
||||
},
|
||||
golurkmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Adaptability" },
|
||||
},
|
||||
audinomega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Regenerator" },
|
||||
},
|
||||
scolipedemega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Tinted Lens" },
|
||||
},
|
||||
scraftymega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Shed Skin" },
|
||||
},
|
||||
eelektrossmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Hadron Engine" },
|
||||
},
|
||||
chandeluremega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Magic Guard" },
|
||||
},
|
||||
chesnaughtmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Grassy Surge" },
|
||||
},
|
||||
delphoxmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Levitate" },
|
||||
},
|
||||
greninjamega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Protean" },
|
||||
},
|
||||
meowsticmmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Psychic Surge" },
|
||||
},
|
||||
meowsticfmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Psychic Surge" },
|
||||
},
|
||||
pyroarmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Drought" },
|
||||
},
|
||||
dragalgemega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Regenerator" },
|
||||
},
|
||||
floettemega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Regenerator" },
|
||||
},
|
||||
malamarmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Contrary" },
|
||||
},
|
||||
barbaraclemega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Tough Claws" },
|
||||
},
|
||||
hawluchamega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Stamina" },
|
||||
},
|
||||
zygardemega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Aura Break" },
|
||||
},
|
||||
crabominablemega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Ice Scales" },
|
||||
},
|
||||
golisopodmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Heatproof" },
|
||||
},
|
||||
drampamega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Adaptability" },
|
||||
},
|
||||
magearnamega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Soul-Heart" },
|
||||
},
|
||||
magearnaoriginalmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Soul-Heart" },
|
||||
},
|
||||
zeraoramega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Volt Absorb" },
|
||||
},
|
||||
falinksmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Dauntless Shield" },
|
||||
},
|
||||
scovillainmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Contrary" },
|
||||
},
|
||||
glimmoramega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Levitate" },
|
||||
},
|
||||
tatsugiricurlymega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Drizzle" },
|
||||
},
|
||||
tatsugiridroopymega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Drizzle" },
|
||||
},
|
||||
tatsugiristretchymega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Drizzle" },
|
||||
},
|
||||
baxcaliburmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Thermal Exchange" },
|
||||
},
|
||||
};
|
||||
114
data/mods/gen9legendsou/scripts.ts
Normal file
114
data/mods/gen9legendsou/scripts.ts
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
export const Scripts: ModdedBattleScriptsData = {
|
||||
gen: 9,
|
||||
inherit: 'gen9legends',
|
||||
init() {
|
||||
const legalItems = [
|
||||
'assaultvest', 'bigroot', 'blackbelt', 'blackglasses', 'charcoal', 'dragonfang', 'eviolite', 'expertbelt', 'fairyfeather',
|
||||
'focusband', 'focussash', 'hardstone', 'kingsrock', 'leftovers', 'lifeorb', 'lightball', 'magnet', 'metalcoat', 'miracleseed',
|
||||
'muscleband', 'mysticwater', 'nevermeltice', 'normalgem', 'poisonbarb', 'poweranklet', 'powerband', 'powerbelt', 'powerbracer',
|
||||
'powerlens', 'powerweight', 'quickclaw', 'rockyhelmet', 'scopelens', 'sharpbeak', 'shellbell', 'silkscarf', 'silverpowder',
|
||||
'softsand', 'spelltag', 'twistedspoon', 'weaknesspolicy', 'whiteherb', 'wiseglasses', 'bottlecap', 'goldbottlecap', 'dawnstone',
|
||||
'duskstone', 'firestone', 'galaricacuff', 'galaricawreath', 'icestone', 'leafstone', 'moonstone', 'sachet', 'shinystone',
|
||||
'sunstone', 'thunderstone', 'waterstone', 'whippeddream', 'bignugget', 'redorb', 'blueorb', 'leek', 'thickclub', 'upgrade',
|
||||
'dubiousdisc', 'prismscale', 'maliciousarmor', 'auspiciousarmor', 'poweranklet', 'powerband', 'powerbelt', 'powerbracer',
|
||||
'powerlens', 'powerweight', 'bignugget', 'bottlecap', 'goldbottlecap', 'prismscale', 'sachet', 'whippeddream',
|
||||
];
|
||||
const legalBerries = [
|
||||
'aspearberry', 'babiriberry', 'chartiberry', 'cheriberry', 'chestoberry', 'chilanberry', 'chopleberry', 'cobaberry', 'colburberry',
|
||||
'grepaberry', 'habanberry', 'hondewberry', 'kasibberry', 'kebiaberry', 'kelpsyberry', 'lumberry', 'occaberry', 'oranberry', 'passhoberry',
|
||||
'payapaberry', 'pechaberry', 'persimberry', 'pomegberry', 'qualotberry', 'rawstberry', 'rindoberry', 'roseliberry', 'shucaberry',
|
||||
'sitrusberry', 'tamatoberry', 'tangaberry', 'wacanberry', 'yacheberry',
|
||||
];
|
||||
const votedLegalitems = [
|
||||
'heavydutyboots', 'choiceband', 'choicescarf', 'choicespecs', 'airballoon', 'loadeddice', 'mentalherb', 'powerherb', 'mirrorherb',
|
||||
'aguavberry', 'apicotberry', 'custapberry', 'enigmaberry', 'figyberry', 'ganlonberry', 'iapapaberry', 'jabocaberry', 'keeberry',
|
||||
'lansatberry', 'leppaberry', 'liechiberry', 'magoberry', 'marangaberry', 'micleberry', 'petayaberry', 'rowapberry', 'salacberry',
|
||||
'starfberry', 'wikiberry', 'abilityshield', 'blunderpolicy', 'blacksludge', 'lightclay', 'brightpowder', 'adrenalineorb', 'absorbbulb',
|
||||
'clearamulet', 'covertcloak', 'damprock', 'heatrock', 'icyrock', 'smoothrock', 'electricseed', 'mistyseed', 'psychicseed', 'grassyseed',
|
||||
'flameorb', 'toxicorb', 'gripclaw', 'laggingtail', 'metronome', 'protectivepads', 'punchingglove', 'razorclaw', 'razorfang', 'roomservice',
|
||||
'safetygoggles', 'shellbell', 'shedshell', 'stickybarb', 'terrainextender', 'throatspray', 'utilityumbrella', 'zoomlens', 'bindingband',
|
||||
'destinyknot', 'floatstone', 'ironball', 'machobrace', 'ringtarget', 'redcard', 'ejectpack', 'ejectbutton', 'souldew', 'cellbattery',
|
||||
'luminousmoss', 'oddincense', 'roseincense', 'seaincense', 'waveincense', 'snowball',
|
||||
];
|
||||
for (const i in this.data.Items) {
|
||||
if (this.data.Items[i].isNonstandard === 'CAP' || this.data.Items[i].isNonstandard === 'Custom') continue;
|
||||
if ([...legalItems, ...votedLegalitems, ...legalBerries].includes(i) ||
|
||||
this.data.Items[i].megaStone || this.data.Items[i].onDrive ||
|
||||
(this.data.Items[i].onPlate && !this.data.Items[i].zMove)) {
|
||||
this.modData('Items', i).isNonstandard = null;
|
||||
} else {
|
||||
this.modData('Items', i).isNonstandard = 'Past';
|
||||
}
|
||||
}
|
||||
for (const i in this.data.Moves) {
|
||||
if (this.data.Moves[i].isNonstandard !== 'Past') continue;
|
||||
this.modData('Moves', i).isNonstandard = null;
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
canMegaEvo(pokemon) {
|
||||
const species = pokemon.baseSpecies;
|
||||
const altForme = species.otherFormes && this.dex.species.get(species.otherFormes[0]);
|
||||
const item = pokemon.getItem();
|
||||
// Mega Rayquaza
|
||||
if ((this.battle.gen <= 7 || this.battle.ruleTable.has('+pokemontag:past') ||
|
||||
this.battle.ruleTable.has('+pokemontag:future')) &&
|
||||
altForme?.isMega && altForme?.requiredMove &&
|
||||
pokemon.baseMoves.includes(this.battle.toID(altForme.requiredMove)) && !item.zMove) {
|
||||
return altForme.name;
|
||||
}
|
||||
if (Array.isArray(item.megaEvolves)) {
|
||||
if (!Array.isArray(item.megaStone)) {
|
||||
throw new Error(`${item.name}#megaEvolves and ${item.name}#megaStone type mismatch`);
|
||||
}
|
||||
if (item.megaEvolves.length !== item.megaStone.length) {
|
||||
throw new Error(`${item.name}#megaEvolves and ${item.name}#megaStone length mismatch`);
|
||||
}
|
||||
const index = item.megaEvolves.indexOf(species.name);
|
||||
if (index < 0) return null;
|
||||
return item.megaStone[index];
|
||||
} else {
|
||||
if (item.megaEvolves === species.name) {
|
||||
if (Array.isArray(item.megaStone)) throw new Error(`${item.name}#megaEvolves and ${item.name}#megaStone type mismatch`);
|
||||
return item.megaStone;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
runMegaEvo(pokemon) {
|
||||
const speciesid = pokemon.canMegaEvo || pokemon.canUltraBurst;
|
||||
if (!speciesid) return false;
|
||||
|
||||
pokemon.formeChange(speciesid, pokemon.getItem(), true);
|
||||
|
||||
// Limit one mega evolution
|
||||
const wasMega = pokemon.canMegaEvo;
|
||||
for (const ally of pokemon.side.pokemon) {
|
||||
if (wasMega) {
|
||||
ally.canMegaEvo = false;
|
||||
} else {
|
||||
ally.canUltraBurst = null;
|
||||
}
|
||||
}
|
||||
|
||||
// will finish coding this later, not important since zygarde is banned
|
||||
if (speciesid === 'Zygarde-Mega') {
|
||||
const coreEnforcer = pokemon.moveSlots.findIndex(x => x.id === 'coreenforcer');
|
||||
if (coreEnforcer >= 0) {
|
||||
const nihilLight = this.battle.dex.moves.get('nihillight');
|
||||
pokemon.moveSlots[coreEnforcer] = pokemon.baseMoveSlots[coreEnforcer] = {
|
||||
id: nihilLight.id,
|
||||
move: nihilLight.name,
|
||||
pp: pokemon.moveSlots[coreEnforcer].pp,
|
||||
maxpp: pokemon.moveSlots[coreEnforcer].maxpp,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
this.battle.runEvent('AfterMega', pokemon);
|
||||
return true;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -499,6 +499,54 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
flags: {},
|
||||
},
|
||||
|
||||
// Cassiopeia
|
||||
hacking: {
|
||||
name: "Hacking",
|
||||
shortDesc: "Hacks into PS and finds out if the enemy has any super effective moves.",
|
||||
onStart(pokemon) {
|
||||
const name = (pokemon.illusion || pokemon).name;
|
||||
this.add(`c:|${getName(name)}|One moment, please. One does not simply go into battle blind.`);
|
||||
const side = pokemon.side.id === 'p1' ? 'p2' : 'p1';
|
||||
this.add(
|
||||
`message`,
|
||||
(
|
||||
`ssh sim@pokemonshowdown.com && nc -U logs/repl/sim <<< ` +
|
||||
`"Users.get('${this.toID(name)}').popup(battle.sides.get('${side}').pokemon.map(m => Teams.exportSet(m)))"`
|
||||
)
|
||||
);
|
||||
let warnMoves: (Move | Pokemon)[][] = [];
|
||||
let warnBp = 1;
|
||||
for (const target of pokemon.foes()) {
|
||||
for (const moveSlot of target.moveSlots) {
|
||||
const move = this.dex.moves.get(moveSlot.move);
|
||||
let bp = move.basePower;
|
||||
if (move.ohko) bp = 150;
|
||||
if (move.id === 'counter' || move.id === 'metalburst' || move.id === 'mirrorcoat') bp = 120;
|
||||
if (bp === 1) bp = 80;
|
||||
if (!bp && move.category !== 'Status') bp = 80;
|
||||
if (bp > warnBp) {
|
||||
warnMoves = [[move, target]];
|
||||
warnBp = bp;
|
||||
} else if (bp === warnBp) {
|
||||
warnMoves.push([move, target]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!warnMoves.length) {
|
||||
this.add(`c:|${getName(name)}|Fascinating. None of your sets have any moves of interest.`);
|
||||
return;
|
||||
}
|
||||
const [warnMoveName, warnTarget] = this.sample(warnMoves);
|
||||
this.add(
|
||||
'message',
|
||||
`${name} hacked into PS and looked at ${name === 'Cassiopeia' ? 'her' : 'their'} opponent's sets. ` +
|
||||
`${warnTarget.name}'s move ${warnMoveName} drew ${name === 'Cassiopeia' ? 'her' : 'their'} eye.`
|
||||
);
|
||||
this.add(`c:|${getName(name)}|Interesting. With that in mind, bring it!`);
|
||||
},
|
||||
flags: {},
|
||||
},
|
||||
|
||||
// Chloe
|
||||
acetosa: {
|
||||
shortDesc: "This Pokemon's moves are changed to be Grass type and have 1.2x power.",
|
||||
|
|
@ -936,54 +984,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
flags: {},
|
||||
},
|
||||
|
||||
// Hecate
|
||||
hacking: {
|
||||
name: "Hacking",
|
||||
shortDesc: "Hacks into PS and finds out if the enemy has any super effective moves.",
|
||||
onStart(pokemon) {
|
||||
const name = (pokemon.illusion || pokemon).name;
|
||||
this.add(`c:|${getName(name)}|One moment, please. One does not simply go into battle blind.`);
|
||||
const side = pokemon.side.id === 'p1' ? 'p2' : 'p1';
|
||||
this.add(
|
||||
`message`,
|
||||
(
|
||||
`ssh sim@pokemonshowdown.com && nc -U logs/repl/sim <<< ` +
|
||||
`"Users.get('${this.toID(name)}').popup(battle.sides.get('${side}').pokemon.map(m => Teams.exportSet(m)))"`
|
||||
)
|
||||
);
|
||||
let warnMoves: (Move | Pokemon)[][] = [];
|
||||
let warnBp = 1;
|
||||
for (const target of pokemon.foes()) {
|
||||
for (const moveSlot of target.moveSlots) {
|
||||
const move = this.dex.moves.get(moveSlot.move);
|
||||
let bp = move.basePower;
|
||||
if (move.ohko) bp = 150;
|
||||
if (move.id === 'counter' || move.id === 'metalburst' || move.id === 'mirrorcoat') bp = 120;
|
||||
if (bp === 1) bp = 80;
|
||||
if (!bp && move.category !== 'Status') bp = 80;
|
||||
if (bp > warnBp) {
|
||||
warnMoves = [[move, target]];
|
||||
warnBp = bp;
|
||||
} else if (bp === warnBp) {
|
||||
warnMoves.push([move, target]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!warnMoves.length) {
|
||||
this.add(`c:|${getName(name)}|Fascinating. None of your sets have any moves of interest.`);
|
||||
return;
|
||||
}
|
||||
const [warnMoveName, warnTarget] = this.sample(warnMoves);
|
||||
this.add(
|
||||
'message',
|
||||
`${name} hacked into PS and looked at ${name === 'Hecate' ? 'her' : 'their'} opponent's sets. ` +
|
||||
`${warnTarget.name}'s move ${warnMoveName} drew ${name === 'Hecate' ? 'her' : 'their'} eye.`
|
||||
);
|
||||
this.add(`c:|${getName(name)}|Interesting. With that in mind, bring it!`);
|
||||
},
|
||||
flags: {},
|
||||
},
|
||||
|
||||
// HoeenHero
|
||||
misspelled: {
|
||||
shortDesc: "Swift Swim + Special Attack 1.5x, Accuracy 0.8x. Never misses, only misspells.",
|
||||
|
|
@ -1935,7 +1935,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
if (target.getMoveHitData(move).typeMod > 0) {
|
||||
this.effectState.superHit = true;
|
||||
target.removeVolatile('ultramystik');
|
||||
target.setAbility('Healer', null, true);
|
||||
target.setAbility('Healer', null, null, true);
|
||||
target.baseAbility = target.ability;
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -168,28 +168,28 @@ export const Conditions: { [id: IDEntry]: ModdedConditionData & { innateName?: s
|
|||
april: {
|
||||
noCopy: true,
|
||||
onStart(pokemon) {
|
||||
if (this.ruleTable.has('zmovesclause')) {
|
||||
if (this.ruleTable.has('zmoveclause')) {
|
||||
this.add(`c:|${getName('April')}|Fool's Day`);
|
||||
} else {
|
||||
this.add(`c:|${getName('April')}|I said, "Do you have something against dogs?"`);
|
||||
}
|
||||
},
|
||||
onSwitchOut() {
|
||||
if (this.ruleTable.has('zmovesclause')) {
|
||||
if (this.ruleTable.has('zmoveclause')) {
|
||||
this.add(`c:|${getName('April')}|Fool's Day`);
|
||||
} else {
|
||||
this.add(`c:|${getName('April')}|(Is it the chorus yet?)`);
|
||||
}
|
||||
},
|
||||
onFaint() {
|
||||
if (this.ruleTable.has('zmovesclause')) {
|
||||
if (this.ruleTable.has('zmoveclause')) {
|
||||
this.add(`c:|${getName('April')}|Fool's Day`);
|
||||
} else {
|
||||
this.add(`c:|${getName('April')}|Don't get too impressed, you might lose your breath...`);
|
||||
}
|
||||
},
|
||||
onTryHit() {
|
||||
if (this.ruleTable.has('zmovesclause')) {
|
||||
if (this.ruleTable.has('zmoveclause')) {
|
||||
this.add(`c:|${getName('April')}|Fool's Day`);
|
||||
}
|
||||
},
|
||||
|
|
@ -356,9 +356,6 @@ export const Conditions: { [id: IDEntry]: ModdedConditionData & { innateName?: s
|
|||
case 'rumia':
|
||||
this.add(`c:|${getName('ausma')}|oh no... it's poomia....`);
|
||||
break;
|
||||
case 'lily':
|
||||
this.add(`c:|${getName('ausma')}|togedemaru`);
|
||||
break;
|
||||
case 'lumari':
|
||||
this.add(`c:|${getName('ausma')}|we should watch the next ladybug ep after this tbh`);
|
||||
break;
|
||||
|
|
@ -591,6 +588,18 @@ export const Conditions: { [id: IDEntry]: ModdedConditionData & { innateName?: s
|
|||
this.add(`c:|${getName('calmvibes ♫')}|The vibes are off... :(`);
|
||||
},
|
||||
},
|
||||
cassiopeia: {
|
||||
noCopy: true,
|
||||
onStart() {
|
||||
this.add(`c:|${getName('Cassiopeia')}|git pull ps cassiopeia`);
|
||||
},
|
||||
onSwitchOut() {
|
||||
this.add(`c:|${getName('Cassiopeia')}|git switch`);
|
||||
},
|
||||
onFaint() {
|
||||
this.add(`c:|${getName('Cassiopeia')}|git checkout --detach HEAD && git commit -m "war crimes"`);
|
||||
},
|
||||
},
|
||||
chaos: {
|
||||
noCopy: true,
|
||||
},
|
||||
|
|
@ -978,18 +987,6 @@ export const Conditions: { [id: IDEntry]: ModdedConditionData & { innateName?: s
|
|||
this.add(`c:|${getName('havi')}|the nightmare swirls and churns unending n_n`);
|
||||
},
|
||||
},
|
||||
hecate: {
|
||||
noCopy: true,
|
||||
onStart() {
|
||||
this.add(`c:|${getName('Hecate')}|git pull ps hecate`);
|
||||
},
|
||||
onSwitchOut() {
|
||||
this.add(`c:|${getName('Hecate')}|git switch`);
|
||||
},
|
||||
onFaint() {
|
||||
this.add(`c:|${getName('Hecate')}|git checkout --detach HEAD && git commit -m "war crimes"`);
|
||||
},
|
||||
},
|
||||
hizo: {
|
||||
noCopy: true,
|
||||
onStart() {
|
||||
|
|
@ -1361,18 +1358,6 @@ export const Conditions: { [id: IDEntry]: ModdedConditionData & { innateName?: s
|
|||
this.add(`c:|${getName('Lets go shuckles')}|He who lives by the Shuckle shall die by the Shuckle.`);
|
||||
},
|
||||
},
|
||||
lily: {
|
||||
noCopy: true,
|
||||
onStart() {
|
||||
this.add(`c:|${getName('Lily')}|buying gf`);
|
||||
},
|
||||
onSwitchOut() {
|
||||
this.add(`c:|${getName('Lily')}|accidentally burnt the shrimps`);
|
||||
},
|
||||
onFaint() {
|
||||
this.add(`c:|${getName('Lily')}|oh dear, i am dead`);
|
||||
},
|
||||
},
|
||||
loethalion: {
|
||||
noCopy: true,
|
||||
onStart(pokemon) {
|
||||
|
|
@ -3099,7 +3084,7 @@ export const Conditions: { [id: IDEntry]: ModdedConditionData & { innateName?: s
|
|||
},
|
||||
},
|
||||
|
||||
// Effects needed to be overriden for things to happen
|
||||
// Effects needed to be overridden for things to happen
|
||||
attract: {
|
||||
onStart(pokemon, source, effect) {
|
||||
if (!(pokemon.gender === 'M' && source.gender === 'F') && !(pokemon.gender === 'F' && source.gender === 'M')) {
|
||||
|
|
|
|||
|
|
@ -1402,6 +1402,85 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
type: "Fairy",
|
||||
},
|
||||
|
||||
// Cassiopeia
|
||||
testinginproduction: {
|
||||
accuracy: true,
|
||||
basePower: 0,
|
||||
category: "Status",
|
||||
shortDesc: "+2, -2 to random stats, small chance of harm.",
|
||||
desc: "The user boosts a random stat by 2 stages, and the user lowers a random stat by 2 stages. These can be the same stat, and cannot include Accuracy or Evasion. Independently, there is a 10% chance for the user to lose 10% of their maximum HP, and there is a 5% chance for the user to gain a random non-volatile status condition.",
|
||||
name: "Testing in Production",
|
||||
gen: 9,
|
||||
pp: 5,
|
||||
priority: 0,
|
||||
flags: {},
|
||||
onPrepareHit() {
|
||||
this.attrLastMove('[anim] Curse');
|
||||
},
|
||||
onHit(pokemon) {
|
||||
this.add(`c:|${getName((pokemon.illusion || pokemon).name)}|Please don't break...`);
|
||||
let stats: BoostID[] = [];
|
||||
const boost: SparseBoostsTable = {};
|
||||
let statPlus: BoostID;
|
||||
for (statPlus in pokemon.boosts) {
|
||||
if (statPlus === 'accuracy' || statPlus === 'evasion') continue;
|
||||
if (pokemon.boosts[statPlus] < 6) {
|
||||
stats.push(statPlus);
|
||||
}
|
||||
}
|
||||
let randomStat: BoostID | undefined = stats.length ? this.sample(stats) : undefined;
|
||||
if (randomStat) boost[randomStat] = 2;
|
||||
|
||||
stats = [];
|
||||
let statMinus: BoostID;
|
||||
for (statMinus in pokemon.boosts) {
|
||||
if (statMinus === 'accuracy' || statMinus === 'evasion') continue;
|
||||
if (pokemon.boosts[statMinus] > -6) {
|
||||
stats.push(statMinus);
|
||||
}
|
||||
}
|
||||
randomStat = stats.length ? this.sample(stats) : undefined;
|
||||
if (randomStat) {
|
||||
if (boost[randomStat]) {
|
||||
boost[randomStat] = 0;
|
||||
this.add(`c:|${getName((pokemon.illusion || pokemon).name)}|Well. Guess that broke. Time to roll back.`);
|
||||
return;
|
||||
} else {
|
||||
boost[randomStat] = -2;
|
||||
}
|
||||
}
|
||||
|
||||
this.boost(boost, pokemon, pokemon);
|
||||
},
|
||||
onAfterMove(pokemon) {
|
||||
if (this.randomChance(1, 10)) {
|
||||
this.add(`c:|${getName((pokemon.illusion || pokemon).name)}|Ouch! That crash is really getting on my nerves...`);
|
||||
this.damage(pokemon.baseMaxhp / 10);
|
||||
if (pokemon.hp <= 0) return;
|
||||
}
|
||||
|
||||
if (this.randomChance(1, 20)) {
|
||||
const status = this.sample(['frz', 'brn', 'psn', 'par']);
|
||||
let statusText = status;
|
||||
if (status === 'frz') {
|
||||
statusText = 'froze';
|
||||
} else if (status === 'brn') {
|
||||
statusText = 'burned';
|
||||
} else if (status === 'par') {
|
||||
statusText = 'paralyzed';
|
||||
} else if (status === 'psn') {
|
||||
statusText = 'poisoned';
|
||||
}
|
||||
|
||||
this.add(`c:|${getName((pokemon.illusion || pokemon).name)}|Darn. A bug ${statusText} me. Guess I should have tested this first.`);
|
||||
pokemon.setStatus(status);
|
||||
}
|
||||
},
|
||||
secondary: null,
|
||||
target: "self",
|
||||
type: "Electric",
|
||||
},
|
||||
|
||||
// chaos
|
||||
outage: {
|
||||
accuracy: 95,
|
||||
|
|
@ -2377,85 +2456,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
type: "Ghost",
|
||||
},
|
||||
|
||||
// Hecate
|
||||
testinginproduction: {
|
||||
accuracy: true,
|
||||
basePower: 0,
|
||||
category: "Status",
|
||||
shortDesc: "+2, -2 to random stats, small chance of harm.",
|
||||
desc: "The user boosts a random stat by 2 stages, and the user lowers a random stat by 2 stages. These can be the same stat, and cannot include Accuracy or Evasion. Independently, there is a 10% chance for the user to lose 10% of their maximum HP, and there is a 5% chance for the user to gain a random non-volatile status condition.",
|
||||
name: "Testing in Production",
|
||||
gen: 9,
|
||||
pp: 5,
|
||||
priority: 0,
|
||||
flags: {},
|
||||
onPrepareHit() {
|
||||
this.attrLastMove('[anim] Curse');
|
||||
},
|
||||
onHit(pokemon) {
|
||||
this.add(`c:|${getName((pokemon.illusion || pokemon).name)}|Please don't break...`);
|
||||
let stats: BoostID[] = [];
|
||||
const boost: SparseBoostsTable = {};
|
||||
let statPlus: BoostID;
|
||||
for (statPlus in pokemon.boosts) {
|
||||
if (statPlus === 'accuracy' || statPlus === 'evasion') continue;
|
||||
if (pokemon.boosts[statPlus] < 6) {
|
||||
stats.push(statPlus);
|
||||
}
|
||||
}
|
||||
let randomStat: BoostID | undefined = stats.length ? this.sample(stats) : undefined;
|
||||
if (randomStat) boost[randomStat] = 2;
|
||||
|
||||
stats = [];
|
||||
let statMinus: BoostID;
|
||||
for (statMinus in pokemon.boosts) {
|
||||
if (statMinus === 'accuracy' || statMinus === 'evasion') continue;
|
||||
if (pokemon.boosts[statMinus] > -6) {
|
||||
stats.push(statMinus);
|
||||
}
|
||||
}
|
||||
randomStat = stats.length ? this.sample(stats) : undefined;
|
||||
if (randomStat) {
|
||||
if (boost[randomStat]) {
|
||||
boost[randomStat] = 0;
|
||||
this.add(`c:|${getName((pokemon.illusion || pokemon).name)}|Well. Guess that broke. Time to roll back.`);
|
||||
return;
|
||||
} else {
|
||||
boost[randomStat] = -2;
|
||||
}
|
||||
}
|
||||
|
||||
this.boost(boost, pokemon, pokemon);
|
||||
},
|
||||
onAfterMove(pokemon) {
|
||||
if (this.randomChance(1, 10)) {
|
||||
this.add(`c:|${getName((pokemon.illusion || pokemon).name)}|Ouch! That crash is really getting on my nerves...`);
|
||||
this.damage(pokemon.baseMaxhp / 10);
|
||||
if (pokemon.hp <= 0) return;
|
||||
}
|
||||
|
||||
if (this.randomChance(1, 20)) {
|
||||
const status = this.sample(['frz', 'brn', 'psn', 'par']);
|
||||
let statusText = status;
|
||||
if (status === 'frz') {
|
||||
statusText = 'froze';
|
||||
} else if (status === 'brn') {
|
||||
statusText = 'burned';
|
||||
} else if (status === 'par') {
|
||||
statusText = 'paralyzed';
|
||||
} else if (status === 'psn') {
|
||||
statusText = 'poisoned';
|
||||
}
|
||||
|
||||
this.add(`c:|${getName((pokemon.illusion || pokemon).name)}|Darn. A bug ${statusText} me. Guess I should have tested this first.`);
|
||||
pokemon.setStatus(status);
|
||||
}
|
||||
},
|
||||
secondary: null,
|
||||
target: "self",
|
||||
type: "Electric",
|
||||
},
|
||||
|
||||
// HiZo
|
||||
scapegoat: {
|
||||
accuracy: true,
|
||||
|
|
@ -2696,7 +2696,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
basePower: 0,
|
||||
category: "Status",
|
||||
shortDesc: "Changes target to a Randbats set.",
|
||||
desc: "Z-Move requiring Irpatuzinium Z. Nearly always moves first. Permanently transforms the target into a randomized Pokemon that would be generated in one of the following formats: Gen 9 Random Battle, Gen 9 Hackmons Cup, Gen 9 Challenge Cup, or Computer-Generated Teams. In the vast majority of circumstances, this also prevents the target from acting this turn.",
|
||||
desc: "Z-Move requiring Irpatuzinium Z. Nearly always moves first. Permanently transforms the target into a randomized Pokemon that would be generated in one of the following formats: Gen 9 Random Battle, Gen 9 Hackmons Cup, or Gen 9 Challenge Cup. In the vast majority of circumstances, this also prevents the target from acting this turn.",
|
||||
name: "Bibbidi-Bobbidi-Rands",
|
||||
gen: 9,
|
||||
pp: 1,
|
||||
|
|
@ -2706,7 +2706,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
this.attrLastMove('[anim] Doom Desire');
|
||||
},
|
||||
onHit(target, source) {
|
||||
const formats = ['gen9randombattle', 'gen9hackmonscup', 'gen9challengecup1v1', 'gen9computergeneratedteams'];
|
||||
const formats = ['gen9randombattle', 'gen9hackmonscup', 'gen9challengecup1v1'];
|
||||
const randFormat = this.sample(formats);
|
||||
let msg;
|
||||
switch (randFormat) {
|
||||
|
|
@ -2719,9 +2719,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
case 'gen9challengecup1v1':
|
||||
msg = "The only difference between a Challenge Cup Pokémon and my in-game one is that the former actually surpassed lvl. 60, enjoy n.n";
|
||||
break;
|
||||
case 'gen9computergeneratedteams':
|
||||
msg = "We asked an AI to make a randbats set. YOU WON'T BELIEVE WHAT IT CAME UP WITH N.N";
|
||||
break;
|
||||
}
|
||||
let team = [] as PokemonSet[];
|
||||
const unModdedDex = Dex.mod('base');
|
||||
|
|
@ -3412,35 +3409,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
type: "Psychic",
|
||||
},
|
||||
|
||||
// Lily
|
||||
powerup: {
|
||||
accuracy: true,
|
||||
basePower: 0,
|
||||
category: "Status",
|
||||
name: "Power Up",
|
||||
shortDesc: "Heals 50% HP. Heals 3% more per fainted ally.",
|
||||
desc: "Heals the user for 50% of their maximum HP. Heals an additional 3% of the user's maximum HP for each team member on the user's side that has fainted.",
|
||||
pp: 5,
|
||||
priority: 0,
|
||||
flags: { heal: 1 },
|
||||
onModifyMove(move, source, target) {
|
||||
const fntAllies = source.side.pokemon.filter(ally => ally !== source && ally.fainted);
|
||||
if (move.heal) move.heal[0] = 50 + (3 * fntAllies.length);
|
||||
},
|
||||
onTryMove() {
|
||||
this.attrLastMove('[still]');
|
||||
},
|
||||
onPrepareHit(pokemon) {
|
||||
this.add('-anim', pokemon, 'Shore Up', pokemon);
|
||||
this.add('-anim', pokemon, 'Charge', pokemon);
|
||||
this.add('-anim', pokemon, 'Moonlight', pokemon);
|
||||
},
|
||||
heal: [50, 100],
|
||||
secondary: null,
|
||||
target: "self",
|
||||
type: "Electric",
|
||||
},
|
||||
|
||||
// Loethalion
|
||||
darkmooncackle: {
|
||||
accuracy: 100,
|
||||
|
|
|
|||
|
|
@ -220,6 +220,16 @@ export const Pokedex: import('../../../sim/dex-species').ModdedSpeciesDataTable
|
|||
abilities: { 0: "Huge Power" },
|
||||
},
|
||||
|
||||
// Cassiopeia
|
||||
mewtwo: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Hacking" },
|
||||
},
|
||||
mewtwomegax: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Hacking" },
|
||||
},
|
||||
|
||||
// chaos
|
||||
ironjugulis: {
|
||||
inherit: true,
|
||||
|
|
@ -396,16 +406,6 @@ export const Pokedex: import('../../../sim/dex-species').ModdedSpeciesDataTable
|
|||
abilities: { 0: "Mensis Cage" },
|
||||
},
|
||||
|
||||
// Hecate
|
||||
mewtwo: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Hacking" },
|
||||
},
|
||||
mewtwomegax: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Hacking" },
|
||||
},
|
||||
|
||||
// HiZo
|
||||
zoroarkhisui: {
|
||||
inherit: true,
|
||||
|
|
@ -559,12 +559,6 @@ export const Pokedex: import('../../../sim/dex-species').ModdedSpeciesDataTable
|
|||
abilities: { 0: "Persistent" },
|
||||
},
|
||||
|
||||
// Lily
|
||||
togedemaru: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Unaware" },
|
||||
},
|
||||
|
||||
// Loethalion
|
||||
ralts: {
|
||||
inherit: true,
|
||||
|
|
|
|||
|
|
@ -27,9 +27,9 @@ export const ssbSets: SSBSets = {
|
|||
signatureMove: 'Move Name',
|
||||
evs: {stat: number}, ivs: {stat: number}, nature: 'Nature', teraType: 'Type',
|
||||
},
|
||||
// Species, ability, and item need to be captialized properly ex: Ludicolo, Swift Swim, Life Orb
|
||||
// Species, ability, and item need to be capitalized properly ex: Ludicolo, Swift Swim, Life Orb
|
||||
// Gender can be M, F, N, or left as an empty string
|
||||
// each slot in moves needs to be a string (the move name, captialized properly ex: Hydro Pump), or an array of strings (also move names)
|
||||
// each slot in moves needs to be a string (the move name, capitalized properly ex: Hydro Pump), or an array of strings (also move names)
|
||||
// signatureMove also needs to be capitalized properly ex: Scripting
|
||||
// You can skip Evs (defaults to 84 all) and/or Ivs (defaults to 31 all), or just skip part of the Evs (skipped evs are 0) and/or Ivs (skipped Ivs are 31)
|
||||
// You can also skip shiny, defaults to false. Level can be skipped (defaults to 100).
|
||||
|
|
@ -264,6 +264,12 @@ export const ssbSets: SSBSets = {
|
|||
signatureMove: 'Good Vibes Only',
|
||||
evs: { hp: 4, atk: 252, spe: 252 }, nature: 'Adamant', teraType: 'Water', shiny: true,
|
||||
},
|
||||
Cassiopeia: {
|
||||
species: 'Mewtwo', ability: 'Hacking', item: 'Mewtwonite X', gender: 'F',
|
||||
moves: ['Photon Geyser', 'Drain Punch', 'Iron Head'],
|
||||
signatureMove: 'Testing in Production',
|
||||
evs: { atk: 252, spa: 4, spe: 252 }, nature: 'Jolly',
|
||||
},
|
||||
chaos: {
|
||||
species: 'Iron Jugulis', ability: 'Transistor', item: 'Heavy-Duty Boots', gender: 'N',
|
||||
moves: [['Oblivion Wing', 'Hurricane'], ['Thunderclap', 'Volt Switch'], ['Defog', 'Roost']],
|
||||
|
|
@ -433,12 +439,6 @@ export const ssbSets: SSBSets = {
|
|||
signatureMove: 'Augur of Ebrietas',
|
||||
evs: { spa: 252, spd: 4, spe: 252 }, nature: 'Timid', teraType: 'Ghost',
|
||||
},
|
||||
Hecate: {
|
||||
species: 'Mewtwo', ability: 'Hacking', item: 'Mewtwonite X', gender: 'F',
|
||||
moves: ['Photon Geyser', 'Drain Punch', 'Iron Head'],
|
||||
signatureMove: 'Testing in Production',
|
||||
evs: { atk: 252, spa: 4, spe: 252 }, nature: 'Jolly',
|
||||
},
|
||||
HiZo: {
|
||||
species: 'Zoroark-Hisui', ability: 'Justified', item: 'Heavy-Duty Boots', gender: 'M',
|
||||
moves: ['Last Respects', 'Blood Moon', 'Spirit Break'],
|
||||
|
|
@ -571,12 +571,6 @@ export const ssbSets: SSBSets = {
|
|||
signatureMove: 'Shuckle Power',
|
||||
evs: { hp: 252, def: 252, spd: 4 }, ivs: { spe: 0 }, nature: 'Relaxed', teraType: 'Ground', shiny: 213,
|
||||
},
|
||||
Lily: {
|
||||
species: 'Togedemaru', ability: 'Unaware', item: 'Leftovers', gender: 'F',
|
||||
moves: ['Victory Dance', 'Plasma Fists', 'Meteor Mash'],
|
||||
signatureMove: 'Power Up',
|
||||
evs: { hp: 252, def: 4, spd: 252 }, nature: 'Careful', teraType: 'Fairy', shiny: 1734,
|
||||
},
|
||||
Loethalion: {
|
||||
species: 'Ralts', ability: 'Psychic Surge', item: 'Gardevoirite', gender: '',
|
||||
moves: ['Esper Wing', 'Calm Mind', 'Lunar Blessing'],
|
||||
|
|
@ -1111,7 +1105,7 @@ export class RandomStaffBrosTeams extends RandomTeams {
|
|||
const debug: string[] = []; // Set this to a list of SSB sets to override the normal pool for debugging.
|
||||
const ruleTable = this.dex.formats.getRuleTable(this.format);
|
||||
const meme = ruleTable.has('dynamaxclause') && !debug.length;
|
||||
const afd = !ruleTable.has('dynamaxclause') && ruleTable.has('zmovesclause') && debug.length;
|
||||
const afd = !ruleTable.has('dynamaxclause') && ruleTable.has('zmoveclause') && !debug.length;
|
||||
const monotype = this.forceMonotype || (ruleTable.has('sametypeclause') ?
|
||||
this.sample(this.dex.types.names().filter(x => x !== 'Stellar')) : false);
|
||||
|
||||
|
|
@ -1124,7 +1118,7 @@ export class RandomStaffBrosTeams extends RandomTeams {
|
|||
}
|
||||
pool = debug;
|
||||
}
|
||||
if (monotype && !debug.length) {
|
||||
if (monotype && !debug.length && !afd && !meme) {
|
||||
pool = pool.filter(x => this.dex.species.get(ssbSets[x].species).types.includes(monotype));
|
||||
}
|
||||
if (global.Config?.disabledssbsets?.length) {
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ export function changeSet(context: Battle, pokemon: Pokemon, newSet: SSBSet, cha
|
|||
}
|
||||
const details = pokemon.getUpdatedDetails();
|
||||
if (oldShiny !== pokemon.set.shiny || oldGender !== pokemon.gender) context.add('replace', pokemon, details);
|
||||
if (changeAbility) pokemon.setAbility(newSet.ability as string, undefined, true);
|
||||
if (changeAbility) pokemon.setAbility(newSet.ability as string, undefined, undefined, true);
|
||||
|
||||
pokemon.baseMaxhp = pokemon.species.name === 'Shedinja' ? 1 : Math.floor(Math.floor(
|
||||
2 * pokemon.species.baseStats.hp + pokemon.set.ivs.hp + Math.floor(pokemon.set.evs.hp / 4) + 100
|
||||
|
|
@ -387,7 +387,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
if (!species) continue;
|
||||
pokemon.baseSpecies = rawSpecies;
|
||||
pokemon.details = pokemon.getUpdatedDetails();
|
||||
// pokemon.setAbility(species.abilities['0'], null, true);
|
||||
// pokemon.setAbility(species.abilities['0'], null, null, true);
|
||||
// pokemon.baseAbility = pokemon.ability;
|
||||
|
||||
const behemothMove: { [k: string]: string } = {
|
||||
|
|
@ -696,13 +696,6 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
if (pokemon.species.name === 'Terapagos-Terastal' && type === 'Stellar') {
|
||||
pokemon.formeChange('Terapagos-Stellar', null, 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.baseMaxhp;
|
||||
pokemon.hp = newMaxHP - (pokemon.maxhp - pokemon.hp);
|
||||
pokemon.maxhp = newMaxHP;
|
||||
this.battle.add('-heal', pokemon, pokemon.getHealth, '[silent]');
|
||||
}
|
||||
if (!pokemon.illusion && pokemon.name === 'Neko') {
|
||||
this.battle.add(`c:|${getName('Neko')}|Possible thermal failure if operation continues (Meow on fire ?)`);
|
||||
|
|
@ -908,8 +901,8 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
} else {
|
||||
this.battle.add(isDrag ? 'drag' : 'switch', pokemon, pokemon.getFullDetails);
|
||||
}
|
||||
pokemon.abilityState.effectOrder = this.battle.effectOrder++;
|
||||
pokemon.itemState.effectOrder = this.battle.effectOrder++;
|
||||
pokemon.abilityState = this.battle.initEffectState({ id: pokemon.ability, target: pokemon });
|
||||
pokemon.itemState = this.battle.initEffectState({ id: pokemon.item, target: pokemon });
|
||||
if (isDrag && this.battle.gen === 2) pokemon.draggedIn = this.battle.turn;
|
||||
pokemon.previouslySwitchedIn++;
|
||||
|
||||
|
|
@ -943,7 +936,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
|
||||
pokemon.formeChange(speciesid, pokemon.getItem(), true);
|
||||
if (pokemon.canMegaEvo) {
|
||||
pokemon.canMegaEvo = null;
|
||||
pokemon.canMegaEvo = false;
|
||||
} else {
|
||||
pokemon.canUltraBurst = null;
|
||||
}
|
||||
|
|
@ -971,8 +964,23 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
return altForme.name;
|
||||
}
|
||||
// a hacked-in Megazard X can mega evolve into Megazard Y, but not into Megazard X
|
||||
if (item.megaEvolves === species.baseSpecies && item.megaStone !== species.name) {
|
||||
return item.megaStone;
|
||||
if (Array.isArray(item.megaEvolves)) {
|
||||
if (!Array.isArray(item.megaStone)) {
|
||||
throw new Error(`${item.name}#megaEvolves and ${item.name}#megaStone type mismatch`);
|
||||
}
|
||||
if (item.megaEvolves.length !== item.megaStone.length) {
|
||||
throw new Error(`${item.name}#megaEvolves and ${item.name}#megaStone length mismatch`);
|
||||
}
|
||||
// FIXME: Change to species.name when champions comes
|
||||
const index = item.megaEvolves.indexOf(species.baseSpecies);
|
||||
if (index < 0) return null;
|
||||
return item.megaStone[index];
|
||||
// FIXME: Change to species.name when champions comes
|
||||
} else {
|
||||
if (item.megaEvolves === species.baseSpecies) {
|
||||
if (Array.isArray(item.megaStone)) throw new Error(`${item.name}#megaEvolves and ${item.name}#megaStone type mismatch`);
|
||||
return item.megaStone;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
|
@ -1313,7 +1321,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
|
||||
let movename = move.name;
|
||||
if (move.id === 'hiddenpower') movename = 'Hidden Power';
|
||||
if (sourceEffect) attrs += `|[from]${sourceEffect.fullname}`;
|
||||
if (sourceEffect) attrs += `|[from] ${sourceEffect.fullname}`;
|
||||
if (zMove && move.isZ === true) {
|
||||
attrs = '|[anim]' + movename + attrs;
|
||||
movename = 'Z-' + movename;
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
const item = this.data.Items[i];
|
||||
if (!item.megaStone && !item.onDrive && !(item.onPlate && !item.zMove) && !item.onMemory) continue;
|
||||
this.modData('Items', i).onTakeItem = false;
|
||||
if (item.isNonstandard === "Past") this.modData('Items', i).isNonstandard = null;
|
||||
if (item.megaStone) {
|
||||
if (item.isNonstandard === "Past" || item.isNonstandard === "Future") this.modData('Items', i).isNonstandard = null;
|
||||
/* if (item.megaStone) {
|
||||
this.modData('FormatsData', this.toID(item.megaStone)).isNonstandard = null;
|
||||
}
|
||||
} */
|
||||
}
|
||||
},
|
||||
start() {
|
||||
|
|
@ -83,27 +83,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
this.add(`raw|<div class="infobox"><details class="readmore"${open}><summary><strong>${format.customRules.length} custom rule${plural}:</strong></summary> ${format.customRules.join(', ')}</details></div>`);
|
||||
}
|
||||
|
||||
format.onTeamPreview?.call(this);
|
||||
for (const rule of this.ruleTable.keys()) {
|
||||
if ('+*-!'.includes(rule.charAt(0))) continue;
|
||||
const subFormat = this.dex.formats.get(rule);
|
||||
subFormat.onTeamPreview?.call(this);
|
||||
}
|
||||
|
||||
if (this.requestState !== 'teampreview' && this.ruleTable.pickedTeamSize) {
|
||||
this.add('clearpoke');
|
||||
for (const side of this.sides) {
|
||||
for (const pokemon of side.pokemon) {
|
||||
// Still need to hide these formes since they change on battle start
|
||||
const details = pokemon.details.replace(', shiny', '')
|
||||
.replace(/(Zacian|Zamazenta)(?!-Crowned)/g, '$1-*')
|
||||
.replace(/(Xerneas)(-[a-zA-Z?-]+)?/g, '$1-*');
|
||||
this.addSplit(side.id, ['poke', pokemon.side.id, details, '']);
|
||||
}
|
||||
}
|
||||
this.makeRequest('teampreview');
|
||||
}
|
||||
|
||||
this.runPickTeam();
|
||||
this.queue.addChoice({ choice: 'start' });
|
||||
this.midTurn = true;
|
||||
if (!this.requestState) this.turnLoop();
|
||||
|
|
@ -406,8 +386,8 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
|
||||
const item = pokemon.getItem();
|
||||
if (item.megaStone) {
|
||||
if (item.megaStone === pokemon.baseSpecies.name) return null;
|
||||
return item.megaStone;
|
||||
if (item.megaStone.includes(pokemon.baseSpecies.name)) return null;
|
||||
return Array.isArray(item.megaStone) ? item.megaStone[0] : item.megaStone;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -425,12 +405,12 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
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.length !== pokemon.species.types.length || oSpecies.types[1] !== pokemon.species.types[1]) {
|
||||
if (oSpecies.types.join('/') !== pokemon.species.types.join('/')) {
|
||||
this.battle.add('-start', pokemon, 'typechange', pokemon.species.types.join('/'), '[silent]');
|
||||
}
|
||||
// }
|
||||
|
||||
pokemon.canMegaEvo = null;
|
||||
pokemon.canMegaEvo = false;
|
||||
return true;
|
||||
},
|
||||
terastallize(pokemon) {
|
||||
|
|
@ -486,7 +466,12 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
return species;
|
||||
},
|
||||
getFormeChangeDeltas(formeChangeSpecies, pokemon) {
|
||||
const baseSpecies = this.dex.species.get(formeChangeSpecies.baseSpecies);
|
||||
// Should be fine as long as Necrozma-U doesn't get added or Game Freak makes me sad with some convoluted forme change
|
||||
let baseSpecies = this.dex.species.get(formeChangeSpecies.isMega ?
|
||||
formeChangeSpecies.battleOnly as string : formeChangeSpecies.baseSpecies);
|
||||
if (formeChangeSpecies.name === 'Zygarde-Mega') {
|
||||
baseSpecies = this.dex.species.get('Zygarde-Complete');
|
||||
}
|
||||
const deltas: {
|
||||
ability: string,
|
||||
baseStats: SparseStatsTable,
|
||||
|
|
@ -496,6 +481,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
requiredItem: string | undefined,
|
||||
type?: string,
|
||||
formeType?: string,
|
||||
isMega?: boolean,
|
||||
} = {
|
||||
ability: formeChangeSpecies.abilities['0'],
|
||||
baseStats: {},
|
||||
|
|
@ -511,15 +497,19 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
let formeType: string | null = null;
|
||||
if (['Arceus', 'Silvally'].includes(baseSpecies.name)) {
|
||||
deltas.type = formeChangeSpecies.types[0];
|
||||
formeType = 'Arceus';
|
||||
formeType = 'Primary';
|
||||
} else if (formeChangeSpecies.types.length > baseSpecies.types.length) {
|
||||
deltas.type = formeChangeSpecies.types[1];
|
||||
} else if (formeChangeSpecies.types.length < baseSpecies.types.length) {
|
||||
deltas.type = this.battle.ruleTable.has('mixandmegaoldaggronite') ? 'mono' : baseSpecies.types[0];
|
||||
} else if (formeChangeSpecies.types[1] !== baseSpecies.types[1]) {
|
||||
deltas.type = formeChangeSpecies.types[1];
|
||||
} else if (formeChangeSpecies.types[0] !== baseSpecies.types[0]) {
|
||||
deltas.type = formeChangeSpecies.types[0];
|
||||
formeType = 'Primary';
|
||||
deltas.isMega = true;
|
||||
}
|
||||
if (formeChangeSpecies.isMega) formeType = 'Mega';
|
||||
if (formeChangeSpecies.isMega && !formeType) formeType = 'Mega';
|
||||
if (formeChangeSpecies.isPrimal) formeType = 'Primal';
|
||||
if (formeChangeSpecies.name.endsWith('Crowned')) formeType = 'Crowned';
|
||||
if (formeType) deltas.formeType = formeType;
|
||||
|
|
@ -533,7 +523,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
if (!deltas) throw new TypeError("Must specify deltas!");
|
||||
const species = this.dex.deepClone(this.dex.species.get(speciesOrForme));
|
||||
species.abilities = { '0': deltas.ability };
|
||||
if (deltas.formeType === 'Arceus') {
|
||||
if (deltas.formeType === 'Primary') {
|
||||
const secondType = species.types[1];
|
||||
species.types = [deltas.type];
|
||||
if (secondType && secondType !== deltas.type) species.types.push(secondType);
|
||||
|
|
@ -552,7 +542,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
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') species.isMega = true;
|
||||
if (deltas.formeType === 'Mega' || deltas.isMega) species.isMega = true;
|
||||
if (deltas.formeType === 'Primal') species.isPrimal = true;
|
||||
return species;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
if (!species) continue;
|
||||
pokemon.baseSpecies = rawSpecies;
|
||||
pokemon.details = pokemon.getUpdatedDetails();
|
||||
pokemon.setAbility(species.abilities['0'], null, true);
|
||||
pokemon.setAbility(species.abilities['0'], null, null, true);
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
|
||||
const behemothMove: { [k: string]: string } = {
|
||||
|
|
|
|||
|
|
@ -311,28 +311,36 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
this.makeRequest('move');
|
||||
},
|
||||
pokemon: {
|
||||
setAbility(ability, source, isFromFormeChange) {
|
||||
setAbility(ability, source, sourceEffect, isFromFormeChange, isTransform) {
|
||||
if (!this.hp) return false;
|
||||
const BAD_ABILITIES = ['trace', 'imposter', 'neutralizinggas', 'illusion', 'wanderingspirit'];
|
||||
if (typeof ability === 'string') ability = this.battle.dex.abilities.get(ability);
|
||||
const oldAbility = this.ability;
|
||||
if (!sourceEffect && this.battle.effect) sourceEffect = this.battle.effect;
|
||||
const oldAbility = this.battle.dex.abilities.get(this.ability);
|
||||
if (!isFromFormeChange) {
|
||||
if (ability.flags['cantsuppress'] || this.getAbility().flags['cantsuppress']) return false;
|
||||
}
|
||||
if (!this.battle.runEvent('SetAbility', this, source, this.battle.effect, ability)) return false;
|
||||
this.battle.singleEvent('End', this.battle.dex.abilities.get(oldAbility), this.abilityState, this, source);
|
||||
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);
|
||||
const ally = this.side.active.find(mon => mon && mon !== this && !mon.fainted);
|
||||
if (ally?.m.innate) {
|
||||
ally.removeVolatile(ally.m.innate);
|
||||
delete ally.m.innate;
|
||||
}
|
||||
if (this.battle.effect && this.battle.effect.effectType === 'Move' && !isFromFormeChange) {
|
||||
this.battle.add('-endability', this, this.battle.dex.abilities.get(oldAbility),
|
||||
`[from] move: ${this.battle.dex.moves.get(this.battle.effect.id)}`);
|
||||
}
|
||||
this.ability = ability.id;
|
||||
this.abilityState = this.battle.initEffectState({ id: ability.id, target: this });
|
||||
if (ability.id && this.battle.gen > 3) {
|
||||
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 (ally && ally.ability !== this.ability) {
|
||||
if (!this.m.innate) {
|
||||
|
|
@ -345,12 +353,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
}
|
||||
}
|
||||
// Entrainment
|
||||
if (this.m.innate?.endsWith(ability.id)) {
|
||||
this.removeVolatile(this.m.innate);
|
||||
delete this.m.innate;
|
||||
}
|
||||
return oldAbility;
|
||||
return oldAbility.id;
|
||||
},
|
||||
hasAbility(ability) {
|
||||
if (this.ignoringAbility()) return false;
|
||||
|
|
@ -446,7 +449,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
this.knownType = true;
|
||||
this.apparentType = this.terastallized;
|
||||
}
|
||||
if (this.battle.gen > 2) this.setAbility(pokemon.ability, this, true, true);
|
||||
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
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
this.apparentType = this.terastallized;
|
||||
}
|
||||
if (this.battle.gen > 2) {
|
||||
this.setAbility(pokemon.ability, this, true);
|
||||
this.setAbility(pokemon.ability, this, null, true);
|
||||
if (this.m.innates) {
|
||||
for (const innate of this.m.innates) {
|
||||
this.removeVolatile('ability:' + innate);
|
||||
|
|
@ -202,7 +202,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
if (this.illusion) {
|
||||
this.ability = ''; // Don't allow Illusion to wear off
|
||||
}
|
||||
this.setAbility(species.abilities['0'], null, true);
|
||||
this.setAbility(species.abilities['0'], null, null, true);
|
||||
this.baseAbility = this.ability;
|
||||
}
|
||||
if (this.terastallized && this.terastallized !== this.apparentType) {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user