Merge branch 'master' into magician-tests

This commit is contained in:
André Bastos Dias 2026-04-12 14:19:58 +01:00 committed by GitHub
commit 52f2273e71
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
251 changed files with 49933 additions and 18639 deletions

View File

@ -15,7 +15,7 @@ jobs:
last_version: ${{ steps.last_version.outputs.version }}
token_exists: ${{ steps.check_token.outputs.token }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
fetch-depth: 50
# Check if the package.json version field has changed since the last push
@ -40,8 +40,8 @@ jobs:
# We only want to publish if the package.json version field has changed
if: needs.get-version.outputs.current_version != needs.get-version.outputs.last_version && needs.get-version.outputs.token_exists == 'true'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 18
cache: 'npm'

View File

@ -28,12 +28,12 @@ jobs:
node-version: ['18.x']
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
fetch-depth: 100 # assumes PR/push to master is no larger than 100 commits. Other solutions are needlessly complex.
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
@ -43,7 +43,7 @@ jobs:
- name: Determine which files to lint (if pull request)
if: ${{ github.event_name == 'pull_request' }}
id: changed-files
uses: tj-actions/changed-files@v35
uses: tj-actions/changed-files@v47
with:
files: |
./config/*.ts
@ -66,7 +66,7 @@ jobs:
- name: Determine whether test/sim or test/random-battles need to run (if pull request)
if: ${{ github.event_name == 'pull_request' }}
id: changed-directories
uses: tj-actions/changed-files@v35
uses: tj-actions/changed-files@v47
with:
files: |
config/formats.ts

View File

@ -21,9 +21,9 @@ jobs:
update_version:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
node-version: 18
cache: 'npm'
@ -34,7 +34,7 @@ jobs:
npm version ${{ github.event.inputs.version }} --no-git-tag-version
echo "new_version=$(jq -r .version package.json)" >> "$GITHUB_OUTPUT"
- uses: peter-evans/create-pull-request@v7
- uses: peter-evans/create-pull-request@v8
with:
title: Bump package.json version to v${{ steps.bump_version.outputs.new_version }}
body: |

View File

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

View File

@ -7,9 +7,9 @@ Pokémon Showdown is implemented in SockJS. SockJS is a compatibility
layer over raw WebSocket, so you can actually connect to Pokémon
Showdown directly using WebSocket:
ws://sim.smogon.com:8000/showdown/websocket
or
wss://sim3.psim.us/showdown/websocket
or
ws://sim3.psim.us:8000/showdown/websocket
Client implementations you might want to look at for reference include:

View File

@ -25,6 +25,15 @@ exports.bindaddress = '0.0.0.0';
*/
exports.wsdeflate = null;
/**
* lazysockets - disables eager initialization of network services
* Turn this on if you'd prefer to manually connect Showdown to the network,
* or you intend to run it offline.
*
* @type {boolean}
*/
exports.lazysockets = false;
/*
// example:
exports.wsdeflate = {

File diff suppressed because it is too large Load Diff

View File

@ -1003,6 +1003,28 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
rating: 3.5,
num: 88,
},
dragonize: {
isNonstandard: "Future",
onModifyTypePriority: -1,
onModifyType(move, pokemon) {
const noModifyType = [
'judgment', 'multiattack', 'naturalgift', 'revelationdance', 'technoblast', 'terrainpulse', 'weatherball',
];
if (move.type === 'Normal' && (!noModifyType.includes(move.id) || this.activeMove?.isMax) &&
!(move.isZ && move.category !== 'Status') && !(move.name === 'Tera Blast' && pokemon.terastallized)) {
move.type = 'Dragon';
move.typeChangerBoosted = this.effect;
}
},
onBasePowerPriority: 23,
onBasePower(basePower, pokemon, target, move) {
if (move.typeChangerBoosted === this.effect) return this.chainModify([4915, 4096]);
},
flags: {},
name: "Dragonize",
rating: 4,
num: 312,
},
dragonsmaw: {
onModifyAtkPriority: 5,
onModifyAtk(atk, attacker, defender, move) {
@ -1059,7 +1081,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
}
},
onWeather(target, source, effect) {
if (target.hasItem('utilityumbrella')) return;
if (target.effectiveWeather() !== effect.id) return;
if (effect.id === 'raindance' || effect.id === 'primordialsea') {
this.heal(target.baseMaxhp / 8);
} else if (effect.id === 'sunnyday' || effect.id === 'desolateland') {
@ -1094,14 +1116,14 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
},
effectspore: {
onDamagingHit(damage, target, source, move) {
if (this.checkMoveMakesContact(move, source, target) && !source.status && source.runStatusImmunity('powder')) {
if (this.checkMoveMakesContact(move, source, target) && source.runStatusImmunity('powder')) {
const r = this.random(100);
if (r < 11) {
source.setStatus('slp', target);
source.trySetStatus('slp', target);
} else if (r < 21) {
source.setStatus('par', target);
source.trySetStatus('par', target);
} else if (r < 30) {
source.setStatus('psn', target);
source.trySetStatus('psn', target);
}
}
},
@ -1987,7 +2009,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
}
},
onEnd(pokemon) {
if (pokemon.illusion) {
if (pokemon.illusion && !pokemon.beingCalledBack) {
this.debug('illusion cleared');
pokemon.illusion = null;
const details = pokemon.getUpdatedDetails();
@ -2303,10 +2325,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
return;
}
if (this.checkMoveMakesContact(move, source, target, !source.isAlly(target))) {
const oldAbility = source.setAbility('lingeringaroma', target);
if (oldAbility) {
this.add('-activate', target, 'ability: Lingering Aroma', this.dex.abilities.get(oldAbility).name, `[of] ${source}`);
}
source.setAbility('lingeringaroma', target);
}
},
flags: {},
@ -2474,6 +2493,20 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
rating: 3,
num: 178,
},
megasol: {
isNonstandard: "Future",
onWeatherModifyDamage(damage, attacker, defender, move) {
if (this.field.weather !== 'sunnyday') {
(this.dex.conditions.getByID('sunnyday' as ID) as any).onWeatherModifyDamage
.call(this, damage, attacker, defender, move);
}
},
flags: {},
name: "Mega Sol",
rating: 3,
num: 315,
// Partially implemented in Pokemon.effectiveWeather() in sim/pokemon.ts
},
merciless: {
onModifyCritRatio(critRatio, source, target) {
if (target && ['psn', 'tox'].includes(target.status)) return 5;
@ -2688,10 +2721,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
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}`);
}
source.setAbility('mummy', target);
}
},
flags: {},
@ -3187,6 +3217,20 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
rating: 0.5,
num: 53,
},
piercingdrill: {
isNonstandard: "Future",
onHitProtect(source, target, move) {
if (move.flags['contact']) {
target.getMoveHitData(move).bypassProtect = this.effect;
return false;
}
},
// breaking protect handled in Battle#checkMoveBypassesProtect()
flags: {},
name: "Piercing Drill",
rating: 1,
num: 311,
},
pixilate: {
onModifyTypePriority: -1,
onModifyType(move, pokemon) {
@ -3652,7 +3696,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
},
raindish: {
onWeather(target, source, effect) {
if (target.hasItem('utilityumbrella')) return;
if (target.effectiveWeather() !== effect.id) return;
if (effect.id === 'raindance' || effect.id === 'primordialsea') {
this.heal(target.baseMaxhp / 16);
}
@ -4095,7 +4139,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
},
sheerforce: {
onModifyMove(move, pokemon) {
if (move.secondaries) {
if (move.secondaries && !move.hasSheerForceBoost) {
delete move.secondaries;
// Technically not a secondary effect, but it is negated
delete move.self;
@ -4106,7 +4150,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
},
onBasePowerPriority: 21,
onBasePower(basePower, pokemon, target, move) {
if (move.hasSheerForce) return this.chainModify([5325, 4096]);
if (move.hasSheerForce || move.hasSheerForceBoost) return this.chainModify([5325, 4096]);
},
flags: {},
name: "Sheer Force",
@ -4229,6 +4273,10 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
return this.chainModify(0.5);
}
},
onEnd(pokemon) {
if (pokemon.beingCalledBack) return;
this.add('-end', pokemon, 'Slow Start', '[silent]');
},
flags: {},
name: "Slow Start",
rating: -1,
@ -4291,7 +4339,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
}
},
onWeather(target, source, effect) {
if (target.hasItem('utilityumbrella')) return;
if (target.effectiveWeather() !== effect.id) return;
if (effect.id === 'sunnyday' || effect.id === 'desolateland') {
this.damage(target.baseMaxhp / 8, target, target);
}
@ -4353,6 +4401,16 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
rating: 4.5,
num: 3,
},
spicyspray: {
isNonstandard: "Future",
onDamagingHit(damage, target, source, move) {
source.trySetStatus('brn', target);
},
flags: {},
name: "Spicy Spray",
rating: 3,
num: 318,
},
stakeout: {
onModifyAtkPriority: 5,
onModifyAtk(atk, attacker, defender) {
@ -5240,20 +5298,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
},
wanderingspirit: {
onDamagingHit(damage, target, source, move) {
if (source.getAbility().flags['failskillswap'] || target.volatiles['dynamax']) return;
if (this.checkMoveMakesContact(move, source, target)) {
const targetCanBeSet = this.runEvent('SetAbility', target, source, this.effect, source.ability);
if (!targetCanBeSet) return targetCanBeSet;
const sourceAbility = source.setAbility('wanderingspirit', target);
if (!sourceAbility) return;
if (target.isAlly(source)) {
this.add('-activate', target, 'Skill Swap', '', '', `[of] ${source}`);
} else {
this.add('-activate', target, 'ability: Wandering Spirit', this.dex.abilities.get(sourceAbility).name, 'Wandering Spirit', `[of] ${source}`);
}
target.setAbility(sourceAbility);
}
if (this.checkMoveMakesContact(move, source, target)) this.skillSwap(source, target);
},
flags: {},
name: "Wandering Spirit",

View File

@ -15,9 +15,11 @@ 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 J",
vgc: "[Gen 9] VGC 2026 Reg F",
bsd: "[Gen 9] VGC 2026 Reg F",
champsou: "[Gen 9 Champions] OU",
cou: "[Gen 9 Champions] OU",
bss: "[Gen 9 Champions] BSS Reg M-A",
vgc: "[Gen 9 Champions] VGC 2026 Reg M-A",
bsd: "[Gen 9 Champions] VGC 2026 Reg M-A",
randdubs: "[Gen 9] Random Doubles Battle",
doubles: "[Gen 9] Doubles OU",
dou: "[Gen 9] Doubles OU",
@ -91,8 +93,10 @@ export const Aliases: import('../sim/dex').AliasesTable = {
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",
omotm: "[Gen 9] Alphabet Cup",
lcotm: "[Gen 9] Cross Evolution",
ommotm: "[Gen 9] STAAABmons",
ommspotlight: "[Gen 9] STAAABmons",
// mega evos --- 1st ordered alphabetically by species, 2nd by alias
megasnow: "Abomasnow-Mega",

View File

@ -484,7 +484,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
return 5;
},
onWeatherModifyDamage(damage, attacker, defender, move) {
if (defender.hasItem('utilityumbrella')) return;
if (defender.effectiveWeather() !== 'raindance') return;
if (move.type === 'Water') {
this.debug('rain water boost');
return this.chainModify(1.5);
@ -525,7 +525,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
}
},
onWeatherModifyDamage(damage, attacker, defender, move) {
if (defender.hasItem('utilityumbrella')) return;
if (defender.effectiveWeather() !== 'primordialsea') return;
if (move.type === 'Water') {
this.debug('Rain water boost');
return this.chainModify(1.5);
@ -554,11 +554,11 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
return 5;
},
onWeatherModifyDamage(damage, attacker, defender, move) {
if (move.id === 'hydrosteam' && !attacker.hasItem('utilityumbrella')) {
if (move.id === 'hydrosteam' && attacker.effectiveWeather() === 'sunnyday') {
this.debug('Sunny Day Hydro Steam boost');
return this.chainModify(1.5);
}
if (defender.hasItem('utilityumbrella')) return;
if (defender.effectiveWeather() !== 'sunnyday') return;
if (move.type === 'Fire') {
this.debug('Sunny Day fire boost');
return this.chainModify(1.5);
@ -577,7 +577,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
}
},
onImmunity(type, pokemon) {
if (pokemon.hasItem('utilityumbrella')) return;
if (pokemon.effectiveWeather() !== 'sunnyday') return;
if (type === 'frz') return false;
},
onFieldResidualOrder: 1,
@ -603,9 +603,9 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
}
},
onWeatherModifyDamage(damage, attacker, defender, move) {
if (defender.hasItem('utilityumbrella')) return;
if (defender.effectiveWeather() !== 'desolateland') return;
if (move.type === 'Fire') {
this.debug('Sunny Day fire boost');
this.debug('Desolate Land fire boost');
return this.chainModify(1.5);
}
},
@ -613,7 +613,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
this.add('-weather', 'DesolateLand', '[from] ability: ' + effect.name, `[of] ${source}`);
},
onImmunity(type, pokemon) {
if (pokemon.hasItem('utilityumbrella')) return;
if (pokemon.effectiveWeather() !== 'desolateland') return;
if (type === 'frz') return false;
},
onFieldResidualOrder: 1,
@ -879,6 +879,67 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
return [type];
},
},
zacian: {
name: 'Zacian',
onBattleStart(pokemon) {
if (pokemon.item !== 'rustedsword') return;
const rawSpecies = this.dex.species.get('Zacian-Crowned');
const species = pokemon.setSpecies(rawSpecies);
if (!species) return;
pokemon.baseSpecies = rawSpecies;
pokemon.details = pokemon.getUpdatedDetails();
pokemon.setAbility(species.abilities['0'], null, null, true);
pokemon.baseAbility = pokemon.ability;
const ironHeadIndex = pokemon.baseMoves.indexOf('ironhead');
if (ironHeadIndex >= 0) {
const move = this.dex.moves.get('behemothblade');
const pp = this.calculatePP(move, pokemon.ppUps[ironHeadIndex]);
pokemon.baseMoveSlots[ironHeadIndex] = {
move: move.name,
id: move.id,
pp,
maxpp: pp,
target: move.target,
disabled: false,
disabledSource: '',
used: false,
};
pokemon.moveSlots = pokemon.baseMoveSlots.slice();
}
},
},
zamazenta: {
name: 'Zamazenta',
onBattleStart(pokemon) {
if (pokemon.item !== 'rustedshield') return;
const rawSpecies = this.dex.species.get('Zamazenta-Crowned');
const species = pokemon.setSpecies(rawSpecies);
if (!species) return;
pokemon.baseSpecies = rawSpecies;
pokemon.details = pokemon.getUpdatedDetails();
pokemon.setAbility(species.abilities['0'], null, null, true);
pokemon.baseAbility = pokemon.ability;
const ironHeadIndex = pokemon.baseMoves.indexOf('ironhead');
if (ironHeadIndex >= 0) {
const move = this.dex.moves.get('behemothbash');
const pp = this.calculatePP(move, pokemon.ppUps[ironHeadIndex]);
pokemon.baseMoveSlots[ironHeadIndex] = {
move: move.name,
id: move.id,
pp,
maxpp: pp,
target: move.target,
disabled: false,
disabledSource: '',
used: false,
};
pokemon.moveSlots = pokemon.baseMoveSlots.slice();
}
},
},
rolloutstorage: {
name: 'rolloutstorage',
duration: 2,

View File

@ -101,7 +101,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
beedrillmega: {
isNonstandard: "Past",
tier: "Illegal",
natDexTier: "UU",
natDexTier: "RU",
},
pidgey: {
isNonstandard: "Past",
@ -381,7 +381,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
tier: "NFE",
},
vileplume: {
tier: "NU",
tier: "PU",
doublesTier: "(DUU)",
natDexTier: "RU",
},
@ -464,7 +464,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
tier: "LC",
},
primeape: {
tier: "ZU",
tier: "NFE",
doublesTier: "NFE",
natDexTier: "NFE",
},
@ -475,7 +475,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
tier: "LC",
},
arcanine: {
tier: "PU",
tier: "NU",
doublesTier: "(DUU)",
natDexTier: "RU",
},
@ -560,7 +560,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
tentacruel: {
tier: "NU",
doublesTier: "(DUU)",
natDexTier: "UU",
natDexTier: "RU",
},
geodude: {
tier: "LC",
@ -613,7 +613,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
slowbro: {
tier: "RU",
doublesTier: "(DUU)",
natDexTier: "UU",
natDexTier: "OU",
},
slowbromega: {
isNonstandard: "Past",
@ -621,7 +621,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
natDexTier: "RUBL",
},
slowbrogalar: {
tier: "NU",
tier: "PU",
doublesTier: "(DUU)",
natDexTier: "RU",
},
@ -696,7 +696,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
natDexTier: "RU",
},
shellder: {
tier: "LC",
tier: "NFE",
},
cloyster: {
tier: "NUBL",
@ -1116,7 +1116,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
tier: "NFE",
},
porygon2: {
tier: "ZUBL",
tier: "PU",
doublesTier: "DUU",
natDexTier: "NFE",
},
@ -1159,7 +1159,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
tier: "LC",
},
snorlax: {
tier: "ZU",
tier: "PU",
doublesTier: "(DUU)",
natDexTier: "RU",
},
@ -1194,7 +1194,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
},
moltresgalar: {
tier: "UUBL",
doublesTier: "DUU",
doublesTier: "DOU",
natDexTier: "RUBL",
},
dratini: {
@ -1228,7 +1228,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
natDexTier: "Uber",
},
mew: {
tier: "RU",
tier: "UU",
doublesTier: "DUU",
natDexTier: "UU",
},
@ -1316,7 +1316,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
tier: "LC",
},
lanturn: {
tier: "ZU",
tier: "PU",
doublesTier: "(DUU)",
natDexTier: "RU",
},
@ -1521,17 +1521,19 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
natDexTier: "RU",
},
heracross: {
tier: "PUBL",
tier: "PU",
doublesTier: "(DUU)",
natDexTier: "RU",
},
heracrossmega: {
isNonstandard: "Past",
tier: "Illegal",
natDexTier: "UU",
natDexTier: "RUBL",
},
sneasel: {
tier: "NFE",
tier: "ZU",
doublesTier: "NFE",
natDexTier: "NFE",
},
sneaselhisui: {
tier: "ZU",
@ -1557,7 +1559,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
ursaluna: {
tier: "UUBL",
doublesTier: "DOU",
natDexTier: "UU",
natDexTier: "RUBL",
},
ursalunabloodmoon: {
tier: "Uber",
@ -1579,7 +1581,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
tier: "NFE",
},
mamoswine: {
tier: "RUBL",
tier: "UU",
doublesTier: "(DUU)",
natDexTier: "RUBL",
},
@ -1700,7 +1702,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
tyranitarmega: {
isNonstandard: "Past",
tier: "Illegal",
natDexTier: "UUBL",
natDexTier: "OU",
},
lugia: {
tier: "Uber",
@ -1758,7 +1760,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
swampert: {
tier: "NU",
doublesTier: "(DUU)",
natDexTier: "RU",
natDexTier: "UU",
},
swampertmega: {
isNonstandard: "Past",
@ -1877,11 +1879,11 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
gardevoirmega: {
isNonstandard: "Past",
tier: "Illegal",
natDexTier: "RUBL",
natDexTier: "UU",
},
gallade: {
tier: "RU",
doublesTier: "(DUU)",
doublesTier: "DUU",
natDexTier: "RU",
},
gallademega: {
@ -1980,7 +1982,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
sableyemega: {
isNonstandard: "Past",
tier: "Illegal",
natDexTier: "RUBL",
natDexTier: "UU",
},
mawile: {
isNonstandard: "Past",
@ -2096,7 +2098,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
sharpedomega: {
isNonstandard: "Past",
tier: "Illegal",
natDexTier: "RU",
natDexTier: "RUBL",
},
wailmer: {
isNonstandard: "Past",
@ -2701,7 +2703,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
tier: "LC",
},
skuntank: {
tier: "PU",
tier: "ZU",
doublesTier: "(DUU)",
natDexTier: "RU",
},
@ -2838,12 +2840,12 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
natDexTier: "RU",
},
rotommow: {
tier: "ZU",
tier: "PU",
doublesTier: "(DUU)",
natDexTier: "RU",
},
uxie: {
tier: "PU",
tier: "NU",
doublesTier: "(DUU)",
natDexTier: "RU",
},
@ -2926,7 +2928,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
tier: "Illegal",
},
shaymin: {
tier: "ZU",
tier: "PU",
doublesTier: "(DUU)",
natDexTier: "RU",
},
@ -3136,7 +3138,9 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
tier: "LC",
},
gurdurr: {
tier: "NFE",
tier: "ZU",
doublesTier: "NFE",
natDexTier: "NFE",
},
conkeldurr: {
tier: "UU",
@ -3290,7 +3294,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
tier: "NFE",
},
scrafty: {
tier: "NU",
tier: "PU",
doublesTier: "DUU",
natDexTier: "RU",
},
@ -3646,7 +3650,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
mandibuzz: {
tier: "UU",
doublesTier: "(DUU)",
natDexTier: "UU",
natDexTier: "RU",
},
heatmor: {
isNonstandard: "Past",
@ -3665,7 +3669,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
tier: "NFE",
},
hydreigon: {
tier: "RUBL",
tier: "UU",
doublesTier: "(DUU)",
natDexTier: "UU",
},
@ -3683,7 +3687,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
natDexTier: "RU",
},
terrakion: {
tier: "NUBL",
tier: "RU",
doublesTier: "(DUU)",
natDexTier: "RUBL",
},
@ -3848,7 +3852,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
tier: "NFE",
},
talonflame: {
tier: "RU",
tier: "UU",
doublesTier: "(DUU)",
natDexTier: "RU",
},
@ -4197,7 +4201,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
},
hoopaunbound: {
tier: "UUBL",
doublesTier: "(DUU)",
doublesTier: "DUU",
natDexTier: "UUBL",
},
volcanion: {
@ -4241,7 +4245,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
primarina: {
tier: "OU",
doublesTier: "DOU",
natDexTier: "UU",
natDexTier: "RU",
},
pikipek: {
tier: "LC",
@ -4294,7 +4298,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
tier: "Illegal",
},
oricorio: {
tier: "ZU",
tier: "ZUBL",
doublesTier: "(DUU)",
natDexTier: "RU",
},
@ -4304,7 +4308,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
natDexTier: "RU",
},
oricoriopau: {
tier: "ZU",
tier: "ZUBL",
doublesTier: "(DUU)",
natDexTier: "RU",
},
@ -4342,7 +4346,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
natDexTier: "RU",
},
lycanrocdusk: {
tier: "RU",
tier: "NUBL",
doublesTier: "(DUU)",
natDexTier: "RU",
},
@ -4448,7 +4452,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
natDexTier: "RU",
},
passimian: {
tier: "ZU",
tier: "PU",
doublesTier: "(DUU)",
natDexTier: "RU",
},
@ -4460,7 +4464,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
golisopod: {
isNonstandard: "Past",
tier: "Illegal",
natDexTier: "UU",
natDexTier: "RU",
},
golisopodmega: {
isNonstandard: "Future",
@ -4717,7 +4721,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
natDexTier: "RU",
},
necrozma: {
tier: "NUBL",
tier: "RU",
doublesTier: "(DUU)",
natDexTier: "RU",
},
@ -4777,7 +4781,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
zeraora: {
isNonstandard: "Past",
tier: "Illegal",
natDexTier: "RU",
natDexTier: "UU",
},
zeraoramega: {
isNonstandard: "Future",
@ -4808,7 +4812,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
rillaboom: {
tier: "OU",
doublesTier: "DOU",
natDexTier: "UU",
natDexTier: "OU",
},
rillaboomgmax: {
isNonstandard: "Past",
@ -4998,7 +5002,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
tier: "LC",
},
barraskewda: {
tier: "NU",
tier: "RU",
doublesTier: "(DUU)",
natDexTier: "RU",
},
@ -5006,7 +5010,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
tier: "LC",
},
toxtricity: {
tier: "NU",
tier: "RU",
doublesTier: "(DUU)",
natDexTier: "RU",
},
@ -5154,7 +5158,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
dracozolt: {
isNonstandard: "Past",
tier: "Illegal",
natDexTier: "UU",
natDexTier: "RU",
},
arctozolt: {
isNonstandard: "Past",
@ -5322,7 +5326,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
quaquaval: {
tier: "UUBL",
doublesTier: "(DUU)",
natDexTier: "UU",
natDexTier: "RUBL",
},
lechonk: {
tier: "LC",
@ -5351,7 +5355,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
lokix: {
tier: "UU",
doublesTier: "(DUU)",
natDexTier: "UU",
natDexTier: "RU",
},
rellor: {
tier: "LC",
@ -5548,7 +5552,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
garganacl: {
tier: "OU",
doublesTier: "DUU",
natDexTier: "UU",
natDexTier: "RU",
},
glimmet: {
tier: "LC",
@ -5556,7 +5560,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
glimmora: {
tier: "OU",
doublesTier: "DOU",
natDexTier: "RU",
natDexTier: "UU",
},
glimmoramega: {
isNonstandard: "Future",
@ -5686,7 +5690,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
natDexTier: "Uber",
},
wochien: {
tier: "NU",
tier: "PU",
doublesTier: "(DUU)",
natDexTier: "RU",
},
@ -5727,7 +5731,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
ceruledge: {
tier: "OU",
doublesTier: "(DUU)",
natDexTier: "UUBL",
natDexTier: "OU",
},
toedscool: {
tier: "LC",
@ -5772,8 +5776,8 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
},
okidogi: {
tier: "UUBL",
doublesTier: "(DUU)",
natDexTier: "RUBL",
doublesTier: "DOU",
natDexTier: "UUBL",
},
munkidori: {
tier: "NU",
@ -5786,7 +5790,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
natDexTier: "RU",
},
ogerpon: {
tier: "UU",
tier: "OU",
doublesTier: "(DUU)",
natDexTier: "RU",
},
@ -5828,7 +5832,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
ironboulder: {
tier: "UUBL",
doublesTier: "(DUU)",
natDexTier: "UU",
natDexTier: "RUBL",
},
ironcrown: {
tier: "OU",
@ -5848,7 +5852,7 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
pecharunt: {
tier: "OU",
doublesTier: "(DUU)",
natDexTier: "UU",
natDexTier: "UUBL",
},
missingno: {
isNonstandard: "Custom",
@ -6162,6 +6166,10 @@ export const FormatsData: import('../sim/dex-species').SpeciesFormatsDataTable =
isNonstandard: "CAP",
tier: "CAP",
},
flox: {
isNonstandard: "CAP",
tier: "CAP LC",
},
shox: {
isNonstandard: "CAP",
tier: "CAP",

File diff suppressed because it is too large Load Diff

View File

@ -32244,18 +32244,22 @@ export const Learnsets: import('../sim/dex-species').LearnsetDataTable = {
smeargle: {
learnset: {
captivate: ["5D"],
falseswipe: ["5S1"],
flamethrower: ["6S2"],
furyswipes: ["6S2"],
meanlook: ["5S1"],
odorsleuth: ["5S1"],
seismictoss: ["6S2"],
sketch: ["9L1", "7L1", "7V", "6L1", "6S2", "5L1", "5D", "4L1", "3L1", "3S0"],
doubleslap: ["3S1"],
falseswipe: ["5S2"],
flamethrower: ["6S3"],
furyswipes: ["6S3"],
irontail: ["3S1"],
meanlook: ["5S2"],
odorsleuth: ["5S2"],
seismictoss: ["6S3"],
sketch: ["9L1", "7L1", "7V", "6L1", "6S3", "5L1", "5D", "4L1", "3L1", "3S1", "3S0"],
sleeptalk: ["5D"],
spore: ["5S1"],
spore: ["5S2"],
tailwhip: ["3S1"],
},
eventData: [
{generation: 3, level: 10, gender: "M", abilities: ["owntempo"], moves: ["sketch"], pokeball: "pokeball"},
{generation: 3, level: 45, abilities: ["owntempo"], moves: ["sketch", "tailwhip", "doubleslap", "irontail"]},
{generation: 5, level: 50, gender: "F", nature: "Jolly", ivs: {atk: 31, spe: 31}, abilities: ["technician"], moves: ["falseswipe", "spore", "odorsleuth", "meanlook"], pokeball: "cherishball"},
{generation: 6, level: 40, gender: "M", nature: "Jolly", abilities: ["owntempo"], moves: ["sketch", "furyswipes", "seismictoss", "flamethrower"], pokeball: "cherishball"},
],
@ -49730,12 +49734,85 @@ export const Learnsets: import('../sim/dex-species').LearnsetDataTable = {
},
gastrodoneast: {
learnset: {
earthpower: ["9S3", "9S2", "8S1", "8S0"],
icebeam: ["9S2", "8S1", "8S0"],
icywind: ["9S3"],
protect: ["9S3", "9S2", "8S1", "8S0"],
surf: ["8S0"],
yawn: ["9S3", "9S2", "8S1"],
amnesia: ["9M", "8M"],
ancientpower: ["9L20", "8L20", "4T"],
attract: ["8M", "7M", "6M", "5M", "4M"],
blizzard: ["9M", "8M", "7M", "6M", "5M", "4M"],
block: ["7T", "6T", "5T", "4T"],
bodyslam: ["9M", "9L25", "8M", "8L25", "7L29", "6L29", "5L29", "4L29"],
brine: ["8M", "4M"],
bulldoze: ["9M", "8M", "7M", "6M", "5M"],
captivate: ["4M"],
chillingwater: ["9M"],
confide: ["7M", "6M"],
curse: ["9M"],
dig: ["9M", "8M", "6M", "5M", "4M"],
dive: ["8M", "6M", "5M", "4T"],
doubleteam: ["7M", "6M", "5M", "4M"],
earthpower: ["9M", "9L39", "9S2", "9S3", "8M", "8L39", "8S0", "8S1", "7T", "6T", "5T", "4T"],
earthquake: ["9M", "8M", "7M", "6M", "5M", "4M"],
endure: ["9M", "8M", "4M"],
facade: ["9M", "8M", "7M", "6M", "5M", "4M"],
flash: ["6M", "5M", "4M"],
frustration: ["7M", "6M", "5M", "4M"],
gigaimpact: ["9M", "8M", "7M", "6M", "5M", "4M"],
hail: ["8M", "7M", "6M", "5M", "4M"],
harden: ["9L1", "8L1", "7L1", "6L1", "5L1", "4L1"],
headbutt: ["4T"],
helpinghand: ["9M"],
hiddenpower: ["7M", "7L16", "6M", "6L16", "5M", "5L16", "4M", "4L16"],
hydropump: ["9M", "8M"],
hyperbeam: ["9M", "8M", "7M", "6M", "5M", "4M"],
icebeam: ["9M", "9S2", "8M", "8S0", "8S1", "7M", "6M", "5M", "4M"],
icywind: ["9M", "9S3", "8M", "7T", "6T", "5T", "4T"],
infestation: ["7M", "6M"],
liquidation: ["9M"],
memento: ["9L53", "8L53"],
mudbomb: ["7L11", "6L11", "5L11", "4L11"],
muddywater: ["9M", "9L33", "8M", "8L33", "7L41", "6L41", "5L41", "4L41"],
mudshot: ["9M", "8M"],
mudslap: ["9M", "9L1", "8L1", "7L1", "6L1", "5L1", "4T", "4L1"],
mudsport: ["7L1", "6L1", "5L1", "4L1"],
naturalgift: ["4M"],
painsplit: ["9M", "7T", "6T", "5T", "4T"],
protect: ["9M", "9S2", "9S3", "8M", "8S0", "8S1", "7M", "6M", "5M", "4M"],
raindance: ["9M", "9L46", "8M", "8L46", "7M", "7L22", "6M", "6L22", "5M", "5L22", "4M", "4L22"],
recover: ["9L1", "8L1", "7L54", "6L54", "5L54", "4L54"],
rest: ["9M", "8M", "7M", "6M", "5M", "4M"],
return: ["7M", "6M", "5M", "4M"],
rockblast: ["9M"],
rockslide: ["9M", "8M", "7M", "6M", "5M", "4M"],
rocksmash: ["6M", "5M", "4M"],
rocktomb: ["9M", "8M", "7M", "6M", "5M", "4M"],
round: ["8M", "7M", "6M", "5M"],
sandstorm: ["9M", "8M", "7M", "6M", "5M", "4M"],
sandtomb: ["9M", "8M"],
scald: ["8M", "7M", "6M", "5M"],
secretpower: ["6M", "4M"],
skittersmack: ["9M", "8T"],
sleeptalk: ["9M", "8M", "7M", "6M", "5T", "4M"],
sludgebomb: ["9M", "8M", "7M", "6M", "5M", "4M"],
sludgewave: ["9M", "8M", "7M", "6M", "5M"],
snore: ["8M", "7T", "6T", "5T", "4T"],
snowscape: ["9M"],
spikes: ["9M"],
stealthrock: ["9M"],
stompingtantrum: ["9M", "8M", "7T"],
stoneedge: ["9M", "8M", "7M", "6M", "5M", "4M"],
strength: ["6M", "5M", "4M"],
stringshot: ["4T"],
substitute: ["9M", "8M", "7M", "6M", "5M", "4M"],
surf: ["9M", "8M", "8S0", "7M", "6M", "5M", "4M"],
swagger: ["7M", "6M", "5M", "4M"],
takedown: ["9M"],
terablast: ["9M"],
toxic: ["7M", "6M", "5M", "4M"],
waterfall: ["9M", "8M", "7M", "6M", "5M", "4M"],
watergun: ["9L1", "8L1"],
waterpulse: ["9M", "9L15", "8L15", "7T", "7L1", "6T", "6L1", "5L1", "4M", "4L1"],
weatherball: ["9M", "8M"],
whirlpool: ["9M", "8M", "4M"],
yawn: ["9S2", "9S3", "8S1"],
},
eventData: [
{generation: 8, level: 50, gender: "F", nature: "Quiet", abilities: ["stormdrain"], ivs: {hp: 31, atk: 2, def: 31, spa: 31, spd: 31, spe: 0}, moves: ["protect", "surf", "icebeam", "earthpower"], pokeball: "cherishball"},
@ -53582,7 +53659,7 @@ export const Learnsets: import('../sim/dex-species').LearnsetDataTable = {
{generation: 6, level: 1, moves: ["tailglow", "bubble", "watersport", "heartswap"], pokeball: "cherishball"},
{generation: 6, level: 100, moves: ["tailglow", "bubble", "watersport"], pokeball: "cherishball"},
{generation: 7, level: 15, moves: ["tailglow", "waterpulse", "aquaring", "heartswap"], pokeball: "cherishball"},
{generation: 8, moves: ['tailglow', 'watergun'], pokeball: 'pokeball', source: "gen8bdsp"},
{generation: 8, level: 1, moves: ['tailglow', 'watergun'], pokeball: 'pokeball', source: "gen8bdsp"},
{generation: 8, level: 50, moves: ["waterpulse", "zenheadbutt", "moonblast", "bubble"], source: "gen8legends"},
{generation: 9, level: 50, shiny: true, nature: "Calm", ivs: {hp: 31, atk: 20, def: 31, spa: 20, spd: 31, spe: 20}, moves: ["bubblebeam", "acidarmor", "whirlpool", "waterpulse"], pokeball: "cherishball"},
],
@ -72938,10 +73015,79 @@ export const Learnsets: import('../sim/dex-species').LearnsetDataTable = {
},
pumpkaboosuper: {
learnset: {
astonish: ["6S0"],
scaryface: ["6S0"],
shadowsneak: ["6S0"],
trickortreat: ["6S0"],
allyswitch: ["8M", "7T"],
astonish: ["8L1", "7L1", "6L1", "6S0"],
attract: ["8M", "7M", "6M"],
bestow: ["7E", "6E"],
bulletseed: ["8M", "8L20", "7L26", "6L26"],
chargebeam: ["7M", "6M"],
confide: ["7M", "6M"],
confuseray: ["8L8", "7L1", "6L1"],
curse: ["8E", "7E"],
darkpulse: ["8M", "7M", "6M"],
destinybond: ["8E", "7E", "6E"],
disable: ["8E", "7E", "6E"],
doubleteam: ["7M", "6M"],
dreameater: ["7M", "6M"],
endure: ["8M"],
energyball: ["8M", "7M", "6M"],
explosion: ["7M", "6M"],
facade: ["8M", "7M", "6M"],
fireblast: ["8M", "7M", "6M"],
flamecharge: ["7M", "6M"],
flamethrower: ["8M", "7M", "6M"],
flash: ["6M"],
foulplay: ["8M", "7T", "6T"],
frustration: ["7M", "6M"],
gigadrain: ["8M", "7T", "6T"],
grassknot: ["8M", "7M", "6M"],
grassyglide: ["8T"],
gyroball: ["8M", "7M", "6M"],
hex: ["8M"],
hiddenpower: ["7M", "6M"],
imprison: ["8M"],
incinerate: ["6M"],
leechseed: ["8L16", "7L20", "6L20"],
lightscreen: ["8M", "7M", "6M"],
magiccoat: ["7T", "6T"],
mysticalfire: ["8M"],
naturepower: ["7M", "6M"],
painsplit: ["8L44", "7T", "7L42", "6T", "6L42"],
poltergeist: ["8T"],
protect: ["8M", "7M", "6M"],
psychic: ["8M", "7M", "6M"],
razorleaf: ["8L12", "7L16", "6L16"],
rest: ["8M", "7M", "6M"],
return: ["7M", "6M"],
rockslide: ["8M", "7M", "6M"],
rocksmash: ["6M"],
roleplay: ["7T", "6T"],
round: ["8M", "7M", "6M"],
safeguard: ["8M", "7M", "6M"],
scaryface: ["8M", "8L24", "7L4", "6L4", "6S0"],
secretpower: ["6M"],
seedbomb: ["8M", "8L32", "7T", "7L48", "6T", "6L48"],
shadowball: ["8M", "8L36", "7M", "7L36", "6M", "6L36"],
shadowsneak: ["8L4", "7L30", "6L30", "6S0"],
skillswap: ["8M", "7T", "6T"],
skittersmack: ["8T"],
sleeptalk: ["8M", "7M", "6M"],
sludgebomb: ["8M", "7M", "6M"],
snore: ["8M"],
solarbeam: ["8M", "7M", "6M"],
spite: ["7T", "6T"],
substitute: ["8M", "7M", "6M"],
sunnyday: ["8M", "7M", "6M"],
swagger: ["7M", "6M"],
synthesis: ["7T", "6T"],
telekinesis: ["7T"],
thief: ["8M", "7M", "6M"],
toxic: ["7M", "6M"],
trick: ["8M", "8L40", "7T", "7L1", "6T", "6L1"],
trickortreat: ["8L1", "7L23", "6L6", "6S0"],
trickroom: ["8M", "7M", "6M"],
willowisp: ["8M", "7M", "6M"],
worryseed: ["8L28", "7T", "7L11", "6T", "6L11"],
},
eventData: [
{generation: 6, level: 50, moves: ["trickortreat", "astonish", "scaryface", "shadowsneak"], pokeball: "cherishball"},
@ -73028,6 +73174,87 @@ export const Learnsets: import('../sim/dex-species').LearnsetDataTable = {
worryseed: ["8L28", "7T", "7L11", "6T", "6L11"],
},
},
gourgeistsuper: {
learnset: {
allyswitch: ["8M", "7T"],
astonish: ["8L1", "7L1", "6L1"],
attract: ["8M", "7M", "6M"],
brutalswing: ["8M"],
bulletseed: ["8M", "8L20", "7L26", "6L26"],
chargebeam: ["7M", "6M"],
confide: ["7M", "6M"],
confuseray: ["8L1", "7L1", "6L1"],
darkpulse: ["8M", "7M", "6M"],
doubleteam: ["7M", "6M"],
dreameater: ["7M", "6M"],
endure: ["8M"],
energyball: ["8M", "7M", "6M"],
explosion: ["8L1", "7M", "7L1", "6M", "6L1"],
facade: ["8M", "7M", "6M"],
fireblast: ["8M", "7M", "6M"],
flamecharge: ["7M", "6M"],
flamethrower: ["8M", "7M", "6M"],
flash: ["6M"],
focusblast: ["8M", "7M", "6M"],
foulplay: ["8M", "7T", "6T"],
frustration: ["7M", "6M"],
gigadrain: ["8M", "7T", "6T"],
gigaimpact: ["8M", "7M", "6M"],
grassknot: ["8M", "7M", "6M"],
grassyglide: ["8T"],
gyroball: ["8M", "7M", "6M"],
hex: ["8M"],
hiddenpower: ["7M", "6M"],
hyperbeam: ["8M", "7M", "6M"],
imprison: ["8M"],
incinerate: ["6M"],
leechseed: ["8L16", "7L20", "6L20"],
lightscreen: ["8M", "7M", "6M"],
magiccoat: ["7T", "6T"],
moonblast: ["8L1"],
mysticalfire: ["8M"],
nastyplot: ["8M"],
naturepower: ["7M", "6M"],
painsplit: ["8L44", "7T", "7L42", "6T", "6L42"],
phantomforce: ["8M", "8L48", "7L1", "6L1"],
poltergeist: ["8T"],
powerwhip: ["8M"],
protect: ["8M", "7M", "6M"],
psychic: ["8M", "7M", "6M"],
razorleaf: ["8L12", "7L16", "6L16"],
rest: ["8M", "7M", "6M"],
return: ["7M", "6M"],
rockslide: ["8M", "7M", "6M"],
rocksmash: ["6M"],
roleplay: ["7T", "6T"],
round: ["8M", "7M", "6M"],
safeguard: ["8M", "7M", "6M"],
scaryface: ["8M", "8L24", "7L1", "6L4"],
secretpower: ["6M"],
seedbomb: ["8M", "8L32", "7T", "7L48", "6T", "6L48"],
shadowball: ["8M", "8L36", "7M", "7L36", "6M", "6L36"],
shadowsneak: ["8L1", "7L30", "6L30"],
skillswap: ["8M", "7T", "6T"],
skittersmack: ["8T"],
sleeptalk: ["8M", "7M", "6M"],
sludgebomb: ["8M", "7M", "6M"],
snore: ["8M"],
solarbeam: ["8M", "7M", "6M"],
spite: ["7T", "6T"],
substitute: ["8M", "7M", "6M"],
sunnyday: ["8M", "7M", "6M"],
swagger: ["7M", "6M"],
synthesis: ["7T", "6T"],
telekinesis: ["7T"],
thief: ["8M", "7M", "6M"],
toxic: ["7M", "6M"],
trick: ["8M", "8L40", "7T", "7L1", "6T", "6L1"],
trickortreat: ["8L1", "7L23", "6L6"],
trickroom: ["8M", "7M", "6M"],
willowisp: ["8M", "7M", "6M"],
worryseed: ["8L28", "7T", "7L11", "6T", "6L11"],
},
},
bergmite: {
learnset: {
afteryou: ["7T", "6T"],
@ -84106,49 +84333,53 @@ export const Learnsets: import('../sim/dex-species').LearnsetDataTable = {
},
sinisteaantique: {
learnset: {
allyswitch: ["9E"],
aromatherapy: ["8S0"],
aromaticmist: ["9L6"],
astonish: ["9L1"],
batonpass: ["9M"],
allyswitch: ["9E", "8M"],
aromatherapy: ["8L30", "8S0"],
aromaticmist: ["9L6", "8L6"],
astonish: ["9L1", "8L1"],
batonpass: ["9M", "8M"],
calmmind: ["9M"],
celebrate: ["8S0"],
confuseray: ["9M"],
curse: ["9M"],
darkpulse: ["9M"],
endure: ["9M"],
facade: ["9M"],
foulplay: ["9M"],
gigadrain: ["9M", "9L36"],
hex: ["9M"],
imprison: ["9M"],
darkpulse: ["9M", "8M"],
endure: ["9M", "8M"],
facade: ["9M", "8M"],
foulplay: ["9M", "8M"],
gigadrain: ["9M", "9L36", "8M", "8L36"],
hex: ["9M", "8M"],
imprison: ["9M", "8M"],
magicalleaf: ["9M"],
megadrain: ["9L12"],
memento: ["9L54", "8S0"],
metronome: ["9M", "8S0"],
nastyplot: ["9M", "9L42"],
megadrain: ["9L12", "8L12"],
memento: ["9L54", "8L54", "8S0"],
metronome: ["9M", "8M", "8S0"],
nastyplot: ["9M", "9L42", "8M", "8L42"],
nightshade: ["9M"],
phantomforce: ["9M"],
poltergeist: ["9M"],
protect: ["9M"],
payback: ["8M"],
phantomforce: ["9M", "8M"],
poltergeist: ["9M", "8T"],
protect: ["9M", "8M", "8L18"],
psybeam: ["9M"],
psychic: ["9M"],
psyshock: ["9M"],
rest: ["9M"],
shadowball: ["9M", "9L48"],
shellsmash: ["9L60"],
psychic: ["9M", "8M"],
psyshock: ["9M", "8M"],
rest: ["9M", "8M"],
round: ["8M"],
shadowball: ["9M", "9L48", "8M", "8L48"],
shellsmash: ["9L60", "8L60"],
skillswap: ["9M"],
sleeptalk: ["9M"],
sleeptalk: ["9M", "8M"],
snore: ["8M"],
spite: ["9M"],
storedpower: ["9M"],
substitute: ["9M"],
suckerpunch: ["9L24"],
storedpower: ["9M", "8M"],
substitute: ["9M", "8M"],
suckerpunch: ["9L24", "8L24"],
sweetscent: ["9L30"],
terablast: ["9M"],
trick: ["9M"],
trick: ["9M", "8M"],
trickroom: ["9M"],
willowisp: ["9M"],
withdraw: ["9L1"],
willowisp: ["9M", "8M"],
withdraw: ["9L1", "8L1"],
wonderroom: ["8M"],
},
eventData: [
{generation: 8, level: 50, isHidden: true, moves: ["memento", "metronome", "aromatherapy", "celebrate"], pokeball: "cherishball"},
@ -84212,6 +84443,64 @@ export const Learnsets: import('../sim/dex-species').LearnsetDataTable = {
wonderroom: ["8M"],
},
},
polteageistantique: {
learnset: {
allyswitch: ["8M"],
aromatherapy: ["8L30"],
aromaticmist: ["9L1", "8L1"],
astonish: ["9L1", "8L1"],
batonpass: ["9M", "8M"],
calmmind: ["9M"],
confuseray: ["9M"],
curse: ["9M", "9L66", "8L66"],
darkpulse: ["9M", "8M"],
endure: ["9M", "8M"],
facade: ["9M", "8M"],
foulplay: ["9M", "8M"],
gigadrain: ["9M", "9L36", "8M", "8L36"],
gigaimpact: ["9M", "8M"],
hex: ["9M", "8M"],
hyperbeam: ["9M", "8M"],
imprison: ["9M", "8M"],
lightscreen: ["9M", "8M"],
magicalleaf: ["9M"],
megadrain: ["9L1", "8L1"],
memento: ["9L54", "8L54"],
metronome: ["9M", "8M"],
nastyplot: ["9M", "9L42", "8M", "8L42"],
nightshade: ["9M"],
painsplit: ["9M"],
payback: ["8M"],
phantomforce: ["9M", "8M"],
poltergeist: ["9M", "8T"],
protect: ["9M", "9L18", "8M", "8L18"],
psybeam: ["9M"],
psychic: ["9M", "8M"],
psyshock: ["9M", "8M"],
reflect: ["9M", "8M"],
rest: ["9M", "8M"],
round: ["8M"],
selfdestruct: ["8M"],
shadowball: ["9M", "9L48", "8M", "8L48"],
shellsmash: ["9L60", "8L60"],
skillswap: ["9M"],
sleeptalk: ["9M", "8M"],
snore: ["8M"],
spite: ["9M"],
storedpower: ["9M", "8M"],
strengthsap: ["9L1", "8L1"],
substitute: ["9M", "8M"],
suckerpunch: ["9L24", "8L24"],
sweetscent: ["9L30"],
teatime: ["9L0", "8L0"],
terablast: ["9M"],
trick: ["9M", "8M"],
trickroom: ["9M"],
willowisp: ["9M", "8M"],
withdraw: ["9L1", "8L1"],
wonderroom: ["8M"],
},
},
hatenna: {
learnset: {
afteryou: ["9E", "8E"],
@ -89284,7 +89573,7 @@ export const Learnsets: import('../sim/dex-species').LearnsetDataTable = {
waterpulse: ["9M"],
},
eventData: [
{generation: 9, moves: ["bodyslam", "amnesia", "icespinner", "doubleedge"]},
{generation: 9, level: 50, moves: ["bodyslam", "amnesia", "icespinner", "doubleedge"]},
],
},
frigibax: {
@ -89471,10 +89760,43 @@ export const Learnsets: import('../sim/dex-species').LearnsetDataTable = {
},
tatsugiristretchy: {
learnset: {
batonpass: ["9M", "9E"],
celebrate: ["9S0"],
dracometeor: ["9S0"],
helpinghand: ["9S0"],
muddywater: ["9S0"],
chillingwater: ["9M"],
counter: ["9E"],
dracometeor: ["9M", "9S0"],
dragoncheer: ["9M"],
dragondance: ["9M"],
dragonpulse: ["9M", "9L52"],
endure: ["9M"],
facade: ["9M"],
gigaimpact: ["9M"],
harden: ["9L6"],
helpinghand: ["9M", "9L12", "9S0"],
hydropump: ["9M"],
hyperbeam: ["9M"],
icywind: ["9M"],
lunge: ["9M"],
memento: ["9L34"],
mirrorcoat: ["9L47"],
muddywater: ["9M", "9L39", "9S0"],
nastyplot: ["9M", "9L43"],
outrage: ["9M"],
protect: ["9M"],
raindance: ["9M"],
rapidspin: ["9E"],
rest: ["9M"],
sleeptalk: ["9M"],
soak: ["9L23"],
splash: ["9L1"],
substitute: ["9M"],
surf: ["9M"],
takedown: ["9M"],
taunt: ["9M", "9L28"],
terablast: ["9M"],
watergun: ["9L1"],
waterpulse: ["9M", "9L17"],
whirlpool: ["9M"],
},
eventData: [
{generation: 9, level: 50, moves: ["dracometeor", "muddywater", "helpinghand", "celebrate"], pokeball: "cherishball"},
@ -99770,6 +100092,67 @@ export const Learnsets: import('../sim/dex-species').LearnsetDataTable = {
{generation: 9, level: 50, shiny: true, abilities: ["armortail"], moves: ["celebrate", "dragontail", "sludgebomb", "dragondance"], pokeball: "cherishball"},
],
},
flox: {
learnset: {
blizzard: ["9M"],
bodyslam: ["9M"],
bulldoze: ["9M"],
charge: ["9M", "9L15"],
chargebeam: ["9M"],
charm: ["9M", "9L15"],
dig: ["9M"],
disarmingvoice: ["9M"],
discharge: ["9L40"],
doubleedge: ["9M", "9L50"],
eerieimpulse: ["9M"],
electricterrain: ["9M"],
electroball: ["9M"],
electroweb: ["9M"],
endeavor: ["9M", "9E"],
endure: ["9M"],
facade: ["9M"],
glare: ["9E"],
growl: ["9L1"],
headbutt: ["9L20"],
helpinghand: ["9M"],
hypervoice: ["9M"],
icebeam: ["9M"],
icywind: ["9M"],
ironhead: ["9M"],
milkdrink: ["9L30"],
mudshot: ["9M"],
mudslap: ["9M"],
nuzzle: ["9E"],
playrough: ["9M"],
protect: ["9M"],
raindance: ["9M"],
rest: ["9M"],
seedbomb: ["9M"],
sleeptalk: ["9M"],
spark: ["9L25"],
spitup: ["9E"],
stockpile: ["9E"],
stompingtantrum: ["9M"],
substitute: ["9M"],
sunnyday: ["9M"],
superfang: ["9M"],
swallow: ["9E"],
tackle: ["9L1"],
takedown: ["9M", "9L35"],
terablast: ["9M"],
thief: ["9M"],
thunder: ["9M"],
thundershock: ["9L10"],
thunderwave: ["9M", "9L5"],
thunderbolt: ["9M"],
trailblaze: ["9M"],
uproar: ["9M"],
voltswitch: ["9M"],
wildcharge: ["9M"],
zapcannon: ["9L55"],
zenheadbutt: ["9M"],
},
},
shox: {
learnset: {
blizzard: ["9M"],

231
data/mods/afd/abilities.ts Normal file
View File

@ -0,0 +1,231 @@
export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTable = {
chaossaliva: {
onSourceDamagingHit(damage, target, source, move) {
// Despite not being a secondary, Shield Dust / Covert Cloak block Poison Touch's effect
if (target.hasAbility('shielddust') || target.hasItem('covertcloak')) return;
if (this.checkMoveMakesContact(move, target, source)) {
if (this.randomChance(2, 10)) {
target.trySetStatus('par', source);
}
if (this.randomChance(2, 10)) {
target.addVolatile('confusion', source);
}
}
},
flags: {},
name: "Chaos Saliva",
gen: 9,
shortDesc: "Contact moves have a 20% chance to paralyze and a 20% chance to confuse.",
},
faststart: {
onStart(pokemon) {
this.add('-start', pokemon, 'ability: Fast Start');
this.effectState.counter = 5;
},
onResidualOrder: 28,
onResidualSubOrder: 2,
onResidual(pokemon) {
if (pokemon.activeTurns && this.effectState.counter) {
this.effectState.counter--;
if (!this.effectState.counter) {
this.add('-end', pokemon, 'Fast Start');
delete this.effectState.counter;
}
}
},
onModifyAtkPriority: 5,
onModifyAtk(atk, pokemon) {
if (this.effectState.counter) {
return this.chainModify(2);
}
},
onModifySpe(spe, pokemon) {
if (this.effectState.counter) {
return this.chainModify(2);
}
},
onEnd(pokemon) {
if (pokemon.beingCalledBack) return;
this.add('-end', pokemon, 'Fast Start', '[silent]');
},
flags: {},
name: "Fast Start",
rating: -1,
gen: 9,
},
ironfist: {
inherit: true,
onBasePower(basePower, attacker, defender, move) {
if (move.flags['punch']) {
this.debug('Iron Fist boost');
return this.chainModify([8192, 4096]);
}
},
},
supermegalauncher: {
onBasePowerPriority: 19,
onBasePower(basePower, attacker, defender, move) {
if (move.flags['pulse']) {
return this.chainModify(4);
}
},
flags: {},
name: "Mega Launcher",
desc: "This Pokemon's pulse moves have their power multiplied by 4. Heal Pulse restores 8/4 of a target's maximum HP, rounded half down.",
shortDesc: "This Pokemon's pulse moves have 4x power. Heal Pulse heals 8/4 target's max HP.",
rating: 3,
gen: 9,
},
discourage: {
onStart(pokemon) {
let activated = false;
for (const target of pokemon.adjacentFoes()) {
if (!activated) {
this.add('-ability', pokemon, 'Discourage', 'boost');
activated = true;
}
if (target.volatiles['substitute']) {
this.add('-immune', target);
} else {
this.boost({ spa: -1 }, target, pokemon, null, true);
}
}
},
flags: {},
name: "Discourage",
rating: 3.5,
num: 999,
gen: 9,
},
adaptability: {
inherit: true,
onModifySTAB(stab, source, target, move) {
if (move.forceSTAB || source.hasType(move.type)) {
const types = source.getTypes();
if (types[0] === move.type) return 2.3;
if (types[1] && types[1] === move.type) return 1.6;
if (stab === 2.3) {
return 2.55;
}
return 2.7;
}
},
},
icebody: {
inherit: true,
onDamagingHit(damage, target, source, move) {
if (this.checkMoveMakesContact(move, source, target)) {
if (this.randomChance(1, 10)) {
source.trySetStatus('frz', target);
}
}
},
},
noretreat: {
onStart(target) {
this.add('-start', target, 'move: No Retreat');
},
onFoeBeforeSwitchOut(pokemon) {
if (!pokemon || pokemon.fainted || pokemon.hp <= 0 || pokemon.hasAbility('noretreat')) return;
const success = !!this.damage(pokemon.maxhp / 4, pokemon, this.effectState.target);
if (success) {
pokemon.tryTrap();
}
},
name: "No Retreat",
flags: { breakable: 1 },
},
itsexcadrillintime: {
onModifySpe(spe, pokemon) {
if (this.field.isWeather('sandstorm')) {
return this.chainModify(2);
}
},
onImmunity(type, pokemon) {
if (type === 'sandstorm') return false;
},
onBasePowerPriority: 21,
onBasePower(basePower, attacker, defender, move) {
if (this.field.isWeather('sandstorm')) {
if (move.type === 'Rock' || move.type === 'Ground' || move.type === 'Steel') {
this.debug('Sand Force boost');
return this.chainModify([5325, 4096]);
}
}
},
name: "It's Excadrillin' Time!",
flags: {},
},
goodasgold: {
inherit: true,
onTryHit(target, source, move) {
if (move.category !== 'Special' && target !== source) {
this.add('-immune', target, '[from] ability: Good as Gold');
return null;
}
},
},
intimidate2: {
onStart(pokemon) {
let activated = false;
let timesActivated = 0;
for (const target of pokemon.adjacentFoes()) {
if (!activated) {
this.add('-ability', pokemon, 'Intimidate 2', 'boost');
activated = true;
}
if (target.volatiles['substitute']) {
this.add('-immune', target);
} else {
this.boost({ atk: -1 }, target, pokemon, null, true);
timesActivated++;
}
}
if (timesActivated > 0) {
for (let i = 0; i < timesActivated; i++) {
this.boost({ atk: 1 }, pokemon, pokemon, null, true);
}
}
},
flags: {},
name: "Intimidate 2",
rating: 3.5,
num: 22,
},
asonemonarch: {
onSwitchInPriority: 1,
onStart(pokemon) {
if (this.effectState.unnerved) return;
this.add('-ability', pokemon, 'As One');
this.add('-ability', pokemon, 'Unnerve');
this.effectState.unnerved = true;
},
onEnd() {
this.effectState.unnerved = false;
},
onFoeTryEatItem() {
return !this.effectState.unnerved;
},
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, cantsuppress: 1 },
name: "As One (Monarch)",
rating: 3.5,
num: 266,
},
intimidate: {
inherit: true,
onStart(pokemon) {
let activated = false;
for (const target of pokemon.adjacentFoes()) {
if (!activated) {
this.add('-ability', pokemon, 'Intimidate', 'boost');
activated = true;
}
if (target.volatiles['substitute']) {
this.add('-immune', target);
} else {
this.boost({ atk: -2 }, target, pokemon, null, true);
}
}
},
},
};

View File

@ -0,0 +1,22 @@
export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDataTable = {
sandstorm: {
inherit: true,
onWeatherModifyDamage(damage, attacker, defender, move) {
if (defender.hasItem('utilityumbrella')) return;
if (move.type === 'Rock') {
this.debug('Sandstorm rock boost');
return this.chainModify(1.5);
}
},
},
snowscape: {
inherit: true,
onModifySpePriority: 10,
onModifySpe(spe, pokemon) {
if (!pokemon.getTypes(false, true).includes('Ice') && !pokemon.getTypes(false, true).includes('Steel') &&
!pokemon.hasAbility(['slushrush', 'snowcloak', 'iceface', 'icebody']) && pokemon.effectiveWeather() === 'snowscape') {
return this.modify(spe, 0.5);
}
},
},
};

93
data/mods/afd/items.ts Normal file
View File

@ -0,0 +1,93 @@
export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
hoots: {
name: "Hoots",
spritenum: 715,
fling: {
basePower: 80,
},
num: 1120,
gen: 8,
// Hazard Immunity implemented in moves.ts
},
luckycharm: {
name: "Lucky Charm",
onModifyMovePriority: -2,
onModifyMove(move, pokemon, target) {
let trigger = false;
if (move.secondaries) {
this.debug('doubling secondary chance');
for (const secondary of move.secondaries) {
if (secondary.chance && secondary.chance < 100) {
secondary.chance = 100;
if (!trigger) trigger = true;
}
}
}
if (move.self?.chance) {
move.self.chance = 100;
trigger = true;
}
if (trigger) {
pokemon.useItem();
}
},
spritenum: 707,
fling: {
basePower: 120,
},
num: 9999,
gen: 9,
},
onikaburger: {
name: "Onika Burger",
desc: "PP and damage of every move is halved. Gain 25% max HP at the end of each turn.",
shortDesc: "PP and damage of every move is halved. Gain 25% max HP at the end of each turn.",
onStart(target) {
if (target.m.onikaBurger) return;
target.m.onikaBurger = true;
for (const moveSlot of target.moveSlots) {
const deductPP = target.deductPP(moveSlot.id, moveSlot.maxpp / 2, target);
if (!deductPP) continue;
this.add('-activate', target, 'item: Onika Burger', moveSlot.move, deductPP);
}
},
onModifyDamage() {
return this.chainModify(0.5);
},
onResidualOrder: 5,
onResidualSubOrder: 4,
onResidual(pokemon) {
this.heal(pokemon.baseMaxhp / 4);
},
},
wardtag: {
name: "Ward Tag",
desc: "Reflects back 125% of the damage that would've been dealt. One-time use.",
shortDesc: "Reflects back 125% of the damage that would've been dealt. One-time use.",
onDamage(damage, target, source, effect) {
if (source && target !== source && effect?.effectType === 'Move' && target.useItem()) {
this.add('-activate', target, 'item: Ward Tag');
this.damage(damage * 5 / 4, source, target);
return 0;
}
},
},
strengthpolicy: {
name: "Strength Policy",
spritenum: 609,
fling: {
basePower: 80,
},
onDamagingHit(damage, target, source, move) {
if (!move.damage && !move.damageCallback && target.getMoveHitData(move).typeMod < 0) {
target.useItem();
}
},
boosts: {
def: 2,
spd: 2,
},
num: 639,
gen: 6,
},
};

599
data/mods/afd/moves.ts Normal file
View File

@ -0,0 +1,599 @@
export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
banefulbunker: {
inherit: true,
condition: {
inherit: true,
onTryHit(target, source, move) {
if (this.checkMoveBypassesProtect(move, source, target)) return;
if (move.smartTarget) {
move.smartTarget = false;
} else {
if (!this.randomChance(2, 10)) {
this.add('-activate', target, 'move: Protect');
if (move.basePower >= 100) {
this.add('message', '**BWUAHAAUAAAANGGGGGG**');
}
} else {
return;
}
}
const lockedmove = source.getVolatile('lockedmove');
if (lockedmove) {
// Outrage counter is reset
if (source.volatiles['lockedmove'].duration === 2) {
delete source.volatiles['lockedmove'];
}
}
if (this.checkMoveMakesContact(move, source, target)) {
source.trySetStatus('psn', target);
}
return this.NOT_FAIL;
},
},
},
burningbulwark: {
inherit: true,
condition: {
inherit: true,
onTryHit(target, source, move) {
if (this.checkMoveBypassesProtect(move, source, target, false)) return;
if (move.smartTarget) {
move.smartTarget = false;
} else {
if (!this.randomChance(2, 10)) {
this.add('-activate', target, 'move: Protect');
if (move.basePower >= 100) {
this.add('message', '**BWUAHAAUAAAANGGGGGG**');
}
} else {
return;
}
}
const lockedmove = source.getVolatile('lockedmove');
if (lockedmove) {
// Outrage counter is reset
if (source.volatiles['lockedmove'].duration === 2) {
delete source.volatiles['lockedmove'];
}
}
if (this.checkMoveMakesContact(move, source, target)) {
source.trySetStatus('brn', target);
}
return this.NOT_FAIL;
},
},
},
kingsshield: {
inherit: true,
condition: {
inherit: true,
onTryHit(target, source, move) {
if (this.checkMoveBypassesProtect(move, source, target, false)) return;
if (move.smartTarget) {
move.smartTarget = false;
} else {
if (!this.randomChance(2, 10)) {
this.add('-activate', target, 'move: Protect');
if (move.basePower >= 100) {
this.add('message', '**BWUAHAAUAAAANGGGGGG**');
}
} else {
return;
}
}
const lockedmove = source.getVolatile('lockedmove');
if (lockedmove) {
// Outrage counter is reset
if (source.volatiles['lockedmove'].duration === 2) {
delete source.volatiles['lockedmove'];
}
}
if (this.checkMoveMakesContact(move, source, target)) {
this.boost({ atk: -1 }, source, target, this.dex.getActiveMove("King's Shield"));
}
return this.NOT_FAIL;
},
},
},
maxguard: {
inherit: true,
condition: {
inherit: true,
onTryHit(target, source, move) {
const bypassesMaxGuard = [
'acupressure', 'afteryou', 'allyswitch', 'aromatherapy', 'aromaticmist', 'coaching', 'confide', 'copycat', 'curse', 'decorate', 'doomdesire', 'feint', 'futuresight', 'gmaxoneblow', 'gmaxrapidflow', 'healbell', 'holdhands', 'howl', 'junglehealing', 'lifedew', 'meanlook', 'perishsong', 'playnice', 'powertrick', 'roar', 'roleplay', 'tearfullook',
];
if (bypassesMaxGuard.includes(move.id)) return;
if (move.smartTarget) {
move.smartTarget = false;
} else {
if (!this.randomChance(2, 10)) {
this.add('-activate', target, 'move: Protect');
if (move.basePower >= 100) {
this.add('message', '**BWUAHAAUAAAANGGGGGG**');
}
} else {
return;
}
}
const lockedmove = source.getVolatile('lockedmove');
if (lockedmove) {
// Outrage counter is reset
if (source.volatiles['lockedmove'].duration === 2) {
delete source.volatiles['lockedmove'];
}
}
return this.NOT_FAIL;
},
},
},
meteorbeam: {
inherit: true,
onTryMove(attacker, defender, move) {
if (attacker.removeVolatile(move.id)) {
return;
}
this.add('-prepare', attacker, move.name);
this.boost({ spa: 1 }, attacker, attacker, move);
if (['sandstorm'].includes(attacker.effectiveWeather())) {
this.attrLastMove('[still]');
this.addMove('-anim', attacker, move.name, defender);
return;
}
if (!this.runEvent('ChargeMove', attacker, defender, move)) {
return;
}
attacker.addVolatile('twoturnmove', defender);
return null;
},
},
obstruct: {
inherit: true,
condition: {
inherit: true,
onTryHit(target, source, move) {
if (this.checkMoveBypassesProtect(move, source, target, false)) return;
if (move.smartTarget) {
move.smartTarget = false;
} else {
if (!this.randomChance(2, 10)) {
this.add('-activate', target, 'move: Protect');
if (move.basePower >= 100) {
this.add('message', '**BWUAHAAUAAAANGGGGGG**');
}
} else {
return;
}
}
const lockedmove = source.getVolatile('lockedmove');
if (lockedmove) {
// Outrage counter is reset
if (source.volatiles['lockedmove'].duration === 2) {
delete source.volatiles['lockedmove'];
}
}
if (this.checkMoveMakesContact(move, source, target)) {
this.boost({ def: -2 }, source, target, this.dex.getActiveMove("Obstruct"));
}
return this.NOT_FAIL;
},
},
},
protect: {
inherit: true,
condition: {
inherit: true,
onTryHit(target, source, move) {
if (this.checkMoveBypassesProtect(move, source, target)) return;
if (move.smartTarget) {
move.smartTarget = false;
} else {
if (!this.randomChance(2, 10)) {
this.add('-activate', target, 'move: Protect');
if (move.basePower >= 100) {
this.add('message', '**BWUAHAAUAAAANGGGGGG**');
}
} else {
return;
}
}
const lockedmove = source.getVolatile('lockedmove');
if (lockedmove) {
// Outrage counter is reset
if (source.volatiles['lockedmove'].duration === 2) {
delete source.volatiles['lockedmove'];
}
}
return this.NOT_FAIL;
},
},
},
silktrap: {
inherit: true,
condition: {
inherit: true,
onTryHit(target, source, move) {
if (this.checkMoveBypassesProtect(move, source, target, false)) return;
if (move.smartTarget) {
move.smartTarget = false;
} else {
if (!this.randomChance(2, 10)) {
this.add('-activate', target, 'move: Protect');
if (move.basePower >= 100) {
this.add('message', '**BWUAHAAUAAAANGGGGGG**');
}
} else {
return;
}
}
const lockedmove = source.getVolatile('lockedmove');
if (lockedmove) {
// Outrage counter is reset
if (source.volatiles['lockedmove'].duration === 2) {
delete source.volatiles['lockedmove'];
}
}
if (this.checkMoveMakesContact(move, source, target)) {
this.boost({ spe: -1 }, source, target, this.dex.getActiveMove("Silk Trap"));
}
return this.NOT_FAIL;
},
},
},
spikyshield: {
inherit: true,
condition: {
inherit: true,
onTryHit(target, source, move) {
if (this.checkMoveBypassesProtect(move, source, target)) return;
if (move.smartTarget) {
move.smartTarget = false;
} else {
if (!this.randomChance(2, 10)) {
this.add('-activate', target, 'move: Protect');
if (move.basePower >= 100) {
this.add('message', '**BWUAHAAUAAAANGGGGGG**');
}
} else {
return;
}
}
const lockedmove = source.getVolatile('lockedmove');
if (lockedmove) {
// Outrage counter is reset
if (source.volatiles['lockedmove'].duration === 2) {
delete source.volatiles['lockedmove'];
}
}
if (this.checkMoveMakesContact(move, source, target)) {
this.damage(source.baseMaxhp / 8, source, target);
}
return this.NOT_FAIL;
},
},
},
stealthrock: {
inherit: true,
condition: {
onSideStart(side) {
this.add('-sidestart', side, 'Stealth Rock');
this.effectState.layers = 1;
},
onSideRestart(side) {
if (this.effectState.layers >= 5) return false;
this.add('-sidestart', side, 'Stealth Rock');
this.effectState.layers++;
},
onSwitchIn(pokemon) {
if (pokemon.hasItem(['heavydutyboots', 'hoots'])) return;
const typeMod = this.clampIntRange(pokemon.runEffectiveness(this.dex.getActiveMove('stealthrock')), -6, 6);
const damageAmounts = [0, 1, 2, 3, 4, 5]; // 2 ** typeMod / 8
this.damage((damageAmounts[this.effectState.layers] / 5) * pokemon.maxhp * ((2 ** typeMod) / 8));
},
},
},
gmaxsteelsurge: {
inherit: true,
condition: {
onSideStart(side) {
this.add('-sidestart', side, 'G-Max Steelsurge');
this.effectState.layers = 1;
},
onSideRestart(side) {
if (this.effectState.layers >= 5) return false;
this.add('-sidestart', side, 'G-Max Steelsurge');
this.effectState.layers++;
},
onSwitchIn(pokemon) {
if (pokemon.hasItem(['heavydutyboots', 'hoots'])) return;
const steelHazard = this.dex.getActiveMove('Stealth Rock');
steelHazard.type = 'Steel';
const typeMod = this.clampIntRange(pokemon.runEffectiveness(steelHazard), -6, 6);
const damageAmounts = [0, 1, 2, 3, 4, 5]; // 2 ** typeMod / 8
this.damage((damageAmounts[this.effectState.layers] / 5) * pokemon.maxhp * ((2 ** typeMod) / 8));
},
},
},
spikes: {
inherit: true,
condition: {
inherit: true,
onSwitchIn(pokemon) {
if (!pokemon.isGrounded() || pokemon.hasItem(['heavydutyboots', 'hoots'])) return;
const damageAmounts = [0, 3, 4, 6]; // 1/8, 1/6, 1/4
this.damage(damageAmounts[this.effectState.layers] * pokemon.maxhp / 24);
},
},
},
stickyweb: {
inherit: true,
condition: {
inherit: true,
onSwitchIn(pokemon) {
if (!pokemon.isGrounded() || pokemon.hasItem(['heavydutyboots', 'hoots'])) return;
this.add('-activate', pokemon, 'move: Sticky Web');
this.boost({ spe: -1 }, pokemon, pokemon.side.foe.active[0], this.dex.getActiveMove('stickyweb'));
},
},
},
toxicspikes: {
inherit: true,
condition: {
inherit: true,
onSwitchIn(pokemon) {
if (!pokemon.isGrounded()) return;
if (pokemon.hasType('Poison')) {
this.add('-sideend', pokemon.side, 'move: Toxic Spikes', `[of] ${pokemon}`);
pokemon.side.removeSideCondition('toxicspikes');
} else if (pokemon.hasType('Steel') || pokemon.hasItem(['heavydutyboots', 'hoots'])) {
// do nothing
} else if (this.effectState.layers >= 2) {
pokemon.trySetStatus('tox', pokemon.side.foe.active[0]);
} else {
pokemon.trySetStatus('psn', pokemon.side.foe.active[0]);
}
},
},
},
suckerpunch: {
inherit: true,
onTry() { },
onModifyPriority(priority, source, target, move) {
if (!target) return priority - 1;
const action = this.queue.willMove(target);
const aMove = action?.choice === 'move' ? action.move : null;
if (!aMove || (aMove.category === 'Status' && aMove.id !== 'mefirst') || target.volatiles['mustrecharge']) {
return priority - 1;
}
return priority;
},
},
thousandarrows: {
inherit: true,
basePower: 120,
},
healpulse: {
inherit: true,
onHit(target, source) {
let success = false;
if (source.hasAbility('supermegalauncher')) {
success = !!this.heal(this.modify(target.baseMaxhp, 2));
} else if (source.hasAbility('megalauncher')) {
success = !!this.heal(this.modify(target.baseMaxhp, 0.75));
} else {
success = !!this.heal(Math.ceil(target.baseMaxhp * 0.5));
}
if (success && !target.isAlly(source)) {
target.staleness = 'external';
}
if (!success) {
this.add('-fail', target, 'heal');
return this.NOT_FAIL;
}
return success;
},
},
headsmash: {
inherit: true,
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1, heal: 1 },
secondary: {
chance: 100,
onHit(target, source, move) {
if (!this.heal(this.modify(target.baseMaxhp, 0.25))) {
return this.NOT_FAIL;
}
},
},
},
knockoff: {
inherit: true,
accuracy: 90,
},
shitpulse: {
num: -400,
gen: 9,
accuracy: 100,
basePower: 75,
category: "Special",
name: "Shit Pulse",
pp: 15,
priority: 0,
flags: { protect: 1, mirror: 1, distance: 1, metronome: 1, pulse: 1 },
secondary: {
chance: 30,
boosts: {
accuracy: -2,
},
},
target: "any",
type: "Poison",
shortDesc: "30% chance to lower foe's accuracy by 2.",
},
solarflare: {
num: -4324534,
gen: 9,
accuracy: 100,
basePower: 75,
category: "Special",
name: "Solar Flare",
pp: 15,
priority: 0,
flags: { protect: 1, mirror: 1, metronome: 1 },
secondary: {
chance: 50,
onHit(target, source, move) {
if (!['sunnyday', 'desolateland'].includes(target.effectiveWeather())) return;
target.trySetStatus('brn', source, move);
},
},
target: "normal",
type: "Fire",
shortDesc: "Sun active: 50% chance to burn.",
},
onslaught: {
num: -3023,
gen: 9,
accuracy: 100,
basePower: 100,
category: "Physical",
name: "Onslaught",
pp: 5,
priority: 0,
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
self: {
boosts: {
atk: -1,
def: -1,
},
},
target: "normal",
type: "Dark",
},
scald: {
inherit: true,
onEffectiveness(typeMod, target, type) {
if (type === 'Steel') return 1;
},
secondary: undefined,
secondaries: [{
chance: 30,
status: 'brn',
}, {
chance: 100,
onHit(target, source, move) {
if (target.hasType(['Normal', 'Fairy'])) {
target.trySetStatus('brn', source, move);
}
},
}],
},
explosion: {
inherit: true,
onAfterMove(pokemon, target, move) {
if (target && target.hp <= 0) {
delete move.selfdestruct;
return;
}
},
},
selfdestruct: {
inherit: true,
onAfterMove(pokemon, target, move) {
if (target && target.hp <= 0) {
delete move.selfdestruct;
return;
}
},
},
mistyexplosion: {
inherit: true,
onAfterMove(pokemon, target, move) {
if (target && target.hp <= 0) {
delete move.selfdestruct;
return;
}
},
},
moonblast: {
inherit: true,
basePower: 90,
accuracy: 90,
secondary: {
chance: 10,
boosts: {
atk: -1,
},
},
category: "Physical",
},
noretreat: {
name: "No Retreat",
// @ts-expect-error
exists: false,
},
blastiodon: {
num: -306345534534523,
gen: 9,
accuracy: 100,
basePower: 0,
basePowerCallback(pokemon, target) {
const targetDef = target.getStat('def', false, true);
const pokemonDef = pokemon.getStat('def', false, true);
let bp;
if (pokemonDef >= targetDef * 5) {
bp = 150;
} else if (pokemonDef >= targetDef * 4) {
bp = 125;
} else if (pokemonDef >= targetDef * 3) {
bp = 100;
} else if (pokemonDef >= targetDef * 2) {
bp = 75;
} else {
bp = 50;
}
this.debug(`BP: ${bp}`);
return bp;
},
category: "Physical",
name: "Blastiodon",
pp: 15,
priority: 0,
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
overrideOffensiveStat: 'def',
secondary: {
chance: 50,
boosts: {
def: -1,
},
},
target: "normal",
type: "Rock",
shortDesc: "Higher user Def than target Def = higher BP.",
},
focusblast: {
inherit: true,
accuracy: 100,
recoil: [1, 4],
category: "Physical",
},
darkvoid: {
inherit: true,
onModifyMove(move, pokemon, target) {
if (pokemon.species.baseSpecies === 'Calyrex') {
move.accuracy = 80;
}
},
onTry(source, target, move) {
if (source.species.baseSpecies === 'Darkrai' || source.species.baseSpecies === 'Calyrex' || move.hasBounced) {
return;
}
this.add('-fail', source, 'move: Dark Void');
this.hint("Only a Pokemon whose form is Darkrai can use this move.");
return null;
},
},
rapidspin: {
inherit: true,
type: "Dark",
},
};

329
data/mods/afd/pokedex.ts Normal file
View File

@ -0,0 +1,329 @@
export const Pokedex: import('../../../sim/dex-species').ModdedSpeciesDataTable = {
seaking: {
inherit: true,
baseStats: { hp: 80, atk: 92, def: 65, spa: 65, spd: 80, spe: 98 },
},
clefablemega: {
inherit: true,
abilities: { 0: "Regenerator" },
},
victreebelmega: {
inherit: true,
abilities: { 0: "Regenerator" },
},
starmiemega: {
inherit: true,
abilities: { 0: "Huge Power" },
},
skarmorymega: {
inherit: true,
abilities: { 0: "Huge Power" },
},
scolipedemega: {
inherit: true,
abilities: { 0: "Huge Power" },
},
scraftymega: {
inherit: true,
abilities: { 0: "Huge Power" },
},
emboarmega: {
inherit: true,
abilities: { 0: "Regenerator" },
},
eelektrossmega: {
inherit: true,
abilities: { 0: "Regenerator" },
},
chesnaughtmega: {
inherit: true,
abilities: { 0: "Regenerator" },
},
delphoxmega: {
inherit: true,
abilities: { 0: "Regenerator" },
},
greninjamega: {
inherit: true,
abilities: { 0: "Regenerator" },
},
pyroarmega: {
inherit: true,
abilities: { 0: "Regenerator" },
},
barbaraclemega: {
inherit: true,
abilities: { 0: "Huge Power" },
},
hawluchamega: {
inherit: true,
abilities: { 0: "Huge Power" },
},
raichumegax: {
inherit: true,
abilities: { 0: "Huge Power" },
},
chimechomega: {
inherit: true,
abilities: { 0: "Regenerator" },
},
baxcaliburmega: {
inherit: true,
abilities: { 0: "Huge Power" },
},
zeraoramega: {
inherit: true,
abilities: { 0: "Huge Power" },
},
absolmegaz: {
inherit: true,
abilities: { 0: "Huge Power" },
},
staraptormega: {
inherit: true,
abilities: { 0: "Huge Power" },
},
golisopodmega: {
inherit: true,
abilities: { 0: "Huge Power" },
},
meowsticfmega: {
inherit: true,
abilities: { 0: "Regenerator" },
},
crabominablemega: {
inherit: true,
abilities: { 0: "Huge Power" },
},
golurkmega: {
inherit: true,
abilities: { 0: "Huge Power" },
},
garchompmegaz: {
inherit: true,
abilities: { 0: "Huge Power" },
},
lucariomegaz: {
inherit: true,
abilities: { 0: "Regenerator" },
},
raichumegay: {
inherit: true,
abilities: { 0: "Regenerator" },
},
falinksmega: {
inherit: true,
abilities: { 0: "No Retreat" },
},
drampamega: {
inherit: true,
abilities: { 0: "Regenerator" },
},
zygardemega: {
inherit: true,
abilities: { 0: "Regenerator" },
},
dragalgemega: {
inherit: true,
abilities: { 0: "Regenerator" },
},
darkraimega: {
inherit: true,
abilities: { 0: "Regenerator" },
},
heatranmega: {
inherit: true,
abilities: { 0: "Regenerator" },
},
floettemega: {
inherit: true,
abilities: { 0: "Regenerator" },
},
chandeluremega: {
inherit: true,
abilities: { 0: "Shadow Tag" },
},
lickitung: {
inherit: true,
abilities: { 0: "Own Tempo", 1: "Oblivious", H: "Chaos Saliva" },
},
mewtwo: {
inherit: true,
abilities: { 0: "Pressure", 1: "Neuroforce", H: "Unnerve" },
},
scovillainmega: {
inherit: true,
abilities: { 0: "Contrary" },
},
mew: {
inherit: true,
abilities: { 0: "Synchronize", 1: "Neuroforce" },
},
smeargle: {
inherit: true,
abilities: { 0: "Own Tempo", 1: "Prankster", H: "Moody" },
},
swampert: {
inherit: true,
abilities: { 0: "Torrent", 1: "Sap Sipper", H: "Damp" },
},
bibarel: {
inherit: true,
baseStats: { hp: 159, atk: 85, def: 60, spa: 55, spd: 60, spe: 151 },
},
skuntank: {
inherit: true,
baseStats: { hp: 103, atk: 93, def: 67, spa: 106, spd: 61, spe: 84 },
abilities: { 0: "Stench", 1: "Aftermath", H: "Mega Launcher" },
},
rampardos: {
inherit: true,
baseStats: { hp: 97, atk: 225, def: 30, spa: 65, spd: 30, spe: 58 },
abilities: { 0: "Rocky Payload", H: "Sheer Force" },
},
gallademega: {
inherit: true,
abilities: { 0: "Sharpness" },
},
garchompmega: {
inherit: true,
abilities: { 0: "Sand Rush" },
},
dusknoir: {
inherit: true,
abilities: { 0: "Damp" },
},
lickilicky: {
inherit: true,
abilities: { 0: "Own Tempo", 1: "Oblivious", H: "Chaos Saliva" },
},
regigigas: {
inherit: true,
abilities: { 0: "Slow Start", H: "Fast Start" },
},
serperior: {
inherit: true,
types: ['Grass', 'Dragon'],
baseStats: { hp: 75, atk: 75, def: 95, spa: 105, spd: 95, spe: 113 },
},
simisage: {
inherit: true,
baseStats: { hp: 120, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 },
},
excadrillmega: {
inherit: true,
abilities: { 0: "It's Excadrillin' Time!" },
},
chandelure: {
inherit: true,
abilities: { 0: "Flash Fire", 1: "Flame Body", H: "Shadow Tag" },
},
delphox: {
inherit: true,
abilities: { 0: "Blaze", H: "Discourage" },
},
clawitzer: {
inherit: true,
abilities: { 0: "Super Mega Launcher" },
},
malamar: {
inherit: true,
baseStats: { hp: 101, atk: 112, def: 88, spa: 68, spd: 75, spe: 73 },
},
malamarmega: {
inherit: true,
baseStats: { hp: 101, atk: 122, def: 88, spa: 98, spd: 120, spe: 88 },
abilities: { 0: "Contrary" },
},
incineroar: {
inherit: true,
types: ['Fire', 'Fighting'],
},
incineroar2: {
num: 2000,
name: "Incineroar 2",
types: ["Ghost", "Steel"],
genderRatio: { M: 0.875, F: 0.125 },
baseStats: { hp: 95, atk: 115, def: 90, spa: 80, spd: 90, spe: 60 },
abilities: { 0: "Intimidate 2" },
heightm: 1.8,
weightkg: 83,
color: "Red",
eggGroups: ["Field"],
},
celesteela: {
inherit: true,
baseStats: { hp: 5, atk: 5, def: 5, spa: 5, spd: 5, spe: 5 },
},
hatterene: {
inherit: true,
types: ['Psychic', 'Dark'],
},
glimmora: {
inherit: true,
baseStats: { hp: 106, atk: 150, def: 70, spa: 194, spd: 120, spe: 140 },
},
glimmoramega: {
inherit: true,
baseStats: { hp: 106, atk: 185, def: 85, spa: 214, spd: 145, spe: 155 },
abilities: { 0: "Regenerator" },
},
tatsugiri: {
inherit: true,
abilities: { 0: "Commander", 1: "Parental Bond", H: "Storm Drain" },
},
tatsugiridroopy: {
inherit: true,
abilities: { 0: "Commander", 1: "Parental Bond", H: "Storm Drain" },
},
tatsugiristretchy: {
inherit: true,
abilities: { 0: "Commander", 1: "Parental Bond", H: "Storm Drain" },
},
tatsugiricurlymega: {
inherit: true,
abilities: { 0: "Parental Bond" },
},
tatsugiridroopymega: {
inherit: true,
abilities: { 0: "Parental Bond" },
},
tatsugiristretchymega: {
inherit: true,
abilities: { 0: "Parental Bond" },
},
calyrex: {
num: 898,
name: "Calyrex",
types: ["Psychic", "Grass"],
gender: "N",
baseStats: { hp: 100, atk: 80, def: 80, spa: 80, spd: 80, spe: 80 },
abilities: { 0: "Unnerve" },
heightm: 1.1,
weightkg: 7.7,
color: "Green",
eggGroups: ["Undiscovered"],
tags: ["Restricted Legendary"],
otherFormes: ["Calyrex-Ice", "Calyrex-Shadow", "Calyrex-Monarch"],
formeOrder: ["Calyrex", "Calyrex-Ice", "Calyrex-Shadow", "Calyrex-Monarch"],
},
calyrexmonarch: {
num: 898,
name: "Calyrex-Monarch",
baseSpecies: "Calyrex",
forme: "Monarch",
types: ["Psychic", "Grass"],
gender: "N",
baseStats: { hp: 200, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 },
abilities: { 0: "As One (Calyrex)" },
heightm: 2.2,
weightkg: 15.4,
color: "Green",
eggGroups: ["Undiscovered"],
changesFrom: "Calyrex",
},
spidops: {
inherit: true,
baseStats: { hp: 100, atk: 100, def: 100, spa: 100, spd: 100, spe: 0 },
},
};

View File

@ -0,0 +1,788 @@
import { Utils } from '../../../lib';
import RandomTeams from '../../random-battles/gen9/teams';
import { toID } from '../../../sim/dex';
export interface TeamData {
typeCount: { [k: string]: number };
typeComboCount: { [k: string]: number };
baseFormes: { [k: string]: number };
megaCount?: number;
zCount?: number;
wantsTeraCount?: number;
has: { [k: string]: number };
forceResult: boolean;
weaknesses: { [k: string]: number };
resistances: { [k: string]: number };
weather?: string;
eeveeLimCount?: number;
gigantamax?: boolean;
}
export interface BattleFactorySpecies {
sets: BattleFactorySet[];
weight: number;
}
interface BattleFactorySet {
species: string;
weight: number;
item: string[];
ability: string[];
nature: string[];
moves: string[][];
teraType: string[];
gender?: string;
wantsTera?: boolean;
evs?: Partial<StatsTable>;
ivs?: Partial<StatsTable>;
shiny?: boolean;
level?: number;
}
export class MoveCounter extends Utils.Multiset<string> {
damagingMoves: Set<Move>;
basePowerMoves: Set<Move>;
constructor() {
super();
this.damagingMoves = new Set();
this.basePowerMoves = new Set();
}
}
// Moves that switch the user out
const PIVOT_MOVES = [
'chillyreception', 'flipturn', 'partingshot', 'shedtail', 'teleport', 'uturn', 'voltswitch',
];
/** Pokemon who should never be in the lead slot */
const NO_LEAD_POKEMON = [
'Zacian', 'Zamazenta',
];
const DEFENSIVE_TERA_BLAST_USERS = [
'alcremie', 'bellossom', 'comfey', 'fezandipiti', 'florges',
];
export class RandomAFDTeams extends RandomTeams {
override shouldCullAbility(
ability: string,
types: string[],
moves: Set<string>,
abilities: string[],
counter: MoveCounter,
teamDetails: RandomTeamsTypes.TeamDetails,
species: Species,
isLead: boolean,
isDoubles: boolean,
teraType: string,
role: RandomTeamsTypes.Role,
): boolean {
switch (ability) {
// Abilities which are primarily useful for certain moves or with team support
case 'Chlorophyll': case 'Solar Power':
return !teamDetails.sun;
case 'Defiant':
return (species.id === 'thundurus' && !!counter.get('Status'));
case 'Hydration': case 'Swift Swim':
return !teamDetails.rain;
case 'Iron Fist': case 'Skill Link':
return !counter.get(toID(ability));
case 'Overgrow':
return !counter.get('Grass');
case 'Prankster':
return !counter.get('Status');
case 'Sand Force': case 'Sand Rush': case 'It\'s Excadrillin\' Time!':
return !teamDetails.sand;
case 'Slush Rush':
return !teamDetails.snow;
case 'Swarm':
return !counter.get('Bug');
case 'Torrent':
return (!counter.get('Water') && !moves.has('flipturn'));
}
return false;
}
override getAbility(
types: string[],
moves: Set<string>,
abilities: string[],
counter: MoveCounter,
teamDetails: RandomTeamsTypes.TeamDetails,
species: Species,
isLead: boolean,
isDoubles: boolean,
teraType: string,
role: RandomTeamsTypes.Role,
): string {
if (abilities.length <= 1) return abilities[0];
// Hard-code abilities here
if (species.id === 'drifblim') return moves.has('defog') ? 'Aftermath' : 'Unburden';
if (abilities.includes('Flash Fire') && this.dex.getEffectiveness('Fire', teraType) >= 1) return 'Flash Fire';
if ((species.id === 'thundurus' || species.id === 'tornadus') && !counter.get('Physical')) return 'Prankster';
if (species.id === 'toucannon' && counter.get('skilllink')) return 'Skill Link';
if (abilities.includes('Slush Rush') && moves.has('snowscape')) return 'Slush Rush';
if (species.id === 'golduck' && teamDetails.rain) return 'Swift Swim';
const abilityAllowed: string[] = [];
// Obtain a list of abilities that are allowed (not culled)
for (const ability of abilities) {
if (!this.shouldCullAbility(
ability, types, moves, abilities, counter, teamDetails, species, isLead, isDoubles, teraType, role
)) {
abilityAllowed.push(ability);
}
}
// Pick a random allowed ability
if (abilityAllowed.length >= 1) return this.sample(abilityAllowed);
// If all abilities are rejected, prioritize weather abilities over non-weather abilities
if (!abilityAllowed.length) {
const weatherAbilities = abilities.filter(
a => ['Chlorophyll', 'Hydration', 'Sand Force', 'Sand Rush', 'Slush Rush', 'Solar Power', 'Swift Swim'].includes(a)
);
if (weatherAbilities.length) return this.sample(weatherAbilities);
}
// Pick a random ability
return this.sample(abilities);
}
override getPriorityItem(
ability: string,
types: string[],
moves: Set<string>,
counter: MoveCounter,
teamDetails: RandomTeamsTypes.TeamDetails,
species: Species,
isLead: boolean,
isDoubles: boolean,
teraType: string,
role: RandomTeamsTypes.Role,
) {
if (role === 'Fast Bulky Setup' && (ability === 'Quark Drive' || ability === 'Protosynthesis')) {
return 'Booster Energy';
}
if (species.id === 'lokix') {
return (role === 'Fast Attacker') ? 'Silver Powder' : 'Life Orb';
}
if (species.requiredItems && species.baseSpecies !== 'Magearna') {
// Z-Crystals aren't available in Gen 9, so require Plates
if (species.baseSpecies === 'Arceus') {
return species.requiredItems[0];
}
return this.sample(species.requiredItems);
}
if (species.id === 'pikachu') return 'Light Ball';
if (role === 'AV Pivot') return 'Assault Vest';
if (species.id === 'regieleki') return 'Magnet';
if (types.includes('Normal') && moves.has('doubleedge') && moves.has('fakeout')) return 'Silk Scarf';
if (
species.id === 'froslass' || moves.has('populationbomb') ||
(ability === 'Hustle' && counter.get('setup') && !isDoubles && this.randomChance(1, 2))
) return 'Wide Lens';
if (species.id === 'smeargle') return 'Focus Sash';
if (moves.has('clangoroussoul') || (species.id === 'toxtricity' && moves.has('shiftgear'))) return 'Throat Spray';
if (
(species.baseSpecies === 'Magearna' && role === 'Tera Blast user') ||
((species.id === 'calyrexice' || species.id === 'necrozmaduskmane') && isDoubles)
) return 'Weakness Policy';
if (['dragonenergy', 'lastrespects', 'waterspout'].some(m => moves.has(m))) return 'Choice Scarf';
if (
!isDoubles && (ability === 'Imposter' || (species.id === 'magnezone' && role === 'Fast Attacker'))
) return 'Choice Scarf';
if (species.id === 'rampardos' && (role === 'Fast Attacker' || isDoubles)) return 'Choice Scarf';
if (species.id === 'palkia' && counter.get('Status')) return 'Lustrous Orb';
if (
moves.has('courtchange') ||
!isDoubles && (species.id === 'luvdisc' || (species.id === 'terapagos' && !moves.has('rest')))
) return 'Hoots';
if (['Cheek Pouch', 'Cud Chew', 'Harvest', 'Ripen'].some(m => ability === m)) {
return 'Sitrus Berry';
}
if (moves.has('bellydrum') || moves.has('filletaway')) return 'Ward Tag';
if (['healingwish', 'switcheroo', 'trick'].some(m => moves.has(m))) {
if (
species.baseStats.spe >= 60 && species.baseStats.spe <= 108 &&
role !== 'Wallbreaker' && role !== 'Doubles Wallbreaker' && !counter.get('priority')
) {
return 'Choice Scarf';
} else {
return (counter.get('Physical') > counter.get('Special')) ? 'Choice Band' : 'Choice Specs';
}
}
if (counter.get('Status') && (species.name === 'Latias' || species.name === 'Latios')) return 'Soul Dew';
if (species.id === 'scyther' && !isDoubles) return (isLead && !moves.has('uturn')) ? 'Eviolite' : 'Hoots';
if (ability === 'Poison Heal' || ability === 'Quick Feet') return 'Toxic Orb';
if (species.nfe) return 'Eviolite';
if ((ability === 'Guts' || moves.has('facade')) && !moves.has('sleeptalk')) {
return (types.includes('Fire') || ability === 'Toxic Boost') ? 'Toxic Orb' : 'Flame Orb';
}
if (ability === 'Magic Guard' || (ability === 'Sheer Force' && counter.get('sheerforce'))) return 'Life Orb';
if (ability === 'Anger Shell') return this.sample(['Expert Belt', 'Lum Berry', 'Scope Lens', 'Sitrus Berry']);
if (moves.has('dragondance') && isDoubles) return 'Clear Amulet';
if (counter.get('skilllink') && ability !== 'Skill Link' && species.id !== 'breloom') return 'Loaded Dice';
if (ability === 'Unburden') {
return (moves.has('closecombat') || moves.has('leafstorm')) ? 'White Herb' : 'Sitrus Berry';
}
if (moves.has('shellsmash') && ability !== 'Weak Armor') return 'White Herb';
if (moves.has('meteorbeam') || (moves.has('electroshot') && !teamDetails.rain)) return 'Power Herb';
if (moves.has('acrobatics') && ability !== 'Protosynthesis') return '';
if (moves.has('auroraveil') || moves.has('lightscreen') && moves.has('reflect')) return 'Light Clay';
if (ability === 'Gluttony') return `${this.sample(['Aguav', 'Figy', 'Iapapa', 'Mago', 'Wiki'])} Berry`;
if (species.id === 'giratina' && !isDoubles && moves.has('rest') && !moves.has('sleeptalk')) return 'Leftovers';
if (
moves.has('rest') && !moves.has('sleeptalk') &&
ability !== 'Natural Cure' && ability !== 'Shed Skin'
) {
return 'Chesto Berry';
}
if (
species.id !== 'yanmega' &&
this.dex.getEffectiveness('Rock', species) >= 2 && (!types.includes('Flying') || !isDoubles)
) return 'Hoots';
}
override getItem(
ability: string,
types: string[],
moves: Set<string>,
counter: MoveCounter,
teamDetails: RandomTeamsTypes.TeamDetails,
species: Species,
isLead: boolean,
teraType: string,
role: RandomTeamsTypes.Role,
): string {
const lifeOrbReqs = ['flamecharge', 'nuzzle', 'rapidspin'].every(m => !moves.has(m));
if (
species.id !== 'jirachi' && (counter.get('Physical') >= moves.size) &&
['dragontail', 'fakeout', 'firstimpression', 'flamecharge', 'rapidspin', 'trailblaze'].every(m => !moves.has(m))
) {
const scarfReqs = (
role !== 'Wallbreaker' &&
(species.baseStats.atk >= 100 || ability === 'Huge Power' || ability === 'Pure Power') &&
species.baseStats.spe >= 60 && species.baseStats.spe <= 108 &&
ability !== 'Speed Boost' && !counter.get('priority')
);
return (scarfReqs && this.randomChance(1, 2)) ? 'Choice Scarf' : 'Choice Band';
}
if (
(counter.get('Special') >= moves.size) ||
(counter.get('Special') >= moves.size - 1 && ['flipturn', 'uturn'].some(m => moves.has(m)))
) {
const scarfReqs = (
role !== 'Wallbreaker' &&
species.baseStats.spa >= 100 &&
species.baseStats.spe >= 60 && species.baseStats.spe <= 108 &&
ability !== 'Speed Boost' && ability !== 'Tinted Lens' && !moves.has('uturn') && !counter.get('priority')
);
return (scarfReqs && this.randomChance(1, 2)) ? 'Choice Scarf' : 'Choice Specs';
}
if (counter.get('speedsetup') && !counter.get('physicalsetup') && role === 'Bulky Setup') return 'Weakness Policy';
if (
!counter.get('Status') &&
!['Fast Attacker', 'Wallbreaker', 'Tera Blast user'].includes(role)
) {
return 'Assault Vest';
}
if (species.id === 'golem') return (counter.get('speedsetup')) ? 'Weakness Policy' : 'Custap Berry';
if (moves.has('substitute')) return 'Leftovers';
if (
moves.has('stickyweb') && isLead &&
(species.baseStats.hp + species.baseStats.def + species.baseStats.spd) <= 235
) return 'Focus Sash';
if (this.dex.getEffectiveness('Rock', species) >= 1) return 'Hoots';
if (
(moves.has('chillyreception') || (
role === 'Fast Support' &&
[...PIVOT_MOVES, 'defog', 'mortalspin', 'rapidspin'].some(m => moves.has(m)) &&
!types.includes('Flying') && ability !== 'Levitate'
))
) return 'Hoots';
// Low Priority
if (moves.has('dragondance') && role === 'Bulky Setup') return 'Weakness Policy';
if (
ability === 'Rough Skin' || (
ability === 'Regenerator' && (role === 'Bulky Support' || role === 'Bulky Attacker') &&
(species.baseStats.hp + species.baseStats.def) >= 180 && this.randomChance(1, 2)
) || (
ability !== 'Regenerator' && !counter.get('setup') && counter.get('recovery') &&
this.dex.getEffectiveness('Fighting', species) < 1 &&
(species.baseStats.hp + species.baseStats.def) > 200 && this.randomChance(1, 2)
)
) return 'Rocky Helmet';
if (role === 'Bulky Support') return 'Onika Burger';
if (moves.has('outrage') && counter.get('setup')) return 'Lum Berry';
if (moves.has('protect') && ability !== 'Speed Boost') return 'Leftovers';
if (
role === 'Fast Support' && isLead && !counter.get('recovery') && !counter.get('recoil') &&
(counter.get('hazards') || counter.get('setup')) &&
(species.baseStats.hp + species.baseStats.def + species.baseStats.spd) < 258
) return 'Focus Sash';
if (
!counter.get('setup') && ability !== 'Levitate' && this.dex.getEffectiveness('Ground', species) >= 2
) return 'Air Balloon';
if (['Bulky Attacker', 'Bulky Setup'].some(m => role === (m))) return 'Leftovers';
if (species.id === 'pawmot' && moves.has('nuzzle')) return 'Leppa Berry';
if (role === 'Fast Support' || role === 'Fast Bulky Setup') {
return (
counter.get('Physical') + counter.get('Special') > counter.get('Status') && lifeOrbReqs
) ? 'Life Orb' : 'Leftovers';
}
if (role === 'Tera Blast user' && DEFENSIVE_TERA_BLAST_USERS.includes(species.id)) return 'Leftovers';
if (
lifeOrbReqs && ['Fast Attacker', 'Setup Sweeper', 'Tera Blast user', 'Wallbreaker'].some(m => role === (m))
) return 'Life Orb';
return 'Leftovers';
}
override getLevel(species: Species): number {
if (this.adjustLevel) return this.adjustLevel;
const file = this.randomAFDSets[species.id] || this.randomSets[species.id];
if (file["level"]) return file["level"];
// Default to tier-based levelling
const tier = species.tier;
const tierScale: Partial<Record<Species['tier'], number>> = {
Uber: 76,
OU: 80,
UUBL: 81,
UU: 82,
RUBL: 83,
RU: 84,
NUBL: 85,
NU: 86,
PUBL: 87,
PU: 88, "(PU)": 88, NFE: 88,
};
return tierScale[tier] || 80;
}
override getForme(species: Species): string {
if (typeof species.battleOnly === 'string') {
// Only change the forme. The species has custom moves, and may have different typing and requirements.
return species.battleOnly;
}
if (species.cosmeticFormes) return this.sample([species.name].concat(species.cosmeticFormes));
// Consolidate mostly-cosmetic formes, at least for the purposes of Random Battles
if (['Dudunsparce', 'Maushold', 'Polteageist', 'Sinistcha', 'Zarude'].includes(species.baseSpecies)) {
return this.sample([species.name].concat(species.otherFormes!));
}
if (species.baseSpecies === 'Basculin') return 'Basculin' + this.sample(['', '-Blue-Striped']);
if (species.baseSpecies === 'Magearna') return 'Magearna' + this.sample(['', '-Original']);
if (species.baseSpecies === 'Pikachu') {
return 'Pikachu' + this.sample(
['', '-Original', '-Hoenn', '-Sinnoh', '-Unova', '-Kalos', '-Alola', '-Partner', '-World']
);
}
return species.name;
}
randomAFDSet(
s: string | Species,
teamDetails: RandomTeamsTypes.TeamDetails = {},
isLead = false,
isDoubles = false
): RandomTeamsTypes.RandomSet {
const species = this.dex.species.get(s);
const forme = this.getForme(species);
if (!this.randomAFDSets[species.id]) return this.randomSet(species, teamDetails, isLead, isDoubles);
const sets = this.randomAFDSets[species.id]["sets"];
const possibleSets: RandomTeamsTypes.RandomSetData[] = [];
const ruleTable = this.dex.formats.getRuleTable(this.format);
for (const set of sets) {
// Prevent Fast Bulky Setup on lead Paradox Pokemon, since it generates Booster Energy.
const abilities = set.abilities!;
if (
isLead && (abilities.includes('Protosynthesis') || abilities.includes('Quark Drive')) &&
set.role === 'Fast Bulky Setup'
) continue;
// Prevent Tera Blast user if the team already has one, or if Terastallizion is prevented.
if ((teamDetails.teraBlast || ruleTable.has('terastalclause')) && set.role === 'Tera Blast user') {
continue;
}
possibleSets.push(set);
}
const set = this.sampleIfArray(possibleSets);
const role = set.role;
const movePool: string[] = [];
for (const movename of set.movepool) {
movePool.push(this.dex.moves.get(movename).id);
}
const teraTypes = set.teraTypes!;
let teraType = this.sampleIfArray(teraTypes);
let ability = '';
let item = undefined;
const evs = { hp: 85, atk: 85, def: 85, spa: 85, spd: 85, spe: 85 };
const ivs = { hp: 31, atk: 31, def: 31, spa: 31, spd: 31, spe: 31 };
const types = species.types;
const abilities = set.abilities!;
// Get moves
const moves = this.randomMoveset(types, abilities, teamDetails, species, isLead, isDoubles, movePool, teraType, role);
const counter = this.queryMoves(moves, species, teraType, abilities);
// Get ability
ability = this.getAbility(types, moves, abilities, counter, teamDetails, species, isLead, isDoubles, teraType, role);
// Get items
// First, the priority items
item = this.getPriorityItem(ability, types, moves, counter, teamDetails, species, isLead, isDoubles, teraType, role);
if (item === undefined) {
item = this.getItem(ability, types, moves, counter, teamDetails, species, isLead, teraType, role);
}
// Get level
const level = this.getLevel(species);
// Prepare optimal HP
const srImmunity = ability === 'Magic Guard' || item === 'Heavy-Duty Boots' || item === 'Hoots';
let srWeakness = srImmunity ? 0 : this.dex.getEffectiveness('Rock', species);
// Crash damage move users want an odd HP to survive two misses
if (['axekick', 'highjumpkick', 'jumpkick', 'supercellslam'].some(m => moves.has(m))) srWeakness = 2;
while (evs.hp > 1) {
const hp = Math.floor(Math.floor(2 * species.baseStats.hp + ivs.hp + Math.floor(evs.hp / 4) + 100) * level / 100 + 10);
if ((moves.has('substitute') && ['Sitrus Berry'].includes(item)) || species.id === 'minior') {
// Two Substitutes should activate Sitrus Berry. Two switch-ins to Stealth Rock should activate Shields Down on Minior.
if (hp % 4 === 0) break;
} else if (
(moves.has('bellydrum') || moves.has('filletaway') || moves.has('shedtail')) &&
(item === 'Sitrus Berry' || ability === 'Gluttony')
) {
// Belly Drum should activate Sitrus Berry
if (hp % 2 === 0) break;
} else if (moves.has('substitute') && moves.has('endeavor')) {
// Luvdisc should be able to Substitute down to very low HP
if (hp % 4 > 0) break;
} else {
// Maximize number of Stealth Rock switch-ins in singles
if (isDoubles) break;
if (srWeakness <= 0 || ability === 'Regenerator' || ['Leftovers', 'Life Orb'].includes(item)) break;
if (item !== 'Sitrus Berry' && hp % (4 / srWeakness) > 0) break;
// Minimise number of Stealth Rock switch-ins to activate Sitrus Berry
if (item === 'Sitrus Berry' && hp % (4 / srWeakness) === 0) break;
}
evs.hp -= 4;
}
// Minimize confusion damage
const noAttackStatMoves = [...moves].every(m => {
const move = this.dex.moves.get(m);
if (move.damageCallback || move.damage) return true;
if (move.id === 'shellsidearm') return false;
// Physical Tera Blast
if (
move.id === 'terablast' && (species.id === 'porygon2' || ['Contrary', 'Defiant'].includes(ability) ||
moves.has('shiftgear') || species.baseStats.atk > species.baseStats.spa)
) return false;
return move.category !== 'Physical' || move.id === 'bodypress' || move.id === 'foulplay';
});
if (
noAttackStatMoves && !moves.has('transform') && this.format.mod !== 'partnersincrime' &&
!ruleTable.has('forceofthefallenmod')
) {
evs.atk = 0;
ivs.atk = 0;
}
if (moves.has('gyroball') || moves.has('trickroom')) {
evs.spe = 0;
ivs.spe = 0;
}
// Enforce Tera Type after all set generation is done to prevent infinite generation
if (this.forceTeraType) teraType = this.forceTeraType;
// shuffle moves to add more randomness to camomons
const shuffledMoves = Array.from(moves);
this.prng.shuffle(shuffledMoves);
let name = species.baseSpecies;
if (name === "Bruxish") name = "Brux";
return {
name,
species: forme,
speciesId: species.id,
gender: species.baseSpecies === 'Greninja' ? 'M' : (species.gender || (this.random(2) ? 'F' : 'M')),
shiny: this.randomChance(1, 1024),
level,
moves: shuffledMoves,
ability,
evs,
ivs,
item,
teraType,
role,
};
}
/**
* Checks if the new species is compatible with the other mons currently on the team.
*/
override getPokemonCompatibility(
species: Species,
pokemon: RandomTeamsTypes.RandomSet[]
): boolean {
const webSetters = [
'ariados', 'smeargle', 'masquerain', 'kricketune', 'leavanny', 'galvantula', 'vikavolt', 'ribombee', 'araquanid', 'spidops',
];
const screenSetters = ['meowstic', 'grimmsnarl', 'ninetalesalola', 'abomasnow'];
const sunSetters = ['ninetales', 'torkoal', 'groudon', 'koraidon'];
const incompatiblePokemon = [
// These Pokemon with support roles are considered too similar to each other.
['blissey', 'chansey'],
['illumise', 'volbeat'],
// These combinations are prevented to avoid double webs or screens.
[webSetters, webSetters],
[screenSetters, screenSetters],
// These Pokemon are incompatible because the presence of one actively harms the other.
// Prevent Dry Skin + sun setting ability
['toxicroak', sunSetters],
];
const incompatibilityList = incompatiblePokemon;
for (const pair of incompatibilityList) {
const monsArrayA = (Array.isArray(pair[0])) ? pair[0] : [pair[0]];
const monsArrayB = (Array.isArray(pair[1])) ? pair[1] : [pair[1]];
if (monsArrayB.includes(species.id)) {
if (pokemon.some(m => monsArrayA.includes(m.speciesId!))) return false;
}
if (monsArrayA.includes(species.id)) {
if (pokemon.some(m => monsArrayB.includes(m.speciesId!))) return false;
}
}
return true;
}
randomAFDSets: { [species: string]: RandomTeamsTypes.RandomSpeciesData } = require('./sets.json');
override randomTeam() {
this.enforceNoDirectCustomBanlistChanges();
const seed = this.prng.getSeed();
const ruleTable = this.dex.formats.getRuleTable(this.format);
const pokemon: RandomTeamsTypes.RandomSet[] = [];
// PotD stuff
const usePotD = global.Config && Config.potd && ruleTable.has('potd');
const potd = usePotD ? this.dex.species.get(Config.potd) : null;
const baseFormes: { [k: string]: number } = {};
const typeCount: { [k: string]: number } = {};
const typeComboCount: { [k: string]: number } = {};
const typeWeaknesses: { [k: string]: number } = {};
const typeDoubleWeaknesses: { [k: string]: number } = {};
const teamDetails: RandomTeamsTypes.TeamDetails = {};
let numMaxLevelPokemon = 0;
const pokemonList = Object.keys(this.randomSets);
const afdList = Object.keys(this.randomAFDSets);
const zaMegaList = Object.keys(this.randomAFDSets).filter(x => (
this.dex.species.get(x).isMega && this.dex.species.get(x).gen === 9
));
const [pokemonPool, baseSpeciesPool] = this.getPokemonPool('', pokemon, false, pokemonList);
const [afdPool, baseAfdPool] = this.getPokemonPool('', pokemon, false, afdList);
const [zaMegaPool, zaBaseMegaPool] = this.getPokemonPool('', pokemon, false, zaMegaList);
let leadsRemaining = this.format.gameType === 'doubles' ? 2 : 1;
while (baseSpeciesPool.length && pokemon.length < this.maxTeamSize) {
let baseSpecies, species;
if (pokemon.length === 0) {
baseSpecies = this.sampleNoReplace(zaBaseMegaPool);
species = this.dex.species.get(this.sample(zaMegaPool[baseSpecies]));
} else if (this.randomChance(1, 5)) {
baseSpecies = this.sampleNoReplace(baseAfdPool);
species = this.dex.species.get(this.sample(afdPool[baseSpecies]));
} else {
baseSpecies = this.sampleNoReplace(baseSpeciesPool);
species = this.dex.species.get(this.sample(pokemonPool[baseSpecies]));
}
if (!species.exists) continue;
// Limit to one of each species (Species Clause)
if (baseFormes[species.baseSpecies]) continue;
// Treat Ogerpon formes and Terapagos like the Tera Blast user role; reject if team has one already
if (['ogerpon', 'ogerponhearthflame', 'terapagos'].includes(species.id) && teamDetails.teraBlast) continue;
// Illusion shouldn't be on the last slot
if (species.baseSpecies === 'Zoroark' && pokemon.length >= (this.maxTeamSize - 1)) continue;
const types = species.types;
const typeCombo = types.slice().sort().join();
const weakToFreezeDry = (
this.dex.getEffectiveness('Ice', species) > 0 ||
(this.dex.getEffectiveness('Ice', species) > -2 && types.includes('Water'))
);
const weakToScald = (
this.dex.getEffectiveness('Water', species) > 0 ||
(this.dex.getEffectiveness('Water', species) > -2 && types.includes('Steel'))
);
// Dynamically scale limits for different team sizes. The default and minimum value is 1.
const limitFactor = Math.round(this.maxTeamSize / 6) || 1;
let skip = false;
// Limit two of any type
for (const typeName of types) {
if (typeCount[typeName] >= 2 * limitFactor) {
skip = true;
break;
}
}
if (skip) continue;
// Limit three weak to any type, and one double weak to any type
for (const typeName of this.dex.types.names()) {
// it's weak to the type
if (this.dex.getEffectiveness(typeName, species) > 0) {
if (!typeWeaknesses[typeName]) typeWeaknesses[typeName] = 0;
if (typeWeaknesses[typeName] >= 3 * limitFactor) {
skip = true;
break;
}
}
if (this.dex.getEffectiveness(typeName, species) > 1) {
if (!typeDoubleWeaknesses[typeName]) typeDoubleWeaknesses[typeName] = 0;
if (typeDoubleWeaknesses[typeName] >= limitFactor) {
skip = true;
break;
}
}
}
if (skip) continue;
// Count Dry Skin/Fluffy as Fire weaknesses
if (
this.dex.getEffectiveness('Fire', species) === 0 &&
Object.values(species.abilities).filter(a => ['Dry Skin', 'Fluffy'].includes(a)).length
) {
if (!typeWeaknesses['Fire']) typeWeaknesses['Fire'] = 0;
if (typeWeaknesses['Fire'] >= 3 * limitFactor) continue;
}
// Limit four weak to Freeze-Dry
if (weakToFreezeDry) {
if (!typeWeaknesses['Freeze-Dry']) typeWeaknesses['Freeze-Dry'] = 0;
if (typeWeaknesses['Freeze-Dry'] >= 4 * limitFactor) continue;
}
if (weakToScald) {
if (!typeWeaknesses['Scald']) typeWeaknesses['Scald'] = 0;
if (typeWeaknesses['Scald'] >= 4 * limitFactor) continue;
}
// Limit one level 100 Pokemon
if (!this.adjustLevel && (this.getLevel(species) === 100) && numMaxLevelPokemon >= limitFactor) {
continue;
}
// Check compatibility with team
if (!this.getPokemonCompatibility(species, pokemon)) continue;
// The Pokemon of the Day
if (potd?.exists && (pokemon.length === 1 || this.maxTeamSize === 1)) species = potd;
let set: RandomTeamsTypes.RandomSet;
if (leadsRemaining) {
if (NO_LEAD_POKEMON.includes(species.baseSpecies)) {
if (pokemon.length + leadsRemaining === this.maxTeamSize) continue;
set = this.randomAFDSet(species, teamDetails, false);
pokemon.push(set);
} else {
set = this.randomAFDSet(species, teamDetails, true);
pokemon.unshift(set);
leadsRemaining--;
}
} else {
set = this.randomAFDSet(species, teamDetails, false);
pokemon.push(set);
}
// Don't bother tracking details for the last Pokemon
if (pokemon.length === this.maxTeamSize) break;
// Now that our Pokemon has passed all checks, we can increment our counters
baseFormes[species.baseSpecies] = 1;
// Increment type counters
for (const typeName of types) {
if (typeName in typeCount) {
typeCount[typeName]++;
} else {
typeCount[typeName] = 1;
}
}
if (typeCombo in typeComboCount) {
typeComboCount[typeCombo]++;
} else {
typeComboCount[typeCombo] = 1;
}
// Increment weakness counter
for (const typeName of this.dex.types.names()) {
// it's weak to the type
if (this.dex.getEffectiveness(typeName, species) > 0) {
typeWeaknesses[typeName]++;
}
if (this.dex.getEffectiveness(typeName, species) > 1) {
typeDoubleWeaknesses[typeName]++;
}
}
// Count Dry Skin/Fluffy as Fire weaknesses
if (['Dry Skin', 'Fluffy'].includes(set.ability) && this.dex.getEffectiveness('Fire', species) === 0) {
typeWeaknesses['Fire']++;
}
if (weakToFreezeDry) typeWeaknesses['Freeze-Dry']++;
if (weakToScald) typeWeaknesses['Scald']++;
// Increment level 100 counter
if (set.level === 100) numMaxLevelPokemon++;
// Track what the team has
if (set.ability === 'Drizzle' || set.moves.includes('raindance')) teamDetails.rain = 1;
if (set.ability === 'Drought' || set.ability === 'Orichalcum Pulse' || set.moves.includes('sunnyday')) {
teamDetails.sun = 1;
}
if (set.ability === 'Sand Stream') teamDetails.sand = 1;
if (set.ability === 'Snow Warning' || set.moves.includes('snowscape') || set.moves.includes('chillyreception')) {
teamDetails.snow = 1;
}
if (set.moves.includes('healbell')) teamDetails.statusCure = 1;
if (set.moves.includes('spikes') || set.moves.includes('ceaselessedge')) {
teamDetails.spikes = (teamDetails.spikes || 0) + 1;
}
if (set.moves.includes('toxicspikes') || set.ability === 'Toxic Debris') teamDetails.toxicSpikes = 1;
if (set.moves.includes('stealthrock') || set.moves.includes('stoneaxe')) teamDetails.stealthRock = 1;
if (set.moves.includes('stickyweb')) teamDetails.stickyWeb = 1;
if (set.moves.includes('defog')) teamDetails.defog = 1;
if (set.moves.includes('rapidspin') || set.moves.includes('mortalspin')) teamDetails.rapidSpin = 1;
if (set.moves.includes('auroraveil') || (set.moves.includes('reflect') && set.moves.includes('lightscreen'))) {
teamDetails.screens = 1;
}
if (set.role === 'Tera Blast user' || ['ogerpon', 'ogerponhearthflame', 'terapagos'].includes(species.id)) {
teamDetails.teraBlast = 1;
}
}
if (pokemon.length < this.maxTeamSize && pokemon.length < 12) { // large teams sometimes cannot be built
throw new Error(`Could not build a random team for ${this.format} (seed=${seed})`);
}
return pokemon;
}
}
export default RandomAFDTeams;

626
data/mods/afd/scripts.ts Normal file
View File

@ -0,0 +1,626 @@
export const Scripts: ModdedBattleScriptsData = {
gen: 9,
init() {
for (const id in this.data.Pokedex) {
const species = this.data.Pokedex[id];
if (species.isCosmeticForme) continue;
if (species.types.includes('Ground')) {
if (this.data.Learnsets[id]?.learnset) this.modData('Learnsets', id).learnset.thousandarrows = ['9L1'];
}
if (species.types.includes('Grass') && !species.types.includes('Fire')) {
if (this.data.Learnsets[id]?.learnset) this.modData('Learnsets', id).learnset.solarflare = ['9L1'];
}
const abilities = this.modData('Pokedex', id, true).abilities;
if (species.baseStats['atk'] >= 130) {
const hasHP = Object.values(abilities).includes('Huge Power') ||
Object.values(abilities).includes('Pure Power');
if (!hasHP) {
const slot = !abilities['1'] ? '1' : !abilities['H'] ? 'H' : 'S';
abilities[slot] ||= 'Huge Power';
}
}
const hasRegen = Object.values(abilities).includes('Regenerator');
if (!hasRegen) {
const slot = !abilities['1'] ? '1' : !abilities['H'] ? 'H' : 'S';
abilities[slot] ||= 'Regenerator';
}
}
this.modData('Learnsets', 'tyranitar').learnset.shoreup = ['9L1'];
this.modData('Learnsets', 'bastiodon').learnset.blastiodon = ['9L1'];
this.modData('Learnsets', 'seaking').learnset.boltbeak = ['9L1'];
this.modData('Learnsets', 'seaking').learnset.fishiousrend = ['9L1'];
this.modData('Learnsets', 'ampharos').learnset.tailglow = ['9L1'];
this.modData('Learnsets', 'ampharos').learnset.dracometeor = ['9L1'];
this.modData('Learnsets', 'serperior').learnset.dracometeor = ['9L1'];
this.modData('Learnsets', 'serperior').learnset.overheat = ['9L1'];
this.modData('Learnsets', 'serperior').learnset.makeitrain = ['9L1'];
this.modData('Learnsets', 'rampardos').learnset.accelerock = ['9L1'];
this.modData('Learnsets', 'bibarel').learnset.bellydrum = ['9L1'];
this.modData('Learnsets', 'bibarel').learnset.storedpower = ['9L1'];
this.modData('Learnsets', 'bibarel').learnset.powertrip = ['9L1'];
this.modData('Learnsets', 'golisopod').learnset.bellydrum = ['9L1'];
this.modData('Learnsets', 'skuntank').learnset.shitpulse = ['9L1'];
this.modData('Learnsets', 'dusknoir').learnset = { explosion: ['9L1'] };
for (const move of this.moves.all()) {
if (move.flags['bite']) {
this.modData('Learnsets', 'bruxish').learnset[move.id] = ['9L1'];
}
}
for (const moveid in this.data.Learnsets['incineroar'].learnset) {
if (this.moves.get(moveid).type === 'Dark') {
delete this.modData('Learnsets', 'incineroar').learnset[moveid];
}
}
},
actions: {
runMegaEvo(pokemon: Pokemon) {
const speciesid = pokemon.canMegaEvo || pokemon.canUltraBurst;
if (!speciesid) return false;
pokemon.formeChange(speciesid, pokemon.getItem(), true);
// Limit one mega evolution
pokemon.canMegaEvo = null;
this.battle.runEvent('AfterMega', pokemon);
return true;
},
switchIn(pokemon, pos, sourceEffect = null, isDrag) {
if (!pokemon || pokemon.isActive) {
this.battle.hint("A switch failed because the Pokémon trying to switch in is already in.");
return false;
}
const side = pokemon.side;
if (pos >= side.active.length) {
throw new Error(`Invalid switch position ${pos} / ${side.active.length}`);
}
const oldActive = side.active[pos];
const unfaintedActive = oldActive?.hp ? oldActive : null;
if (unfaintedActive) {
oldActive.beingCalledBack = true;
let switchCopyFlag: 'copyvolatile' | 'shedtail' | boolean = false;
if (sourceEffect && typeof (sourceEffect as Move).selfSwitch === 'string') {
switchCopyFlag = (sourceEffect as Move).selfSwitch!;
}
if (!oldActive.skipBeforeSwitchOutEventFlag && !isDrag) {
this.battle.runEvent('BeforeSwitchOut', oldActive);
if (this.battle.gen >= 5) {
this.battle.eachEvent('Update');
}
}
oldActive.skipBeforeSwitchOutEventFlag = false;
if (!this.battle.runEvent('SwitchOut', oldActive)) {
// Warning: DO NOT interrupt a switch-out if you just want to trap a pokemon.
// To trap a pokemon and prevent it from switching out, (e.g. Mean Look, Magnet Pull)
// use the 'trapped' flag instead.
// Note: Nothing in the real games can interrupt a switch-out (except Pursuit KOing,
// which is handled elsewhere); this is just for custom formats.
return false;
}
if (!oldActive.hp) {
// a pokemon fainted from Pursuit before it could switch
return 'pursuitfaint';
}
// will definitely switch out at this point
this.battle.singleEvent('End', oldActive.getAbility(), oldActive.abilityState, oldActive);
this.battle.singleEvent('End', oldActive.getItem(), oldActive.itemState, oldActive);
// if a pokemon is forced out by Whirlwind/etc or Eject Button/Pack, it can't use its chosen move
this.battle.queue.cancelAction(oldActive);
let newMove = null;
if (this.battle.gen === 4 && sourceEffect) {
newMove = oldActive.lastMove;
}
if (switchCopyFlag) {
pokemon.copyVolatileFrom(oldActive, switchCopyFlag);
}
if (newMove) pokemon.lastMove = newMove;
oldActive.clearVolatile();
}
if (oldActive) {
oldActive.isActive = false;
oldActive.isStarted = false;
oldActive.usedItemThisTurn = false;
oldActive.statsRaisedThisTurn = false;
oldActive.statsLoweredThisTurn = false;
oldActive.position = pokemon.position;
if (oldActive.fainted) oldActive.status = '';
if (this.battle.gen <= 4) {
pokemon.lastItem = oldActive.lastItem;
oldActive.lastItem = '';
}
pokemon.position = pos;
side.pokemon[pokemon.position] = pokemon;
side.pokemon[oldActive.position] = oldActive;
}
pokemon.isActive = true;
side.active[pos] = pokemon;
pokemon.activeTurns = 0;
pokemon.activeMoveActions = 0;
for (const moveSlot of pokemon.moveSlots) {
moveSlot.used = false;
}
pokemon.abilityState = this.battle.initEffectState({ id: pokemon.ability, target: pokemon });
pokemon.itemState = this.battle.initEffectState({ id: pokemon.item, target: pokemon });
this.battle.runEvent('BeforeSwitchIn', pokemon);
if (sourceEffect) {
this.battle.add(isDrag ? 'drag' : 'switch', pokemon, pokemon.getFullDetails, `[from] ${sourceEffect}`);
} else {
this.battle.add(isDrag ? 'drag' : 'switch', pokemon, pokemon.getFullDetails);
}
if (isDrag && this.battle.gen === 2) pokemon.draggedIn = this.battle.turn;
pokemon.previouslySwitchedIn++;
if (isDrag && this.battle.gen >= 5) {
// runSwitch happens immediately so that Mold Breaker can make hazards bypass Clear Body and Levitate
this.runSwitch(pokemon);
} else {
this.battle.queue.insertChoice({ choice: 'runSwitch', pokemon });
}
if (pokemon.hasType('Flying')) {
this.battle.field.addPseudoWeather('Tailwind', pokemon);
}
return true;
},
useMoveInner(moveOrMoveName, pokemon, options) {
let target = options?.target;
let sourceEffect = options?.sourceEffect;
const zMove = options?.zMove;
const maxMove = options?.maxMove;
if (!sourceEffect && this.battle.effect.id) sourceEffect = this.battle.effect;
if (sourceEffect && ['instruct', 'custapberry'].includes(sourceEffect.id)) sourceEffect = null;
let move = this.dex.getActiveMove(moveOrMoveName);
pokemon.lastMoveUsed = move;
if (move.id === 'weatherball' && zMove) {
// Z-Weather Ball only changes types if it's used directly,
// not if it's called by Z-Sleep Talk or something.
this.battle.singleEvent('ModifyType', move, null, pokemon, target, move, move);
if (move.type !== 'Normal') sourceEffect = move;
}
if (zMove || (move.category !== 'Status' && sourceEffect && (sourceEffect as ActiveMove).isZ)) {
move = this.getActiveZMove(move, pokemon);
}
if (maxMove && move.category !== 'Status') {
// Max move outcome is dependent on the move type after type modifications from ability and the move itself
this.battle.singleEvent('ModifyType', move, null, pokemon, target, move, move);
this.battle.runEvent('ModifyType', pokemon, target, move, move);
}
if (maxMove || (move.category !== 'Status' && sourceEffect && (sourceEffect as ActiveMove).isMax)) {
move = this.getActiveMaxMove(move, pokemon);
}
if (this.battle.activeMove) {
move.priority = this.battle.activeMove.priority;
if (!move.hasBounced) move.pranksterBoosted = this.battle.activeMove.pranksterBoosted;
}
const baseTarget = move.target;
let targetRelayVar = { target };
targetRelayVar = this.battle.runEvent('ModifyTarget', pokemon, target, move, targetRelayVar, true);
if (targetRelayVar.target !== undefined) target = targetRelayVar.target;
if (target === undefined) target = this.battle.getRandomTarget(pokemon, move);
if (move.target === 'self' || move.target === 'allies') {
target = pokemon;
}
if (sourceEffect) {
move.sourceEffect = sourceEffect.id;
move.ignoreAbility = (sourceEffect as ActiveMove).ignoreAbility;
}
let moveResult = false;
this.battle.setActiveMove(move, pokemon, target);
this.battle.singleEvent('ModifyType', move, null, pokemon, target, move, move);
this.battle.singleEvent('ModifyMove', move, null, pokemon, target, move, move);
if (baseTarget !== move.target) {
// Target changed in ModifyMove, so we must adjust it here
// Adjust before the next event so the correct target is passed to the
// event
target = this.battle.getRandomTarget(pokemon, move);
}
move = this.battle.runEvent('ModifyType', pokemon, target, move, move);
move = this.battle.runEvent('ModifyMove', pokemon, target, move, move);
if (baseTarget !== move.target) {
// Adjust again
target = this.battle.getRandomTarget(pokemon, move);
}
if (!move || pokemon.fainted) {
return false;
}
let attrs = '';
let movename = move.name;
if (move.id === 'hiddenpower') movename = 'Hidden Power';
if (sourceEffect) attrs += `|[from] ${sourceEffect.fullname}`;
if (zMove && move.isZ === true) {
attrs = `|[anim]${movename}${attrs}`;
movename = `Z-${movename}`;
}
this.battle.addMove('move', pokemon, movename, `${target}${attrs}`);
if (zMove) this.runZPower(move, pokemon);
if (!target) {
this.battle.attrLastMove('[notarget]');
this.battle.add(this.battle.gen >= 5 ? '-fail' : '-notarget', pokemon);
return false;
}
const { targets, pressureTargets } = pokemon.getMoveTargets(move, target);
if (targets.length) {
target = targets[targets.length - 1]; // in case of redirection
}
const callerMoveForPressure = sourceEffect && (sourceEffect as ActiveMove).pp ? sourceEffect as ActiveMove : null;
if (!sourceEffect || callerMoveForPressure || sourceEffect.id === 'pursuit') {
let extraPP = 0;
for (const source of pressureTargets) {
const ppDrop = this.battle.runEvent('DeductPP', source, pokemon, move);
if (ppDrop !== true) {
extraPP += ppDrop || 0;
}
}
if (extraPP > 0) {
pokemon.deductPP(callerMoveForPressure || moveOrMoveName, extraPP);
}
}
let tryMoveResult = this.battle.singleEvent('TryMove', move, null, pokemon, target, move);
if (tryMoveResult) {
tryMoveResult = this.battle.runEvent('TryMove', pokemon, target, move);
}
if (!tryMoveResult) {
move.mindBlownRecoil = false;
return tryMoveResult;
}
this.battle.singleEvent('UseMoveMessage', move, null, pokemon, target, move);
if (move.ignoreImmunity === undefined) {
move.ignoreImmunity = (move.category === 'Status');
}
if (this.battle.gen !== 4 && move.selfdestruct === 'always') {
this.battle.faint(pokemon, pokemon, move);
}
let damage: number | false | undefined | '' = false;
if (move.target === 'all' || move.target === 'foeSide' || move.target === 'allySide' || move.target === 'allyTeam') {
damage = this.tryMoveHit(targets, pokemon, move);
if (damage === this.battle.NOT_FAIL) pokemon.moveThisTurnResult = null;
if (damage || damage === 0 || damage === undefined) moveResult = true;
} else {
if (!targets.length) {
this.battle.attrLastMove('[notarget]');
this.battle.add(this.battle.gen >= 5 ? '-fail' : '-notarget', pokemon);
return false;
}
if (this.battle.gen === 4 && move.selfdestruct === 'always') {
this.battle.faint(pokemon, pokemon, move);
}
moveResult = this.trySpreadMoveHit(targets, pokemon, move);
}
if (move.selfBoost && moveResult) this.moveHit(pokemon, pokemon, move, move.selfBoost, false, true);
if (!pokemon.hp) {
this.battle.faint(pokemon, pokemon, move);
}
if (!moveResult) {
this.battle.singleEvent('MoveFail', move, null, target, pokemon, move);
return false;
}
if (!(move.hasSheerForce && pokemon.hasAbility('sheerforce')) && !move.flags['futuremove']) {
const originalHp = pokemon.hp;
this.battle.singleEvent('AfterMoveSecondarySelf', move, null, pokemon, target, move);
this.battle.runEvent('AfterMoveSecondarySelf', pokemon, target, move);
if (pokemon && pokemon !== target && move.category !== 'Status') {
if (pokemon.hp <= pokemon.maxhp / 2 && originalHp > pokemon.maxhp / 2) {
this.battle.runEvent('EmergencyExit', pokemon, pokemon);
}
}
}
return true;
},
canTerastallize(pokemon: Pokemon) {
if (this.dex.gen !== 9) {
return null;
}
return pokemon.teraType;
},
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 (species.baseSpecies === 'Magearna' && !species.isMega) {
return species.name.includes('Original') ? 'Magearna-Original-Mega' : 'Magearna-Mega';
}
if (!item.megaStone) return null;
return item.megaStone[species.name];
},
modifyDamage(baseDamage, pokemon, target, move, suppressMessages = false) {
const tr = this.battle.trunc;
if (!move.type) move.type = '???';
const type = move.type;
baseDamage += 2;
if (move.spreadHit) {
// multi-target modifier (doubles only)
const spreadModifier = this.battle.gameType === 'freeforall' ? 0.5 : 0.75;
this.battle.debug(`Spread modifier: ${spreadModifier}`);
baseDamage = this.battle.modify(baseDamage, spreadModifier);
} else if (move.multihitType === 'parentalbond' && move.hit > 1) {
// Parental Bond modifier
const bondModifier = this.battle.gen > 6 ? 0.25 : 0.5;
this.battle.debug(`Parental Bond modifier: ${bondModifier}`);
baseDamage = this.battle.modify(baseDamage, bondModifier);
}
// weather modifier
baseDamage = this.battle.runEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
// crit - not a modifier
const isCrit = target.getMoveHitData(move).crit;
if (isCrit) {
baseDamage = tr(baseDamage * (move.critModifier || (this.battle.gen >= 6 ? 1.5 : 2)));
}
// random factor - also not a modifier
baseDamage = this.battle.randomizer(baseDamage);
// STAB
// The "???" type never gets STAB
// Not even if you Roost in Gen 4 and somehow manage to use
// Struggle in the same turn.
// (On second thought, it might be easier to get a MissingNo.)
if (type !== '???') {
let stab: number | [number, number] = 1;
const pokeTypes = pokemon.getTypes(false, true);
const isPrimarySTAB = move.forceSTAB || (pokemon.hasType(type) && pokeTypes[0] === type);
const isSecondarySTAB = move.forceSTAB || (pokemon.hasType(type) && pokeTypes.length > 1 && pokeTypes[1] === type);
const isSTAB = move.forceSTAB || pokemon.hasType(type) || pokemon.getTypes(false, true).includes(type);
if (isPrimarySTAB) {
stab = 1.7;
}
if (isSecondarySTAB) {
stab = 1.2;
}
// The Stellar tera type makes this incredibly confusing
// If the move's type does not match one of the user's base types,
// the Stellar tera type applies a one-time 1.2x damage boost for that type.
//
// If the move's type does match one of the user's base types,
// then the Stellar tera type applies a one-time 2x STAB boost for that type,
// and then goes back to using the regular 1.5x STAB boost for those types.
if (pokemon.terastallized === 'Stellar') {
if (!pokemon.stellarBoostedTypes.includes(type) || move.stellarBoosted) {
stab = isSTAB ? 2.3 : [4915, 4096];
move.stellarBoosted = true;
if (pokemon.species.name !== 'Terapagos-Stellar') {
pokemon.stellarBoostedTypes.push(type);
}
}
} else {
if (pokemon.terastallized === type && pokeTypes.includes(type)) {
stab = 2.3;
}
stab = this.battle.runEvent('ModifySTAB', pokemon, target, move, stab);
}
baseDamage = this.battle.modify(baseDamage, stab);
}
// types
let typeMod = target.runEffectiveness(move);
typeMod = this.battle.clampIntRange(typeMod, -6, 6);
target.getMoveHitData(move).typeMod = typeMod;
if (typeMod > 0) {
if (!suppressMessages) this.battle.add('-supereffective', target);
for (let i = 0; i < typeMod; i++) {
baseDamage *= 2;
}
}
if (typeMod < 0) {
if (!suppressMessages) this.battle.add('-resisted', target);
for (let i = 0; i > typeMod; i--) {
baseDamage = tr(baseDamage / 2);
}
}
if (isCrit && !suppressMessages) this.battle.add('-crit', target);
if (pokemon.status === 'brn' && move.category === 'Physical' && !pokemon.hasAbility('guts')) {
if (this.battle.gen < 6 || move.id !== 'facade') {
baseDamage = this.battle.modify(baseDamage, 0.5);
}
}
if (pokemon.status === 'psn' && move.category === 'Special') {
if (this.battle.gen < 6 || move.id !== 'facade') {
baseDamage = this.battle.modify(baseDamage, 0.5);
}
}
// Generation 5, but nothing later, sets damage to 1 before the final damage modifiers
if (this.battle.gen === 5 && !baseDamage) baseDamage = 1;
// Final modifier. Modifiers that modify damage after min damage check, such as Life Orb.
baseDamage = this.battle.runEvent('ModifyDamage', pokemon, target, move, baseDamage);
const bypassProtect = target.getMoveHitData(move).bypassProtect;
if (bypassProtect) {
baseDamage = this.battle.modify(baseDamage, 0.25);
if (bypassProtect !== true && bypassProtect.effectType === 'Ability') {
this.battle.add('-ability', pokemon, bypassProtect.name);
}
this.battle.add('-zbroken', target);
}
// Generation 6-7 moves the check for minimum 1 damage after the final modifier...
if (this.battle.gen !== 5 && !baseDamage) return 1;
// ...but 16-bit truncation happens even later, and can truncate to 0
return tr(baseDamage, 16);
},
getDamage(source, target, move, suppressMessages = false) {
if (typeof move === 'string') move = this.dex.getActiveMove(move);
if (typeof move === 'number') {
const basePower = move;
move = new Dex.Move({
basePower,
type: '???',
category: 'Physical',
willCrit: false,
}) as ActiveMove;
move.hit = 0;
}
if (!target.runImmunity(move, !suppressMessages)) {
return false;
}
if (move.ohko) return this.battle.gen === 3 ? target.hp : target.maxhp;
if (move.damageCallback) return move.damageCallback.call(this.battle, source, target);
if (move.damage === 'level') {
return source.level;
} else if (move.damage) {
return move.damage;
}
let category = this.battle.getCategory(move);
let basePower: number | false | null = move.basePower;
if (move.basePowerCallback) {
basePower = move.basePowerCallback.call(this.battle, source, target, move);
}
if (!basePower) return basePower === 0 ? undefined : basePower;
basePower = this.battle.clampIntRange(basePower, 1);
if (move.type === 'Electric' && move.category === 'Physical') {
basePower += 15;
category = 'Special';
}
let critMult;
let critRatio = this.battle.runEvent('ModifyCritRatio', source, target, move, move.critRatio || 0);
if (this.battle.gen <= 5) {
critRatio = this.battle.clampIntRange(critRatio, 0, 5);
critMult = [0, 16, 8, 4, 3, 2];
} else {
critRatio = this.battle.clampIntRange(critRatio, 0, 4);
if (this.battle.gen === 6) {
critMult = [0, 16, 8, 2, 1];
} else {
critMult = [0, 24, 8, 2, 1];
}
}
const moveHit = target.getMoveHitData(move);
moveHit.crit = move.willCrit || false;
if (move.willCrit === undefined) {
if (critRatio) {
moveHit.crit = this.battle.randomChance(1, critMult[critRatio]);
}
}
if (moveHit.crit) {
moveHit.crit = this.battle.runEvent('CriticalHit', target, null, move);
}
// happens after crit calculation
basePower = this.battle.runEvent('BasePower', source, target, move, basePower, true);
if (!basePower) return 0;
basePower = this.battle.clampIntRange(basePower, 1);
// Hacked Max Moves have 0 base power, even if you Dynamax
if ((!source.volatiles['dynamax'] && move.isMax) || (move.isMax && this.dex.moves.get(move.baseMove).isMax)) {
basePower = 0;
}
const dexMove = this.dex.moves.get(move.id);
if (source.terastallized && (source.terastallized === 'Stellar' ?
!source.stellarBoostedTypes.includes(move.type) : source.hasType(move.type)) &&
basePower < 60 && dexMove.priority <= 0 && !dexMove.multihit &&
// Hard move.basePower check for moves like Dragon Energy that have variable BP
!((move.basePower === 0 || move.basePower === 150) && move.basePowerCallback)
) {
basePower = 60;
}
const level = source.level;
const attacker = move.overrideOffensivePokemon === 'target' ? target : source;
const defender = move.overrideDefensivePokemon === 'source' ? source : target;
const isPhysical = move.category === 'Physical';
let attackStat: StatIDExceptHP = move.overrideOffensiveStat || (isPhysical ? 'atk' : 'spa');
const defenseStat: StatIDExceptHP = move.overrideDefensiveStat || (isPhysical ? 'def' : 'spd');
const statTable = { atk: 'Atk', def: 'Def', spa: 'SpA', spd: 'SpD', spe: 'Spe' };
let atkBoosts = attacker.boosts[attackStat];
let defBoosts = defender.boosts[defenseStat];
let ignoreNegativeOffensive = !!move.ignoreNegativeOffensive;
let ignorePositiveDefensive = !!move.ignorePositiveDefensive;
if (moveHit.crit) {
ignoreNegativeOffensive = true;
ignorePositiveDefensive = true;
}
const ignoreOffensive = !!(move.ignoreOffensive || (ignoreNegativeOffensive && atkBoosts < 0));
const ignoreDefensive = !!(move.ignoreDefensive || (ignorePositiveDefensive && defBoosts > 0));
if (ignoreOffensive) {
this.battle.debug('Negating (sp)atk boost/penalty.');
atkBoosts = 0;
}
if (ignoreDefensive) {
this.battle.debug('Negating (sp)def boost/penalty.');
defBoosts = 0;
}
let attack = attacker.calculateStat(attackStat, atkBoosts, 1, source);
let defense = defender.calculateStat(defenseStat, defBoosts, 1, target);
attackStat = (category === 'Physical' ? 'atk' : 'spa');
// Apply Stat Modifiers
attack = this.battle.runEvent('Modify' + statTable[attackStat], source, target, move, attack);
defense = this.battle.runEvent('Modify' + statTable[defenseStat], target, source, move, defense);
if (this.battle.gen <= 4 && ['explosion', 'selfdestruct'].includes(move.id) && defenseStat === 'def') {
defense = this.battle.clampIntRange(Math.floor(defense / 2), 1);
}
const tr = this.battle.trunc;
// int(int(int(2 * L / 5 + 2) * A * P / D) / 50);
const baseDamage = tr(tr(tr(tr(2 * level / 5 + 2) * basePower * attack) / defense) / 50);
// Calculate damage modifiers separately (order differs between generations)
return this.modifyDamage(baseDamage, source, target, move, suppressMessages);
},
},
};

1052
data/mods/afd/sets.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,49 @@
export const TypeChart: import('../../../sim/dex-data').ModdedTypeDataTable = {
fairy: {
damageTaken: {
Bug: 2,
Dark: 2,
Dragon: 3,
Electric: 0,
Fairy: 0,
Fighting: 2,
Fire: 0,
Flying: 0,
Ghost: 0,
Grass: 0,
Ground: 0,
Ice: 0,
Normal: 1,
Poison: 1,
Psychic: 0,
Rock: 0,
Steel: 1,
Stellar: 0,
Water: 0,
},
},
ghost: {
inherit: true,
damageTaken: {
Bug: 3,
Dark: 1,
Dragon: 1,
Electric: 1,
Fairy: 3,
Fighting: 3,
Fire: 1,
Flying: 3,
Ghost: 3,
Grass: 1,
Ground: 3,
Ice: 1,
Normal: 3,
Poison: 3,
Psychic: 1,
Rock: 3,
Steel: 3,
Stellar: 0,
Water: 1,
},
},
};

View File

@ -185,17 +185,20 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
(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 ppUps = move.noPPBoosts ? 0 : 3;
const basePP = this.calculatePP(move, ppUps);
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,
pp: basePP,
maxpp: basePP,
target: move.target,
disabled: false,
used: false,
};
pokemon.baseMoveSlots.push(newMove);
pokemon.moveSlots.push(newMove);
pokemon.ppUps.push(ppUps);
}
}
return;

View File

@ -223,6 +223,24 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
skillswap: {
inherit: true,
onTryHit(target, source) {
const targetAbility = target.getAbility();
const sourceAbility = source.getAbility();
if (sourceAbility.flags['failskillswap'] || targetAbility.flags['failskillswap'] || target.volatiles['dynamax']) {
return false;
}
let sourceCanBeSet = this.runEvent('SetAbility', source, source, this.effect, targetAbility);
if (!this.dex.abilities.get(sourceAbility).exists && this.dex.items.get(sourceAbility.id).exists) {
sourceCanBeSet = this.runEvent('TakeItem', source, source, this.effect, this.dex.items.get(sourceAbility.id));
}
if (!sourceCanBeSet) return sourceCanBeSet;
let targetCanBeSet = this.runEvent('SetAbility', target, source, this.effect, sourceAbility);
if (!this.dex.abilities.get(targetAbility).exists && this.dex.items.get(targetAbility.id).exists) {
targetCanBeSet = this.runEvent('TakeItem', target, source, this.effect, this.dex.items.get(targetAbility.id));
}
if (!targetCanBeSet) return targetCanBeSet;
},
onHit(target, source, move) {
const targetAbility = target.getAbility();
const sourceAbility = source.getAbility();
@ -280,17 +298,20 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
} else {
source.m.scrambled.moves.push({ thing: targetAbility.id, inSlot: 'Ability' });
const bmmMove = Dex.moves.get(targetAbility.id);
const ppUps = move.noPPBoosts ? 0 : 3;
const basePP = this.calculatePP(move, ppUps);
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,
pp: basePP,
maxpp: basePP,
target: bmmMove.target,
disabled: false,
used: false,
};
source.baseMoveSlots.push(newMove);
source.moveSlots.push(newMove);
source.ppUps.push(ppUps);
}
}
this.singleEvent('Start', sourceAbility, target.abilityState, target);
@ -303,17 +324,20 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
} else {
target.m.scrambled.moves.push({ thing: sourceAbility.id, inSlot: 'Ability' });
const bmmMove = Dex.moves.get(sourceAbility.id);
const ppUps = move.noPPBoosts ? 0 : 3;
const basePP = this.calculatePP(move, ppUps);
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,
pp: basePP,
maxpp: basePP,
target: bmmMove.target,
disabled: false,
used: false,
};
target.baseMoveSlots.push(newMove);
target.moveSlots.push(newMove);
target.ppUps.push(ppUps);
}
}
},

View File

@ -63,10 +63,16 @@ export const Scripts: ModdedBattleScriptsData = {
);
},
setAbility(ability, source, sourceEffect, isFromFormeChange = false, isTransform = false) {
const allThings = new Set([
...(this.m.scrambled.abilities as { thing: string }[]).map(e => e.thing),
...(this.m.scrambled.items as { thing: string }[]).map(e => e.thing),
...(this.m.scrambled.moves as { thing: string }[]).map(e => e.thing),
this.ability, ...this.moveSlots.map(e => e.move), this.item,
].map(this.battle.toID));
let isBMMAbil = false;
let isOldBMMAbil = false;
if (!this.hp) return false;
if (!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);
@ -85,13 +91,18 @@ export const Scripts: ModdedBattleScriptsData = {
} as Ability;
}
}
if (ability.name.length && !this.battle.dex.abilities.get(ability).exists) isBMMAbil = true;
if (!sourceEffect && this.battle.effect) sourceEffect = this.battle.effect;
let oldAbility;
if (this.battle.dex.abilities.get(this.ability).exists) {
oldAbility = this.battle.dex.abilities.get(this.ability);
} else {
let abil = this.battle.dex.items.getByID(this.ability) as Item | Move;
if (!abil.exists) abil = this.battle.dex.moves.getByID(this.ability);
if (!abil.exists) {
abil = this.battle.dex.moves.getByID(this.ability);
} else {
if (!this.battle.runEvent('TakeItem', this, source, null, abil as Item)) return false;
}
oldAbility = {
id: this.ability,
name: abil.name || this.ability,
@ -103,6 +114,9 @@ export const Scripts: ModdedBattleScriptsData = {
} as Ability;
isOldBMMAbil = true;
}
if (allThings.has(ability.id)) return false;
if (!isFromFormeChange) {
if (ability.flags['cantsuppress'] || this.getAbility().flags['cantsuppress']) return false;
}
@ -153,11 +167,13 @@ export const Scripts: ModdedBattleScriptsData = {
} else {
this.m.scrambled.moves.push({ thing: ability.id, inSlot: 'Ability' });
const move = Dex.moves.get(ability.id);
const ppUps = move.noPPBoosts ? 0 : 3;
const basePP = this.battle.calculatePP(move, ppUps);
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,
pp: basePP,
maxpp: basePP,
target: move.target,
disabled: false,
used: false,
@ -165,6 +181,7 @@ export const Scripts: ModdedBattleScriptsData = {
if (!isTransform) {
this.baseMoveSlots.push(newMove);
this.moveSlots.push(newMove);
this.ppUps.push(ppUps);
}
}
}
@ -195,14 +212,22 @@ export const Scripts: ModdedBattleScriptsData = {
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;
if (this.battle.toID(this.ability) === 'multitype' || (this.m.scrambled.abilities as { thing: string }[])
.findIndex(e => this.battle.toID(e.thing) === 'multitype') >= 0) {
return false;
}
if (this.battle.toID(source.ability) === 'multitype' || (source.m.scrambled.abilities as { thing: string }[])
.findIndex(e => this.battle.toID(e.thing) === 'multitype') >= 0) {
return false;
}
}
const item = this.getItem();
if (this.battle.runEvent('TakeItem', this, source, null, item)) {
this.item = '';
let wrongSlot = (this.m.scrambled.abilities as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
if (wrongSlot >= 0) {
const dexAbil = this.battle.dex.abilities.get(this.m.scrambled.abilities[wrongSlot].thing);
if (dexAbil.flags['failskillswap']) return false;
this.removeVolatile('ability:' + this.battle.toID(this.m.scrambled.abilities[wrongSlot].thing));
this.m.scrambled.abilities.splice(wrongSlot, 1);
} else if ((this.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item') >= 0) {
@ -225,17 +250,27 @@ export const Scripts: ModdedBattleScriptsData = {
return false;
},
setItem(item, source, effect) {
const allThings = new Set([
...(this.m.scrambled.abilities as { thing: string }[]).map(e => e.thing),
...(this.m.scrambled.items as { thing: string }[]).map(e => e.thing),
...(this.m.scrambled.moves as { thing: string }[]).map(e => e.thing),
this.ability, ...this.moveSlots.map(e => e.move), this.item,
].map(this.battle.toID));
let isBMMItem = false;
let isOldBMMItem = false;
if (!this.hp || !this.isActive) return false;
if (!this.battle.dex.items.get(item).exists) isBMMItem = true;
if (typeof item === 'string') {
if (this.battle.dex.items.get(item).exists) {
if (!item.length || this.battle.dex.items.get(item).exists) {
item = this.battle.dex.items.get(item);
} else {
const itemString = item;
let newData = this.battle.dex.abilities.get(itemString) as Ability | Move;
if (!newData.exists) newData = this.battle.dex.moves.get(itemString);
if (!newData.exists) {
newData = this.battle.dex.moves.get(itemString);
} else {
if ((newData as Ability).flags['failskillswap']) return false;
}
item = {
id: newData.id || itemString,
name: newData.name || itemString,
@ -246,6 +281,8 @@ export const Scripts: ModdedBattleScriptsData = {
} as Item;
}
}
if (item.name.length && !this.battle.dex.items.get(item).exists) isBMMItem = true;
if (allThings.has(item.id)) return false;
const effectid = this.battle.effect ? this.battle.effect.id : '';
if (RESTORATIVE_BERRIES.has('leppaberry' as ID)) {
const inflicted = ['trick', 'switcheroo'].includes(effectid);
@ -288,17 +325,20 @@ export const Scripts: ModdedBattleScriptsData = {
} else {
this.m.scrambled.moves.push({ thing: item.id, inSlot: 'Item' });
const move = Dex.moves.get(item.id);
const ppUps = move.noPPBoosts ? 0 : 3;
const basePP = this.battle.calculatePP(move, ppUps);
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,
pp: basePP,
maxpp: basePP,
target: move.target,
disabled: false,
used: false,
};
this.baseMoveSlots.push(newMove);
this.moveSlots.push(newMove);
this.ppUps.push(ppUps);
}
}
return true;
@ -340,9 +380,11 @@ export const Scripts: ModdedBattleScriptsData = {
const isBMM = this.volatiles[item.id]?.inSlot;
if (isBMM) {
const dexItem = this.battle.dex.items.get(item.name);
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);
const itemIndex = (this.m.scrambled.items as { thing: string, inSlot: string }[]).findIndex(e =>
this.battle.toID(e.thing) === dexItem.id && e.inSlot === isBMM);
if (itemIndex >= 0) this.m.scrambled.items.splice(itemIndex, 1);
if (isBMM === 'Ability') this.setAbility('No Ability');
} else {
this.lastItem = this.item;
@ -391,9 +433,11 @@ export const Scripts: ModdedBattleScriptsData = {
const isBMM = this.volatiles[item.id]?.inSlot;
if (isBMM) {
const dexItem = this.battle.dex.items.get(item.name);
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);
const itemIndex = (this.m.scrambled.items as { thing: string, inSlot: string }[]).findIndex(e =>
this.battle.toID(e.thing) === dexItem.id && e.inSlot === isBMM);
if (itemIndex >= 0) this.m.scrambled.items.splice(itemIndex, 1);
if (isBMM === 'Ability') this.setAbility('No Ability');
} else {
this.lastItem = this.item;
@ -445,16 +489,17 @@ export const Scripts: ModdedBattleScriptsData = {
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) {
for (const [i, moveSlot] of pokemon.moveSlots.entries()) {
let moveName = moveSlot.move;
if (moveSlot.id === 'hiddenpower') {
moveName = 'Hidden Power ' + this.hpType;
}
const move = this.battle.dex.moves.get(moveSlot.id);
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,
pp: Math.min(5, move.pp),
maxpp: this.battle.gen >= 5 ? Math.min(5, move.pp) : moveSlot.maxpp,
target: moveSlot.target,
disabled: false,
used: false,

View File

@ -0,0 +1,66 @@
export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTable = {
angershell: {
inherit: true,
onDamage(damage, target, source, effect) {
this.effectState.checkedAngerShell = !(effect.effectType === "Move" && !effect.multihit);
},
},
berserk: {
inherit: true,
onDamage(damage, target, source, effect) {
this.effectState.checkedBerserk = !(effect.effectType === "Move" && !effect.multihit);
},
},
dragonize: {
inherit: true,
isNonstandard: null,
},
healer: {
inherit: true,
onResidual(pokemon) {
for (const allyActive of pokemon.adjacentAllies()) {
if (allyActive.status && this.randomChance(1, 2)) {
this.add('-activate', pokemon, 'ability: Healer');
allyActive.cureStatus();
}
}
},
desc: "50% chance this Pokemon's ally has its non-volatile status condition cured at the end of each turn.",
shortDesc: "50% chance this Pokemon's ally has its status cured at the end of each turn.",
},
megasol: {
inherit: true,
isNonstandard: null,
},
piercingdrill: {
inherit: true,
isNonstandard: null,
},
shedskin: {
inherit: true,
onResidual(pokemon) {
if (pokemon.hp && pokemon.status && this.randomChance(3, 10)) {
this.debug('shed skin');
this.add('-activate', pokemon, 'ability: Shed Skin');
pokemon.cureStatus();
}
},
desc: "This Pokemon has a 30% chance to have its non-volatile status condition cured at the end of each turn.",
shortDesc: "This Pokemon has a 30% chance to have its status cured at the end of each turn.",
},
spicyspray: {
inherit: true,
isNonstandard: null,
},
unseenfist: {
onModifyMove: undefined, // no inherit
onHitProtect(source, target, move) {
if (move.flags['contact']) {
target.getMoveHitData(move).bypassProtect = this.effect;
return false;
}
},
inherit: true,
shortDesc: "This Pokemon's contact moves ignore a target's protection and deal 1/4 the usual damage.",
},
};

View File

@ -0,0 +1,136 @@
export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDataTable = {
par: {
inherit: true,
onBeforeMove(pokemon) {
if (this.randomChance(1, 8)) {
this.add('cant', pokemon, 'par');
return false;
}
},
},
slp: {
inherit: true,
onStart(target, source, sourceEffect) {
if (sourceEffect && sourceEffect.effectType === 'Ability') {
this.add('-status', target, 'slp', '[from] ability: ' + sourceEffect.name, `[of] ${source}`);
} else if (sourceEffect && sourceEffect.effectType === 'Move') {
this.add('-status', target, 'slp', `[from] move: ${sourceEffect.name}`);
} else {
this.add('-status', target, 'slp');
}
// 1/3 chance for a Pokemon to wake up on turn 2
this.effectState.startTime = this.sample([2, 3, 3]);
this.effectState.time = this.effectState.startTime;
if (target.removeVolatile('nightmare')) {
this.add('-end', target, 'Nightmare', '[silent]');
}
},
},
frz: {
inherit: true,
onStart(target, source, sourceEffect) {
if (sourceEffect && sourceEffect.effectType === 'Ability') {
this.add('-status', target, 'frz', '[from] ability: ' + sourceEffect.name, `[of] ${source}`);
} else {
this.add('-status', target, 'frz');
}
if (target.species.name === 'Shaymin-Sky' && target.baseSpecies.baseSpecies === 'Shaymin') {
target.formeChange('Shaymin', this.effect, true);
}
this.effectState.startTime = 3;
this.effectState.time = this.effectState.startTime;
},
onBeforeMove(pokemon, target, move) {
if (move.flags['defrost'] && !(move.id === 'burnup' && !pokemon.hasType('Fire'))) return;
pokemon.statusState.time--;
if (pokemon.statusState.time <= 0 || this.randomChance(1, 4)) {
pokemon.cureStatus();
return;
}
this.add('cant', pokemon, 'frz');
return false;
},
},
raindance: {
inherit: true,
onWeatherModifyDamage(damage, attacker, defender, move) {
if (attacker.effectiveWeather() !== 'raindance') return;
if (move.type === 'Water') {
this.debug('rain water boost');
return this.chainModify(1.5);
}
if (move.type === 'Fire') {
this.debug('rain fire suppress');
return this.chainModify(0.5);
}
},
},
primordialsea: {
inherit: true,
onWeatherModifyDamage(damage, attacker, defender, move) {
if (attacker.effectiveWeather() !== 'primordialsea') return;
if (move.type === 'Water') {
this.debug('Rain water boost');
return this.chainModify(1.5);
}
},
},
sunnyday: {
inherit: true,
onWeatherModifyDamage(damage, attacker, defender, move) {
if (attacker.effectiveWeather() !== 'sunnyday') return;
if (move.id === 'hydrosteam') {
this.debug('Sunny Day Hydro Steam boost');
return this.chainModify(1.5);
}
if (move.type === 'Fire') {
this.debug('Sunny Day fire boost');
return this.chainModify(1.5);
}
if (move.type === 'Water') {
this.debug('Sunny Day water suppress');
return this.chainModify(0.5);
}
},
},
desolateland: {
inherit: true,
onWeatherModifyDamage(damage, attacker, defender, move) {
if (attacker.effectiveWeather() !== 'desolateland') return;
if (move.type === 'Fire') {
this.debug('Desolate Land fire boost');
return this.chainModify(1.5);
}
},
},
sandstorm: {
inherit: true,
onModifySpD(spd, target, source) {
if (target.hasType('Rock') && source.effectiveWeather() === 'sandstorm') {
return this.modify(spd, 1.5);
}
},
},
snowscape: {
inherit: true,
onModifyDef(def, target, source) {
if (target.hasType('Ice') && source.effectiveWeather() === 'snowscape') {
return this.modify(def, 1.5);
}
},
},
// TODO: check Mega Sol's interaction with Deltastream
// deltastream: {
// inherit: true,
// onEffectiveness(typeMod, target, type, move) {
// if (move && move.effectType === 'Move' && move.category !== 'Status' && type === 'Flying' && typeMod > 0) {
// this.add('-fieldactivate', 'Delta Stream');
// return 0;
// }
// },
// },
};

File diff suppressed because it is too large Load Diff

1053
data/mods/champions/items.ts Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1109
data/mods/champions/moves.ts Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,40 @@
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
standardag: {
inherit: true,
ruleset: [
'Obtainable', 'Team Preview', 'Cancel Mod', 'Endless Battle Clause',
'Adjust Level = 50', 'Species Clause', 'Item Clause = 1',
],
onBegin() {
this.reportPercentages = true;
},
},
standard: {
inherit: true,
ruleset: [
'Standard AG',
'Sleep Moves Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause',
],
},
standarddraft: {
inherit: true,
ruleset: [
'Standard AG',
'Nickname Clause', 'Beat Up Nicknames Mod', 'Sleep Clause Mod', 'OHKO Clause', 'Evasion Clause',
'!Item Clause',
],
onBegin() {
this.reportPercentages = true;
},
// timer: {starting: 60 * 60, grace: 0, addPerTurn: 10, maxPerTurn: 100, timeoutAutoChoose: true},
},
flatrules: {
inherit: true,
desc: "The in-game Flat Rules: Adjust Level 50, Species Clause, Item Clause = 1, -Mythical, -Restricted Legendary, Bring 6 Pick 3-6 depending on game type.",
ruleset: ['Obtainable', 'Team Preview', 'Species Clause', 'Nickname Clause', 'Item Clause = 1', 'Adjust Level = 50', 'Picked Team Size = Auto', 'Cancel Mod'],
banlist: ['Mythical', 'Restricted Legendary'],
onBegin() {
this.reportPercentages = true;
},
},
};

View File

@ -0,0 +1,505 @@
export const Scripts: ModdedBattleScriptsData = {
gen: 9,
init() {
for (const i in this.data.Moves) {
if (this.data.Moves[i].pp > 20) {
this.modData('Moves', i).pp = 20;
}
}
},
statModify(baseStats, set, statName) {
const tr = this.trunc;
let stat = baseStats[statName];
const evs = set.evs[statName];
if (statName === 'hp') {
return stat + evs + 75;
}
stat = stat + evs + 20;
const nature = this.dex.natures.get(set.nature);
// Natures are calculated with 16-bit truncation.
// This only affects Eternatus-Eternamax in Pure Hackmons.
if (nature.plus === statName) {
stat = this.ruleTable.has('overflowstatmod') ? Math.min(stat, 595) : stat;
stat = tr(tr(stat * 110, 16) / 100);
} else if (nature.minus === statName) {
stat = this.ruleTable.has('overflowstatmod') ? Math.min(stat, 728) : stat;
stat = tr(tr(stat * 90, 16) / 100);
}
return stat;
},
calculatePP(move, ppUps) {
return move.noPPBoosts ? move.pp : (move.pp / 5 + 1) * 4;
},
pokemon: {
// Remove Trick Room underflow
getActionSpeed() {
let speed = this.getStat('spe', false, false);
const trickRoomCheck = this.battle.ruleTable.has('twisteddimensionmod') ?
!this.battle.field.getPseudoWeather('trickroom') : this.battle.field.getPseudoWeather('trickroom');
if (trickRoomCheck) {
speed = -speed;
}
return speed;
},
// Don't revert Mega Evolutions after fainting
// TODO: confirm interaction with Revival Blessing
formeChange(speciesId, source, isPermanent, abilitySlot = '0', message) {
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();
let details = (this.illusion || this).details;
if (this.terastallized) details += `, tera:${this.terastallized}`;
this.battle.add('detailschange', this, details);
this.updateMaxHp();
if (!source) {
// Tera forme
// Ogerpon/Terapagos text goes here
this.formeRegression = true;
} else 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, species.requiredItem);
} else {
this.battle.add('-primal', this, species.requiredItem);
}
} 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 && (!source || !['disguise', 'iceface'].includes(source.id))) {
if (this.illusion && source) {
// Tera forme by Ogerpon or Terapagos breaks the Illusion
this.ability = ''; // Don't allow Illusion to wear off
}
const ability = species.abilities[abilitySlot] || species.abilities['0'];
// Ogerpon's forme change doesn't override permanent abilities
if (source || !this.getAbility().flags['cantsuppress']) this.setAbility(ability, null, null, true);
// However, its ability does reset upon switching out
this.baseAbility = this.battle.toID(ability);
}
if (this.terastallized) {
this.knownType = true;
this.apparentType = this.terastallized;
}
return true;
},
// Announce status immunities from abilities without revealing the ability
// TODO: check if this happens to other abilities besides Spicy Spray (Static, Poison Touch, etc.)
setStatus(status, source, sourceEffect, ignoreImmunities) {
if (!this.hp) return false;
status = this.battle.dex.conditions.get(status);
if (this.battle.event) {
if (!source) source = this.battle.event.source;
if (!sourceEffect) sourceEffect = this.battle.effect;
}
if (!source) source = this;
if (this.status === status.id) {
if ((sourceEffect as Move)?.status === this.status) {
this.battle.add('-fail', this, this.status);
} else if ((sourceEffect as Move)?.status) {
this.battle.add('-fail', source);
this.battle.attrLastMove('[still]');
}
return false;
}
if (
!ignoreImmunities && status.id && !(source?.hasAbility('corrosion') && ['tox', 'psn'].includes(status.id))
) {
// the game currently never ignores immunities
if (!this.runStatusImmunity(status.id === 'tox' ? 'psn' : status.id)) {
this.battle.debug('immune to status');
if ((sourceEffect as Move)?.status || sourceEffect?.effectType === 'Ability') {
this.battle.add('-immune', this);
}
return false;
}
}
const prevStatus = this.status;
const prevStatusState = this.statusState;
if (status.id) {
const result: boolean = this.battle.runEvent('SetStatus', this, source, sourceEffect, status);
if (!result) {
this.battle.debug('set status [' + status.id + '] interrupted');
return result;
}
}
this.status = status.id;
this.statusState = this.battle.initEffectState({ id: status.id, target: this });
if (source) this.statusState.source = source;
if (status.duration) this.statusState.duration = status.duration;
if (status.durationCallback) {
this.statusState.duration = status.durationCallback.call(this.battle, this, source, sourceEffect);
}
if (status.id && !this.battle.singleEvent('Start', status, this.statusState, this, source, sourceEffect)) {
this.battle.debug('status start [' + status.id + '] interrupted');
// cancel the setstatus
this.status = prevStatus;
this.statusState = prevStatusState;
return false;
}
if (status.id && !this.battle.runEvent('AfterSetStatus', this, source, sourceEffect, status)) {
return false;
}
return true;
},
// Disable Fake Out if the user has already acted since switching in
getMoves(lockedMove, restrictData) {
if (lockedMove) {
lockedMove = this.battle.toID(lockedMove);
if (lockedMove === 'recharge') {
return [{
move: 'Recharge',
id: 'recharge' as ID,
}];
}
for (const moveSlot of this.moveSlots) {
if (moveSlot.id !== lockedMove) continue;
return [{
move: moveSlot.move,
id: moveSlot.id,
}];
}
// does this happen?
return [{
move: this.battle.dex.moves.get(lockedMove).name,
id: lockedMove,
}];
}
const moves = [];
let hasValidMove = false;
for (const moveSlot of this.moveSlots) {
let moveName = moveSlot.move;
if (moveSlot.id === 'hiddenpower') {
moveName = `Hidden Power ${this.hpType}`;
if (this.battle.gen < 6) moveName += ` ${this.hpPower}`;
} else if (moveSlot.id === 'return' || moveSlot.id === 'frustration') {
const basePowerCallback = this.battle.dex.moves.get(moveSlot.id).basePowerCallback as (pokemon: Pokemon) => number;
moveName += ` ${basePowerCallback(this)}`;
}
let target = moveSlot.target;
switch (moveSlot.id) {
case 'curse':
if (!this.hasType('Ghost')) {
target = this.battle.dex.moves.get('curse').nonGhostTarget;
}
break;
case 'pollenpuff':
// Heal Block only prevents Pollen Puff from targeting an ally when the user has Heal Block
if (this.volatiles['healblock']) {
target = 'adjacentFoe';
}
break;
case 'terastarstorm':
if (this.species.name === 'Terapagos-Stellar') {
target = 'allAdjacentFoes';
}
break;
}
let disabled = moveSlot.disabled;
if (this.volatiles['dynamax']) {
// if each of a Pokemon's base moves are disabled by one of these effects, it will Struggle
const canCauseStruggle = ['Encore', 'Disable', 'Taunt', 'Assault Vest', 'Belch', 'Stuff Cheeks'];
disabled = this.maxMoveDisabled(moveSlot.id) || disabled && canCauseStruggle.includes(moveSlot.disabledSource!);
} else if (moveSlot.pp <= 0 || (moveSlot.id === 'fakeout' && this.activeMoveActions > 0)) {
disabled = true;
}
if (disabled === 'hidden') {
disabled = !restrictData;
}
if (!disabled) {
hasValidMove = true;
}
moves.push({
move: moveName,
id: moveSlot.id,
pp: moveSlot.pp,
maxpp: moveSlot.maxpp,
target,
disabled,
});
}
return hasValidMove ? moves : [];
},
},
actions: {
canTerastallize(pokemon) {
return null;
},
canMegaEvo(pokemon: 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(toID(altForme.requiredMove)) && !item.zMove) {
return altForme.name;
}
return item.megaStone?.[species.name] || null;
},
// Announce 4x and 0.25x effectiveness
modifyDamage(baseDamage, pokemon, target, move, suppressMessages) {
const tr = this.battle.trunc;
if (!move.type) move.type = '???';
const type = move.type;
baseDamage += 2;
if (move.spreadHit) {
// multi-target modifier (doubles only)
const spreadModifier = this.battle.gameType === 'freeforall' ? 0.5 : 0.75;
this.battle.debug(`Spread modifier: ${spreadModifier}`);
baseDamage = this.battle.modify(baseDamage, spreadModifier);
} else if (move.multihitType === 'parentalbond' && move.hit > 1) {
// Parental Bond modifier
const bondModifier = this.battle.gen > 6 ? 0.25 : 0.5;
this.battle.debug(`Parental Bond modifier: ${bondModifier}`);
baseDamage = this.battle.modify(baseDamage, bondModifier);
}
// weather modifier
baseDamage = this.battle.runEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
// crit - not a modifier
const isCrit = target.getMoveHitData(move).crit;
if (isCrit) {
baseDamage = tr(baseDamage * (move.critModifier || (this.battle.gen >= 6 ? 1.5 : 2)));
}
// random factor - also not a modifier
baseDamage = this.battle.randomizer(baseDamage);
// STAB
// The "???" type never gets STAB
// Not even if you Roost in Gen 4 and somehow manage to use
// Struggle in the same turn.
// (On second thought, it might be easier to get a MissingNo.)
if (type !== '???') {
let stab: number | [number, number] = 1;
const isSTAB = move.forceSTAB || pokemon.hasType(type) || pokemon.getTypes(false, true).includes(type);
if (isSTAB) {
stab = 1.5;
}
// The Stellar tera type makes this incredibly confusing
// If the move's type does not match one of the user's base types,
// the Stellar tera type applies a one-time 1.2x damage boost for that type.
//
// If the move's type does match one of the user's base types,
// then the Stellar tera type applies a one-time 2x STAB boost for that type,
// and then goes back to using the regular 1.5x STAB boost for those types.
if (pokemon.terastallized === 'Stellar') {
if (!pokemon.stellarBoostedTypes.includes(type) || move.stellarBoosted) {
stab = isSTAB ? 2 : [4915, 4096];
move.stellarBoosted = true;
if (pokemon.species.name !== 'Terapagos-Stellar') {
pokemon.stellarBoostedTypes.push(type);
}
}
} else {
if (pokemon.terastallized === type && pokemon.getTypes(false, true).includes(type)) {
stab = 2;
}
stab = this.battle.runEvent('ModifySTAB', pokemon, target, move, stab);
}
baseDamage = this.battle.modify(baseDamage, stab);
}
// types
let typeMod = target.runEffectiveness(move);
typeMod = this.battle.clampIntRange(typeMod, -6, 6);
target.getMoveHitData(move).typeMod = typeMod;
if (typeMod > 0) {
if (!suppressMessages) this.battle.add('-supereffective', target, Math.min(typeMod, 2));
for (let i = 0; i < typeMod; i++) {
baseDamage *= 2;
}
}
if (typeMod < 0) {
if (!suppressMessages) this.battle.add('-resisted', target, Math.min(-typeMod, 2));
for (let i = 0; i > typeMod; i--) {
baseDamage = tr(baseDamage / 2);
}
}
if (isCrit && !suppressMessages) this.battle.add('-crit', target);
if (pokemon.status === 'brn' && move.category === 'Physical' && !pokemon.hasAbility('guts')) {
if (this.battle.gen < 6 || move.id !== 'facade') {
baseDamage = this.battle.modify(baseDamage, 0.5);
}
}
// Generation 5, but nothing later, sets damage to 1 before the final damage modifiers
if (this.battle.gen === 5 && !baseDamage) baseDamage = 1;
// Final modifier. Modifiers that modify damage after min damage check, such as Life Orb.
baseDamage = this.battle.runEvent('ModifyDamage', pokemon, target, move, baseDamage);
const bypassProtect = target.getMoveHitData(move).bypassProtect;
if (bypassProtect) {
baseDamage = this.battle.modify(baseDamage, 0.25);
if (bypassProtect !== true && bypassProtect.effectType === 'Ability') {
this.battle.add('-ability', pokemon, bypassProtect.name);
}
this.battle.add('-zbroken', target);
}
// Generation 6-7 moves the check for minimum 1 damage after the final modifier...
if (this.battle.gen !== 5 && !baseDamage) return 1;
// ...but 16-bit truncation happens even later, and can truncate to 0
return tr(baseDamage, 16);
},
// Run `AfterHit` events even if the source fainted
spreadMoveHit(targets, pokemon, moveOrMoveName, hitEffect?, isSecondary?, isSelf?) {
// Hardcoded for single-target purposes
// (no spread moves have any kind of onTryHit handler)
const target = targets[0];
let damage: (number | boolean | undefined)[] = [];
for (const i of targets.keys()) {
damage[i] = true;
}
const move = this.dex.getActiveMove(moveOrMoveName);
let hitResult: boolean | number | null = true;
let moveData = hitEffect!;
if (!moveData) moveData = move;
if (!moveData.flags) moveData.flags = {};
if (move.target === 'all' && !isSelf) {
hitResult = this.battle.singleEvent('TryHitField', moveData, {}, target || null, pokemon, move);
} else if ((move.target === 'foeSide' || move.target === 'allySide' || move.target === 'allyTeam') && !isSelf) {
hitResult = this.battle.singleEvent('TryHitSide', moveData, {}, target || null, pokemon, move);
} else if (target) {
hitResult = this.battle.singleEvent('TryHit', moveData, {}, target, pokemon, move);
}
if (!hitResult) {
if (hitResult === false) {
this.battle.add('-fail', pokemon);
this.battle.attrLastMove('[still]');
}
return [[false], targets]; // single-target only
}
// 0. check for substitute
if (!isSecondary && !isSelf) {
if (move.target !== 'all' && move.target !== 'allyTeam' && move.target !== 'allySide' && move.target !== 'foeSide') {
damage = this.tryPrimaryHitEvent(damage, targets, pokemon, move, moveData, isSecondary);
}
}
for (const i of targets.keys()) {
if (damage[i] === this.battle.HIT_SUBSTITUTE) {
damage[i] = true;
targets[i] = null;
}
if (targets[i] && isSecondary && !moveData.self) {
damage[i] = true;
}
if (!damage[i]) targets[i] = false;
}
// 1. call to this.battle.getDamage
damage = this.getSpreadDamage(damage, targets, pokemon, move, moveData, isSecondary, isSelf);
for (const i of targets.keys()) {
if (damage[i] === false) targets[i] = false;
}
// 2. call to this.battle.spreadDamage
damage = this.battle.spreadDamage(damage, targets, pokemon, move);
for (const i of targets.keys()) {
if (damage[i] === false) targets[i] = false;
}
// 3. onHit event happens here
damage = this.runMoveEffects(damage, targets, pokemon, move, moveData, isSecondary, isSelf);
for (const i of targets.keys()) {
if (!damage[i] && damage[i] !== 0) targets[i] = false;
}
// steps 4 and 5 can mess with this.battle.activeTarget, which needs to be preserved for Dancer
const activeTarget = this.battle.activeTarget;
// 4. self drops (start checking for targets[i] === false here)
if (moveData.self && !move.selfDropped) this.selfDrops(targets, pokemon, move, moveData, isSecondary);
// 5. secondary effects
if (moveData.secondaries) this.secondaries(targets, pokemon, move, moveData, isSelf);
this.battle.activeTarget = activeTarget;
// 6. force switch
if (moveData.forceSwitch) damage = this.forceSwitch(damage, targets, pokemon, move);
for (const i of targets.keys()) {
if (!damage[i] && damage[i] !== 0) targets[i] = false;
}
const damagedTargets: Pokemon[] = [];
const damagedDamage = [];
for (const [i, t] of targets.entries()) {
if (typeof damage[i] === 'number' && t) {
damagedTargets.push(t);
damagedDamage.push(damage[i]);
}
}
const pokemonOriginalHP = pokemon.hp;
if (damagedDamage.length && !isSecondary && !isSelf) {
if (this.battle.gen >= 5) {
this.battle.runEvent('DamagingHit', damagedTargets, pokemon, move, damagedDamage);
}
if (moveData.onAfterHit) {
for (const t of damagedTargets) {
this.battle.singleEvent('AfterHit', moveData, {}, t, pokemon, move);
}
}
if (this.battle.gen < 5) {
this.battle.runEvent('DamagingHit', damagedTargets, pokemon, move, damagedDamage);
}
if (pokemon.hp && pokemon.hp <= pokemon.maxhp / 2 && pokemonOriginalHP > pokemon.maxhp / 2) {
this.battle.runEvent('EmergencyExit', pokemon);
}
}
return [damage, targets];
},
},
};

View File

@ -953,4 +953,41 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
},
shortDesc: "This Pokemon can poison a Pokemon regardless of its typing and hit them with Poison moves.",
},
jellobody: {
onTryHit(pokemon, target, move) {
if (move.selfSwitch) {
this.add('-immune', pokemon, '[from] ability: Jello Body');
this.heal(target.baseMaxhp / 2);
return null;
}
},
onModifyMove(move, source, target) {
move.drain = [1, 2];
},
flags: { breakable: 1 },
name: "Jello Body",
rating: 5,
num: -122,
shortDesc: "Immune to pivot moves, heals 50% HP when hit by one. All moves drain 50%.",
},
nibblenibble: {
onPrepareHit(source, target, move) {
if (move.category === 'Status' || move.multihit || move.flags['noparentalbond'] || move.flags['charge'] ||
move.flags['futuremove'] || move.spreadHit || move.isZ || move.isMax || !move.flags['bite']) return;
move.multihit = 2;
move.multihitType = 'parentalbond';
},
// Damage modifier implemented in BattleActions#modifyDamage()
onSourceModifySecondaries(secondaries, target, source, move) {
if (move.multihitType === 'parentalbond' && move.id === 'secretpower' && move.hit < 2) {
// hack to prevent accidentally suppressing King's Rock/Razor Fang
return secondaries.filter(effect => effect.volatileStatus === 'flinch');
}
},
flags: {},
name: "Nibble Nibble",
rating: 5,
num: -123,
shortDesc: "Parental Bond but for Bite moves.",
},
};

View File

@ -13,12 +13,10 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
masquerainite: {
name: "Masquerainite",
spritenum: 1,
megaStone: "Masquerain-Mega",
megaEvolves: "Masquerain",
megaStone: { "Masquerain": "Masquerain-Mega" },
itemUser: ["Masquerain"],
onTakeItem(item, source) {
if (item.megaEvolves === source.baseSpecies.baseSpecies) return false;
return true;
return !item.megaStone?.[source.baseSpecies.baseSpecies];
},
num: -1,
gen: 9,
@ -59,12 +57,10 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
typhlosionite: {
name: "Typhlosionite",
spritenum: 1,
megaStone: "Typhlosion-Mega",
megaEvolves: "Typhlosion",
megaStone: { "Typhlosion": "Typhlosion-Mega" },
itemUser: ["Typhlosion"],
onTakeItem(item, source) {
if (item.megaEvolves === source.baseSpecies.baseSpecies) return false;
return true;
return !item.megaStone?.[source.baseSpecies.baseSpecies];
},
num: -2,
gen: 9,
@ -127,14 +123,28 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
onDamagePriority: -40,
onDamage(damage, target, source, effect) {
const chance = Math.max(Math.floor(target.hp / target.maxhp), 10);
const chance = Math.max(Math.floor(100 - (target.maxhp - target.hp)), 10);
if (this.randomChance(chance, 100) && damage >= target.hp && effect && effect.effectType === 'Move') {
this.add("-activate", target, "item: Focus Band");
return target.hp - 1;
} else {
return damage;
}
},
num: 230,
gen: 2,
desc: "Chance to survive attack equal to percentage of remaining HP, minimum 10%.",
},
raticite: {
name: "Raticite",
spritenum: 1,
megaStone: { "Raticate": "Raticate-Mega" },
itemUser: ["Raticate"],
onTakeItem(item, source) {
return !item.megaStone?.[source.baseSpecies.baseSpecies];
},
num: -3,
gen: 9,
desc: "If held by a Raticate, this item allows it to Mega Evolve in battle.",
},
};

View File

@ -2,7 +2,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
ancientpower: {
inherit: true,
category: "Physical",
secondary: null,
secondary: undefined, // no inherit
// Ancient Power is physical and boosts on-kill
onAfterMoveSecondarySelf(pokemon, target, move) {
if (!target || target.fainted || target.hp <= 0) {
@ -44,7 +44,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.add('-anim', source, 'Crunch', target);
this.add('-anim', source, 'Rock Slide', target);
},
secondary: null,
target: "normal",
type: "Rock",
contestType: "Clever",
@ -60,7 +59,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
pp: 10,
priority: 0,
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
secondary: null,
target: "normal",
type: "Poison",
contestType: "Tough",
@ -197,7 +195,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.field.setWeather('snowscape');
},
},
secondary: null,
target: "normal",
type: "Ice",
contestType: "Clever",
@ -254,7 +251,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
onAfterSubDamage(damage, target, source, move) {
if (!source.isAlly(target)) this.hint(move.category + " Geyser");
},
secondary: null,
target: "normal",
type: "Water",
desc: "This move is Special + no contact if it would be stronger.",
@ -281,7 +277,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
target.addVolatile('encore');
},
weather: 'raindance',
secondary: null,
target: "normal",
type: "Water",
zMove: { boost: { spe: 1 } },
@ -343,7 +338,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.add('-anim', source, 'Ivy Cudgel Rock', target);
this.add('-anim', source, 'Splash');
},
secondary: null,
target: "normal",
type: "Rock",
contestType: "Beautiful",
@ -366,7 +360,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
onPrepareHit(target, source, move) {
this.add('-anim', source, 'Metal Claw', target);
},
secondary: null,
target: "normal",
type: "Steel",
contestType: "Beautiful",
@ -395,7 +388,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
thunderouskick: {
inherit: true,
secondary: null,
secondary: undefined, // no inherit
onHit(target, source, move) {
// random # 0 or 1
const randomNum = this.random(2);
@ -444,7 +437,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
},
},
secondary: null,
target: "foeSide",
type: "Rock",
zMove: { boost: { def: 1 } },
@ -487,7 +479,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
},
},
secondary: null,
target: "foeSide",
type: "Ground",
zMove: { boost: { def: 1 } },
@ -584,8 +575,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
source.switchFlag = true;
},
secondary: null,
hasSheerForce: true,
hasSheerForceBoost: true,
target: "normal",
type: "Dragon",
desc: "Dondozo eats a mon on the user's team, KOing it. Dondozo then gains a stat boost depending on the eaten mon's highest stat: +3 Attack for Atk/SpA, +2 Def/+2 SpD for Def/SpD, and +3 Speed for Speed.",
@ -658,7 +648,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.add('-anim', source, 'Spirit Shackle', target);
},
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
secondary: null,
target: "normal",
type: "Ghost",
contestType: "Clever",
@ -687,7 +676,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
},
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
secondary: null,
target: "normal",
type: "Fighting",
contestType: "Clever",
@ -833,7 +821,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
return success;
},
flags: { protect: 1, mirror: 1, metronome: 1, wind: 1 },
secondary: null,
target: "allAdjacentFoes",
type: "Dragon",
contestType: "Cool",
@ -853,7 +840,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.add('-start', target, 'typechange', 'Steel');
},
flags: { protect: 1, mirror: 1, metronome: 1, bullet: 1 },
secondary: null,
target: "normal",
type: "Steel",
contestType: "Cool",
@ -890,7 +876,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.add('-anim', source, 'Extreme Speed', target);
this.add('-anim', source, 'Thunder', target);
},
secondary: null,
secondary: undefined, // no inherit
desc: "Nearly always goes first.",
shortDesc: "Nearly always goes first.",
},
@ -938,7 +924,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
selfSwitch: true,
secondary: null,
target: "normal",
type: "Fire",
contestType: "Cute",
@ -1078,7 +1063,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
pp: 10,
priority: 0,
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
secondary: null,
target: "normal",
type: "Rock",
contestType: "Tough",
@ -1122,10 +1106,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
onTryHitPriority: 3,
onTryHit(target, source, move) {
if (!move.flags['protect'] || move.category === 'Status') {
if (move.isZ || move.isMax) target.getMoveHitData(move).zBrokeProtect = true;
return;
}
if (this.checkMoveBypassesProtect(move, source, target, false)) return;
if (move.smartTarget) {
move.smartTarget = false;
} else {
@ -1174,7 +1155,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
priority: 0,
flags: { protect: 1, mirror: 1, metronome: 1 },
drain: [1, 2],
secondary: null,
target: "normal",
type: "Fire",
zMove: { basePower: 160 },
@ -1209,7 +1189,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
pp: 10,
priority: 0,
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
secondary: null,
target: "normal",
type: "Grass",
contestType: "Tough",
@ -1275,7 +1254,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
},
},
secondary: null,
target: "self",
type: "Normal",
zMove: { effect: 'clearnegativeboost' },
@ -1311,10 +1289,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.add('-fail', source, 'move: Crowverload');
return this.NOT_FAIL;
}
if (source.hp <= source.maxhp / 4) {
this.add('-fail', source, 'move: Substitute', '[weak]');
return this.NOT_FAIL;
}
},
onAfterMove(source, target, move) {
this.actions.useMove('substitute', source, { });
@ -1323,7 +1297,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
flags: { protect: 1, mirror: 1, metronome: 1 },
multihit: [10, 10],
secondary: null,
target: "normal",
type: "Dark",
zMove: { basePower: 140 },
@ -1372,7 +1345,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
return null;
},
callsMove: true,
secondary: null,
target: "normal",
type: "Normal",
contestType: "Beautiful",
@ -1399,7 +1371,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
return priority + 1;
}
},
secondary: null,
target: "normal",
type: "Fairy",
contestType: "Cool",
@ -1426,7 +1397,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
return priority + 1;
}
},
secondary: null,
target: "normal",
type: "Electric",
contestType: "Cool",
@ -1454,7 +1424,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.boost({ spe: 1 }, source, source);
}
},
secondary: null,
target: "normal",
type: "Psychic",
contestType: "Cool",
@ -1532,16 +1501,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
return false;
}
},
onTryHeal(damage, target, source, effect) {
if (effect && (effect.id === 'zpower' || (effect as Move).isZ)) return damage;
if (source && target !== source && target.hp !== target.maxhp && effect.name === "Pollen Puff") {
this.attrLastMove('[still]');
// FIXME: Wrong error message, correct one not supported yet
this.add('cant', source, 'move: Electric Terrain', effect);
return null;
}
return false;
},
onFieldResidualOrder: 27,
onFieldResidualSubOrder: 7,
onFieldEnd() {
@ -1631,10 +1590,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.add('-anim', source, 'Explosion', target);
this.add('-anim', source, 'Mind Blown', target);
},
secondary: null,
target: "normal",
type: "Normal",
contestType: "Cute",
shortDesc: "Present but better.",
},
sinisterarrows: {
num: -1016,
@ -1708,13 +1667,56 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
},
},
secondary: null,
target: "normal",
type: "Ghost",
contestType: "Clever",
shortDesc: "Hits for 4 turns, even if user switches out.",
},
mortalspin: {
inherit: true,
category: "Special",
},
lastbreakfast: {
num: -1020,
accuracy: 100,
basePower: 80,
category: "Physical",
name: "Last Breakfast",
pp: 15,
priority: 0,
flags: { protect: 1, mirror: 1, metronome: 1, contact: 1, bite: 1 },
onHit(target, source, move) {
const numberBerries = 0 + 1 * Number(source.side.totalFainted);
for (let i = 0; i < numberBerries; i++) {
const possibleBerries = ['aguavberry', 'apicotberry', 'enigmaberry', 'figyberry', 'ganlonberry', 'iapapaberry',
'keeberry', 'lansatberry', 'leppaberry', 'liechiberry', 'lumberry', 'magoberry',
'marangaberry', 'micleberry',
'oranberry', 'petayaberry', 'salacberry', 'sitrusberry', 'starfberry', 'wikiberry',
'aspearberry', 'cheriberry', 'chestoberry', 'lumberry', 'pechaberry', 'rawstberry', 'persimberry'];
const chosenBerry = this.sample(possibleBerries);
const berry = this.dex.items.get(chosenBerry);
if (source.hp && berry.isBerry) {
if (this.singleEvent('Eat', berry, null, source, source, move)) {
this.runEvent('EatItem', source, source, move, berry);
}
if (berry.onEat) source.ateBerry = true;
}
}
},
onTryMove() {
this.attrLastMove('[still]');
},
onPrepareHit(target, source) {
this.add('-anim', source, 'Curse', target);
this.add('-anim', source, 'Bug Bite', target);
},
target: "normal",
type: "Ghost",
contestType: "Cute",
shortDesc: "Eats X random berries, where X is fainted teammates.",
},
superfang: {
inherit: true,
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1, bite: 1 },
},
};

View File

@ -482,10 +482,33 @@ export const Pokedex: import('../../../sim/dex-species').ModdedSpeciesDataTable
ogerponcornerstone: {
inherit: true,
abilities: { 0: "Solid Rock" },
types: ["Psychic", "Normal"],
},
glimmora: {
inherit: true,
abilities: { 0: "Corrosion" },
},
wobbuffet: {
inherit: true,
abilities: { 0: "Jello Body" },
},
raticate: {
inherit: true,
abilities: { 0: "Hustle" },
baseStats: { hp: 90, atk: 81, def: 60, spa: 50, spd: 70, spe: 97 },
},
raticatemega: {
num: -977,
name: "Raticate-Mega",
baseSpecies: "Raticate",
forme: "Mega",
types: ["Normal", "Ghost"],
genderRatio: { M: 0.5, F: 0.5 },
baseStats: { hp: 90, atk: 105, def: 60, spa: 50, spd: 70, spe: 173 },
abilities: { 0: "Nibble Nibble" },
heightm: 0.7,
weightkg: 5,
color: "Black",
eggGroups: ["Field"],
requiredItem: "Raticite",
},
};

View File

@ -294,5 +294,11 @@ export const Scripts: ModdedBattleScriptsData = {
this.modData('Learnsets', 'glimmora').learnset.icebeam = ['9L1'];
this.modData('Learnsets', 'glimmora').learnset.malignantchain = ['9L1'];
this.modData('Learnsets', 'wobbuffet').learnset.nightshade = ['9L1'];
this.modData('Learnsets', 'wobbuffet').learnset.guillotine = ['9L1'];
this.modData('Learnsets', 'wobbuffet').learnset.shedtail = ['9L1'];
this.modData('Learnsets', 'raticate').learnset.lastbreakfast = ['9L1'];
},
};

View File

@ -80,6 +80,9 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
onAfterMoveSelf(pokemon) {
if (pokemon.statusState.time <= 0) pokemon.cureStatus();
},
onDisableMove(target) {
target.maybeLocked = false; // the player knows it is locked
},
},
frz: {
name: 'frz',
@ -98,6 +101,9 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
target.cureStatus();
}
},
onDisableMove(target) {
target.maybeLocked = false; // the player knows it is locked
},
},
psn: {
name: 'psn',
@ -202,12 +208,11 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
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';
},
onDisableMovePriority: 1, // higher priority so it gets undone by frz, slp or Bide
onDisableMove(target) {
target.maybeLocked = true;
if (this.effectState.maybeLocked) {
target.maybeLocked = true;
}
},
},
fakepartiallytrapped: {
@ -215,6 +220,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
// Wrap ended this turn, but you don't know that
// until you try to use an attack
duration: 2,
onDisableMovePriority: 1, // higher priority so it gets undone by frz, slp or Bide
onDisableMove(target) {
target.maybeLocked = true;
},
@ -234,9 +240,6 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
this.effectState.locked = foe;
foe.addVolatile('partiallytrapped', target, effect);
},
onOverrideAction(pokemon, target, move) {
return this.effectState.move;
},
onBeforeMove(pokemon, target, move) {
if (target !== this.effectState.locked) {
pokemon.removeVolatile('partialtrappinglock');
@ -256,20 +259,25 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
}
} else {
target.addVolatile('partiallytrapped', pokemon, move);
if (this.effectState.totalDuration - this.effectState.duration! > 0) {
target.volatiles['partiallytrapped'].maybeLocked = true;
}
}
},
onLockMove() {
onSemiLockMove() {
return this.effectState.move;
},
onDisableMove(pokemon) {
pokemon.maybeLocked = true;
if (this.effectState.totalDuration - this.effectState.duration! > 1) {
pokemon.maybeLocked = true;
}
},
},
mustrecharge: {
inherit: true,
duration: 0,
onBeforeMovePriority: 7,
onStart() {},
onStart: undefined, // no inherit
onAfterMove(pokemon, target, move) {
if (target && target.hp <= 0) {
delete pokemon.volatiles['mustrecharge'];

View File

@ -32,7 +32,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
bide: {
inherit: true,
priority: 0,
accuracy: true,
condition: {
onStart(pokemon) {
@ -60,15 +59,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.add('-activate', pokemon, 'Bide');
return false;
},
onDisableMove(pokemon) {
if (!pokemon.hasMove('bide')) {
return;
}
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id !== 'bide') {
pokemon.disableMove(moveSlot.id);
}
}
onSemiLockMove: 'bide',
onDisableMove(target) {
target.maybeLocked = false; // the player knows it is locked
},
},
type: "???", // Will look as Normal but it's STAB-less
@ -162,14 +155,14 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
// - if Counter is used by the opponent, it will succeed if the player's last selected move is Counterable
// - (Counter will thus desync if the target's last used move is not as counterable as the target's last selected move)
// - if Counter succeeds it will deal twice the last move damage dealt in battle (even if it's from a different pokemon because of a switch)
const isCounterable = (move: Move | null) => move && move.basePower > 0 &&
['Normal', 'Fighting'].includes(move.type) && move.id !== 'counter';
const lastMove = target.side.lastMove && this.dex.moves.get(target.side.lastMove.id);
const lastMoveIsCounterable = lastMove && lastMove.basePower > 0 &&
['Normal', 'Fighting'].includes(lastMove.type) && lastMove.id !== 'counter';
const lastMoveIsCounterable = isCounterable(lastMove);
const lastSelectedMove = target.side.lastSelectedMove && this.dex.moves.get(target.side.lastSelectedMove);
const lastSelectedMoveIsCounterable = lastSelectedMove && lastSelectedMove.basePower > 0 &&
['Normal', 'Fighting'].includes(lastSelectedMove.type) && lastSelectedMove.id !== 'counter';
const lastSelectedMoveIsCounterable = isCounterable(lastSelectedMove || null);
if (!lastMoveIsCounterable && !lastSelectedMoveIsCounterable) {
this.debug("Gen 1 Counter: last move was not Counterable");
@ -211,33 +204,23 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
},
disable: {
num: 50,
accuracy: 55,
basePower: 0,
category: "Status",
name: "Disable",
pp: 20,
priority: 0,
flags: { protect: 1, mirror: 1, bypasssub: 1, metronome: 1 },
volatileStatus: 'disable',
inherit: true,
onTryHit(target) {
// This function should not return if the checks are met. Adding && undefined ensures this happens.
return target.moveSlots.some(ms => ms.pp > 0) &&
!('disable' in target.volatiles) &&
undefined;
return target.moveSlots.some(ms => ms.pp > 0);
},
condition: {
inherit: true,
durationCallback: undefined, // no inherit
onStart(pokemon) {
// disable can only select moves that have pp > 0, hence the onTryHit modification
const moveSlot = this.sample(pokemon.moveSlots.filter(ms => ms.pp > 0));
const [slotIndex, moveSlot] = this.sample(Array.from(pokemon.moveSlots.entries()).filter(([i, ms]) => ms.pp > 0));
this.debug(`Disable: disabling move ${moveSlot.move} in slot ${slotIndex}`);
this.add('-start', pokemon, 'Disable', moveSlot.move);
this.effectState.move = moveSlot.id;
this.effectState.slotIndex = slotIndex;
// 1-8 turns (which will in effect translate to 0-7 missed turns for the target)
this.effectState.time = this.random(1, 9);
},
onEnd(pokemon) {
this.add('-end', pokemon, 'Disable');
},
onBeforeMovePriority: 6,
onBeforeMove(pokemon, target, move) {
pokemon.volatiles['disable'].time--;
@ -253,20 +236,17 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
},
onDisableMove(pokemon) {
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id === this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
// disable the move slot
if (pokemon.moveSlots.length > this.effectState.slotIndex) {
pokemon.moveSlots[this.effectState.slotIndex].disabled = true;
pokemon.moveSlots[this.effectState.slotIndex].disabledSource = this.effect.name;
}
},
},
secondary: null,
target: "normal",
type: "Normal",
},
dizzypunch: {
inherit: true,
secondary: null,
secondary: undefined, // no inherit
},
doubleedge: {
inherit: true,
@ -319,11 +299,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
focusenergy: {
inherit: true,
condition: {
onStart(pokemon) {
this.add('-start', pokemon, 'move: Focus Energy');
},
inherit: true,
// This does nothing as it's dealt with on critical hit calculation.
onModifyMove() {},
onModifyCritRatio: undefined, // no inherit
},
},
glare: {
@ -349,6 +327,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
for (const pokemon of this.getAllActive()) {
pokemon.clearBoosts();
if (pokemon !== source) {
if (['frz', 'slp'].includes(pokemon.status)) {
pokemon.side.lastSelectedMove = 'cannotmove' as ID;
if (this.queue.willMove(pokemon)) {
this.queue.changeAction(pokemon, { choice: 'move', pokemon, moveid: 'cannotmove' });
}
}
pokemon.cureStatus(true);
}
if (pokemon.status === 'tox') {
@ -406,11 +390,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
leechseed: {
inherit: true,
onHit() {},
onHit: undefined, // no inherit
condition: {
onStart(target) {
this.add('-start', target, 'move: Leech Seed');
},
inherit: true,
onAfterMoveSelfPriority: 1,
onAfterMoveSelf(pokemon) {
const leecher = this.getAtSlot(pokemon.volatiles['leechseed'].sourceSlot);
@ -436,15 +418,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
},
lightscreen: {
num: 113,
accuracy: true,
basePower: 0,
category: "Status",
name: "Light Screen",
pp: 30,
priority: 0,
flags: { metronome: 1 },
inherit: true,
volatileStatus: 'lightscreen',
sideCondition: undefined, // no inherit
onTryHit(pokemon) {
if (pokemon.volatiles['lightscreen']) {
return false;
@ -456,14 +432,28 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
},
target: "self",
type: "Psychic",
},
metronome: {
inherit: true,
onHit(pokemon) {
const moves = this.dex.moves.all().filter(move => (
(!move.isNonstandard || move.isNonstandard === 'Unobtainable') && move.flags['metronome']
));
let randomMove = '';
if (moves.length) {
moves.sort((a, b) => a.num - b.num);
randomMove = this.sample(moves).id;
}
if (!randomMove) return false;
pokemon.side.lastSelectedMove = this.toID(randomMove);
this.actions.useMove(randomMove, pokemon);
},
},
mimic: {
inherit: true,
flags: { protect: 1, bypasssub: 1, metronome: 1 },
onHit(target, source) {
const moveslot = source.moves.indexOf('mimic');
if (moveslot < 0) return false;
const moveslot = source.side.lastSelectedMoveSlot;
const moves = target.moves;
const moveid = this.sample(moves);
if (!moveid) return false;
@ -472,7 +462,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
move: move.name,
id: move.id,
pp: source.moveSlots[moveslot].pp,
maxpp: move.pp * 8 / 5,
maxpp: this.calculatePP(move, source.ppUps[moveslot] || 0),
target: move.target,
disabled: false,
used: false,
@ -481,6 +471,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.add('-start', source, 'Mimic', move.name);
},
},
minimize: {
inherit: true,
condition: {
inherit: true,
onSourceModifyDamage: undefined, // no inherit
},
},
mirrormove: {
inherit: true,
onHit(pokemon) {
@ -495,9 +492,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
mist: {
inherit: true,
condition: {
onStart(pokemon) {
this.add('-start', pokemon, 'Mist');
},
inherit: true,
onTryBoost(boost, target, source, effect) {
if (effect.effectType === 'Move' && effect.category !== 'Status') return;
if (source && target !== source) {
@ -523,7 +518,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
petaldance: {
inherit: true,
onMoveFail() {},
onMoveFail: undefined, // no inherit
},
poisonsting: {
inherit: true,
@ -546,9 +541,15 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
basePower: 1,
damageCallback(pokemon) {
if ([0, 1, 171].includes(pokemon.level)) {
this.hint("Desync Clause Mod activated!");
this.hint("In Gen 1, if a Pokémon at level 0, 1 or 171 uses Psywave, the game softlocks.");
return false;
}
const psywaveDamage = (this.random(0, this.trunc(1.5 * pokemon.level)));
if (psywaveDamage <= 0) {
this.hint("Desync Clause Mod activated!");
this.hint("In Gen 1, Psywave can roll 0 damage.");
return false;
}
return psywaveDamage;
@ -595,7 +596,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
recover: {
inherit: true,
heal: null,
heal: undefined, // no inherit
onHit(target) {
if (target.hp === target.maxhp) return false;
// Fail when health is 255 or 511 less than max, unless it is divisible by 256
@ -613,15 +614,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
},
reflect: {
num: 115,
accuracy: true,
basePower: 0,
category: "Status",
name: "Reflect",
pp: 20,
priority: 0,
flags: { metronome: 1 },
inherit: true,
volatileStatus: 'reflect',
sideCondition: undefined, // no inherit
onTryHit(pokemon) {
if (pokemon.volatiles['reflect']) {
return false;
@ -632,13 +627,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.add('-start', pokemon, 'Reflect');
},
},
secondary: null,
target: "self",
type: "Psychic",
},
rest: {
inherit: true,
onTry() {},
onTry: undefined, // no inherit
onHit(target, source, move) {
if (target.hp === target.maxhp) return false;
// Fail when health is 255 or 511 less than max, unless it is divisible by 256
@ -661,12 +654,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
roar: {
inherit: true,
forceSwitch: false,
onTryHit() {},
onTryHit: undefined, // no inherit
priority: 0,
},
rockslide: {
inherit: true,
secondary: null,
secondary: undefined, // no inherit
target: "normal",
},
rockthrow: {
@ -742,7 +735,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
softboiled: {
inherit: true,
heal: null,
heal: undefined, // no inherit
onHit(target) {
if (target.hp === target.maxhp) return false;
// Fail when health is 255 or 511 less than max, unless it is divisible by 256
@ -763,18 +756,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
pp: 10,
recoil: [1, 2],
onModifyMove() {},
onModifyMove: undefined, // no inherit
},
substitute: {
num: 164,
accuracy: true,
basePower: 0,
category: "Status",
name: "Substitute",
pp: 10,
priority: 0,
flags: { metronome: 1 },
volatileStatus: 'substitute',
inherit: true,
onTryHit(target) {
if (target.volatiles['substitute']) {
this.add('-fail', target, 'move: Substitute');
@ -794,11 +779,16 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
},
condition: {
inherit: true,
onStart(target) {
this.add('-start', target, 'Substitute');
this.effectState.hp = Math.floor(target.maxhp / 4) + 1;
delete target.volatiles['partiallytrapped'];
if (target.volatiles['partiallytrapped']) {
this.add('-end', target, target.volatiles['partiallytrapped'].sourceEffect, '[partiallytrapped]', '[silent]');
delete target.volatiles['partiallytrapped'];
}
},
onTryPrimaryHit: undefined, // no inherit
onTryHitPriority: -1,
onTryHit(target, source, move) {
if (move.category === 'Status') {
@ -862,13 +852,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
return 0;
},
onEnd(target) {
this.add('-end', target, 'Substitute');
},
},
secondary: null,
target: "self",
type: "Normal",
},
superfang: {
inherit: true,
@ -877,7 +861,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
thrash: {
inherit: true,
onMoveFail() {},
onMoveFail: undefined, // no inherit
},
thunder: {
inherit: true,
@ -888,14 +872,14 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
triattack: {
inherit: true,
onHit() {},
secondary: null,
onHit: undefined, // no inherit
secondary: undefined, // no inherit
},
whirlwind: {
inherit: true,
accuracy: 85,
forceSwitch: false,
onTryHit() {},
onTryHit: undefined, // no inherit
priority: 0,
},
wingattack: {

View File

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

View File

@ -25,6 +25,27 @@ export const Scripts: ModdedBattleScriptsData = {
// BattlePokemon scripts.
pokemon: {
inherit: true,
deductPP(move, amount) {
// deduct PP based on side.lastSelectedMoveSlot
const ppData = this.getMoveSlot(this.side.lastSelectedMoveSlot);
if (!ppData) return 0;
ppData.used = true;
if (!amount) amount = 1;
ppData.pp -= amount;
if (ppData.pp < 0) {
this.battle.hint("In Gen 1, if a Pokémon is forced to use a move with 0 PP, the move will underflow to have 63 PP.");
}
ppData.pp = ((ppData.pp % 64) + 64) % 64;
if (ppData.virtual && !this.transformed) {
// sync PP from Mimic's slot, or Metronome/Mirror Move that called Mimic
this.baseMoveSlots[this.side.lastSelectedMoveSlot].pp = ppData.pp;
}
return amount;
},
getStat(statName, unmodified) {
// @ts-expect-error type checking prevents 'hp' from being passed, but we're paranoid
if (statName === 'hp') throw new Error("Please read `maxhp` directly");
@ -136,12 +157,30 @@ export const Scripts: ModdedBattleScriptsData = {
}
}
// If a faster partial trapping move misses against a user of Hyper Beam during a recharge turn,
// the user of Hyper Beam will automatically use Hyper Beam during that turn.
if (move.id === 'recharge' && !pokemon.volatiles['mustrecharge'] && !pokemon.volatiles['partiallytrapped']) {
move = this.battle.dex.getActiveMove('hyperbeam');
this.battle.hint(`In Gen 1, partial trapping moves like Wrap remove Hyper Beam recharges. ` +
`If the target would have recharged, it will automatically use Hyper Beam instead.`, true);
const abortMove = () => {
this.battle.clearActiveMove(true);
this.battle.runEvent('AfterMoveSelf', pokemon, target, move);
};
if (move.id === 'cannotmove') {
if (pokemon.status === 'slp') {
this.battle.hint(
"In Gen 1, if a Pokémon spends a turn partially trapped and switches to a Pokémon that is asleep, " +
"the sleep counter will not decrease until you select a move with a different Pokémon."
);
} else if (pokemon.getLockedMove()) {
this.battle.hint(
"In Gen 1, when Haze cures the sleep/freeze status of a Pokémon during a multi-turn move, " +
"that Pokémon will become soft-locked."
);
} else if (pokemon.getSemiLockedMove()) {
this.battle.hint(
"In Gen 1, when Haze cures the sleep/freeze status of a Pokémon during Bide, " +
"the move execution will never resolve."
);
}
abortMove();
return;
}
if (target?.subFainted) target.subFainted = null;
@ -149,37 +188,36 @@ export const Scripts: ModdedBattleScriptsData = {
this.battle.setActiveMove(move, pokemon, target);
if (pokemon.moveThisTurn || !this.battle.runEvent('BeforeMove', pokemon, target, move)) {
this.battle.clearActiveMove(true);
// This is only run for sleep.
this.battle.runEvent('AfterMoveSelf', pokemon, target, move);
abortMove();
return;
}
if (move.beforeMoveCallback?.call(this.battle, pokemon, target, move)) {
this.battle.clearActiveMove(true);
abortMove();
return;
}
const lockedMove = pokemon.getLockedMove();
if (lockedMove) sourceEffect = move;
if (move.id !== 'struggle') {
const lockedMove = pokemon.getLockedMove() || pokemon.getSemiLockedMove();
if (lockedMove) sourceEffect = move;
// Locked moves don't deduct PP
// Two-turn moves like Sky Attack deduct PP on their second turn.
if (!lockedMove || pokemon.volatiles['twoturnmove']) {
const ppMove = pokemon.volatiles['twoturnmove']?.ppMove || move.id;
pokemon.deductPP(ppMove, null, target);
const moveSlot = pokemon.getMoveData(ppMove);
if (moveSlot && moveSlot.pp < 0) {
moveSlot.pp += 64;
this.battle.hint("In Gen 1, if a pokemon is forced to use a move with 0 PP, the move will underflow to have 63 PP.");
// Locked moves don't deduct PP
// Two-turn moves like Sky Attack deduct PP on their second turn.
if ((!lockedMove && !TWO_TURN_MOVES.includes(move.id)) || pokemon.volatiles['twoturnmove']) {
const moveSlot = pokemon.getMoveSlot(pokemon.side.lastSelectedMoveSlot);
if (moveSlot) pokemon.deductPP(moveSlot.id, null, target);
}
if (!lockedMove && move.id !== pokemon.getMoveSlot(pokemon.side.lastSelectedMoveSlot)?.id) {
this.battle.hint("Desync Clause Mod activated!");
this.battle.hint(
"In Gen 1, a Pokémon might default to using a move that doesn't match the move of the slot it last selected.",
);
abortMove();
return;
}
}
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.
@ -195,6 +233,19 @@ export const Scripts: ModdedBattleScriptsData = {
}
if (sourceEffect) move.sourceEffect = sourceEffect.id;
if (sourceEffect?.id === 'metronome' || sourceEffect?.id === 'mirrormove') {
if (TWO_TURN_MOVES.includes(move.id)) {
const moveSlot = pokemon.getMoveSlot(pokemon.side.lastSelectedMoveSlot);
if (moveSlot) pokemon.deductPP(moveSlot.id, -1, target);
}
// FIXME: this should happen even if the slot was empty before Transform
// https://bulbapedia.bulbagarden.net/wiki/List_of_Transform_glitches#Transform_.2B_Mirror_Move.2FMetronome_PP_error
if (pokemon.transformed && pokemon.side.lastSelectedMoveSlot < pokemon.baseMoveSlots.length) {
pokemon.baseMoveSlots[pokemon.side.lastSelectedMoveSlot].pp += 1;
pokemon.baseMoveSlots[pokemon.side.lastSelectedMoveSlot].pp %= 64;
}
}
this.battle.singleEvent('ModifyMove', move, null, pokemon, target, move, move);
if (baseMove.target !== move.target) {
// Target changed in ModifyMove, so we must adjust it here
@ -414,7 +465,7 @@ export const Scripts: ModdedBattleScriptsData = {
let i: number;
for (i = 0; i < hits && target.hp && pokemon.hp; i++) {
move.hit = i + 1;
if (move.hit === hits) move.lastHit = true;
move.lastHit = move.hit === hits;
moveDamage = this.moveHit(target, pokemon, move);
if (moveDamage === false) break;
damage = (moveDamage || 0);

View File

@ -13,12 +13,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
substitute: {
inherit: true,
condition: {
onStart(target) {
this.add('-start', target, 'Substitute');
this.effectState.hp = Math.floor(target.maxhp / 4) + 1;
delete target.volatiles['partiallytrapped'];
},
onTryHitPriority: -1,
inherit: true,
onTryHit(target, source, move) {
if (move.drain) {
this.add('-miss', source);
@ -76,9 +71,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
return accuracy;
},
onEnd(target) {
this.add('-end', target, 'Substitute');
},
},
},
swift: {

View File

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

View File

@ -101,7 +101,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
},
flinch: {
inherit: true,
onStart() {},
onStart: undefined, // no inherit
},
partiallytrapped: {
name: 'partiallytrapped',

View File

@ -160,11 +160,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
volatileStatus: 'rage',
},
condition: {
inherit: true,
// Rage lock
onStart(target, source, effect) {
this.effectState.move = 'rage';
},
onLockMove: 'rage',
onHit(target, source, move) {
if (target.boosts.atk < 6 && (move.category !== 'Status' || move.id === 'disable')) {
this.boost({ atk: 1 });
@ -174,7 +174,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
recover: {
inherit: true,
heal: null,
onHit(target) {
if (target.hp === target.maxhp) {
return false;
@ -197,7 +196,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
softboiled: {
inherit: true,
heal: null,
onHit(target) {
// Fail when health is 255 or 511 less than max
if (target.hp === target.maxhp) {
@ -220,12 +218,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
},
condition: {
onStart(target) {
this.add('-start', target, 'Substitute');
this.effectState.hp = Math.floor(target.maxhp / 4);
delete target.volatiles['partiallytrapped'];
},
onTryHitPriority: -1,
inherit: true,
onTryHit(target, source, move) {
if (target === source) {
this.debug('sub bypass: self hit');
@ -275,11 +268,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
return 0;
},
onEnd(target) {
this.add('-end', target, 'Substitute');
},
},
secondary: null,
target: "self",
type: "Normal",
},

View File

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

View File

@ -93,8 +93,7 @@ export const Scripts: ModdedBattleScriptsData = {
return;
}
}
let lockedMove = this.battle.runEvent('LockMove', pokemon);
if (lockedMove === true) lockedMove = false;
const lockedMove = pokemon.getLockedMove() || pokemon.getSemiLockedMove();
if (
!lockedMove &&
(!pokemon.volatiles['partialtrappinglock'] || pokemon.volatiles['partialtrappinglock'].locked !== target)
@ -332,7 +331,7 @@ export const Scripts: ModdedBattleScriptsData = {
let i: number;
for (i = 0; i < hits && target.hp && pokemon.hp; i++) {
move.hit = i + 1;
if (move.hit === hits) move.lastHit = true;
move.lastHit = move.hit === hits;
moveDamage = this.moveHit(target, pokemon, move);
if (moveDamage === false) break;
damage = (moveDamage || 0);

View File

@ -62,8 +62,8 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
this.add('cant', pokemon, 'frz');
return false;
},
onModifyMove() {},
onDamagingHit() {},
onModifyMove: undefined, // no inherit
onDamagingHit: undefined, // no inherit
onAfterMoveSecondary(target, source, move) {
if ((move.secondary && move.secondary.status === 'brn') || move.statusRoll === 'brn') {
target.cureStatus();
@ -187,7 +187,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
delete target.volatiles['confusion'];
if (!target.side.getSideCondition('safeguard')) target.addVolatile('confusion');
},
onLockMove(pokemon) {
onLockMove() {
return this.effectState.move;
},
onMoveAborted(pokemon) {

View File

@ -12,7 +12,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
charmeleon: {
tier: "ZU",
tier: "ZUBL",
},
charizard: {
tier: "UUBL",
@ -57,7 +57,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
raticate: {
tier: "NU",
tier: "PU",
},
spearow: {
tier: "LC",
@ -69,7 +69,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
arbok: {
tier: "NU",
tier: "PU",
},
pichu: {
tier: "LC",
@ -267,7 +267,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "UU",
},
farfetchd: {
tier: "NU",
tier: "PU",
},
doduo: {
tier: "ZU",
@ -345,10 +345,10 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "NU",
},
hitmonchan: {
tier: "PUBL",
tier: "PU",
},
hitmontop: {
tier: "PU",
tier: "NU",
},
lickitung: {
tier: "NU",
@ -540,7 +540,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
furret: {
tier: "PUBL",
tier: "PU",
},
hoothoot: {
tier: "LC",
@ -558,7 +558,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
ariados: {
tier: "ZU",
tier: "ZUBL",
},
chinchou: {
tier: "NU",
@ -591,7 +591,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
azumarill: {
tier: "NU",
tier: "PU",
},
sudowoodo: {
tier: "NU",
@ -645,7 +645,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "OU",
},
dunsparce: {
tier: "NU",
tier: "PU",
},
gligar: {
tier: "UU",
@ -705,7 +705,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "OU",
},
houndour: {
tier: "NU",
tier: "PU",
},
houndoom: {
tier: "UUBL",

View File

@ -5,7 +5,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
blackbelt: {
inherit: true,
onModifyAtk() {},
onModifyAtk: undefined, // no inherit
onModifyDamage(damage, source, target, move) {
if (move?.type === 'Fighting') {
return damage * 1.1;
@ -14,7 +14,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
blackglasses: {
inherit: true,
onModifySpA() {},
onModifySpA: undefined, // no inherit
onModifyDamage(damage, source, target, move) {
if (move?.type === 'Dark') {
return damage * 1.1;
@ -31,7 +31,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
charcoal: {
inherit: true,
onModifySpA() {},
onModifySpA: undefined, // no inherit
onModifyDamage(damage, source, target, move) {
if (move?.type === 'Fire') {
return damage * 1.1;
@ -40,7 +40,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
dragonfang: {
inherit: true,
onModifySpA() {},
onModifySpA: undefined, // no inherit
},
dragonscale: {
inherit: true,
@ -65,7 +65,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
hardstone: {
inherit: true,
onModifyAtk() {},
onModifyAtk: undefined, // no inherit
onModifyDamage(damage, source, target, move) {
if (move?.type === 'Rock') {
return damage * 1.1;
@ -106,7 +106,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
lightball: {
inherit: true,
// In Gen 2 this happens in stat calculation directly.
onModifySpA() {},
onModifySpA: undefined, // no inherit
},
loveball: {
inherit: true,
@ -127,7 +127,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
magnet: {
inherit: true,
onModifySpA() {},
onModifySpA: undefined, // no inherit
onModifyDamage(damage, source, target, move) {
if (move?.type === 'Electric') {
return damage * 1.1;
@ -136,7 +136,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
metalcoat: {
inherit: true,
onModifyAtk() {},
onModifyAtk: undefined, // no inherit
onModifyDamage(damage, source, target, move) {
if (move?.type === 'Steel') {
return damage * 1.1;
@ -146,12 +146,12 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
metalpowder: {
inherit: true,
// In Gen 2 this happens in stat calculation directly.
onModifyDef() {},
onModifySpD() {},
onModifyDef: undefined, // no inherit
onModifySpD: undefined, // no inherit
},
miracleseed: {
inherit: true,
onModifySpA() {},
onModifySpA: undefined, // no inherit
onModifyDamage(damage, source, target, move) {
if (move?.type === 'Grass') {
return damage * 1.1;
@ -164,7 +164,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
mysticwater: {
inherit: true,
onModifySpA() {},
onModifySpA: undefined, // no inherit
onModifyDamage(damage, source, target, move) {
if (move?.type === 'Water') {
return damage * 1.1;
@ -173,7 +173,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
nevermeltice: {
inherit: true,
onModifySpA() {},
onModifySpA: undefined, // no inherit
onModifyDamage(damage, source, target, move) {
if (move?.type === 'Ice') {
return damage * 1.1;
@ -182,7 +182,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
poisonbarb: {
inherit: true,
onModifyAtk() {},
onModifyAtk: undefined, // no inherit
onModifyDamage(damage, source, target, move) {
if (move?.type === 'Poison') {
return damage * 1.1;
@ -191,7 +191,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
sharpbeak: {
inherit: true,
onModifyAtk() {},
onModifyAtk: undefined, // no inherit
onModifyDamage(damage, source, target, move) {
if (move?.type === 'Flying') {
return damage * 1.1;
@ -200,7 +200,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
silverpowder: {
inherit: true,
onModifyAtk() {},
onModifyAtk: undefined, // no inherit
onModifyDamage(damage, source, target, move) {
if (move?.type === 'Bug') {
return damage * 1.1;
@ -209,7 +209,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
softsand: {
inherit: true,
onModifyAtk() {},
onModifyAtk: undefined, // no inherit
onModifyDamage(damage, source, target, move) {
if (move?.type === 'Ground') {
return damage * 1.1;
@ -218,7 +218,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
spelltag: {
inherit: true,
onModifyAtk() {},
onModifyAtk: undefined, // no inherit
onModifyDamage(damage, source, target, move) {
if (move?.type === 'Ghost') {
return damage * 1.1;
@ -241,11 +241,11 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
thickclub: {
inherit: true,
// In Gen 2 this happens in stat calculation directly.
onModifyAtk() {},
onModifyAtk: undefined, // no inherit
},
twistedspoon: {
inherit: true,
onModifySpA() {},
onModifySpA: undefined, // no inherit
onModifyDamage(damage, source, target, move) {
if (move?.type === 'Psychic') {
return damage * 1.1;
@ -290,7 +290,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
pinkbow: {
inherit: true,
onBasePower() {},
onBasePower: undefined, // no inherit
onModifyDamage(damage, source, target, move) {
if (move?.type === 'Normal') {
return damage * 1.1;
@ -300,7 +300,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
polkadotbow: {
inherit: true,
onBasePower() {},
onBasePower: undefined, // no inherit
onModifyDamage(damage, source, target, move) {
if (move?.type === 'Normal') {
return damage * 1.1;

View File

@ -51,64 +51,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
bide: {
inherit: true,
condition: {
duration: 3,
inherit: true,
durationCallback(target, source, effect) {
return this.random(3, 5);
},
onLockMove: 'bide',
onStart(pokemon) {
this.effectState.totalDamage = 0;
this.add('-start', pokemon, 'move: Bide');
},
onDamagePriority: -101,
onDamage(damage, target, source, move) {
if (!move || move.effectType !== 'Move' || !source) return;
this.effectState.totalDamage += damage;
this.effectState.lastDamageSource = source;
},
onBeforeMove(pokemon, target, move) {
if (this.effectState.duration === 1) {
this.add('-end', pokemon, 'move: Bide');
if (!this.effectState.totalDamage) {
this.add('-fail', pokemon);
return false;
}
target = this.effectState.lastDamageSource;
if (!target) {
this.add('-fail', pokemon);
return false;
}
if (!target.isActive) {
const possibleTarget = this.getRandomTarget(pokemon, this.dex.moves.get('pound'));
if (!possibleTarget) {
this.add('-miss', pokemon);
return false;
}
target = possibleTarget;
}
const moveData = {
id: 'bide',
name: "Bide",
accuracy: 100,
damage: this.effectState.totalDamage * 2,
category: "Physical",
priority: 0,
flags: { contact: 1, protect: 1 },
effectType: 'Move',
type: 'Normal',
} as unknown as ActiveMove;
this.actions.tryMoveHit(target, pokemon, moveData);
pokemon.removeVolatile('bide');
return false;
}
this.add('-activate', pokemon, 'move: Bide');
},
onMoveAborted(pokemon) {
pokemon.removeVolatile('bide');
},
onEnd(pokemon) {
this.add('-end', pokemon, 'move: Bide', '[silent]');
},
onLockMove: undefined, // no inherit
onSemiLockMove: 'bide',
},
},
counter: {
@ -123,8 +71,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
return false;
},
beforeTurnCallback() {},
onTry() {},
beforeTurnCallback: undefined, // no inherit
onTry: undefined, // no inherit
condition: {},
priority: -1,
},
@ -139,12 +87,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
curse: {
inherit: true,
condition: {
onStart(pokemon, source) {
this.add('-start', pokemon, 'Curse', `[of] ${source}`);
},
inherit: true,
onAfterMoveSelfPriority: 0, // explicit
onAfterMoveSelf(pokemon) {
this.damage(pokemon.baseMaxhp / 4);
},
onResidual: undefined, // no inherit
},
},
detect: {
@ -157,10 +105,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
return source.status !== 'slp';
},
condition: {
duration: 2,
onImmunity(type, pokemon) {
if (type === 'sandstorm') return false;
},
inherit: true,
onInvulnerability(target, source, move) {
if (move.id === 'earthquake' || move.id === 'magnitude' || move.id === 'fissure') {
return;
@ -172,6 +117,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
if (source.volatiles['lockon'] && target === source.volatiles['lockon'].source) return;
return false;
},
onSourceModifyDamage: undefined, // no inherit
onSourceBasePower(basePower, target, source, move) {
if (move.id === 'earthquake' || move.id === 'magnitude') {
return this.chainModify(2);
@ -186,9 +132,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
encore: {
inherit: true,
condition: {
durationCallback() {
return this.random(3, 7);
},
inherit: true,
onStart(target) {
const lockedMove = target.lastMoveEncore?.id || '';
const moveSlot = lockedMove ? target.getMoveData(lockedMove) : null;
@ -199,30 +143,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.effectState.move = lockedMove;
this.add('-start', target, 'Encore');
},
onOverrideAction(pokemon) {
return this.effectState.move;
},
onResidualOrder: 13,
onResidual(target) {
const lockedMoveSlot = target.getMoveData(this.effectState.move);
if (lockedMoveSlot && lockedMoveSlot.pp <= 0) {
// early termination if you run out of PP
target.removeVolatile('encore');
}
},
onEnd(target) {
this.add('-end', target, 'Encore');
},
onDisableMove(pokemon) {
if (!this.effectState.move || !pokemon.hasMove(this.effectState.move)) {
return;
}
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id !== this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
}
},
onResidualSubOrder: undefined, // no inherit
},
},
endure: {
@ -244,7 +166,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
return source.status !== 'slp';
},
condition: {
duration: 2,
inherit: true,
onInvulnerability(target, source, move) {
if (move.id === 'gust' || move.id === 'twister' || move.id === 'thunder' || move.id === 'whirlwind') {
return;
@ -260,6 +182,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
if (source.volatiles['lockon'] && target === source.volatiles['lockon'].source) return;
return false;
},
onSourceModifyDamage: undefined, // no inherit
onSourceBasePower(basePower, target, source, move) {
if (move.id === 'gust' || move.id === 'twister') {
return this.chainModify(2);
@ -270,9 +193,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
focusenergy: {
inherit: true,
condition: {
onStart(pokemon) {
this.add('-start', pokemon, 'move: Focus Energy');
},
inherit: true,
onModifyCritRatio(critRatio) {
return critRatio + 1;
},
@ -284,17 +205,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
if (target.volatiles['foresight']) return false;
},
condition: {
onStart(pokemon) {
this.add('-start', pokemon, 'Foresight');
},
onNegateImmunity(pokemon, type) {
if (pokemon.hasType('Ghost') && ['Normal', 'Fighting'].includes(type)) return false;
},
onModifyBoost(boosts) {
if (boosts.evasion && boosts.evasion > 0) {
boosts.evasion = 0;
}
},
inherit: true,
noCopy: false,
},
},
frustration: {
@ -338,11 +250,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
leechseed: {
inherit: true,
onHit() {},
onHit: undefined, // no inherit
condition: {
onStart(target) {
this.add('-start', target, 'move: Leech Seed');
},
inherit: true,
onResidual: undefined, // no inherit
onAfterMoveSelfPriority: 2,
onAfterMoveSelf(pokemon) {
if (!pokemon.hp) return;
@ -378,19 +289,15 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
if (target.volatiles['foresight'] || target.volatiles['lockon']) return false;
},
condition: {
duration: 2,
onSourceAccuracy(accuracy, target, source, move) {
if (move && source === this.effectState.target && target === this.effectState.source) return true;
},
inherit: true,
onSourceInvulnerability: undefined, // no inherit
},
},
lowkick: {
inherit: true,
accuracy: 90,
basePower: 50,
basePowerCallback() {
return 50;
},
basePowerCallback: undefined, // no inherit
secondary: {
chance: 30,
volatileStatus: 'flinch',
@ -427,8 +334,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
return false;
},
beforeTurnCallback() {},
onTry() {},
beforeTurnCallback: undefined, // no inherit
onTry: undefined, // no inherit
condition: {},
priority: -1,
},
@ -449,15 +356,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
},
mist: {
num: 54,
accuracy: true,
basePower: 0,
category: "Status",
name: "Mist",
pp: 30,
priority: 0,
flags: { metronome: 1 },
inherit: true,
volatileStatus: 'mist',
sideCondition: undefined, // no inherit
condition: {
onStart(pokemon) {
this.add('-start', pokemon, 'Mist');
@ -478,9 +379,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
},
},
secondary: null,
target: "self",
type: "Ice",
},
moonlight: {
inherit: true,
@ -509,13 +408,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
nightmare: {
inherit: true,
condition: {
noCopy: true,
onStart(pokemon) {
if (pokemon.status !== 'slp') {
return false;
}
this.add('-start', pokemon, 'Nightmare');
},
inherit: true,
onResidual: undefined, // no inherit
onAfterMoveSelfPriority: 1,
onAfterMoveSelf(pokemon) {
if (pokemon.status === 'slp') this.damage(pokemon.baseMaxhp / 4);
@ -535,16 +429,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
perishsong: {
inherit: true,
condition: {
duration: 4,
onEnd(target) {
this.add('-start', target, 'perish0');
target.faint();
},
inherit: true,
onResidualOrder: 4,
onResidual(pokemon) {
const duration = pokemon.volatiles['perishsong'].duration;
this.add('-start', pokemon, `perish${duration}`);
},
},
},
petaldance: {
@ -573,9 +459,18 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
pursuit: {
inherit: true,
onModifyMove() {},
beforeTurnCallback(pokemon, target) {
if (pokemon.isAlly(target)) return;
target.addVolatile('pursuit');
const data = target.volatiles['pursuit'];
if (!data.sources) {
data.sources = [];
}
data.sources.push(pokemon);
},
onModifyMove: undefined, // no inherit
condition: {
duration: 1,
inherit: true,
onBeforeSwitchOut(pokemon) {
this.debug('Pursuit start');
let alreadyAdded = false;
@ -649,7 +544,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
target.statusState.source = target;
this.heal(target.maxhp);
},
secondary: null,
},
return: {
inherit: true,
@ -675,41 +569,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
safeguard: {
inherit: true,
condition: {
duration: 5,
durationCallback(target, source, effect) {
if (source?.hasAbility('persistent')) {
this.add('-activate', source, 'ability: Persistent', effect);
return 7;
}
return 5;
},
onSetStatus(status, target, source, effect) {
if (!effect || !source) return;
if (effect.id === 'yawn') return;
if (effect.effectType === 'Move' && effect.infiltrates && !target.isAlly(source)) return;
if (target !== source) {
this.debug('interrupting setStatus');
if (effect.id === 'synchronize' || (effect.effectType === 'Move' && !effect.secondaries)) {
this.add('-activate', target, 'move: Safeguard');
}
return null;
}
},
onTryAddVolatile(status, target, source, effect) {
if (!effect || !source) return;
if (effect.effectType === 'Move' && effect.infiltrates && !target.isAlly(source)) return;
if ((status.id === 'confusion' || status.id === 'yawn') && target !== source) {
if (effect.effectType === 'Move' && !effect.secondaries) this.add('-activate', target, 'move: Safeguard');
return null;
}
},
onSideStart(side) {
this.add('-sidestart', side, 'Safeguard');
},
inherit: true,
onSideResidualOrder: 8,
onSideEnd(side) {
this.add('-sideend', side, 'Safeguard');
},
},
},
selfdestruct: {
@ -736,7 +597,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
onPrepareHit(target, source) {
return source.status !== 'slp';
},
secondary: null,
secondary: undefined, // no inherit
},
slash: {
inherit: true,
@ -766,7 +627,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
return source.status !== 'slp';
},
// Rain weakening done directly in the damage formula
onBasePower() {},
onBasePower: undefined, // no inherit
},
spiderweb: {
inherit: true,
@ -775,31 +636,14 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
spikes: {
inherit: true,
condition: {
// this is a side condition
onSideStart(side) {
if (!this.effectState.layers || this.effectState.layers === 0) {
this.add('-sidestart', side, 'Spikes');
this.effectState.layers = 1;
} else {
return false;
}
},
onSwitchIn(pokemon) {
if (!pokemon.runImmunity('Ground')) return;
const damageAmounts = [0, 3];
this.damage(damageAmounts[this.effectState.layers] * pokemon.maxhp / 24);
},
inherit: true,
onSideRestart: undefined, // no inherit
},
},
substitute: {
inherit: true,
condition: {
onStart(target) {
this.add('-start', target, 'Substitute');
this.effectState.hp = Math.floor(target.maxhp / 4);
delete target.volatiles['partiallytrapped'];
},
onTryPrimaryHitPriority: -1,
inherit: true,
onTryPrimaryHit(target, source, move) {
if (move.stallingMove) {
this.add('-fail', source);
@ -852,9 +696,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.runEvent('AfterSubDamage', target, source, move, damage);
return this.HIT_SUBSTITUTE;
},
onEnd(target) {
this.add('-end', target, 'Substitute');
},
},
},
swagger: {
@ -880,7 +721,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
thief: {
inherit: true,
onAfterHit() {},
onAfterHit: undefined, // no inherit
secondary: {
chance: 100,
onHit(target, source) {
@ -916,7 +757,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
triattack: {
inherit: true,
onHit(target, source, move) {
move.statusRoll = ['par', 'frz', 'brn'][this.random(3)];
move.statusRoll = this.sample(['par', 'frz', 'brn']);
},
secondary: {
chance: 20,

View File

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

View File

@ -125,8 +125,7 @@ export const Scripts: ModdedBattleScriptsData = {
}
}
pokemon.lastDamage = 0;
let lockedMove = this.battle.runEvent('LockMove', pokemon);
if (lockedMove === true) lockedMove = false;
const lockedMove = pokemon.getLockedMove() || pokemon.getSemiLockedMove();
if (!lockedMove) {
if (!pokemon.deductPP(move, null, target) && (move.id !== 'struggle')) {
this.battle.add('cant', pokemon, 'nopp', move);
@ -273,7 +272,7 @@ export const Scripts: ModdedBattleScriptsData = {
for (i = 0; i < hits && target.hp && pokemon.hp; i++) {
if (pokemon.status === 'slp' && !isSleepUsable) break;
move.hit = i + 1;
if (move.hit === hits) move.lastHit = true;
move.lastHit = move.hit === hits;
moveDamage = this.moveHit(target, pokemon, move);
if (moveDamage === false) break;
if (nullDamage && (moveDamage || moveDamage === 0 || moveDamage === undefined)) nullDamage = false;

View File

@ -10,6 +10,6 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
dragonscale: {
inherit: true,
onModifyDamage() {},
onModifyDamage: undefined, // no inherit
},
};

View File

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

View File

@ -208,7 +208,7 @@ export const Scripts: ModdedBattleScriptsData = {
for (i = 0; i < hits && target.hp && pokemon.hp; i++) {
if (pokemon.status === 'slp' && !isSleepUsable) break;
move.hit = i + 1;
if (move.hit === hits) move.lastHit = true;
move.lastHit = move.hit === hits;
moveDamage = this.moveHit(target, pokemon, move);
if (moveDamage === false) break;
if (nullDamage && (moveDamage || moveDamage === 0 || moveDamage === undefined)) nullDamage = false;

View File

@ -12,15 +12,9 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
effectspore: {
inherit: true,
onDamagingHit(damage, target, source, move) {
if (damage && move.flags['contact'] && !source.status) {
const r = this.random(300);
if (r < 10) {
source.setStatus('slp', target);
} else if (r < 20) {
source.setStatus('par', target);
} else if (r < 30) {
source.setStatus('psn', target);
}
if (damage && move.flags['contact'] && this.randomChance(1, 10)) {
const status = this.sample(['slp', 'par', 'psn']);
source.trySetStatus(status, target);
}
},
},
@ -91,6 +85,8 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
},
},
lightningrod: {
inherit: true,
onAnyRedirectTarget: undefined, // no inherit
onFoeRedirectTarget(target, source, source2, move) {
// don't count Hidden Power as Electric-type
if (this.dex.moves.get(move.id).type !== 'Electric') return;
@ -98,15 +94,11 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
return this.effectState.target;
}
},
flags: { breakable: 1 },
name: "Lightning Rod",
rating: 0,
num: 32,
},
magnetpull: {
inherit: true,
onFoeTrapPokemon() {},
onFoeMaybeTrapPokemon() {},
onFoeTrapPokemon: undefined, // no inherit
onFoeMaybeTrapPokemon: undefined, // no inherit
onAnyTrapPokemon(pokemon) {
if (pokemon.hasType('Steel') && pokemon.isAdjacent(this.effectState.target)) {
pokemon.tryTrap(true);
@ -158,7 +150,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
},
raindish: {
inherit: true,
onWeather() {},
onWeather: undefined, // no inherit
onResidualOrder: 10,
onResidualSubOrder: 3,
onResidual(pokemon) {
@ -193,7 +185,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
},
trace: {
inherit: true,
onUpdate() {},
onUpdate: undefined, // no inherit
onStart(pokemon) {
const target = pokemon.side.randomFoe();
if (!target || target.fainted) return;
@ -204,7 +196,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
},
truant: {
inherit: true,
onStart() {},
onStart: undefined, // no inherit
onSwitchIn(pokemon) {
pokemon.truantTurn = this.turn !== 0;
},

View File

@ -51,6 +51,6 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
},
sandstorm: {
inherit: true,
onModifySpD() {},
onModifySpD: undefined, // no inherit
},
};

View File

@ -63,7 +63,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
fearow: {
tier: "UU",
tier: "RUBL",
},
ekans: {
tier: "LC",
@ -312,7 +312,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "ZU",
},
hypno: {
tier: "UU",
tier: "RU",
},
krabby: {
tier: "LC",
@ -930,7 +930,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
tier: "LC",
},
manectric: {
tier: "UU",
tier: "RU",
},
plusle: {
tier: "NU",

View File

@ -1,7 +1,7 @@
export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
aguavberry: {
inherit: true,
onUpdate() {},
onUpdate: undefined, // no inherit
onResidualOrder: 10,
onResidualSubOrder: 4,
onResidual(pokemon) {
@ -12,7 +12,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
apicotberry: {
inherit: true,
onUpdate() {},
onUpdate: undefined, // no inherit
onResidualOrder: 10,
onResidualSubOrder: 4,
onResidual(pokemon) {
@ -23,7 +23,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
berryjuice: {
inherit: true,
onUpdate() {},
onUpdate: undefined, // no inherit
onResidualOrder: 10,
onResidualSubOrder: 4,
onResidual(pokemon) {
@ -37,7 +37,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
blackbelt: {
inherit: true,
onBasePower() {},
onBasePower: undefined, // no inherit
onModifyAtkPriority: 1,
onModifyAtk(atk, user, target, move) {
if (move?.type === 'Fighting') {
@ -47,7 +47,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
blackglasses: {
inherit: true,
onBasePower() {},
onBasePower: undefined, // no inherit
onModifySpAPriority: 1,
onModifySpA(spa, user, target, move) {
if (move?.type === 'Dark') {
@ -57,7 +57,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
charcoal: {
inherit: true,
onBasePower() {},
onBasePower: undefined, // no inherit
onModifySpAPriority: 1,
onModifySpA(spa, user, target, move) {
if (move?.type === 'Fire') {
@ -67,7 +67,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
dragonfang: {
inherit: true,
onBasePower() {},
onBasePower: undefined, // no inherit
onModifySpAPriority: 1,
onModifySpA(spa, user, target, move) {
if (move?.type === 'Dragon') {
@ -82,6 +82,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
num: 208,
gen: 3,
isNonstandard: "Unobtainable",
// No competitive use
},
fastball: {
inherit: true,
@ -89,7 +90,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
figyberry: {
inherit: true,
onUpdate() {},
onUpdate: undefined, // no inherit
onResidualOrder: 10,
onResidualSubOrder: 4,
onResidual(pokemon) {
@ -100,7 +101,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
ganlonberry: {
inherit: true,
onUpdate() {},
onUpdate: undefined, // no inherit
onResidualOrder: 10,
onResidualSubOrder: 4,
onResidual(pokemon) {
@ -111,7 +112,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
hardstone: {
inherit: true,
onBasePower() {},
onBasePower: undefined, // no inherit
onModifyAtkPriority: 1,
onModifyAtk(atk, user, target, move) {
if (move?.type === 'Rock') {
@ -125,7 +126,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
iapapaberry: {
inherit: true,
onUpdate() {},
onUpdate: undefined, // no inherit
onResidualOrder: 10,
onResidualSubOrder: 4,
onResidual(pokemon) {
@ -151,7 +152,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
lansatberry: {
inherit: true,
onUpdate() {},
onUpdate: undefined, // no inherit
onResidualOrder: 10,
onResidualSubOrder: 4,
onResidual(pokemon) {
@ -174,7 +175,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
liechiberry: {
inherit: true,
onUpdate() {},
onUpdate: undefined, // no inherit
onResidualOrder: 10,
onResidualSubOrder: 4,
onResidual(pokemon) {
@ -190,7 +191,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
return this.chainModify(2);
}
},
onBasePower() {},
onBasePower: undefined, // no inherit
},
loveball: {
inherit: true,
@ -202,7 +203,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
magnet: {
inherit: true,
onBasePower() {},
onBasePower: undefined, // no inherit
onModifySpAPriority: 1,
onModifySpA(spa, user, target, move) {
if (move?.type === 'Electric') {
@ -212,7 +213,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
magoberry: {
inherit: true,
onUpdate() {},
onUpdate: undefined, // no inherit
onResidualOrder: 10,
onResidualSubOrder: 4,
onResidual(pokemon) {
@ -223,7 +224,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
metalcoat: {
inherit: true,
onBasePower() {},
onBasePower: undefined, // no inherit
onModifyAtkPriority: 1,
onModifyAtk(atk, user, target, move) {
if (move?.type === 'Steel') {
@ -233,7 +234,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
miracleseed: {
inherit: true,
onBasePower() {},
onBasePower: undefined, // no inherit
onModifySpAPriority: 1,
onModifySpA(spa, user, target, move) {
if (move?.type === 'Grass') {
@ -247,7 +248,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
mysticwater: {
inherit: true,
onBasePower() {},
onBasePower: undefined, // no inherit
onModifySpAPriority: 1,
onModifySpA(spa, user, target, move) {
if (move?.type === 'Water') {
@ -257,7 +258,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
nevermeltice: {
inherit: true,
onBasePower() {},
onBasePower: undefined, // no inherit
onModifySpAPriority: 1,
onModifySpA(spa, user, target, move) {
if (move?.type === 'Ice') {
@ -267,7 +268,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
oranberry: {
inherit: true,
onUpdate() {},
onUpdate: undefined, // no inherit
onResidualOrder: 10,
onResidualSubOrder: 4,
onResidual(pokemon) {
@ -278,7 +279,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
petayaberry: {
inherit: true,
onUpdate() {},
onUpdate: undefined, // no inherit
onResidualOrder: 10,
onResidualSubOrder: 4,
onResidual(pokemon) {
@ -289,7 +290,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
poisonbarb: {
inherit: true,
onBasePower() {},
onBasePower: undefined, // no inherit
onModifyAtkPriority: 1,
onModifyAtk(atk, user, target, move) {
if (move?.type === 'Poison') {
@ -299,12 +300,12 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
quickclaw: {
inherit: true,
onFractionalPriority() {},
onFractionalPriority: undefined, // no inherit
// implemented in Pokemon#getActionSpeed()
},
salacberry: {
inherit: true,
onUpdate() {},
onUpdate: undefined, // no inherit
onResidualOrder: 10,
onResidualSubOrder: 4,
onResidual(pokemon) {
@ -315,7 +316,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
seaincense: {
inherit: true,
onBasePower() {},
onBasePower: undefined, // no inherit
onModifySpAPriority: 1,
onModifySpA(spa, user, target, move) {
if (move?.type === 'Water') {
@ -325,7 +326,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
sharpbeak: {
inherit: true,
onBasePower() {},
onBasePower: undefined, // no inherit
onModifyAtkPriority: 1,
onModifyAtk(atk, user, target, move) {
if (move?.type === 'Flying') {
@ -335,7 +336,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
silkscarf: {
inherit: true,
onBasePower() {},
onBasePower: undefined, // no inherit
onModifyAtkPriority: 1,
onModifyAtk(atk, user, target, move) {
if (move?.type === 'Normal') {
@ -345,7 +346,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
silverpowder: {
inherit: true,
onBasePower() {},
onBasePower: undefined, // no inherit
onModifyAtkPriority: 1,
onModifyAtk(atk, user, target, move) {
if (move?.type === 'Bug') {
@ -355,7 +356,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
sitrusberry: {
inherit: true,
onUpdate() {},
onUpdate: undefined, // no inherit
onResidualOrder: 10,
onResidualSubOrder: 4,
onResidual(pokemon) {
@ -369,7 +370,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
softsand: {
inherit: true,
onBasePower() {},
onBasePower: undefined, // no inherit
onModifyAtkPriority: 1,
onModifyAtk(atk, user, target, move) {
if (move?.type === 'Ground') {
@ -379,7 +380,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
spelltag: {
inherit: true,
onBasePower() {},
onBasePower: undefined, // no inherit
onModifyAtkPriority: 1,
onModifyAtk(atk, user, target, move) {
if (move?.type === 'Ghost') {
@ -393,7 +394,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
starfberry: {
inherit: true,
onUpdate() {},
onUpdate: undefined, // no inherit
onResidualOrder: 10,
onResidualSubOrder: 4,
onResidual(pokemon) {
@ -404,7 +405,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
twistedspoon: {
inherit: true,
onBasePower() {},
onBasePower: undefined, // no inherit
onModifySpAPriority: 1,
onModifySpA(spa, user, target, move) {
if (move?.type === 'Psychic') {
@ -414,7 +415,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
wikiberry: {
inherit: true,
onUpdate() {},
onUpdate: undefined, // no inherit
onResidualOrder: 10,
onResidualSubOrder: 4,
onResidual(pokemon) {

View File

@ -26,10 +26,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
astonish: {
inherit: true,
basePowerCallback(pokemon, target) {
if (target.volatiles['minimize']) return 60;
return 30;
},
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1, minimize: 1 },
},
beatup: {
inherit: true,
@ -44,8 +41,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
duration: 1,
onModifySpAPriority: -101,
onModifySpA(atk, pokemon, defender, move) {
// https://www.smogon.com/forums/posts/8992145/
// this.add('-activate', pokemon, 'move: Beat Up', '[of] ' + move.allies![0].name);
if (!this.ruleTable.has('beatupnicknamesmod')) {
this.add('-activate', pokemon, 'move: Beat Up', '[of] ' + move.allies![0].name);
}
this.event.modifier = 1;
return this.dex.species.get(move.allies!.shift()!.set.species).baseStats.atk;
},
@ -61,18 +59,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
accuracy: 100,
priority: 0,
condition: {
duration: 3,
onLockMove: 'bide',
onStart(pokemon) {
this.effectState.totalDamage = 0;
this.add('-start', pokemon, 'move: Bide');
},
onDamagePriority: -101,
onDamage(damage, target, source, move) {
if (!move || move.effectType !== 'Move' || !source) return;
this.effectState.totalDamage += damage;
this.effectState.lastDamageSource = source;
},
inherit: true,
onAfterSetStatus: undefined, // no inherit
onBeforeMove(pokemon, target, move) {
if (this.effectState.duration === 1) {
this.add('-end', pokemon, 'move: Bide');
@ -110,17 +98,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
this.add('-activate', pokemon, 'move: Bide');
},
onMoveAborted(pokemon) {
pokemon.removeVolatile('bide');
},
onEnd(pokemon) {
this.add('-end', pokemon, 'move: Bide', '[silent]');
},
},
},
blizzard: {
inherit: true,
onModifyMove() { },
onModifyMove: undefined, // no inherit
},
brickbreak: {
inherit: true,
@ -133,7 +115,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
charge: {
inherit: true,
boosts: null,
boosts: undefined, // no inherit
},
conversion: {
inherit: true,
@ -181,17 +163,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
counter: {
inherit: true,
condition: {
duration: 1,
noCopy: true,
onStart(target, source, move) {
this.effectState.slot = null;
this.effectState.damage = 0;
},
onRedirectTargetPriority: -1,
inherit: true,
onRedirectTarget(target, source, source2) {
if (source !== this.effectState.target || !this.effectState.slot) return;
return this.getAtSlot(this.effectState.slot);
},
onDamagingHit: undefined, // no inherit
onDamagePriority: -101,
onDamage(damage, target, source, effect) {
if (
@ -225,48 +202,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
accuracy: 55,
flags: { protect: 1, mirror: 1, bypasssub: 1, metronome: 1 },
volatileStatus: 'disable',
condition: {
inherit: true,
durationCallback() {
return this.random(2, 6);
},
noCopy: true,
onStart(pokemon) {
if (!this.queue.willMove(pokemon)) {
this.effectState.duration!++;
}
if (!pokemon.lastMove) {
return false;
}
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id === pokemon.lastMove.id) {
if (!moveSlot.pp) {
return false;
} else {
this.add('-start', pokemon, 'Disable', moveSlot.move);
this.effectState.move = pokemon.lastMove.id;
return;
}
}
}
return false;
},
onEnd(pokemon) {
this.add('-end', pokemon, 'move: Disable');
},
onBeforeMove(attacker, defender, move) {
if (move.id === this.effectState.move) {
this.add('cant', attacker, 'Disable', move);
return false;
}
},
onDisableMove(pokemon) {
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id === this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
}
},
"onResidualOrder": undefined, // no inherit
"onResidualSubOrder": undefined, // no inherit
},
},
dive: {
@ -310,51 +252,15 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
volatileStatus: 'encore',
condition: {
inherit: true,
durationCallback() {
return this.random(3, 7);
},
onStart(target, source) {
const moveSlot = target.lastMove ? target.getMoveData(target.lastMove.id) : null;
if (!target.lastMove || target.lastMove.flags['failencore'] || !moveSlot || moveSlot.pp <= 0) {
// it failed
return false;
}
this.effectState.move = target.lastMove.id;
this.add('-start', target, 'Encore');
},
onOverrideAction(pokemon) {
return this.effectState.move;
},
onResidualOrder: 10,
onResidualSubOrder: 14,
onResidual(target) {
const moveSlot = target.getMoveData(this.effectState.move);
if (moveSlot && moveSlot.pp <= 0) {
// early termination if you run out of PP
target.removeVolatile('encore');
}
},
onEnd(target) {
this.add('-end', target, 'Encore');
},
onDisableMove(pokemon) {
if (!this.effectState.move || !pokemon.hasMove(this.effectState.move)) {
return;
}
for (const moveSlot of pokemon.moveSlots) {
if (moveSlot.id !== this.effectState.move) {
pokemon.disableMove(moveSlot.id);
}
}
},
},
},
extrasensory: {
inherit: true,
basePowerCallback(pokemon, target) {
if (target.volatiles['minimize']) return 160;
return 80;
},
flags: { protect: 1, mirror: 1, metronome: 1, minimize: 1 },
},
fakeout: {
inherit: true,
@ -396,15 +302,14 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
followme: {
inherit: true,
volatileStatus: undefined,
volatileStatus: undefined, // no inherit
slotCondition: 'followme',
condition: {
duration: 1,
inherit: true,
onStart(target, source, effect) {
this.add('-singleturn', target, 'move: Follow Me');
this.effectState.slot = target.getSlot();
},
onFoeRedirectTargetPriority: 1,
onFoeRedirectTarget(target, source, source2, move) {
const userSlot = this.getAtSlot(this.effectState.slot);
if (this.validTarget(userSlot, source, move.target)) {
@ -502,17 +407,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
mirrorcoat: {
inherit: true,
condition: {
duration: 1,
noCopy: true,
onStart(target, source, move) {
this.effectState.slot = null;
this.effectState.damage = 0;
},
onRedirectTargetPriority: -1,
inherit: true,
onRedirectTarget(target, source, source2) {
if (source !== this.effectState.target || !this.effectState.slot) return;
return this.getAtSlot(this.effectState.slot);
},
onDamagingHit: undefined, // no inherit
onDamagePriority: -101,
onDamage(damage, target, source, effect) {
if (
@ -528,7 +428,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
mirrormove: {
inherit: true,
flags: { metronome: 1, failencore: 1, nosleeptalk: 1, noassist: 1 },
onTryHit() { },
onTryHit: undefined, // no inherit
onHit(pokemon) {
const noMirror = [
'assist', 'curse', 'doomdesire', 'focuspunch', 'futuresight', 'magiccoat', 'metronome', 'mimic', 'mirrormove', 'naturepower', 'psychup', 'roleplay', 'sketch', 'sleeptalk', 'spikes', 'spitup', 'taunt', 'teeterdance', 'transform',
@ -553,10 +453,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
needlearm: {
inherit: true,
basePowerCallback(pokemon, target) {
if (target.volatiles['minimize']) return 120;
return 60;
},
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1, minimize: 1 },
},
nightmare: {
inherit: true,
@ -578,6 +475,20 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
basePower: 70,
},
pursuit: {
inherit: true,
beforeTurnCallback(pokemon, target) {
if (['frz', 'slp'].includes(pokemon.status) ||
(pokemon.hasAbility('truant') && pokemon.truantTurn)) return;
if (pokemon.isAlly(target)) return;
target.addVolatile('pursuit');
const data = target.volatiles['pursuit'];
if (!data.sources) {
data.sources = [];
}
data.sources.push(pokemon);
},
},
recover: {
inherit: true,
pp: 20,
@ -681,28 +592,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
flags: { protect: 1, bypasssub: 1, metronome: 1 },
condition: {
inherit: true,
duration: 2,
onStart(target) {
this.add('-start', target, 'move: Taunt');
},
onResidualOrder: 10,
onResidualSubOrder: 15,
durationCallback: undefined, // no inherit
onEnd(target) {
this.add('-end', target, 'move: Taunt', '[silent]');
},
onDisableMove(pokemon) {
for (const moveSlot of pokemon.moveSlots) {
if (this.dex.moves.get(moveSlot.move).category === 'Status') {
pokemon.disableMove(moveSlot.id);
}
}
},
onBeforeMove(attacker, defender, move) {
if (move.category === 'Status') {
this.add('cant', attacker, 'move: Taunt', move);
return false;
}
},
onBeforeMovePriority: undefined, // no inherit
},
},
teeterdance: {
@ -716,37 +612,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
uproar: {
inherit: true,
condition: {
onStart(target) {
this.add('-start', target, 'Uproar');
// 2-5 turns
this.effectState.duration = this.random(2, 6);
},
onResidual(target) {
if (target.volatiles['throatchop']) {
target.removeVolatile('uproar');
return;
}
if (target.lastMove && target.lastMove.id === 'struggle') {
// don't lock
delete target.volatiles['uproar'];
}
this.add('-start', target, 'Uproar', '[upkeep]');
},
onResidualOrder: 10,
onResidualSubOrder: 11,
onEnd(target) {
this.add('-end', target, 'Uproar');
},
onLockMove: 'uproar',
onAnySetStatus(status, pokemon) {
if (status.id === 'slp') {
if (pokemon === this.effectState.target) {
this.add('-fail', pokemon, 'slp', '[from] Uproar', '[msg]');
} else {
this.add('-fail', pokemon, 'slp', '[from] Uproar');
}
return null;
}
inherit: true,
durationCallback() {
return this.random(2, 6);
},
},
},
@ -756,11 +624,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
volttackle: {
inherit: true,
secondary: null,
secondary: undefined, // no inherit
},
waterfall: {
inherit: true,
secondary: null,
secondary: undefined, // no inherit
},
weatherball: {
inherit: true,

View File

@ -3,14 +3,17 @@ export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable
effectType: 'ValidatorRule',
name: 'Standard',
desc: "The standard ruleset for all official Smogon singles tiers (Ubers, OU, etc.)",
ruleset: ['Obtainable', 'Sleep Clause Mod', 'Switch Priority Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Items Clause', 'Evasion Moves Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod'],
ruleset: [
'Standard AG',
'Sleep Clause Mod', 'Switch Priority Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Items Clause', 'Evasion Moves Clause',
],
},
standarddraft: {
effectType: 'ValidatorRule',
name: 'Standard Draft',
desc: "The custom Draft League ruleset",
ruleset: [
'Obtainable', 'Nickname Clause', '+Unreleased', 'Sleep Clause Mod', 'OHKO Clause', 'Evasion Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod',
'Obtainable', 'Nickname Clause', 'Beat Up Nicknames Mod', '+Unreleased', 'Sleep Clause Mod', 'OHKO Clause', 'Evasion Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod',
'One Boost Passer Clause', 'Freeze Clause Mod', 'Accuracy Moves Clause', 'Baton Pass Trap Clause',
],
banlist: [

View File

@ -409,6 +409,7 @@ export const Scripts: ModdedBattleScriptsData = {
for (i = 0; i < hits && target.hp && pokemon.hp; i++) {
if (pokemon.status === 'slp' && !isSleepUsable) break;
move.hit = i + 1;
move.lastHit = move.hit === hits;
if (move.multiaccuracy && i > 0) {
accuracy = move.accuracy;

View File

@ -5,30 +5,20 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
perishsong: {
inherit: true,
onTryMove(attacker, defender, move) {
let immuneMon = false;
for (const mon of attacker.side.active) {
if (this.runEvent('Immunity', mon, attacker, move)) {
immuneMon = true;
}
if (attacker.side.pokemonLeft === 1) {
this.add('-fail', attacker, 'move: Perish Song');
this.hint("Self KO Clause: The last pokemon on a team cannot use moves that force fainting");
return false;
}
for (const mon of attacker.side.foe.active) {
if (this.runEvent('Immunity', mon, attacker, move)) {
immuneMon = true;
}
}
if (immuneMon) return;
if (this.format.gameType === 'singles') {
if (attacker.side.pokemonLeft === 1 && attacker.side.foe.pokemonLeft === 1) {
return false;
}
} else if (this.format.gameType === 'doubles') {
if (attacker.side.pokemonLeft === 2 && attacker.side.foe.pokemonLeft === 2) {
return false;
}
},
},
destinybond: {
inherit: true,
onTryMove(attacker, defender, move) {
if (attacker.side.pokemonLeft === 1) {
this.add('-fail', attacker, 'move: Perish Song');
this.hint("Self KO Clause: The last pokemon on a team cannot use moves that force fainting");
return false;
}
},
},

View File

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

View File

@ -0,0 +1,63 @@
function attemptStatuses(battle: Battle, target: Pokemon, source: Pokemon, move: ActiveMove, status: string) {
const attackerStatused = source.trySetStatus(status, target);
if (move.multihit && move.id !== 'triplekick' &&
(move.lastHit || (attackerStatused && status === 'slp')) &&
battle.randomChance(1, 100)) {
const defenderStatused = target.trySetStatus(status, target, move);
if (defenderStatused) {
battle.hint("In Pokemon Ruby, Sapphire, FireRed, LeafGreen, and Colosseum, if the final hit of a multihit move (except for Triple Kick) that makes contact triggers an ability that inflicts status, then there is a 1% chance that the defender is afflicted by the same status.");
}
}
}
export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTable = {
effectspore: {
inherit: true,
onDamagingHit(damage, target, source, move) {
if (damage && move.flags['contact'] && !source.status) {
const r = this.random(300);
let status = null;
if (r < 10) {
status = 'slp';
} else if (r < 20) {
status = 'par';
} else if (r < 30) {
status = 'psn';
}
if (status) {
attemptStatuses(this, target, source, move, status);
}
}
},
},
flamebody: {
inherit: true,
onDamagingHit(damage, target, source, move) {
if (damage && move.flags['contact']) {
if (this.randomChance(1, 3)) {
attemptStatuses(this, target, source, move, 'brn');
}
}
},
},
poisonpoint: {
inherit: true,
onDamagingHit(damage, target, source, move) {
if (damage && move.flags['contact']) {
if (this.randomChance(1, 3)) {
attemptStatuses(this, target, source, move, 'psn');
}
}
},
},
static: {
inherit: true,
onDamagingHit(damage, target, source, move) {
if (damage && move.flags['contact']) {
if (this.randomChance(1, 3)) {
attemptStatuses(this, target, source, move, 'par');
}
}
},
},
};

File diff suppressed because it is too large Load Diff

146
data/mods/gen3frlg/items.ts Normal file
View File

@ -0,0 +1,146 @@
export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
aguavberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
apicotberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
brightpowder: {
inherit: true,
isNonstandard: "Unobtainable",
},
choiceband: {
inherit: true,
isNonstandard: "Unobtainable",
},
clawfossil: {
inherit: true,
isNonstandard: "Unobtainable",
},
cornnberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
deepseascale: {
inherit: true,
isNonstandard: "Unobtainable",
},
deepseatooth: {
inherit: true,
isNonstandard: "Unobtainable",
},
diveball: {
inherit: true,
isNonstandard: "Unobtainable",
},
enigmaberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
figyberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
ganlonberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
grepaberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
hondewberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
kelpsyberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
lansatberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
liechiberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
lightball: {
inherit: true,
isNonstandard: "Unobtainable",
},
magoberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
magostberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
mentalherb: {
inherit: true,
isNonstandard: "Unobtainable",
},
nomelberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
petayaberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
pomegberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
premierball: {
inherit: true,
isNonstandard: "Unobtainable",
},
qualotberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
rabutaberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
rootfossil: {
inherit: true,
isNonstandard: "Unobtainable",
},
salacberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
scopelens: {
inherit: true,
isNonstandard: "Unobtainable",
},
shellbell: {
inherit: true,
isNonstandard: "Unobtainable",
},
souldew: {
inherit: true,
isNonstandard: "Unobtainable",
},
starfberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
tamatoberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
whiteherb: {
inherit: true,
isNonstandard: "Unobtainable",
},
wikiberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,40 @@
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
standard: {
effectType: 'ValidatorRule',
name: 'Standard',
desc: "The standard ruleset for all official Smogon singles tiers (Ubers, OU, etc.)",
ruleset: [
'Standard AG',
'Sleep Clause Mod', 'Switch Priority Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Items Clause', 'Evasion Moves Clause',
],
},
standarddraft: {
effectType: 'ValidatorRule',
name: 'Standard Draft',
desc: "The custom Draft League ruleset",
ruleset: [
'Obtainable', 'Nickname Clause', 'Beat Up Nicknames Mod', '+Unreleased', 'Sleep Clause Mod', 'OHKO Clause', 'Evasion Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod',
'One Boost Passer Clause', 'Freeze Clause Mod', 'Accuracy Moves Clause', 'Baton Pass Trap Clause',
],
banlist: [
'Uber', 'Smeargle + Ingrain', 'Swagger', 'Focus Band', 'King\'s Rock', 'Quick Claw', 'Baton Pass + Ancient Power', 'Baton Pass + Silver Wind',
],
// timer: {starting: 60 * 60, grace: 0, addPerTurn: 10, maxPerTurn: 100, timeoutAutoChoose: true},
},
obtainable: {
inherit: true,
onValidateSet(set) {
const species = this.dex.species.get(set.species);
if (['entei', 'raikou', 'suicune'].includes(species.id)) {
if (!set.ivs) set.ivs = { hp: 31, atk: 31, def: 31, spa: 31, spd: 31, spe: 31 };
for (const stat in set.ivs) {
if ((stat === 'atk' && set.ivs[stat] > 7) || (stat !== 'hp' && set.ivs[stat as 'def'] > 0)) {
return [
`${set.name} must have 7 or fewer Attack IVs and 0 IVs in all other stats except HP, due to the Roaming IVs glitch.`,
];
}
}
}
},
},
};

View File

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

View File

@ -0,0 +1,63 @@
function attemptStatuses(battle: Battle, target: Pokemon, source: Pokemon, move: ActiveMove, status: string) {
const attackerStatused = source.trySetStatus(status, target);
if (move.multihit && move.id !== 'triplekick' &&
(move.lastHit || (attackerStatused && status === 'slp')) &&
battle.randomChance(1, 100)) {
const defenderStatused = target.trySetStatus(status, target, move);
if (defenderStatused) {
battle.hint("In Pokemon Ruby, Sapphire, FireRed, LeafGreen, and Colosseum, if the final hit of a multihit move (except for Triple Kick) that makes contact triggers an ability that inflicts status, then there is a 1% chance that the defender is afflicted by the same status.");
}
}
}
export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTable = {
effectspore: {
inherit: true,
onDamagingHit(damage, target, source, move) {
if (damage && move.flags['contact'] && !source.status) {
const r = this.random(300);
let status = null;
if (r < 10) {
status = 'slp';
} else if (r < 20) {
status = 'par';
} else if (r < 30) {
status = 'psn';
}
if (status) {
attemptStatuses(this, target, source, move, status);
}
}
},
},
flamebody: {
inherit: true,
onDamagingHit(damage, target, source, move) {
if (damage && move.flags['contact']) {
if (this.randomChance(1, 3)) {
attemptStatuses(this, target, source, move, 'brn');
}
}
},
},
poisonpoint: {
inherit: true,
onDamagingHit(damage, target, source, move) {
if (damage && move.flags['contact']) {
if (this.randomChance(1, 3)) {
attemptStatuses(this, target, source, move, 'psn');
}
}
},
},
static: {
inherit: true,
onDamagingHit(damage, target, source, move) {
if (damage && move.flags['contact']) {
if (this.randomChance(1, 3)) {
attemptStatuses(this, target, source, move, 'par');
}
}
},
},
};

View File

@ -7,10 +7,6 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
inherit: true,
isNonstandard: "Unobtainable",
},
enigmaberry: {
inherit: true,
isNonstandard: "Unobtainable",
},
fastball: {
inherit: true,
isNonstandard: "Unobtainable",

View File

@ -4356,6 +4356,7 @@ export const Learnsets: import('../../../sim/dex-species').ModdedLearnsetDataTab
toxic: ["3M"],
uproar: ["3E"],
waterpulse: ["3M"],
wish: ["3E"],
},
},
delcatty: {
@ -4813,6 +4814,7 @@ export const Learnsets: import('../../../sim/dex-species').ModdedLearnsetDataTab
thunderbolt: ["3M"],
thunderwave: ["3L4"],
toxic: ["3M"],
wish: ["3E"],
},
},
minun: {
@ -4846,6 +4848,7 @@ export const Learnsets: import('../../../sim/dex-species').ModdedLearnsetDataTab
thunderbolt: ["3M"],
thunderwave: ["3L4"],
toxic: ["3M"],
wish: ["3E"],
},
},
volbeat: {
@ -5462,6 +5465,7 @@ export const Learnsets: import('../../../sim/dex-species').ModdedLearnsetDataTab
trick: ["3E"],
uproar: ["3L5"],
waterpulse: ["3M"],
wish: ["3E"],
},
},
trapinch: {

View File

@ -1,7 +1,7 @@
export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTable = {
airlock: {
inherit: true,
onSwitchIn() {},
onSwitchIn: undefined, // no inherit
onStart(pokemon) {
pokemon.abilityState.ending = false;
},
@ -23,6 +23,9 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
onResidualSubOrder: 10,
},
blaze: {
inherit: true,
onModifyAtk: undefined, // no inherit
onModifySpA: undefined, // no inherit
onBasePowerPriority: 2,
onBasePower(basePower, attacker, defender, move) {
if (move.type === 'Fire' && attacker.hp <= attacker.maxhp / 3) {
@ -30,13 +33,10 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
return this.chainModify(1.5);
}
},
name: "Blaze",
rating: 2,
num: 66,
},
cloudnine: {
inherit: true,
onSwitchIn() {},
onSwitchIn: undefined, // no inherit
onStart(pokemon) {
pokemon.abilityState.ending = false;
},
@ -51,14 +51,14 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
this.add('-start', target, 'typechange', type, '[from] ability: Color Change');
}
},
onAfterMoveSecondary() {},
onAfterMoveSecondary: undefined, // no inherit
},
compoundeyes: {
onSourceModifyAccuracyPriority: 9,
onSourceModifyAccuracy(accuracy) {
if (typeof accuracy !== 'number') return;
this.debug('compoundeyes - enhancing accuracy');
return accuracy * 1.3;
return this.chainModify(1.3);
},
inherit: true,
},
@ -92,15 +92,9 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
effectspore: {
inherit: true,
onDamagingHit(damage, target, source, move) {
if (damage && move.flags['contact'] && !source.status) {
const r = this.random(100);
if (r < 10) {
source.setStatus('slp', target);
} else if (r < 20) {
source.setStatus('par', target);
} else if (r < 30) {
source.setStatus('psn', target);
}
if (damage && move.flags['contact'] && this.randomChance(3, 10)) {
const status = this.sample(['slp', 'par', 'psn']);
source.trySetStatus(status, target);
}
},
},
@ -128,19 +122,15 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
}
},
condition: {
noCopy: true, // doesn't get copied by Baton Pass
onStart(target) {
this.add('-start', target, 'ability: Flash Fire');
},
inherit: true,
onModifyAtk: undefined, // no inherit
onModifySpA: undefined, // no inherit
onModifyDamagePhase1(atk, attacker, defender, move) {
if (move.type === 'Fire') {
this.debug('Flash Fire boost');
return this.chainModify(1.5);
}
},
onEnd(target) {
this.add('-end', target, 'ability: Flash Fire', '[silent]');
},
},
},
flowergift: {
@ -200,20 +190,19 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
onSourceModifyAccuracyPriority: 7,
onSourceModifyAccuracy(accuracy, target, source, move) {
if (move.category === 'Physical' && typeof accuracy === 'number') {
return accuracy * 0.8;
return this.chainModify(0.8);
}
},
},
hydration: {
inherit: true,
onResidual: undefined, // no inherit
onWeather(target, source, effect) {
if (effect.id === 'raindance' && target.status) {
this.add('-activate', target, 'ability: Hydration');
target.cureStatus();
}
},
name: "Hydration",
rating: 1.5,
num: 93,
},
insomnia: {
inherit: true,
@ -255,7 +244,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
},
lightningrod: {
inherit: true,
onTryHit() {},
onTryHit: undefined, // no inherit
rating: 0,
},
liquidooze: {
@ -270,35 +259,33 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
},
},
magicguard: {
onDamage(damage, target, source, effect) {
if (effect.effectType !== 'Move') {
return false;
}
},
inherit: true,
onSetStatus(status, target, source, effect) {
if (effect && effect.id === 'toxicspikes') {
return false;
}
},
name: "Magic Guard",
rating: 4.5,
num: 98,
},
minus: {
inherit: true,
onModifySpAPriority: undefined, // no inherit
onModifySpA(spa, pokemon) {
for (const ally of pokemon.allies()) {
if (ally.ability === 'plus') {
return spa * 1.5;
for (const allyActive of pokemon.allies()) {
if (allyActive.hasAbility('plus')) {
return this.chainModify(1.5);
}
}
},
name: "Minus",
rating: 0,
num: 58,
},
multitype: {
inherit: true,
onTakeItem: false,
onSetAbility: false, // redundant but hardcoded
},
naturalcure: {
inherit: true,
onCheckShow(pokemon) {},
onCheckShow: undefined, // no inherit
onSwitchOut(pokemon) {
if (!pokemon.status || pokemon.status === 'fnt') return;
@ -318,6 +305,9 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
},
},
overgrow: {
inherit: true,
onModifyAtk: undefined, // no inherit
onModifySpA: undefined, // no inherit
onBasePowerPriority: 2,
onBasePower(basePower, attacker, defender, move) {
if (move.type === 'Grass' && attacker.hp <= attacker.maxhp / 3) {
@ -325,26 +315,23 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
return this.chainModify(1.5);
}
},
name: "Overgrow",
rating: 2,
num: 65,
},
pickup: {
name: "Pickup",
inherit: true,
onResidual: undefined, // no inherit
rating: 0,
num: 53,
// No competitive use
},
plus: {
inherit: true,
onModifySpAPriority: undefined, // no inherit
onModifySpA(spa, pokemon) {
for (const ally of pokemon.allies()) {
if (ally.ability === 'minus') {
return spa * 1.5;
for (const allyActive of pokemon.allies()) {
if (allyActive.hasAbility('minus')) {
return this.chainModify(1.5);
}
}
},
name: "Plus",
rating: 0,
num: 57,
},
poisonpoint: {
inherit: true,
@ -357,16 +344,12 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
},
},
pressure: {
onStart(pokemon) {
this.add('-ability', pokemon, 'Pressure');
},
inherit: true,
onDeductPP(target, source) {
if (target === source) return;
return 1;
},
name: "Pressure",
rating: 1.5,
num: 46,
},
roughskin: {
inherit: true,
@ -383,7 +366,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
if (typeof accuracy !== 'number') return;
if (this.field.isWeather('sandstorm')) {
this.debug('Sand Veil - decreasing accuracy');
return accuracy * 0.8;
return this.chainModify(0.8);
}
},
},
@ -404,16 +387,14 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
onResidualSubOrder: 3,
},
simple: {
inherit: true,
onChangeBoost: undefined, // no inherit
onModifyBoost(boosts) {
let key: BoostID;
for (key in boosts) {
boosts[key]! *= 2;
}
},
flags: { breakable: 1 },
name: "Simple",
rating: 4,
num: 86,
},
snowcloak: {
inherit: true,
@ -422,7 +403,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
if (typeof accuracy !== 'number') return;
if (this.field.isWeather('hail')) {
this.debug('Snow Cloak - decreasing accuracy');
return accuracy * 0.8;
return this.chainModify(0.8);
}
},
},
@ -431,6 +412,13 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
onResidualOrder: 10,
onResidualSubOrder: 3,
},
stall: {
inherit: true,
onFractionalPriority(priority, pokemon) {
// don't override Lagging Tail and Full Incense's -0.2 fractional priority
if (priority >= 0) return -0.1;
},
},
static: {
inherit: true,
onDamagingHit(damage, target, source, move) {
@ -442,9 +430,10 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
},
},
stench: {
name: "Stench",
inherit: true,
onModifyMove: undefined, // no inherit
rating: 0,
num: 1,
// No competitive use
},
stickyhold: {
inherit: true,
@ -457,15 +446,18 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
},
stormdrain: {
inherit: true,
onTryHit() {},
onTryHit: undefined, // no inherit
rating: 0,
},
sturdy: {
inherit: true,
onDamage() {},
onDamage: undefined, // no inherit
rating: 0,
},
swarm: {
inherit: true,
onModifyAtk: undefined, // no inherit
onModifySpA: undefined, // no inherit
onBasePowerPriority: 2,
onBasePower(basePower, attacker, defender, move) {
if (move.type === 'Bug' && attacker.hp <= attacker.maxhp / 3) {
@ -473,9 +465,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
return this.chainModify(1.5);
}
},
name: "Swarm",
rating: 2,
num: 68,
},
synchronize: {
inherit: true,
@ -495,23 +484,25 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
if (typeof accuracy !== 'number') return;
if (target?.volatiles['confusion']) {
this.debug('Tangled Feet - decreasing accuracy');
return accuracy * 0.5;
return this.chainModify(0.5);
}
},
},
thickfat: {
inherit: true,
onSourceModifyAtk: undefined, // no inherit
onSourceModifySpA: undefined, // no inherit
onSourceBasePowerPriority: 1,
onSourceBasePower(basePower, attacker, defender, move) {
if (move.type === 'Ice' || move.type === 'Fire') {
return this.chainModify(0.5);
}
},
flags: { breakable: 1 },
name: "Thick Fat",
rating: 3.5,
num: 47,
},
torrent: {
inherit: true,
onModifyAtk: undefined, // no inherit
onModifySpA: undefined, // no inherit
onBasePowerPriority: 2,
onBasePower(basePower, attacker, defender, move) {
if (move.type === 'Water' && attacker.hp <= attacker.maxhp / 3) {
@ -519,9 +510,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
return this.chainModify(1.5);
}
},
name: "Torrent",
rating: 2,
num: 67,
},
trace: {
inherit: true,
@ -530,10 +518,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
const target = pokemon.side.randomFoe();
if (!target || target.fainted) return;
const ability = target.getAbility();
const bannedAbilities = ['forecast', 'multitype', 'trace'];
if (bannedAbilities.includes(target.ability)) {
return;
}
if (ability.flags['notrace']) return;
pokemon.setAbility(ability, target);
},
flags: { notrace: 1 },
@ -559,6 +544,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
},
rebound: {
inherit: true,
onTryHitSide() {},
onTryHitSide: undefined, // no inherit
},
};

View File

@ -118,7 +118,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
},
lockedmove: {
inherit: true,
onAfterMove() {},
onAfterMove: undefined, // no inherit
},
choicelock: {
inherit: true,

View File

@ -32,24 +32,24 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
choiceband: {
inherit: true,
onStart() {},
onModifyMove() {},
onStart: undefined, // no inherit
onModifyMove: undefined, // no inherit
onAfterMove(pokemon) {
pokemon.addVolatile('choicelock');
},
},
choicescarf: {
inherit: true,
onStart() {},
onModifyMove() {},
onStart: undefined, // no inherit
onModifyMove: undefined, // no inherit
onAfterMove(pokemon) {
pokemon.addVolatile('choicelock');
},
},
choicespecs: {
inherit: true,
onStart() {},
onModifyMove() {},
onStart: undefined, // no inherit
onModifyMove: undefined, // no inherit
onAfterMove(pokemon) {
pokemon.addVolatile('choicelock');
},
@ -72,7 +72,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
custapberry: {
inherit: true,
onFractionalPriority() {},
onFractionalPriority: undefined, // no inherit
onBeforeTurn(pokemon) {
if (pokemon.hp <= pokemon.maxhp / 4 || (pokemon.hp <= pokemon.maxhp / 2 && pokemon.ability === 'gluttony')) {
const action = this.queue.willMove(pokemon);
@ -144,7 +144,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
focussash: {
inherit: true,
onDamage() { },
onDamage: undefined, // no inherit
onTryHit(target, source, move) {
if (target !== source && target.hp === target.maxhp) {
target.addVolatile('focussash');
@ -164,6 +164,11 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
},
},
fullincense: {
inherit: true,
onFractionalPriorityPriority: 1,
onFractionalPriority: -0.2,
},
griseousorb: {
inherit: true,
onBasePower(basePower, user, target, move) {
@ -171,6 +176,8 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
return this.chainModify(1.2);
}
},
onTakeItem: false,
onSetAbility: false,
},
heavyball: {
inherit: true,
@ -186,7 +193,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
ironball: {
inherit: true,
onEffectiveness() {},
onEffectiveness: undefined, // no inherit
},
ironplate: {
inherit: true,
@ -207,6 +214,11 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
}
},
},
laggingtail: {
inherit: true,
onFractionalPriorityPriority: 1,
onFractionalPriority: -0.2,
},
laxincense: {
inherit: true,
onModifyAccuracyPriority: 5,
@ -227,8 +239,8 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
lifeorb: {
inherit: true,
onModifyDamage() {},
onAfterMoveSecondarySelf() {},
onModifyDamage: undefined, // no inherit
onAfterMoveSecondarySelf: undefined, // no inherit
onBasePower(basePower, user, target) {
if (!target.volatiles['substitute']) {
user.addVolatile('lifeorb');
@ -250,8 +262,8 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
lightball: {
inherit: true,
onModifyAtk() {},
onModifySpA() {},
onModifyAtk: undefined, // no inherit
onModifySpA: undefined, // no inherit
onBasePower(basePower, pokemon) {
if (pokemon.species.name === 'Pikachu') {
return this.chainModify(2);
@ -306,11 +318,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
metronome: {
inherit: true,
condition: {
onStart(pokemon) {
this.effectState.numConsecutive = 0;
this.effectState.lastMove = '';
},
onTryMovePriority: -2,
inherit: true,
onTryMove(pokemon, target, move) {
if (!pokemon.hasItem('metronome')) {
pokemon.removeVolatile('metronome');
@ -323,6 +331,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
}
this.effectState.lastMove = move.id;
},
onModifyDamage: undefined, // no inherit
onModifyDamagePhase2(damage, source, target, move) {
return damage * (1 + (this.effectState.numConsecutive / 10));
},
@ -331,7 +340,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
micleberry: {
inherit: true,
condition: {
duration: 2,
inherit: true,
onSourceModifyAccuracyPriority: 3,
onSourceModifyAccuracy(accuracy, target, source) {
this.add('-enditem', source, 'Micle Berry');

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,16 @@
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
standardag: {
inherit: true,
ruleset: [
'Obtainable', 'HP Percentage Mod', 'Cancel Mod', 'Beat Up Nicknames Mod', 'Endless Battle Clause',
],
},
standard: {
inherit: true,
ruleset: ['Obtainable', 'Sleep Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Items Clause', 'Evasion Moves Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod'],
ruleset: [
'Standard AG',
'Sleep Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Items Clause', 'Evasion Moves Clause',
],
},
flatrules: {
inherit: true,
@ -21,26 +30,4 @@ export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable
this.makeRequest('teampreview');
},
},
validatestats: {
inherit: true,
onValidateSet(set) {
const species = this.dex.species.get(set.species);
const item = this.dex.items.get(set.item);
if (item && item.id === 'griseousorb' && species.num !== 487) {
return ['Griseous Orb can only be held by Giratina in Generation 4.'];
}
if (species.num === 493 && set.evs) {
const isEventArceus = set.moves.includes('roaroftime') || set.moves.includes('shadowforce') ||
set.moves.includes('spacialrend');
if (isEventArceus) {
let stat: StatID;
for (stat in set.evs) {
if (set.evs[stat] > 100) {
return ["Event Arceus may not have more than 100 of any EVs in Generation 4."];
}
}
}
}
},
},
};

View File

@ -1,7 +1,18 @@
export const Scripts: ModdedBattleScriptsData = {
inherit: 'gen5',
gen: 4,
pokemon: {
inherit: true,
getActionSpeed() {
let speed = this.getStat('spe', false, false);
const trickRoomCheck = this.battle.ruleTable.has('twisteddimensionmod') ?
!this.battle.field.getPseudoWeather('trickroom') : this.battle.field.getPseudoWeather('trickroom');
if (trickRoomCheck) {
speed = -speed;
}
return speed;
},
},
actions: {
inherit: true,
runSwitch(pokemon) {
@ -12,6 +23,16 @@ export const Scripts: ModdedBattleScriptsData = {
if (this.battle.gen <= 2) {
// pokemon.lastMove is reset for all Pokemon on the field after a switch. This affects Mirror Move.
for (const poke of this.battle.getAllActive()) poke.lastMove = null;
if (this.battle.gen === 1) pokemon.side.lastSelectedMoveSlot = 0;
for (const poke of pokemon.foes()) {
if (poke.volatiles['partialtrappinglock'] && poke.moveSlots[poke.side.lastSelectedMoveSlot].id === 'metronome') {
// this is not done for Mirror Move, potentially resulting in a desync
poke.side.lastSelectedMove = 'metronome' as ID;
if (this.battle.queue.willMove(poke)) {
this.battle.queue.changeAction(poke, { choice: 'move', poke, moveid: 'metronome' });
}
}
}
if (!pokemon.side.faintedThisTurn && pokemon.draggedIn !== this.battle.turn) {
this.battle.runEvent('AfterSwitchInSelf', pokemon);
}
@ -55,10 +76,6 @@ export const Scripts: ModdedBattleScriptsData = {
// Weather
baseDamage = this.battle.runEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
if (this.battle.gen === 3 && move.category === 'Physical' && !Math.floor(baseDamage)) {
baseDamage = 1;
}
baseDamage += 2;
const isCrit = target.getMoveHitData(move).crit;

View File

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

View File

@ -31,7 +31,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
},
keeneye: {
inherit: true,
onModifyMove() {},
onModifyMove: undefined, // no inherit
},
magicbounce: {
inherit: true,
@ -68,13 +68,13 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
onImmunity(type, pokemon) {
if (type === 'sandstorm' || type === 'hail') return false;
},
onTryHit() {},
onTryHit: undefined, // no inherit
flags: {},
rating: 0.5,
},
sapsipper: {
inherit: true,
onAllyTryHitSide() {},
onAllyTryHitSide: undefined, // no inherit
},
serenegrace: {
inherit: true,
@ -89,7 +89,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
},
soundproof: {
inherit: true,
onAllyTryHitSide() {},
onAllyTryHitSide: undefined, // no inherit
},
rebound: {
inherit: true,

View File

@ -36,8 +36,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
autotomize: {
inherit: true,
volatileStatus: 'autotomize',
onHit(pokemon) {
},
onHit: undefined, // no inherit
condition: {
noCopy: true, // doesn't get copied by Baton Pass
onStart(pokemon) {
@ -78,6 +77,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
flags: { protect: 1, reflectable: 1, mirror: 1, metronome: 1 },
},
bodyslam: {
inherit: true,
flags: { contact: 1, protect: 1, mirror: 1, nonsky: 1, metronome: 1 },
},
bounce: {
inherit: true,
flags: { contact: 1, charge: 1, protect: 1, mirror: 1, gravity: 1, distance: 1, metronome: 1, nosleeptalk: 1 },
@ -149,7 +152,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
cottonspore: {
inherit: true,
onTryHit() {},
onTryHit: undefined, // no inherit
target: "normal",
},
covet: {
@ -192,6 +195,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
flags: { contact: 1, protect: 1, mirror: 1, punch: 1, metronome: 1 },
},
dragonrush: {
inherit: true,
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
},
dreameater: {
inherit: true,
flags: { protect: 1, mirror: 1, metronome: 1 },
@ -260,10 +267,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
basePower: 20,
condition: {
duration: 2,
onStart() {
this.effectState.multiplier = 1;
},
inherit: true,
onRestart() {
if (this.effectState.multiplier < 8) {
this.effectState.multiplier <<= 1;
@ -363,6 +367,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
return success;
},
},
heatcrash: {
inherit: true,
flags: { contact: 1, protect: 1, mirror: 1, nonsky: 1, metronome: 1 },
},
heatwave: {
inherit: true,
basePower: 100,
@ -477,7 +485,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
knockoff: {
inherit: true,
basePower: 20,
onBasePower() {},
onBasePower: undefined, // no inherit
},
leafstorm: {
inherit: true,
@ -494,13 +502,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
lightscreen: {
inherit: true,
condition: {
duration: 5,
durationCallback(target, source, effect) {
if (source?.hasItem('lightclay')) {
return 8;
}
return 5;
},
inherit: true,
onAnyModifyDamage(damage, source, target, move) {
if (target !== source && this.effectState.target.hasAlly(target) && this.getCategory(move) === 'Special') {
if (!target.getMoveHitData(move).crit && !move.infiltrates) {
@ -510,14 +512,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
}
},
onSideStart(side) {
this.add('-sidestart', side, 'move: Light Screen');
},
onSideResidualOrder: 26,
onSideResidualSubOrder: 2,
onSideEnd(side) {
this.add('-sideend', side, 'move: Light Screen');
},
},
},
lowsweep: {
@ -527,24 +521,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
magiccoat: {
inherit: true,
condition: {
duration: 1,
onStart(target, source, effect) {
this.add('-singleturn', target, 'move: Magic Coat');
if (effect?.effectType === 'Move') {
this.effectState.pranksterBoosted = effect.pranksterBoosted;
}
},
onTryHitPriority: 2,
onTryHit(target, source, move) {
if (target === source || move.hasBounced || !move.flags['reflectable'] || target.isSemiInvulnerable()) {
return;
}
const newMove = this.dex.getActiveMove(move.id);
newMove.hasBounced = true;
newMove.pranksterBoosted = this.effectState.pranksterBoosted;
this.actions.useMove(newMove, target, { target: source });
return null;
},
inherit: true,
onAllyTryHitSide(target, source, move) {
if (target.isAlly(source) || move.hasBounced || !move.flags['reflectable']) {
return;
@ -587,12 +564,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
pp: 20,
condition: {
noCopy: true,
onSourceModifyDamage(damage, source, target, move) {
if (['stomp', 'steamroller'].includes(move.id)) {
return this.chainModify(2);
}
},
inherit: true,
onAccuracy: undefined, // no inherit
},
},
moonlight: {
@ -605,7 +578,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
mudsport: {
inherit: true,
pseudoWeather: undefined,
pseudoWeather: undefined, // no inherit
volatileStatus: 'mudsport',
condition: {
noCopy: true,
@ -623,7 +596,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
naturepower: {
inherit: true,
onTryHit() {},
onTryHit: undefined, // no inherit
onHit(pokemon) {
this.actions.useMove('earthquake', pokemon);
},
@ -655,7 +628,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
poisonpowder: {
inherit: true,
onTryHit() {},
onTryHit: undefined, // no inherit
},
powergem: {
inherit: true,
@ -689,17 +662,14 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
source.addVolatile('stall');
},
condition: {
duration: 1,
onSideStart(target, source) {
this.add('-singleturn', source, 'Quick Guard');
},
onTryHitPriority: 4,
onTryHit(target, source, effect) {
inherit: true,
onTryHit(target, source, move) {
// Quick Guard only blocks moves with a natural positive priority
// (e.g. it doesn't block 0 priority moves boosted by Prankster)
if (effect && (effect.id === 'feint' || this.dex.moves.get(effect.id).priority <= 0)) {
if (move.id === 'feint' || this.dex.moves.get(move.id).priority <= 0) {
return;
}
if (this.checkMoveBypassesProtect(move, source, target)) return;
this.add('-activate', target, 'Quick Guard');
const lockedmove = source.getVolatile('lockedmove');
if (lockedmove) {
@ -716,17 +686,24 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
priority: 3,
flags: { noassist: 1, failcopycat: 1 },
condition: {
inherit: true,
onFoeRedirectTarget(target, source, source2, move) {
const ragePowderUser = this.effectState.target;
if (ragePowderUser.isSkyDropped()) return;
if (this.validTarget(ragePowderUser, source, move.target)) {
if (move.smartTarget) move.smartTarget = false;
this.debug("Rage Powder redirected target of move");
return ragePowderUser;
}
},
},
},
reflect: {
inherit: true,
condition: {
duration: 5,
durationCallback(target, source, effect) {
if (source?.hasItem('lightclay')) {
return 8;
}
return 5;
},
inherit: true,
onAnyModifyDamage(damage, source, target, move) {
if (target !== source && this.effectState.target.hasAlly(target) && this.getCategory(move) === 'Physical') {
if (!target.getMoveHitData(move).crit && !move.infiltrates) {
@ -736,14 +713,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
}
}
},
onSideStart(side) {
this.add('-sidestart', side, 'Reflect');
},
onSideResidualOrder: 26,
onSideResidualSubOrder: 1,
onSideEnd(side) {
this.add('-sideend', side, 'Reflect');
},
},
},
relicsong: {
@ -794,19 +763,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
flags: { protect: 1, reflectable: 1, mirror: 1, sound: 1, metronome: 1 },
},
skillswap: {
inherit: true,
onHit(target, source) {
const targetAbility = target.ability;
const sourceAbility = source.ability;
if (targetAbility === sourceAbility) {
return false;
}
this.add('-activate', source, 'move: Skill Swap', this.dex.abilities.get(targetAbility), this.dex.abilities.get(sourceAbility), `[of] ${target}`);
source.setAbility(targetAbility);
target.setAbility(sourceAbility);
},
},
skullbash: {
inherit: true,
basePower: 100,
@ -838,7 +794,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
sleeppowder: {
inherit: true,
onTryHit() {},
onTryHit: undefined, // no inherit
},
smellingsalts: {
inherit: true,
@ -871,7 +827,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
spore: {
inherit: true,
onTryHit() {},
onTryHit: undefined, // no inherit
},
stormthrow: {
inherit: true,
@ -889,17 +845,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
stunspore: {
inherit: true,
onTryHit() {},
onTryHit: undefined, // no inherit
},
substitute: {
inherit: true,
condition: {
onStart(target) {
this.add('-start', target, 'Substitute');
this.effectState.hp = Math.floor(target.maxhp / 4);
delete target.volatiles['partiallytrapped'];
},
onTryPrimaryHitPriority: -1,
inherit: true,
onTryPrimaryHit(target, source, move) {
if (target === source || move.flags['bypasssub']) {
return;
@ -931,9 +882,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
this.runEvent('AfterSubDamage', target, source, move, damage);
return this.HIT_SUBSTITUTE;
},
onEnd(target) {
this.add('-end', target, 'Substitute');
},
},
},
submission: {
@ -990,7 +938,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
toxic: {
inherit: true,
onPrepareHit() {},
onPrepareHit: undefined, // no inherit
},
uproar: {
inherit: true,
@ -1018,7 +966,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
watersport: {
inherit: true,
pseudoWeather: undefined,
pseudoWeather: undefined, // no inherit
volatileStatus: 'watersport',
condition: {
noCopy: true,

View File

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

View File

@ -1,117 +0,0 @@
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;
}
},
},
};

View File

@ -1,17 +0,0 @@
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);
}
}
},
},
},
};

View File

@ -1,215 +0,0 @@
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;
},
},
};

View File

@ -54,7 +54,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
move.type = 'Normal';
}
},
onBasePower() {},
onBasePower: undefined, // no inherit
rating: -1,
},
parentalbond: {
@ -93,7 +93,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
const targetForme = (move.id === 'kingsshield' ? 'Aegislash' : 'Aegislash-Blade');
if (attacker.species.name !== targetForme) attacker.formeChange(targetForme);
},
onModifyMove() {},
onModifyMove: undefined, // no inherit
},
symbiosis: {
inherit: true,

View File

@ -40,6 +40,6 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
},
choicelock: {
inherit: true,
onBeforeMove() {},
onBeforeMove: undefined, // no inherit
},
};

View File

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

View File

@ -165,7 +165,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
},
souldew: {
inherit: true,
onBasePower() {},
onBasePower: undefined, // no inherit
onModifySpAPriority: 1,
onModifySpA(spa, pokemon) {
if (pokemon.baseSpecies.num === 380 || pokemon.baseSpecies.num === 381) {

View File

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

View File

@ -34,7 +34,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
innerfocus: {
inherit: true,
rating: 1,
onTryBoost() {},
onTryBoost: undefined, // no inherit
},
moody: {
inherit: true,
@ -65,25 +65,19 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
},
oblivious: {
inherit: true,
onTryBoost() {},
onTryBoost: undefined, // no inherit
},
owntempo: {
inherit: true,
onTryBoost() {},
onTryBoost: undefined, // no inherit
},
rattled: {
onDamagingHit(damage, target, source, move) {
if (['Dark', 'Bug', 'Ghost'].includes(move.type)) {
this.boost({ spe: 1 });
}
},
name: "Rattled",
rating: 1.5,
num: 155,
inherit: true,
onAfterBoost: undefined, // no inherit
},
scrappy: {
inherit: true,
onTryBoost() {},
onTryBoost: undefined, // no inherit
},
slowstart: {
inherit: true,

View File

@ -592,7 +592,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
doublesTier: "NFE",
},
tangrowth: {
tier: "OU",
tier: "(OU)",
doublesTier: "(DUU)",
},
kangaskhan: {

View File

@ -182,47 +182,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
electricterrain: {
inherit: true,
condition: {
effectType: 'Terrain',
duration: 5,
durationCallback(source, effect) {
if (source?.hasItem('terrainextender')) {
return 8;
}
return 5;
},
onSetStatus(status, target, source, effect) {
if (status.id === 'slp' && target.isGrounded() && !target.isSemiInvulnerable()) {
if (effect.id === 'yawn' || (effect.effectType === 'Move' && !effect.secondaries)) {
this.add('-activate', target, 'move: Electric Terrain');
}
return false;
}
},
onTryAddVolatile(status, target) {
if (!target.isGrounded() || target.isSemiInvulnerable()) return;
if (status.id === 'yawn') {
this.add('-activate', target, 'move: Electric Terrain');
return null;
}
},
inherit: true,
onBasePower(basePower, attacker, defender, move) {
if (move.type === 'Electric' && attacker.isGrounded() && !attacker.isSemiInvulnerable()) {
this.debug('electric terrain boost');
return this.chainModify(1.5);
}
},
onFieldStart(field, source, effect) {
if (effect && effect.effectType === 'Ability') {
this.add('-fieldstart', 'move: Electric Terrain', `[from] ability: ${effect}`, `[of] ${source}`);
} else {
this.add('-fieldstart', 'move: Electric Terrain');
}
},
onFieldResidualOrder: 27,
onFieldResidualSubOrder: 7,
onFieldEnd() {
this.add('-fieldend', 'move: Electric Terrain');
},
},
},
embargo: {
@ -307,7 +273,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
grassknot: {
inherit: true,
onTryHit() {},
onTryHit: undefined, // no inherit
},
grasswhistle: {
inherit: true,
@ -316,14 +282,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
grassyterrain: {
inherit: true,
condition: {
effectType: 'Terrain',
duration: 5,
durationCallback(source, effect) {
if (source?.hasItem('terrainextender')) {
return 8;
}
return 5;
},
inherit: true,
onBasePower(basePower, attacker, defender, move) {
const weakenedMoves = ['earthquake', 'bulldoze', 'magnitude'];
if (weakenedMoves.includes(move.id) && defender.isGrounded() && !defender.isSemiInvulnerable()) {
@ -335,27 +294,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
return this.chainModify(1.5);
}
},
onFieldStart(field, source, effect) {
if (effect && effect.effectType === 'Ability') {
this.add('-fieldstart', 'move: Grassy Terrain', `[from] ability: ${effect}`, `[of] ${source}`);
} else {
this.add('-fieldstart', 'move: Grassy Terrain');
}
},
onResidualOrder: 5,
onResidualSubOrder: 2,
onResidual(pokemon) {
if (pokemon.isGrounded() && !pokemon.isSemiInvulnerable()) {
this.heal(pokemon.baseMaxhp / 16, pokemon, pokemon);
} else {
this.debug(`Pokemon semi-invuln or not grounded; Grassy Terrain skipped`);
}
},
onFieldResidualOrder: 27,
onFieldResidualSubOrder: 7,
onFieldEnd() {
this.add('-fieldend', 'move: Grassy Terrain');
},
},
},
guardianofalola: {
@ -429,11 +367,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
heatcrash: {
inherit: true,
onTryHit() {},
onTryHit: undefined, // no inherit
},
heavyslam: {
inherit: true,
onTryHit() {},
onTryHit: undefined, // no inherit
},
hiddenpower: {
inherit: true,
@ -558,16 +496,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
kingsshield: {
inherit: true,
condition: {
duration: 1,
onStart(target) {
this.add('-singleturn', target, 'Protect');
},
onTryHitPriority: 3,
inherit: true,
onTryHit(target, source, move) {
if (!move.flags['protect'] || move.category === 'Status') {
if (move.isZ || move.isMax) target.getMoveHitData(move).zBrokeProtect = true;
return;
}
if (this.checkMoveBypassesProtect(move, source, target, false)) return;
this.add('-activate', target, 'move: Protect');
const lockedmove = source.getVolatile('lockedmove');
if (lockedmove) {
@ -602,7 +533,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
},
lowkick: {
inherit: true,
onTryHit() {},
onTryHit: undefined, // no inherit
},
luckychant: {
inherit: true,
@ -780,48 +711,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
psychicterrain: {
inherit: true,
condition: {
effectType: 'Terrain',
duration: 5,
durationCallback(source, effect) {
if (source?.hasItem('terrainextender')) {
return 8;
}
return 5;
},
onTryHitPriority: 4,
onTryHit(target, source, effect) {
if (effect && (effect.priority <= 0.1 || effect.target === 'self')) {
return;
}
if (target.isSemiInvulnerable() || target.isAlly(source)) return;
if (!target.isGrounded()) {
const baseMove = this.dex.moves.get(effect.id);
if (baseMove.priority > 0) {
this.hint("Psychic Terrain doesn't affect Pokémon immune to Ground.");
}
return;
}
this.add('-activate', target, 'move: Psychic Terrain');
return null;
},
inherit: true,
onBasePower(basePower, attacker, defender, move) {
if (move.type === 'Psychic' && attacker.isGrounded() && !attacker.isSemiInvulnerable()) {
this.debug('psychic terrain boost');
return this.chainModify(1.5);
}
},
onFieldStart(field, source, effect) {
if (effect && effect.effectType === 'Ability') {
this.add('-fieldstart', 'move: Psychic Terrain', `[from] ability: ${effect}`, `[of] ${source}`);
} else {
this.add('-fieldstart', 'move: Psychic Terrain');
}
},
onFieldResidualOrder: 27,
onFieldResidualSubOrder: 7,
onFieldEnd() {
this.add('-fieldend', 'move: Psychic Terrain');
},
},
},
psychoboost: {
@ -876,7 +772,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
rapidspin: {
inherit: true,
basePower: 20,
secondary: null,
secondary: undefined, // no inherit
},
razorwind: {
inherit: true,
@ -1182,6 +1078,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
basePower: 50,
pp: 15,
willCrit: true,
secondary: null,
secondary: undefined, // no inherit
},
};

View File

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

View File

@ -19,6 +19,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
doubleironbash: {
inherit: true,
isNonstandard: null,
flags: { contact: 1, protect: 1, mirror: 1, punch: 1, minimize: 1 },
},
floatyfall: {
inherit: true,
@ -41,8 +42,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
inherit: true,
desc: "A random move that was introduced in gen 1 is selected for use, other than Counter, Mimic, Mirror Move, Struggle, or Transform.",
shortDesc: "Picks a random move from gen 1.",
onHit(target, source, effect) {
const moves = this.dex.moves.all().filter(move => move.gen === 1 && move.flags['metronome']);
onHit(target) {
const moves = this.dex.moves.all().filter(move => (
(!move.isNonstandard || move.isNonstandard === 'Unobtainable') &&
move.flags['metronome'] && move.gen === 1
));
let randomMove = '';
if (moves.length) {
moves.sort((a, b) => a.num - b.num);

View File

@ -1,10 +1,16 @@
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
standard: {
inherit: true,
ruleset: ['LGPE Normal Rules', 'Obtainable', 'Team Preview', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'HP Percentage Mod', 'Cancel Mod', 'Sleep Clause Mod'],
ruleset: [
'Standard AG',
'LGPE Normal Rules', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'Sleep Clause Mod',
],
},
standarddoubles: {
inherit: true,
ruleset: ['LGPE Normal Rules', 'Obtainable', 'Team Preview', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'HP Percentage Mod', 'Cancel Mod'],
ruleset: [
'Standard AG',
'LGPE Normal Rules', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause',
],
},
};

View File

@ -1,117 +0,0 @@
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;
}
},
},
};

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