mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-03-21 17:25:10 -05:00
Update rotational ladders (#11785)
* Update Kalos starter Mega abilities * Update rotational ladders
This commit is contained in:
parent
8a0685b03f
commit
be25932aff
|
|
@ -358,6 +358,21 @@ export const Formats: import('../sim/dex-formats').FormatList = [
|
|||
'Sneasel-Hisui', 'Ursaring', 'Vigoroth', 'Vulpix-Base', 'Arena Trap', 'Magnet Pull', 'Moody', 'Shadow Tag', 'Baton Pass',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "[Gen 9] Ubers UU",
|
||||
mod: 'gen9',
|
||||
searchShow: false,
|
||||
ruleset: ['[Gen 9] Ubers'],
|
||||
banlist: [
|
||||
// Ubers OU
|
||||
'Arceus-Normal', 'Arceus-Fairy', 'Arceus-Ghost', 'Arceus-Ground', 'Arceus-Water', 'Calyrex-Ice', 'Chien-Pao', 'Deoxys-Attack', 'Deoxys-Speed', 'Ditto',
|
||||
'Dondozo', 'Eternatus', 'Flutter Mane', 'Giratina-Origin', 'Glimmora', 'Gliscor', 'Grimmsnarl', 'Groudon', 'Hatterene', 'Ho-Oh', 'Kingambit', 'Koraidon',
|
||||
'Kyogre', 'Kyurem-Black', 'Landorus-Therian', 'Lunala', 'Necrozma-Dusk-Mane', 'Rayquaza', 'Ribombee', 'Skeledirge', 'Terapagos', 'Ting-Lu', 'Zacian-Crowned',
|
||||
// Ubers UUBL + Lunala, Arceus-Ghost, Arceus-Water
|
||||
'Arceus-Dragon', 'Arceus-Electric', 'Arceus-Fire', 'Arceus-Flying', 'Arceus-Steel', 'Giratina', 'Necrozma-Dawn-Wings', 'Shaymin-Sky', 'Spectrier', 'Zacian',
|
||||
'Zekrom',
|
||||
],
|
||||
},
|
||||
|
||||
// Draft League
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
|
@ -481,199 +496,135 @@ export const Formats: import('../sim/dex-formats').FormatList = [
|
|||
ruleset: ['Flat Rules', 'VGC Timer', 'Best of = 3'],
|
||||
},
|
||||
{
|
||||
name: "[Gen 9] Flipped",
|
||||
desc: `All Pokémon have their base stats flipped. For example, Sylveon's HP and Speed stats, Attack and Special Defense stats, and Defense and Special Attack stats swap.`,
|
||||
mod: 'gen9',
|
||||
ruleset: ['Standard OMs', 'Sleep Moves Clause', 'Evasion Abilities Clause', 'Evasion Items Clause', 'Flipped Mod'],
|
||||
banlist: [
|
||||
'Annihilape', 'Araquanid', 'Arceus', 'Azumarill', 'Blissey', 'Calyrex-Ice', 'Calyrex-Shadow', 'Cloyster', 'Cyclizar', 'Deoxys-Attack', 'Deoxys-Normal',
|
||||
'Deoxys-Speed', 'Dialga', 'Dialga-Origin', 'Espathra', 'Eternatus', 'Giratina', 'Giratina-Origin', 'Groudon', 'Ho-Oh', 'Hoopa-Unbound', 'Koraidon', 'Kyogre',
|
||||
'Kyurem-Black', 'Kyurem-White', 'Lugia', 'Lunala', 'Magearna', 'Mewtwo', 'Miraidon', 'Mienshao', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia',
|
||||
'Palkia-Origin', 'Rayquaza', 'Regieleki', 'Reshiram', 'Shaymin-Sky', 'Snorlax', 'Solgaleo', 'Sylveon', 'Terapagos', 'Torkoal', 'Tornadus-Therian', 'Zacian',
|
||||
'Zacian-Crowned', 'Zamazenta-Crowned', 'Zekrom', 'Arena Trap', 'Moody', 'Shadow Tag', 'Damp Rock', 'King\'s Rock', 'Light Clay', 'Razor Fang', 'Baton Pass',
|
||||
'Last Respects', 'Shed Tail',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "[Gen 9] The Loser's Game",
|
||||
desc: `The first player to lose all of their Pokémon wins.`,
|
||||
mod: 'gen9',
|
||||
name: "[Gen 9] Linked",
|
||||
desc: `The first two moves in a Pokémon's moveset are used simultaneously.`,
|
||||
mod: 'linked',
|
||||
// searchShow: false,
|
||||
ruleset: ['Standard OMs', 'Sleep Clause Mod', '!OHKO Clause', 'Picked Team Size = 6', 'Adjust Level = 100'],
|
||||
banlist: ['Infiltrator', 'Choice Scarf', 'Explosion', 'Final Gambit', 'Healing Wish', 'Lunar Dance', 'Magic Room', 'Memento', 'Misty Explosion', 'Self-Destruct'],
|
||||
onValidateTeam(team) {
|
||||
const familyTable = new Set<ID>();
|
||||
for (const set of team) {
|
||||
let species = this.dex.species.get(set.species);
|
||||
while (species.prevo) {
|
||||
species = this.dex.species.get(species.prevo);
|
||||
}
|
||||
if (familyTable.has(species.id)) {
|
||||
return [
|
||||
`You are limited to one Pokémon from each family by the Family Clause.`,
|
||||
`(You have more than one evolution of ${species.name}.)`,
|
||||
];
|
||||
}
|
||||
familyTable.add(species.id);
|
||||
}
|
||||
},
|
||||
battle: {
|
||||
tiebreak() {
|
||||
if (this.ended) return false;
|
||||
|
||||
this.inputLog.push(`>tiebreak`);
|
||||
this.add('message', "Time's up! Going to tiebreaker...");
|
||||
const notFainted = this.sides.map(side => (
|
||||
side.pokemon.filter(pokemon => !pokemon.fainted).length
|
||||
));
|
||||
this.add('-message', this.sides.map((side, i) => (
|
||||
`${side.name}: ${notFainted[i]} Pokemon left`
|
||||
)).join('; '));
|
||||
const maxNotFainted = Math.max(...notFainted);
|
||||
let tiedSides = this.sides.filter((side, i) => notFainted[i] === maxNotFainted);
|
||||
if (tiedSides.length <= 1) {
|
||||
return this.win(tiedSides[1]);
|
||||
}
|
||||
|
||||
const hpPercentage = tiedSides.map(side => (
|
||||
side.pokemon.map(pokemon => pokemon.hp / pokemon.maxhp).reduce((a, b) => a + b) * 100 / 6
|
||||
));
|
||||
this.add('-message', tiedSides.map((side, i) => (
|
||||
`${side.name}: ${Math.round(hpPercentage[i])}% total HP left`
|
||||
)).join('; '));
|
||||
const maxPercentage = Math.max(...hpPercentage);
|
||||
tiedSides = tiedSides.filter((side, i) => hpPercentage[i] === maxPercentage);
|
||||
if (tiedSides.length <= 1) {
|
||||
return this.win(tiedSides[1]);
|
||||
}
|
||||
|
||||
const hpTotal = tiedSides.map(side => (
|
||||
side.pokemon.map(pokemon => pokemon.hp).reduce((a, b) => a + b)
|
||||
));
|
||||
this.add('-message', tiedSides.map((side, i) => (
|
||||
`${side.name}: ${Math.round(hpTotal[i])} total HP left`
|
||||
)).join('; '));
|
||||
const maxTotal = Math.max(...hpTotal);
|
||||
tiedSides = tiedSides.filter((side, i) => hpTotal[i] === maxTotal);
|
||||
if (tiedSides.length <= 1) {
|
||||
return this.win(tiedSides[1]);
|
||||
}
|
||||
return this.tie();
|
||||
},
|
||||
checkWin(faintData) {
|
||||
const team1PokemonLeft = this.sides[0].pokemonLeft;
|
||||
const team2PokemonLeft = this.sides[1].pokemonLeft;
|
||||
if (!team1PokemonLeft && !team2PokemonLeft) {
|
||||
this.win(faintData?.target.side || null);
|
||||
return true;
|
||||
}
|
||||
for (const side of this.sides) {
|
||||
if (!side.pokemonLeft) {
|
||||
this.win(side);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "[Gen 9] STABmons Mix and Mega",
|
||||
desc: `Mega evolve any Pokémon with any mega stone, or transform them with Genesect Drives, Primal orbs, Origin orbs, Rusted items, Ogerpon Masks, Arceus Plates, and Silvally Memories with no limit. Pokémon can use any move of their typing, in addition to the moves they can normally learn. Mega and Primal boosts based on form changes from gen 7.`,
|
||||
mod: 'mixandmega',
|
||||
ruleset: ['Standard OMs', 'STABmons Move Legality', 'Evasion Items Clause', 'Evasion Abilities Clause', 'Sleep Moves Clause', 'Terastal Clause'],
|
||||
ruleset: ['Standard OMs', 'Sleep Moves Clause', 'Evasion Clause', 'Terastal Clause'],
|
||||
banlist: [
|
||||
'Arceus', 'Calyrex-Shadow', 'Enamorus-Incarnate', 'Koraidon', 'Kyogre', 'Miraidon', 'Komala', 'Moody', 'Shadow Tag',
|
||||
'Beedrillite', 'Blazikenite', 'Gengarite', 'Kangaskhanite', 'Lucarionite Z', 'Malamarite', 'Mawilite', 'Medichamite', 'Pidgeotite', 'Red Orb', 'Zygardite',
|
||||
'King\'s Rock', 'Razor Fang', 'Baton Pass', 'Shed Tail',
|
||||
'Annihilape', 'Arceus', 'Archaludon', 'Baxcalibur', 'Calyrex-Ice', 'Calyrex-Shadow', 'Chien-Pao', 'Deoxys-Attack', 'Deoxys-Normal', 'Dialga', 'Dialga-Origin', 'Eternatus',
|
||||
'Flutter Mane', 'Giratina', 'Giratina-Origin', 'Gouging Fire', 'Groudon', 'Ho-Oh', 'Iron Bundle', 'Koraidon', 'Kyogre', 'Kyurem-Black', 'Kyurem-White', 'Landorus-Incarnate',
|
||||
'Lugia', 'Lunala', 'Magearna', 'Mewtwo', 'Miraidon', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Ogerpon-Hearthflame', 'Palafin', 'Palkia', 'Palkia-Origin', 'Raichu-Alola',
|
||||
'Rayquaza', 'Reshiram', 'Roaring Moon', 'Shaymin-Sky', 'Sneasler', 'Solgaleo', 'Spectrier', 'Ursaluna-Bloodmoon', 'Urshifu-Single-Strike', 'Urshifu-Rapid-Strike', 'Volcarona',
|
||||
'Zacian', 'Zacian-Crowned', 'Zamazenta-Crowned', 'Zekrom', 'Arena Trap', 'Chlorophyll', 'Moody', 'Sand Rush', 'Shadow Tag', 'Slush Rush', 'Speed Boost', 'Swift Swim', 'Unburden',
|
||||
'King\'s Rock', 'Razor Fang', 'Baton Pass', 'Last Respects', 'Shed Tail',
|
||||
],
|
||||
restricted: [
|
||||
'Basculegion-M', 'Calyrex-Ice', 'Deoxys-Normal', 'Deoxys-Attack', 'Dialga', 'Dragapult', 'Eternatus', 'Flutter Mane', 'Gengar', 'Giratina', 'Gouging Fire',
|
||||
'Groudon', 'Ho-Oh', 'Iron Bundle', 'Kyurem-Black', 'Kyurem-White', 'Lugia', 'Lunala', 'Manaphy', 'Meloetta', 'Mewtwo', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane',
|
||||
'Palkia', 'Rayquaza', 'Regigigas', 'Reshiram', 'Slaking', 'Sneasler', 'Solgaleo', 'Ursaluna', 'Ursaluna-Bloodmoon', 'Urshifu-Single-Strike', 'Walking Wake',
|
||||
'Zacian', 'Zekrom', 'Zoroark-Hisui', 'Acupressure', 'Astral Barrage', 'Belly Drum', 'Blood Moon', 'Boomburst', 'Ceaseless Edge', 'Clangorous Soul', 'Dire Claw',
|
||||
'Dragon Energy', 'Electro Shot', 'Extreme Speed', 'Fillet Away', 'Gigaton Hammer', 'Jet Punch', 'Last Respects', 'Lumina Crash', 'No Retreat', 'Power Trip',
|
||||
'Rage Fist', 'Revival Blessing', 'Shell Smash', 'Shift Gear', 'Surging Strikes', 'Torch Song', 'Triple Arrows', 'V-create', 'Victory Dance', 'Wicked Blow',
|
||||
'Baneful Bunker', 'Bounce', 'Burning Bulwark', 'Detect', 'Dig', 'Dive', 'Fly', 'Imprison', 'Phantom Force', 'Protect',
|
||||
'Ruination', 'Shadow Force', 'Silk Trap', 'Spiky Shield', 'Super Fang', 'Taunt', 'Trick Room',
|
||||
],
|
||||
onValidateTeam(team) {
|
||||
const itemTable = new Set<ID>();
|
||||
for (const set of team) {
|
||||
const item = this.dex.items.get(set.item);
|
||||
if (!(item.forcedForme && !item.zMove) && !item.megaStone &&
|
||||
!item.isPrimalOrb && !item.name.startsWith('Rusted')) continue;
|
||||
const natdex = this.ruleTable.has('natdexmod');
|
||||
if (natdex && item.id !== 'ultranecroziumz') continue;
|
||||
const species = this.dex.species.get(set.species);
|
||||
if (species.isNonstandard && !this.ruleTable.has(`+pokemontag:${this.toID(species.isNonstandard)}`)) {
|
||||
return [`${species.baseSpecies} does not exist in gen 9.`];
|
||||
onValidateSet(set) {
|
||||
const problems = [];
|
||||
for (const [i, moveid] of set.moves.entries()) {
|
||||
const move = this.dex.moves.get(moveid);
|
||||
if ([0, 1].includes(i) && this.ruleTable.isRestricted(`move:${move.id}`)) {
|
||||
problems.push(`${set.name || set.species}'s move ${move.name} cannot be linked.`);
|
||||
}
|
||||
if (((item.itemUser?.includes(species.name) || item.forcedForme === species.name) &&
|
||||
!item.megaStone && !item.isPrimalOrb) || (natdex && species.name.startsWith('Necrozma-') &&
|
||||
item.id === 'ultranecroziumz')) {
|
||||
continue;
|
||||
}
|
||||
return problems;
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "[Gen 9] 350 Cup",
|
||||
desc: `Pokemon with a BST of 350 or lower have their stats doubled.`,
|
||||
mod: 'gen9',
|
||||
// searchShow: false,
|
||||
ruleset: ['Standard OMs', 'Sleep Moves Clause', '350 Cup Mod', 'Evasion Clause'],
|
||||
banlist: ['Calyrex-Shadow', 'Flittle', 'Gastly', 'Miraidon', 'Pikachu', 'Rufflet', 'Arena Trap', 'Moody', 'Shadow Tag', 'Eviolite', 'Baton Pass'],
|
||||
},
|
||||
{
|
||||
name: "[Gen 9] Pokebilities AAA",
|
||||
desc: `Pokémon have all of their released abilities simultaneously, as well as one ability they cannot normally use.`,
|
||||
mod: 'pokebilities',
|
||||
// searchShow: false,
|
||||
ruleset: ['Standard OMs', '!Obtainable Abilities', 'Ability Clause = 1', 'AAA Restricted Abilities', 'Terastal Clause', 'Sleep Moves Clause'],
|
||||
banlist: [
|
||||
'Annihilape', 'Arcanine-Hisui', 'Arceus', 'Archaludon', 'Azumarill', 'Basculegion', 'Basculin', 'Baxcalibur', 'Blaziken', 'Braviary-Hisui', 'Calyrex-Ice', 'Calyrex-Shadow',
|
||||
'Ceruledge', 'Chi-Yu', 'Chien-Pao', 'Clefable', 'Cloyster', 'Conkeldurr', 'Darkrai', 'Deoxys', 'Deoxys-Attack', 'Dialga', 'Enamorus-Base', 'Espathra', 'Eternatus', 'Excadrill',
|
||||
'Flutter Mane', 'Gholdengo', 'Giratina', 'Gouging Fire', 'Groudon', 'Hawlucha', 'Ho-Oh', 'Hoopa-Unbound', 'Iron Bundle', 'Iron Valiant', 'Kingambit', 'Keldeo', 'Kleavor',
|
||||
'Koraidon', 'Kyogre', 'Kyurem', 'Kyurem-Black', 'Kyurem-White', 'Landorus-Base', 'Lugia', 'Lunala', 'Magearna', 'Manaphy', 'Mewtwo', 'Miraidon', 'Necrozma-Dawn-Wings',
|
||||
'Necrozma-Dusk-Mane', 'Noivern', 'Ogerpon-Hearthflame', 'Palkia', 'Porygon-Z', 'Raging Bolt', 'Rayquaza', 'Reshiram', 'Roaring Moon', 'Serperior', 'Shaymin-Sky', 'Smeargle',
|
||||
'Sneasler', 'Solgaleo', 'Spectrier', 'Ursaluna', 'Ursaluna-Bloodmoon', 'Urshifu-Single-Strike', 'Urshifu-Rapid-Strike', 'Volcarona', 'Walking Wake', 'Weavile', 'Zacian',
|
||||
'Zacian-Crowned', 'Zapdos-Galar', 'Zekrom', 'Zoroark-Hisui', 'Arena Trap', 'Magnet Pull', 'Moody', 'Shadow Tag', 'Regenerator + Wimp Out', 'Regenerator + Emergency Exit',
|
||||
'Regenerator > 2',
|
||||
'Drizzle + Swift Swim', 'Primordial Sea + Swift Swim', 'Drought + Chlorophyll', 'Desolate Land + Chlorophyll', 'Electric Surge + Surge Surfer', 'Hadron Engine + Surge Surfer',
|
||||
'Hadron Engine + Quark Drive', 'Electric Surge + Quark Drive', 'Drought + Protosynthesis', 'Sand Stream + Sand Rush', 'Sand Stream + Sand Veil', 'Snow Warning + Snow Cloak',
|
||||
'Snow Warning + Slush Rush', 'King\'s Rock', 'Razor Fang', 'Baton Pass', 'Last Respects', 'Revival Blessing', 'Shed Tail',
|
||||
],
|
||||
restricted: [
|
||||
'Comatose', 'Contrary', 'Fur Coat', 'Good as Gold', 'Gorilla Tactics', 'Huge Power', 'Ice Scales', 'Illusion', 'Imposter', 'Innards Out', 'Magic Bounce', 'Neutralizing Gas',
|
||||
'Orichalcum Pulse', 'Parental Bond', 'Poison Heal', 'Pure Power', 'Simple', 'Speed Boost', 'Stakeout', 'Toxic Debris', 'Triage', 'Unburden', 'Water Bubble', 'Wonder Guard',
|
||||
],
|
||||
onValidateSet(set) {
|
||||
const species = this.dex.species.get(set.species);
|
||||
const unSeenAbilities = Object.keys(species.abilities)
|
||||
.filter(key => key !== 'S' && (key !== 'H' || !species.unreleasedHidden))
|
||||
.map(key => species.abilities[key as "0" | "1" | "H" | "S"])
|
||||
.filter(ability => ability !== set.ability);
|
||||
if (unSeenAbilities.length && this.toID(set.ability) !== this.toID(species.abilities['S'])) {
|
||||
for (const abilityName of unSeenAbilities) {
|
||||
const banReason = this.ruleTable.check('ability:' + this.toID(abilityName));
|
||||
if (banReason) {
|
||||
return [`${set.name}'s ability ${abilityName} is ${banReason}.`];
|
||||
}
|
||||
}
|
||||
if (this.ruleTable.isRestrictedSpecies(species) || this.toID(set.ability) === 'powerconstruct') {
|
||||
return [`${species.name} is not allowed to hold ${item.name}.`];
|
||||
}
|
||||
if (itemTable.has(item.id)) {
|
||||
return [
|
||||
`You are limited to one of each Mega Stone/Primal Orb/Rusted item/Origin item/Ogerpon Mask/Arceus Plate/Silvally Memory.`,
|
||||
`(You have more than one ${item.name})`,
|
||||
];
|
||||
}
|
||||
itemTable.add(item.id);
|
||||
}
|
||||
},
|
||||
onBegin() {
|
||||
for (const pokemon of this.getAllPokemon()) {
|
||||
pokemon.m.originalSpecies = pokemon.baseSpecies.name;
|
||||
if (pokemon.ability === this.toID(pokemon.species.abilities['S'])) {
|
||||
continue;
|
||||
}
|
||||
pokemon.m.innates = Object.keys(pokemon.species.abilities)
|
||||
.filter(key => key !== 'S' && (key !== 'H' || !pokemon.species.unreleasedHidden))
|
||||
.map(key => this.toID(pokemon.species.abilities[key as "0" | "1" | "H" | "S"]))
|
||||
.filter(ability => ability !== pokemon.ability);
|
||||
}
|
||||
},
|
||||
onSwitchIn(pokemon) {
|
||||
const originalSpecies = this.dex.species.get((pokemon.species as any).originalSpecies);
|
||||
if (originalSpecies.exists && pokemon.m.originalSpecies !== originalSpecies.baseSpecies) {
|
||||
// Place volatiles on the Pokémon to show its mega-evolved condition and details
|
||||
this.add('-start', pokemon, originalSpecies.requiredItems?.[0] || originalSpecies.requiredItem || originalSpecies.requiredMove, '[silent]');
|
||||
const oSpecies = this.dex.species.get(pokemon.m.originalSpecies);
|
||||
if (oSpecies.types.join('/') !== pokemon.species.types.join('/')) {
|
||||
this.add('-start', pokemon, 'typechange', pokemon.species.types.join('/'), '[silent]');
|
||||
onBeforeSwitchIn(pokemon) {
|
||||
if (pokemon.m.innates) {
|
||||
for (const innate of pokemon.m.innates) {
|
||||
if (pokemon.hasAbility(innate)) continue;
|
||||
const effect = 'ability:' + this.toID(innate);
|
||||
pokemon.volatiles[effect] = this.initEffectState({ id: effect, target: pokemon });
|
||||
}
|
||||
}
|
||||
},
|
||||
onSwitchOut(pokemon) {
|
||||
const originalSpecies = this.dex.species.get((pokemon.species as any).originalSpecies);
|
||||
if (originalSpecies.exists && pokemon.m.originalSpecies !== originalSpecies.baseSpecies) {
|
||||
this.add('-end', pokemon, originalSpecies.requiredItems?.[0] || originalSpecies.requiredItem || originalSpecies.requiredMove, '[silent]');
|
||||
for (const innate of Object.keys(pokemon.volatiles).filter(i => i.startsWith('ability:'))) {
|
||||
pokemon.removeVolatile(innate);
|
||||
}
|
||||
},
|
||||
onFaint(pokemon) {
|
||||
for (const innate of Object.keys(pokemon.volatiles).filter(i => i.startsWith('ability:'))) {
|
||||
const innateEffect = this.dex.conditions.get(innate) as Effect;
|
||||
this.singleEvent('End', innateEffect, null, pokemon);
|
||||
}
|
||||
},
|
||||
onAfterMega(pokemon) {
|
||||
for (const innate of Object.keys(pokemon.volatiles).filter(i => i.startsWith('ability:'))) {
|
||||
pokemon.removeVolatile(innate);
|
||||
}
|
||||
pokemon.m.innates = undefined;
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "[Gen 9] Ubers UU",
|
||||
mod: 'gen9',
|
||||
// searchShow: false,
|
||||
ruleset: ['[Gen 9] Ubers'],
|
||||
name: "[Gen 9] 4v4 Doubles UU",
|
||||
desc: "VGC rules, but only Pokémon that get less than 4.52% usage on the VGC ladder are legal, as well as a few other guidelines.",
|
||||
ruleset: ['[Gen 9] VGC 2026 Reg F', 'Evasion Abilities Clause', 'Evasion Moves Clause', 'OHKO Clause'],
|
||||
banlist: [
|
||||
// Ubers OU
|
||||
'Arceus-Normal', 'Arceus-Fairy', 'Arceus-Ghost', 'Arceus-Ground', 'Arceus-Water', 'Calyrex-Ice', 'Chien-Pao', 'Deoxys-Attack', 'Deoxys-Speed', 'Ditto',
|
||||
'Dondozo', 'Eternatus', 'Flutter Mane', 'Giratina-Origin', 'Glimmora', 'Gliscor', 'Grimmsnarl', 'Groudon', 'Hatterene', 'Ho-Oh', 'Kingambit', 'Koraidon',
|
||||
'Kyogre', 'Kyurem-Black', 'Landorus-Therian', 'Lunala', 'Necrozma-Dusk-Mane', 'Rayquaza', 'Ribombee', 'Skeledirge', 'Terapagos', 'Ting-Lu', 'Zacian-Crowned',
|
||||
// Ubers UUBL + Lunala, Arceus-Ghost, Arceus-Water
|
||||
'Arceus-Dragon', 'Arceus-Electric', 'Arceus-Fire', 'Arceus-Flying', 'Arceus-Steel', 'Giratina', 'Necrozma-Dawn-Wings', 'Shaymin-Sky', 'Spectrier', 'Zacian',
|
||||
'Zekrom',
|
||||
'Amoonguss', 'Annihilape', 'Arcanine-Hisui', 'Basculegion-M', 'Chi-Yu', 'Chien-Pao', 'Cresselia', 'Dondozo', 'Dragonite', 'Enamorus-Incarnate', 'Farigiraf', 'Flutter Mane',
|
||||
'Gholdengo', 'Gouging Fire', 'Incineroar', 'Indeedee-F', 'Iron Crown', 'Landorus-Incarnate', 'Landorus-Therian', 'Ogerpon-Cornerstone', 'Ogerpon-Hearthflame', 'Ogerpon-Wellspring',
|
||||
'Porygon2', 'Raging Bolt', 'Regidrago', 'Rillaboom', 'Roaring Moon', 'Sneasler', 'Ting-Lu', 'Torkoal', 'Tornadus-Incarnate', 'Ursaluna-Base', 'Urshifu-Single-Strike',
|
||||
'Urshifu-Rapid-Strike', 'Whimsicott', 'Commander', 'Bright Powder', 'King\'s Rock', 'Razor Fang',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "[Gen 9] National Dex Ubers UU",
|
||||
name: "[Gen 9] National Dex RU",
|
||||
mod: 'gen9',
|
||||
// searchShow: false,
|
||||
ruleset: ['[Gen 9] National Dex Ubers'],
|
||||
banlist: [
|
||||
'Alomomola', 'Arceus-Normal', 'Arceus-Dark', 'Arceus-Ground', 'Calyrex-Ice', 'Chansey', 'Deoxys-Attack', 'Ditto', 'Dondozo', 'Eternatus', 'Giratina-Origin', 'Groudon-Primal',
|
||||
'Hatterene', 'Ho-Oh', 'Kingambit', 'Kyogre-Primal', 'Lunala', 'Marshadow', 'Mewtwo-Mega-Y', 'Necrozma-Dusk-Mane', 'Necrozma-Ultra', 'Salamence-Mega', 'Smeargle', 'Yveltal',
|
||||
'Zacian-Crowned', 'Zygarde-50%',
|
||||
// UUBL
|
||||
'Arceus-Dragon', 'Arceus-Fairy', 'Arceus-Fire', 'Arceus-Flying', 'Arceus-Ghost', 'Arceus-Water', 'Blaziken-Mega', 'Chi-Yu', 'Chien-Pao', 'Dracovish', 'Flutter Mane', 'Groudon',
|
||||
'Kyogre', 'Kyurem-Black', 'Rayquaza', 'Shaymin-Sky', 'Zacian', 'Zekrom', 'Power Construct', 'Light Clay', 'Ultranecrozium Z', 'Last Respects',
|
||||
],
|
||||
ruleset: ['[Gen 9] National Dex UU'],
|
||||
banlist: ['ND UU', 'ND RUBL', 'Slowbronite'],
|
||||
},
|
||||
{
|
||||
name: "[Gen 9] Six by Six Random Battle",
|
||||
|
|
@ -718,32 +669,27 @@ export const Formats: import('../sim/dex-formats').FormatList = [
|
|||
},
|
||||
},
|
||||
{
|
||||
name: "[Gen 3] Ubers",
|
||||
mod: 'gen3',
|
||||
name: "[Gen 4] Ubers",
|
||||
mod: 'gen4',
|
||||
// searchShow: false,
|
||||
ruleset: ['Standard', 'Deoxys Camouflage Clause', 'One Baton Pass Clause'],
|
||||
banlist: ['Wobbuffet + Leftovers', 'Wynaut + Leftovers', 'Baton Pass'],
|
||||
ruleset: ['Standard'],
|
||||
banlist: ['AG'],
|
||||
},
|
||||
{
|
||||
name: "[Gen 1] NC 1997",
|
||||
mod: 'gen1jpn',
|
||||
bestOfDefault: true,
|
||||
name: "[Gen 6] NU",
|
||||
mod: 'gen6',
|
||||
// searchShow: false,
|
||||
ruleset: [
|
||||
'Picked Team Size = 3', 'Min Level = 50', 'Max Level = 55', 'Max Total Level = 155',
|
||||
'Obtainable', 'Team Preview', 'Stadium Sleep Clause', 'Species Clause', 'Nickname Clause', 'Cancel Mod', 'NC 1997 Move Legality',
|
||||
],
|
||||
banlist: ['Uber'],
|
||||
ruleset: ['[Gen 6] RU'],
|
||||
banlist: ['RU', 'NUBL'],
|
||||
},
|
||||
{
|
||||
name: "[Gen 7] VGC 2019",
|
||||
mod: 'gen7',
|
||||
name: "[Gen 4] VGC 2009",
|
||||
mod: 'gen4pt',
|
||||
gameType: 'doubles',
|
||||
// searchShow: false,
|
||||
bestOfDefault: true,
|
||||
ruleset: ['Flat Rules', '!! Adjust Level = 50', 'Min Source Gen = 7', 'VGC Timer', 'Limit Two Restricted'],
|
||||
restricted: ['Restricted Legendary'],
|
||||
banlist: ['Unown', 'Battle Bond'],
|
||||
// searchShow: false,
|
||||
ruleset: ['Flat Rules', '! Adjust Level Down', 'Max Level = 50'],
|
||||
banlist: ['Tyranitar', 'Rotom', 'Judgment', 'Soul Dew'],
|
||||
},
|
||||
|
||||
// Other Metagames
|
||||
|
|
@ -1003,14 +949,6 @@ export const Formats: import('../sim/dex-formats').FormatList = [
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "[Gen 9] 350 Cup",
|
||||
desc: `Pokemon with a BST of 350 or lower have their stats doubled.`,
|
||||
mod: 'gen9',
|
||||
searchShow: false,
|
||||
ruleset: ['Standard OMs', 'Sleep Moves Clause', '350 Cup Mod', 'Evasion Clause'],
|
||||
banlist: ['Calyrex-Shadow', 'Flittle', 'Gastly', 'Miraidon', 'Pikachu', 'Rufflet', 'Arena Trap', 'Moody', 'Shadow Tag', 'Eviolite', 'Baton Pass'],
|
||||
},
|
||||
{
|
||||
name: "[Gen 9] Alphabet Cup",
|
||||
desc: `Allows Pokémon to use any move that shares the same first letter as their name or a previous evolution's name.`,
|
||||
|
|
@ -1482,6 +1420,21 @@ export const Formats: import('../sim/dex-formats').FormatList = [
|
|||
],
|
||||
// Implemented the mechanics as a Rule because I'm too lazy to make battles read base format for `onResidual` at the moment
|
||||
},
|
||||
{
|
||||
name: "[Gen 9] Flipped",
|
||||
desc: `All Pokémon have their base stats flipped. For example, Sylveon's HP and Speed stats, Attack and Special Defense stats, and Defense and Special Attack stats swap.`,
|
||||
mod: 'gen9',
|
||||
searchShow: false,
|
||||
ruleset: ['Standard OMs', 'Sleep Moves Clause', 'Evasion Abilities Clause', 'Evasion Items Clause', 'Flipped Mod'],
|
||||
banlist: [
|
||||
'Annihilape', 'Araquanid', 'Arceus', 'Azumarill', 'Blissey', 'Calyrex-Ice', 'Calyrex-Shadow', 'Cloyster', 'Cyclizar', 'Deoxys-Attack', 'Deoxys-Normal',
|
||||
'Deoxys-Speed', 'Dialga', 'Dialga-Origin', 'Espathra', 'Eternatus', 'Giratina', 'Giratina-Origin', 'Groudon', 'Ho-Oh', 'Hoopa-Unbound', 'Koraidon', 'Kyogre',
|
||||
'Kyurem-Black', 'Kyurem-White', 'Lugia', 'Lunala', 'Magearna', 'Mewtwo', 'Miraidon', 'Mienshao', 'Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane', 'Palkia',
|
||||
'Palkia-Origin', 'Rayquaza', 'Regieleki', 'Reshiram', 'Shaymin-Sky', 'Snorlax', 'Solgaleo', 'Sylveon', 'Terapagos', 'Torkoal', 'Tornadus-Therian', 'Zacian',
|
||||
'Zacian-Crowned', 'Zamazenta-Crowned', 'Zekrom', 'Arena Trap', 'Moody', 'Shadow Tag', 'Damp Rock', 'King\'s Rock', 'Light Clay', 'Razor Fang', 'Baton Pass',
|
||||
'Last Respects', 'Shed Tail',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "[Gen 9] Foresighters",
|
||||
desc: `Moves in the first moveslot will be delayed by two turns.`,
|
||||
|
|
@ -2741,6 +2694,88 @@ export const Formats: import('../sim/dex-formats').FormatList = [
|
|||
pokemon.apparentType = pokemon.getTypes(true).join('/');
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "[Gen 9] The Loser's Game",
|
||||
desc: `The first player to lose all of their Pokémon wins.`,
|
||||
mod: 'gen9',
|
||||
searchShow: false,
|
||||
ruleset: ['Standard OMs', 'Sleep Clause Mod', '!OHKO Clause', 'Picked Team Size = 6', 'Adjust Level = 100'],
|
||||
banlist: ['Infiltrator', 'Choice Scarf', 'Explosion', 'Final Gambit', 'Healing Wish', 'Lunar Dance', 'Magic Room', 'Memento', 'Misty Explosion', 'Self-Destruct'],
|
||||
onValidateTeam(team) {
|
||||
const familyTable = new Set<ID>();
|
||||
for (const set of team) {
|
||||
let species = this.dex.species.get(set.species);
|
||||
while (species.prevo) {
|
||||
species = this.dex.species.get(species.prevo);
|
||||
}
|
||||
if (familyTable.has(species.id)) {
|
||||
return [
|
||||
`You are limited to one Pokémon from each family by the Family Clause.`,
|
||||
`(You have more than one evolution of ${species.name}.)`,
|
||||
];
|
||||
}
|
||||
familyTable.add(species.id);
|
||||
}
|
||||
},
|
||||
battle: {
|
||||
tiebreak() {
|
||||
if (this.ended) return false;
|
||||
|
||||
this.inputLog.push(`>tiebreak`);
|
||||
this.add('message', "Time's up! Going to tiebreaker...");
|
||||
const notFainted = this.sides.map(side => (
|
||||
side.pokemon.filter(pokemon => !pokemon.fainted).length
|
||||
));
|
||||
this.add('-message', this.sides.map((side, i) => (
|
||||
`${side.name}: ${notFainted[i]} Pokemon left`
|
||||
)).join('; '));
|
||||
const maxNotFainted = Math.max(...notFainted);
|
||||
let tiedSides = this.sides.filter((side, i) => notFainted[i] === maxNotFainted);
|
||||
if (tiedSides.length <= 1) {
|
||||
return this.win(tiedSides[1]);
|
||||
}
|
||||
|
||||
const hpPercentage = tiedSides.map(side => (
|
||||
side.pokemon.map(pokemon => pokemon.hp / pokemon.maxhp).reduce((a, b) => a + b) * 100 / 6
|
||||
));
|
||||
this.add('-message', tiedSides.map((side, i) => (
|
||||
`${side.name}: ${Math.round(hpPercentage[i])}% total HP left`
|
||||
)).join('; '));
|
||||
const maxPercentage = Math.max(...hpPercentage);
|
||||
tiedSides = tiedSides.filter((side, i) => hpPercentage[i] === maxPercentage);
|
||||
if (tiedSides.length <= 1) {
|
||||
return this.win(tiedSides[1]);
|
||||
}
|
||||
|
||||
const hpTotal = tiedSides.map(side => (
|
||||
side.pokemon.map(pokemon => pokemon.hp).reduce((a, b) => a + b)
|
||||
));
|
||||
this.add('-message', tiedSides.map((side, i) => (
|
||||
`${side.name}: ${Math.round(hpTotal[i])} total HP left`
|
||||
)).join('; '));
|
||||
const maxTotal = Math.max(...hpTotal);
|
||||
tiedSides = tiedSides.filter((side, i) => hpTotal[i] === maxTotal);
|
||||
if (tiedSides.length <= 1) {
|
||||
return this.win(tiedSides[1]);
|
||||
}
|
||||
return this.tie();
|
||||
},
|
||||
checkWin(faintData) {
|
||||
const team1PokemonLeft = this.sides[0].pokemonLeft;
|
||||
const team2PokemonLeft = this.sides[1].pokemonLeft;
|
||||
if (!team1PokemonLeft && !team2PokemonLeft) {
|
||||
this.win(faintData?.target.side || null);
|
||||
return true;
|
||||
}
|
||||
for (const side of this.sides) {
|
||||
if (!side.pokemonLeft) {
|
||||
this.win(side);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "[Gen 9] Tier Shift",
|
||||
desc: `Pokémon below OU get their stats, excluding HP, boosted. UU/RUBL get +15, RU/NUBL get +20, NU/PUBL get +25, and PU or lower get +30.`,
|
||||
|
|
@ -3205,11 +3240,18 @@ export const Formats: import('../sim/dex-formats').FormatList = [
|
|||
banlist: ['ND OU', 'ND UUBL', 'Drizzle', 'Drought', 'Light Clay'],
|
||||
},
|
||||
{
|
||||
name: "[Gen 9] National Dex RU",
|
||||
name: "[Gen 9] National Dex Ubers UU",
|
||||
mod: 'gen9',
|
||||
searchShow: false,
|
||||
ruleset: ['[Gen 9] National Dex UU'],
|
||||
banlist: ['ND UU', 'ND RUBL', 'Slowbronite'],
|
||||
ruleset: ['[Gen 9] National Dex Ubers'],
|
||||
banlist: [
|
||||
'Alomomola', 'Arceus-Normal', 'Arceus-Dark', 'Arceus-Ground', 'Calyrex-Ice', 'Chansey', 'Deoxys-Attack', 'Ditto', 'Dondozo', 'Eternatus', 'Giratina-Origin', 'Groudon-Primal',
|
||||
'Hatterene', 'Ho-Oh', 'Kingambit', 'Kyogre-Primal', 'Lunala', 'Marshadow', 'Mewtwo-Mega-Y', 'Necrozma-Dusk-Mane', 'Necrozma-Ultra', 'Salamence-Mega', 'Smeargle', 'Yveltal',
|
||||
'Zacian-Crowned', 'Zygarde-50%',
|
||||
// UUBL
|
||||
'Arceus-Dragon', 'Arceus-Fairy', 'Arceus-Fire', 'Arceus-Flying', 'Arceus-Ghost', 'Arceus-Water', 'Blaziken-Mega', 'Chi-Yu', 'Chien-Pao', 'Dracovish', 'Flutter Mane', 'Groudon',
|
||||
'Kyogre', 'Kyurem-Black', 'Rayquaza', 'Shaymin-Sky', 'Zacian', 'Zekrom', 'Power Construct', 'Light Clay', 'Ultranecrozium Z', 'Last Respects',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "[Gen 9] National Dex LC",
|
||||
|
|
@ -4552,6 +4594,16 @@ export const Formats: import('../sim/dex-formats').FormatList = [
|
|||
ruleset: ['[Gen 7] Doubles OU'],
|
||||
banlist: ['DOU', 'DBL'],
|
||||
},
|
||||
{
|
||||
name: "[Gen 7] VGC 2019",
|
||||
mod: 'gen7',
|
||||
gameType: 'doubles',
|
||||
searchShow: false,
|
||||
bestOfDefault: true,
|
||||
ruleset: ['Flat Rules', '!! Adjust Level = 50', 'Min Source Gen = 7', 'VGC Timer', 'Limit Two Restricted'],
|
||||
restricted: ['Restricted Legendary'],
|
||||
banlist: ['Unown', 'Battle Bond'],
|
||||
},
|
||||
{
|
||||
name: "[Gen 7] VGC 2018",
|
||||
mod: 'gen7',
|
||||
|
|
@ -4628,13 +4680,6 @@ export const Formats: import('../sim/dex-formats').FormatList = [
|
|||
ruleset: ['[Gen 6] UU'],
|
||||
banlist: ['UU', 'RUBL'],
|
||||
},
|
||||
{
|
||||
name: "[Gen 6] NU",
|
||||
mod: 'gen6',
|
||||
searchShow: false,
|
||||
ruleset: ['[Gen 6] RU'],
|
||||
banlist: ['RU', 'NUBL'],
|
||||
},
|
||||
{
|
||||
name: "[Gen 6] PU",
|
||||
mod: 'gen6',
|
||||
|
|
@ -4982,13 +5027,6 @@ export const Formats: import('../sim/dex-formats').FormatList = [
|
|||
section: "DPP Singles",
|
||||
column: 4,
|
||||
},
|
||||
{
|
||||
name: "[Gen 4] Ubers",
|
||||
mod: 'gen4',
|
||||
searchShow: false,
|
||||
ruleset: ['Standard'],
|
||||
banlist: ['AG'],
|
||||
},
|
||||
{
|
||||
name: "[Gen 4] UU",
|
||||
mod: 'gen4',
|
||||
|
|
@ -5134,15 +5172,6 @@ export const Formats: import('../sim/dex-formats').FormatList = [
|
|||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "[Gen 4] VGC 2009",
|
||||
mod: 'gen4pt',
|
||||
gameType: 'doubles',
|
||||
searchShow: false,
|
||||
bestOfDefault: true,
|
||||
ruleset: ['Flat Rules', '! Adjust Level Down', 'Max Level = 50'],
|
||||
banlist: ['Tyranitar', 'Rotom', 'Judgment', 'Soul Dew'],
|
||||
},
|
||||
{
|
||||
name: "[Gen 4] Doubles Custom Game",
|
||||
mod: 'gen4',
|
||||
|
|
@ -5162,11 +5191,11 @@ export const Formats: import('../sim/dex-formats').FormatList = [
|
|||
column: 4,
|
||||
},
|
||||
{
|
||||
name: "[Gen 3] RU",
|
||||
name: "[Gen 3] Ubers",
|
||||
mod: 'gen3',
|
||||
searchShow: false,
|
||||
ruleset: ['Standard'],
|
||||
banlist: ['Uber', 'OU', 'UUBL', 'UU', 'RUBL', 'Glalie', 'Smeargle + Ingrain', 'Arena Trap', 'Baton Pass', 'Swagger'],
|
||||
ruleset: ['Standard', 'Deoxys Camouflage Clause', 'One Baton Pass Clause'],
|
||||
banlist: ['Wobbuffet + Leftovers', 'Wynaut + Leftovers', 'Baton Pass'],
|
||||
},
|
||||
{
|
||||
name: "[Gen 3] UU",
|
||||
|
|
@ -5175,6 +5204,13 @@ export const Formats: import('../sim/dex-formats').FormatList = [
|
|||
ruleset: ['Standard'],
|
||||
banlist: ['Uber', 'OU', 'UUBL', 'Smeargle + Ingrain', 'Arena Trap', 'Baton Pass', 'Swagger'],
|
||||
},
|
||||
{
|
||||
name: "[Gen 3] RU",
|
||||
mod: 'gen3',
|
||||
searchShow: false,
|
||||
ruleset: ['Standard'],
|
||||
banlist: ['Uber', 'OU', 'UUBL', 'UU', 'RUBL', 'Glalie', 'Smeargle + Ingrain', 'Arena Trap', 'Baton Pass', 'Swagger'],
|
||||
},
|
||||
{
|
||||
name: "[Gen 3] NU",
|
||||
mod: 'gen3',
|
||||
|
|
@ -5406,6 +5442,17 @@ export const Formats: import('../sim/dex-formats').FormatList = [
|
|||
],
|
||||
banlist: ['Mew', 'Mewtwo', 'Bind', 'Clamp', 'Explosion', 'Fire Spin', 'Self-Destruct', 'Wrap'],
|
||||
},
|
||||
{
|
||||
name: "[Gen 1] NC 1997",
|
||||
mod: 'gen1jpn',
|
||||
bestOfDefault: true,
|
||||
searchShow: false,
|
||||
ruleset: [
|
||||
'Picked Team Size = 3', 'Min Level = 50', 'Max Level = 55', 'Max Total Level = 155',
|
||||
'Obtainable', 'Team Preview', 'Stadium Sleep Clause', 'Species Clause', 'Nickname Clause', 'Cancel Mod', 'NC 1997 Move Legality',
|
||||
],
|
||||
banlist: ['Uber'],
|
||||
},
|
||||
{
|
||||
name: "[Gen 1] Japanese OU",
|
||||
desc: `Generation 1 with Japanese battle mechanics.`,
|
||||
|
|
|
|||
|
|
@ -91,10 +91,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] Flipped",
|
||||
lcotm: "[Gen 9] The Loser's Game",
|
||||
ommotm: "[Gen 9] STABmons Mix and Mega",
|
||||
ommspotlight: "[Gen 9] STABmons Mix and Mega",
|
||||
omotm: "[Gen 9] Linked",
|
||||
lcotm: "[Gen 9] 350 Cup",
|
||||
ommotm: "[Gen 9] Pokebilities AAA",
|
||||
ommspotlight: "[Gen 9] Pokebilities AAA",
|
||||
|
||||
// mega evos --- 1st ordered alphabetically by species, 2nd by alias
|
||||
megasnow: "Abomasnow-Mega",
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
||||
leppaberry: {
|
||||
inherit: true,
|
||||
onUpdate(pokemon) {
|
||||
if (!pokemon.hp) return;
|
||||
const moveSlot = pokemon.getMoveData(pokemon.m.lastMoveAbsolute);
|
||||
if (moveSlot?.pp === 0) {
|
||||
pokemon.addVolatile('leppaberry');
|
||||
pokemon.volatiles['leppaberry'].moveSlot = moveSlot;
|
||||
pokemon.eatItem();
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -21,7 +21,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
frz: {
|
||||
inherit: true,
|
||||
onBeforeMove(pokemon, target, move) {
|
||||
if (move.flags['defrost']) return;
|
||||
if (move.flags['defrost'] && !(move.id === 'burnup' && !pokemon.hasType('Fire'))) return;
|
||||
if (this.effectState.durationRolled !== this.turn && this.randomChance(1, 5)) {
|
||||
pokemon.cureStatus();
|
||||
return;
|
||||
|
|
@ -46,17 +46,14 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
}
|
||||
}
|
||||
this.add('-activate', pokemon, 'confusion');
|
||||
if (!this.randomChance(1, 3)) {
|
||||
if (!this.randomChance(33, 100)) {
|
||||
return;
|
||||
}
|
||||
this.activeTarget = pokemon;
|
||||
const damage = this.actions.getDamage(pokemon, pokemon, 40);
|
||||
const damage = this.actions.getConfusionDamage(pokemon, 40);
|
||||
if (typeof damage !== 'number') throw new Error("Confusion damage not dealt");
|
||||
this.damage(damage, pokemon, pokemon, {
|
||||
id: 'confused' as ID,
|
||||
effectType: 'Move',
|
||||
type: '???',
|
||||
} as unknown as ActiveMove);
|
||||
const activeMove = { id: this.toID('confused'), effectType: 'Move', type: '???' };
|
||||
this.damage(damage, pokemon, pokemon, activeMove as ActiveMove);
|
||||
return false;
|
||||
},
|
||||
},
|
||||
|
|
@ -1,35 +1,38 @@
|
|||
export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
||||
pursuit: {
|
||||
inherit: true,
|
||||
beforeTurnCallback(pokemon, target) {
|
||||
beforeTurnCallback(pokemon) {
|
||||
// @ts-expect-error modded
|
||||
const linkedMoves: [string, string] = pokemon.getLinkedMoves();
|
||||
if (linkedMoves.length) {
|
||||
if (linkedMoves[0] !== 'pursuit' && linkedMoves[1] === 'pursuit') return;
|
||||
}
|
||||
|
||||
target.side.addSideCondition('pursuit', pokemon);
|
||||
if (!target.side.sideConditions['pursuit'].sources) {
|
||||
target.side.sideConditions['pursuit'].sources = [];
|
||||
for (const target of pokemon.foes()) {
|
||||
target.addVolatile('pursuit');
|
||||
const data = target.volatiles['pursuit'];
|
||||
if (!data.sources) {
|
||||
data.sources = [];
|
||||
}
|
||||
data.sources.push(pokemon);
|
||||
}
|
||||
target.side.sideConditions['pursuit'].sources.push(pokemon);
|
||||
},
|
||||
},
|
||||
mefirst: {
|
||||
inherit: true,
|
||||
onTryHit(target, pokemon) {
|
||||
const action = this.queue.willMove(target);
|
||||
if (action) {
|
||||
// Mod-specific: Me First copies the first move in the link
|
||||
// @ts-expect-error modded
|
||||
const move = this.dex.getActiveMove(action.linked?.[0] || action.move);
|
||||
if (move.category !== 'Status' && !move.flags['failmefirst']) {
|
||||
pokemon.addVolatile('mefirst');
|
||||
this.actions.useMove(move, pokemon, { target });
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
if (!action) return false;
|
||||
// Mod-specific: Me First copies the first move in the link
|
||||
// @ts-expect-error modded
|
||||
const move = this.dex.getActiveMove(action.linked?.[0] || action.move.id);
|
||||
if (action.zmove || move.isZ || move.isMax) return false;
|
||||
if (target.volatiles['mustrecharge']) return false;
|
||||
if (move.category === 'Status' || move.flags['failmefirst']) return false;
|
||||
|
||||
pokemon.addVolatile('mefirst');
|
||||
this.actions.useMove(move, pokemon, { target });
|
||||
return null;
|
||||
},
|
||||
},
|
||||
|
||||
|
|
@ -38,7 +41,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
onTry(source, target) {
|
||||
const action = this.queue.willMove(target);
|
||||
if (!action || action.choice !== 'move') {
|
||||
if (!action || action.choice !== 'move' ||
|
||||
// @ts-expect-error modded
|
||||
(!action.linked && action.move.category === 'Status' && action.move.id !== 'mefirst')) {
|
||||
this.attrLastMove('[still]');
|
||||
this.add('-fail', source);
|
||||
return null;
|
||||
|
|
@ -51,13 +56,67 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
return null;
|
||||
}
|
||||
// @ts-expect-error modded
|
||||
if (!action.linked) {
|
||||
if (action.move.category === 'Status' && action.move.id !== 'mefirst') {
|
||||
this.attrLastMove('[still]');
|
||||
this.add('-fail', source);
|
||||
return null;
|
||||
if (action.linked) {
|
||||
// @ts-expect-error modded
|
||||
for (const linkedMove of action.linked) {
|
||||
if (linkedMove.category !== 'Status' || linkedMove.id === 'mefirst') return;
|
||||
}
|
||||
} else {
|
||||
this.attrLastMove('[still]');
|
||||
this.add('-fail', source);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
},
|
||||
thunderclap: {
|
||||
inherit: true,
|
||||
onTry(source, target) {
|
||||
const action = this.queue.willMove(target);
|
||||
if (!action || action.choice !== 'move' ||
|
||||
// @ts-expect-error modded
|
||||
(!action.linked && action.move.category === 'Status' && action.move.id !== 'mefirst')) {
|
||||
this.attrLastMove('[still]');
|
||||
this.add('-fail', source);
|
||||
return null;
|
||||
}
|
||||
if (target.volatiles.mustrecharge && target.volatiles.mustrecharge.duration! < 2) {
|
||||
// Duration may not be lower than 2 if Sucker Punch is used as a low-priority move
|
||||
// i.e. if Sucker Punch is linked with a negative priority move
|
||||
this.attrLastMove('[still]');
|
||||
this.add('-fail', source);
|
||||
return null;
|
||||
}
|
||||
// @ts-expect-error modded
|
||||
if (action.linked) {
|
||||
// @ts-expect-error modded
|
||||
for (const linkedMove of action.linked) {
|
||||
if (linkedMove.category !== 'Status' || linkedMove.id === 'mefirst') return;
|
||||
}
|
||||
this.attrLastMove('[still]');
|
||||
this.add('-fail', source);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
},
|
||||
upperhand: {
|
||||
inherit: true,
|
||||
onTry(source, target) {
|
||||
const action = this.queue.willMove(target);
|
||||
if (!action || action.choice !== 'move' || action.move.priority < 0.1 ||
|
||||
// @ts-expect-error modded
|
||||
(!action.linked && action.move.category === 'Status' && action.move.id !== 'mefirst')) {
|
||||
this.attrLastMove('[still]');
|
||||
this.add('-fail', source);
|
||||
return null;
|
||||
}
|
||||
if (target.volatiles.mustrecharge && target.volatiles.mustrecharge.duration! < 2) {
|
||||
// Duration may not be lower than 2 if Sucker Punch is used as a low-priority move
|
||||
// i.e. if Sucker Punch is linked with a negative priority move
|
||||
this.attrLastMove('[still]');
|
||||
this.add('-fail', source);
|
||||
return null;
|
||||
}
|
||||
// @ts-expect-error modded
|
||||
if (action.linked) {
|
||||
// @ts-expect-error modded
|
||||
for (const linkedMove of action.linked) {
|
||||
if (linkedMove.category !== 'Status' || linkedMove.id === 'mefirst') return;
|
||||
|
|
@ -73,13 +132,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
sketch: {
|
||||
inherit: true,
|
||||
onHit(target, source) {
|
||||
const disallowedMoves = ['chatter', 'sketch', 'struggle'];
|
||||
const lastMove: Move = target.m.lastMoveAbsolute;
|
||||
if (source.transformed || !lastMove || disallowedMoves.includes(lastMove.id) ||
|
||||
source.moves.includes(lastMove.id) || lastMove.isZ) return false;
|
||||
const move = target.m.lastMoveAbsolute;
|
||||
if (source.transformed || !move || source.moves.includes(move.id)) return false;
|
||||
if (move.flags['nosketch'] || move.isZ || move.isMax) return false;
|
||||
const sketchIndex = source.moves.indexOf('sketch');
|
||||
if (sketchIndex < 0) return false;
|
||||
const move = this.dex.moves.get(lastMove);
|
||||
const sketchedMove = {
|
||||
move: move.name,
|
||||
id: move.id,
|
||||
|
|
@ -97,12 +154,14 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
mimic: {
|
||||
inherit: true,
|
||||
onHit(target, source) {
|
||||
const lastMove: Move = target.m.lastMoveAbsolute;
|
||||
if (source.transformed || !lastMove || lastMove.flags['failmimic'] ||
|
||||
source.moves.includes(lastMove.id) || lastMove.isZ) return false;
|
||||
const move = target.m.lastMoveAbsolute;
|
||||
if (source.transformed || !move || move.flags['failmimic'] || source.moves.includes(move.id)) {
|
||||
return false;
|
||||
}
|
||||
if (move.isZ || move.isMax) return false;
|
||||
const mimicIndex = source.moves.indexOf('mimic');
|
||||
if (mimicIndex < 0) return false;
|
||||
const move = this.dex.moves.get(lastMove);
|
||||
|
||||
source.moveSlots[mimicIndex] = {
|
||||
move: move.name,
|
||||
id: move.id,
|
||||
|
|
@ -121,25 +180,30 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
instruct: {
|
||||
inherit: true,
|
||||
onHit(target, source) {
|
||||
const lastMove: Move | ActiveMove | null = target.m.lastMoveAbsolute;
|
||||
const lastMove = target.m.lastMoveAbsolute;
|
||||
if (!lastMove || target.volatiles['dynamax']) return false;
|
||||
const moveIndex = target.moves.indexOf(lastMove.id);
|
||||
const moveSlot = target.getMoveData(lastMove.id);
|
||||
if (
|
||||
lastMove.flags['failinstruct'] || lastMove.isZ || lastMove.isMax ||
|
||||
lastMove.flags['charge'] || lastMove.flags['recharge'] ||
|
||||
target.volatiles['beakblast'] || target.volatiles['focuspunch'] || target.volatiles['shelltrap'] ||
|
||||
(target.moveSlots[moveIndex] && target.moveSlots[moveIndex].pp <= 0)
|
||||
(moveSlot && moveSlot.pp <= 0)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
this.add('-singleturn', target, 'move: Instruct', `[of] ${source}`);
|
||||
this.actions.runMove(lastMove.id, target, target.lastMoveTargetLoc!);
|
||||
this.queue.prioritizeAction(this.queue.resolveAction({
|
||||
choice: 'move',
|
||||
pokemon: target,
|
||||
moveid: lastMove.id,
|
||||
targetLoc: target.lastMoveTargetLoc!,
|
||||
})[0] as MoveAction);
|
||||
},
|
||||
},
|
||||
mirrormove: {
|
||||
inherit: true,
|
||||
onTryHit(target, pokemon) {
|
||||
const move: Move | ActiveMove | null = target.m.lastMoveAbsolute;
|
||||
const move = target.m.lastMoveAbsolute;
|
||||
if (!move?.flags['mirror'] || move.isZ || move.isMax) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -155,15 +219,16 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
duration: 5,
|
||||
noCopy: true, // doesn't get copied by Baton Pass
|
||||
onStart(pokemon, source, effect) {
|
||||
const lastMove: Move | ActiveMove | null = pokemon.m.lastMoveAbsolute;
|
||||
// The target hasn't taken its turn, or Cursed Body activated and the move was not used through Dancer or Instruct
|
||||
if (
|
||||
this.queue.willMove(pokemon) ||
|
||||
(pokemon === this.activePokemon && this.activeMove && !this.activeMove.isExternal)
|
||||
) {
|
||||
this.effectState.duration!--;
|
||||
}
|
||||
const lastMove = pokemon.m.lastMoveAbsolute;
|
||||
if (!lastMove) {
|
||||
this.debug('pokemon hasn\'t moved yet');
|
||||
this.debug(`Pokemon hasn't moved yet`);
|
||||
return false;
|
||||
}
|
||||
for (const moveSlot of pokemon.moveSlots) {
|
||||
|
|
@ -171,18 +236,15 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
if (!moveSlot.pp) {
|
||||
this.debug('Move out of PP');
|
||||
return false;
|
||||
} else {
|
||||
if (effect.id === 'cursedbody') {
|
||||
this.add('-start', pokemon, 'Disable', moveSlot.move, '[from] ability: Cursed Body', `[of] ${source}`);
|
||||
} else {
|
||||
this.add('-start', pokemon, 'Disable', moveSlot.move);
|
||||
}
|
||||
this.effectState.move = lastMove.id;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
if (effect.effectType === 'Ability') {
|
||||
this.add('-start', pokemon, 'Disable', lastMove.name, '[from] ability: ' + effect.name, `[of] ${source}`);
|
||||
} else {
|
||||
this.add('-start', pokemon, 'Disable', lastMove.name);
|
||||
}
|
||||
this.effectState.move = lastMove.id;
|
||||
},
|
||||
onResidualOrder: 14,
|
||||
onEnd(pokemon) {
|
||||
|
|
@ -190,7 +252,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
onBeforeMovePriority: 7,
|
||||
onBeforeMove(attacker, defender, move) {
|
||||
if (!move.isZ && move.id === this.effectState.move) {
|
||||
if (!(move.isZ && move.isZOrMaxPowered) && move.id === this.effectState.move) {
|
||||
this.add('cant', attacker, 'Disable', move);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -210,28 +272,26 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
duration: 3,
|
||||
noCopy: true, // doesn't get copied by Z-Baton Pass
|
||||
onStart(target) {
|
||||
let lastMove: Move | ActiveMove | null = target.m.lastMoveAbsolute;
|
||||
if (!lastMove || target.volatiles['dynamax']) return false;
|
||||
if ((lastMove as ActiveMove).isZOrMaxPowered) lastMove = this.dex.moves.get(lastMove.baseMove);
|
||||
let move: Move | ActiveMove | null = target.m.lastMoveAbsolute;
|
||||
if (!move || target.volatiles['dynamax']) return false;
|
||||
// Encore only works on Max Moves if the base move is not itself a Max Move
|
||||
if (move.isMax && move.baseMove) move = this.dex.moves.get(move.baseMove);
|
||||
// @ts-expect-error modded
|
||||
const linkedMoves: [string, string] = target.getLinkedMoves(true);
|
||||
const moveIndex = target.moves.indexOf(lastMove.id);
|
||||
if (linkedMoves.includes(lastMove.id) && this.dex.moves.get((linkedMoves[0])).flags['failencore'] &&
|
||||
this.dex.moves.get((linkedMoves[1])).flags['failencore']) {
|
||||
const moveSlot = target.getMoveData(move.id);
|
||||
if (linkedMoves.includes(move.id) && linkedMoves.every(m => !!this.dex.moves.get(m).flags['failencore'])) {
|
||||
// both moves cannot be encored
|
||||
delete target.volatiles['encore'];
|
||||
return false;
|
||||
}
|
||||
if (lastMove.isZ || lastMove.flags['failencore'] ||
|
||||
(target.moveSlots[moveIndex] && target.moveSlots[moveIndex].pp <= 0)) {
|
||||
if (move.isZ || move.isMax || move.flags['failencore'] || !moveSlot || moveSlot.pp <= 0) {
|
||||
// it failed
|
||||
delete target.volatiles['encore'];
|
||||
return false;
|
||||
}
|
||||
this.effectState.turnsActivated = {};
|
||||
this.effectState.move = lastMove.id;
|
||||
this.effectState.timesActivated = {};
|
||||
this.effectState.move = move.id;
|
||||
this.add('-start', target, 'Encore');
|
||||
if (linkedMoves.includes(lastMove.id)) {
|
||||
if (linkedMoves.includes(move.id)) {
|
||||
this.effectState.move = linkedMoves;
|
||||
}
|
||||
if (!this.queue.willMove(target)) {
|
||||
|
|
@ -239,51 +299,50 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
}
|
||||
},
|
||||
onOverrideAction(pokemon, target, move) {
|
||||
if (!this.effectState.turnsActivated[this.turn]) {
|
||||
if (!this.effectState.timesActivated[this.turn]) {
|
||||
// Initialize Encore effect for this turn
|
||||
this.effectState.turnsActivated[this.turn] = 0;
|
||||
} else if (
|
||||
this.effectState.turnsActivated[this.turn] >= (Array.isArray(this.effectState.move) ?
|
||||
this.effectState.move.length : 1)) {
|
||||
this.effectState.timesActivated[this.turn] = 0;
|
||||
} else if (this.effectState.timesActivated[this.turn] >= (Array.isArray(this.effectState.move) ?
|
||||
this.effectState.move.length : 1)) {
|
||||
// Finish Encore effect for this turn
|
||||
return;
|
||||
}
|
||||
this.effectState.turnsActivated[this.turn]++;
|
||||
this.effectState.timesActivated[this.turn]++;
|
||||
if (!Array.isArray(this.effectState.move)) {
|
||||
this.queue.cancelAction(pokemon);
|
||||
if (move.id !== this.effectState.move) return this.effectState.move;
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Locked into a link
|
||||
switch (this.effectState.turnsActivated[this.turn]) {
|
||||
case 1: {
|
||||
if (this.effectState.move[0] !== move.id) return this.effectState.move[0];
|
||||
return;
|
||||
}
|
||||
case 2:
|
||||
if (this.effectState.move[1] !== move.id) return this.effectState.move[1];
|
||||
return;
|
||||
switch (this.effectState.timesActivated[this.turn]) {
|
||||
case 1: {
|
||||
if (this.effectState.move[0] !== move.id) return this.effectState.move[0];
|
||||
return;
|
||||
}
|
||||
case 2:
|
||||
if (this.effectState.move[1] !== move.id) return this.effectState.move[1];
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
onResidualOrder: 13,
|
||||
onResidual(target) {
|
||||
// early termination if you run out of PP
|
||||
const lastMove = target.m.lastMoveAbsolute;
|
||||
const index = target.moves.indexOf(lastMove.id);
|
||||
if (index === -1) return; // no last move
|
||||
const moveSlot = target.getMoveData(lastMove);
|
||||
if (!moveSlot) {
|
||||
target.removeVolatile('encore');
|
||||
return; // no last move
|
||||
}
|
||||
|
||||
// @ts-expect-error modded
|
||||
if (target.hasLinkedMove(lastMove.id)) {
|
||||
// TODO: Check instead whether the last executed move was linked
|
||||
if (target.moveSlots[0].pp <= 0 || target.moveSlots[1].pp <= 0) {
|
||||
delete target.volatiles.encore;
|
||||
this.add('-end', target, 'Encore');
|
||||
target.removeVolatile('encore');
|
||||
}
|
||||
} else {
|
||||
if (target.moveSlots[index].pp <= 0) {
|
||||
delete target.volatiles.encore;
|
||||
this.add('-end', target, 'Encore');
|
||||
if (moveSlot.pp <= 0) {
|
||||
target.removeVolatile('encore');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -313,22 +372,25 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
condition: {
|
||||
noCopy: true,
|
||||
onStart(pokemon) {
|
||||
onStart(pokemon, source, effect) {
|
||||
if (pokemon.volatiles['dynamax']) {
|
||||
delete pokemon.volatiles['torment'];
|
||||
return false;
|
||||
}
|
||||
if (effect?.id === 'gmaxmeltdown') this.effectState.duration = 3;
|
||||
this.add('-start', pokemon, 'Torment');
|
||||
},
|
||||
onEnd(pokemon) {
|
||||
this.add('-end', pokemon, 'Torment');
|
||||
},
|
||||
onDisableMove(pokemon) {
|
||||
const lastMove = pokemon.lastMove;
|
||||
const lastMove = pokemon.m.lastMoveAbsolute;
|
||||
if (!lastMove || lastMove.id === 'struggle') return;
|
||||
|
||||
if (Array.isArray(lastMove)) {
|
||||
for (const move of lastMove) {
|
||||
// @ts-expect-error
|
||||
if (pokemon.hasLinkedMove(lastMove.id)) {
|
||||
// @ts-expect-error
|
||||
for (const move of pokemon.getLinkedMoves()) {
|
||||
pokemon.disableMove(move.id);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -347,12 +409,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
onFaint(target, source, effect) {
|
||||
if (!source || source.fainted || !effect) return;
|
||||
const lastMove: Move | ActiveMove | null = source.m.lastMoveAbsolute;
|
||||
if (effect.effectType === 'Move' && !effect.flags['futuremove'] && lastMove) {
|
||||
let move = source.m.lastMoveAbsolute;
|
||||
if (effect.effectType === 'Move' && !effect.flags['futuremove'] && move) {
|
||||
if (move.isMax && move.baseMove) move = this.dex.moves.get(move.baseMove);
|
||||
for (const moveSlot of source.moveSlots) {
|
||||
if (moveSlot.id === lastMove.id) {
|
||||
if (moveSlot.id === move.id) {
|
||||
moveSlot.pp = 0;
|
||||
this.add('-activate', source, 'move: Grudge', this.dex.moves.get(lastMove.id).name);
|
||||
this.add('-activate', source, 'move: Grudge', move.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -368,11 +431,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
spite: {
|
||||
inherit: true,
|
||||
onHit(target) {
|
||||
const lastMove: Move | ActiveMove | null = target.m.lastMoveAbsolute;
|
||||
if (!lastMove || lastMove.isZ || lastMove.isMax) return false;
|
||||
const ppDeducted = target.deductPP(lastMove.id, 4);
|
||||
let move: Move | ActiveMove | null = target.m.lastMoveAbsolute;
|
||||
if (!move || move.isZ) return false;
|
||||
if (move.isMax && move.baseMove) move = this.dex.moves.get(move.baseMove);
|
||||
|
||||
const ppDeducted = target.deductPP(move.id, 4);
|
||||
if (!ppDeducted) return false;
|
||||
this.add("-activate", target, 'move: Spite', lastMove.name, ppDeducted);
|
||||
this.add("-activate", target, 'move: Spite', move.name, ppDeducted);
|
||||
},
|
||||
},
|
||||
|
||||
|
|
@ -407,7 +472,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
this.add('-singlemove', pokemon, 'Destiny Bond');
|
||||
},
|
||||
onFaint(target, source, effect) {
|
||||
if (!source || !effect || target.side === source.side) return;
|
||||
if (!source || !effect || target.isAlly(source)) return;
|
||||
if (effect.effectType === 'Move' && !effect.flags['futuremove']) {
|
||||
if (source.volatiles['dynamax']) {
|
||||
this.add('-hint', "Dynamaxed Pokémon are immune to Destiny Bond.");
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
export const Scripts: ModdedBattleScriptsData = {
|
||||
inherit: 'gen8',
|
||||
gen: 8,
|
||||
gen: 9,
|
||||
getActionSpeed(action) {
|
||||
if (action.choice === 'move') {
|
||||
let move = action.move;
|
||||
|
|
@ -106,8 +105,9 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
// @ts-expect-error modded
|
||||
const linkedMoves: ActiveMove[] = action.linked;
|
||||
for (let i = linkedMoves.length - 1; i >= 0; i--) {
|
||||
const validTarget = this.validTargetLoc(action.targetLoc, action.pokemon, linkedMoves[i].target);
|
||||
const targetLoc = validTarget ? action.targetLoc : 0;
|
||||
const isValidTarget = this.validTargetLoc(action.targetLoc, action.pokemon, linkedMoves[i].target);
|
||||
const targetLoc = isValidTarget ? action.targetLoc :
|
||||
action.pokemon.getLocOf(this.getRandomTarget(action.pokemon, linkedMoves[i])!);
|
||||
const pseudoAction: Action = {
|
||||
choice: 'move', priority: action.priority, speed: action.speed, pokemon: action.pokemon,
|
||||
targetLoc, moveid: linkedMoves[i].id, move: linkedMoves[i], mega: action.mega,
|
||||
|
|
@ -334,15 +334,12 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
// THIS IS PURELY A SANITY CHECK
|
||||
// DO NOT TAKE ADVANTAGE OF THIS TO PREVENT A POKEMON FROM MOVING;
|
||||
// USE this.queue.cancelMove INSTEAD
|
||||
this.debug(`${pokemon.id} INCONSISTENT STATE, ALREADY MOVED: ${pokemon.moveThisTurn}`);
|
||||
this.clearActiveMove(true);
|
||||
this.battle.debug(`${pokemon.id} INCONSISTENT STATE, ALREADY MOVED: ${pokemon.moveThisTurn}`);
|
||||
this.battle.clearActiveMove(true);
|
||||
return;
|
||||
} */
|
||||
} */
|
||||
const willTryMove = this.battle.runEvent('BeforeMove', pokemon, target, move);
|
||||
if (!willTryMove) {
|
||||
if (pokemon.volatiles['twoturnmove']?.move === move.id) {
|
||||
pokemon.removeVolatile('twoturnmove');
|
||||
}
|
||||
this.battle.runEvent('MoveAborted', pokemon, target, move);
|
||||
this.battle.clearActiveMove(true);
|
||||
// The event 'BeforeMove' could have returned false or null
|
||||
|
|
@ -351,6 +348,12 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
pokemon.moveThisTurnResult = willTryMove;
|
||||
return;
|
||||
}
|
||||
|
||||
// Used exclusively for a hint later
|
||||
if (move.flags['cantusetwice'] && pokemon.m.lastMoveAbsolute?.id === move.id) {
|
||||
pokemon.addVolatile(move.id);
|
||||
}
|
||||
|
||||
if (move.beforeMoveCallback) {
|
||||
if (move.beforeMoveCallback.call(this.battle, pokemon, target, move)) {
|
||||
this.battle.clearActiveMove(true);
|
||||
|
|
@ -366,10 +369,6 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
if (!lockedMove) {
|
||||
if (!pokemon.deductPP(baseMove, null, target) && (move.id !== 'struggle')) {
|
||||
this.battle.add('cant', pokemon, 'nopp', move);
|
||||
const gameConsole = [
|
||||
null, 'Game Boy', 'Game Boy Color', 'Game Boy Advance', 'DS', 'DS', '3DS', '3DS',
|
||||
][this.battle.gen] || 'Switch';
|
||||
this.battle.hint(`This is not a bug, this is really how it works on the ${gameConsole}; try it yourself if you don't believe us.`);
|
||||
this.battle.clearActiveMove(true);
|
||||
pokemon.moveThisTurnResult = false;
|
||||
return;
|
||||
|
|
@ -382,7 +381,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
|
||||
// Dancer Petal Dance hack
|
||||
// TODO: implement properly
|
||||
const noLock = externalMove && !pokemon.volatiles.lockedmove;
|
||||
const noLock = externalMove && !pokemon.volatiles['lockedmove'];
|
||||
|
||||
if (zMove) {
|
||||
if (pokemon.illusion) {
|
||||
|
|
@ -391,12 +390,19 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
this.battle.add('-zpower', pokemon);
|
||||
pokemon.side.zMoveUsed = true;
|
||||
}
|
||||
|
||||
const oldActiveMove = move;
|
||||
|
||||
const moveDidSomething = this.useMove(baseMove, pokemon, { target, sourceEffect, zMove, maxMove });
|
||||
this.battle.lastSuccessfulMoveThisTurn = moveDidSomething ? this.battle.activeMove && this.battle.activeMove.id : null;
|
||||
if (this.battle.activeMove) move = this.battle.activeMove;
|
||||
this.battle.singleEvent('AfterMove', move, null, pokemon, target, move);
|
||||
this.battle.runEvent('AfterMove', pokemon, target, move);
|
||||
if (move.flags['cantusetwice'] && pokemon.removeVolatile(move.id)) {
|
||||
this.battle.add('-hint', `Some effects can force a Pokemon to use ${move.name} again in a row.`);
|
||||
}
|
||||
|
||||
// TODO: Refactor to use BattleQueue#prioritizeAction in onAnyAfterMove handlers
|
||||
// Dancer's activation order is completely different from any other event, so it's handled separately
|
||||
if (move.flags['dance'] && moveDidSomething && !move.isExternal) {
|
||||
const dancers = [];
|
||||
|
|
@ -410,20 +416,29 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
// Note that the speed stat used is after any volatile replacements like Speed Swap,
|
||||
// but before any multipliers like Agility or Choice Scarf
|
||||
// Ties go to whichever Pokemon has had the ability for the least amount of time
|
||||
dancers.sort((a, b) => -(b.storedStats['spe'] - a.storedStats['spe']) ||
|
||||
b.abilityState.effectOrder - a.abilityState.effectOrder);
|
||||
dancers.sort(
|
||||
(a, b) => -(b.storedStats['spe'] - a.storedStats['spe']) || b.abilityState.effectOrder - a.abilityState.effectOrder
|
||||
);
|
||||
const targetOf1stDance = this.battle.activeTarget!;
|
||||
for (const dancer of dancers) {
|
||||
if (this.battle.faintMessages()) break;
|
||||
if (dancer.fainted) continue;
|
||||
this.battle.add('-activate', dancer, 'ability: Dancer');
|
||||
const dancersTarget = !target!.isAlly(dancer) && pokemon.isAlly(dancer) ? target! : pokemon;
|
||||
this.runMove(move.id, dancer, dancer.getLocOf(dancersTarget),
|
||||
{ sourceEffect: this.dex.abilities.get('dancer'), externalMove: true });
|
||||
const dancersTarget = !targetOf1stDance.isAlly(dancer) && pokemon.isAlly(dancer) ?
|
||||
targetOf1stDance :
|
||||
pokemon;
|
||||
const dancersTargetLoc = dancer.getLocOf(dancersTarget);
|
||||
this.runMove(move.id, dancer, dancersTargetLoc, { sourceEffect: this.dex.abilities.get('dancer'), externalMove: true });
|
||||
}
|
||||
}
|
||||
if (noLock && pokemon.volatiles['lockedmove']) delete pokemon.volatiles['lockedmove'];
|
||||
this.battle.faintMessages();
|
||||
this.battle.checkWin();
|
||||
|
||||
if (this.battle.gen <= 4) {
|
||||
// In gen 4, the outermost move is considered the last move for Copycat
|
||||
this.battle.activeMove = oldActiveMove;
|
||||
}
|
||||
},
|
||||
},
|
||||
queue: {
|
||||
|
|
@ -441,13 +456,16 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
instaswitch: 3,
|
||||
beforeTurn: 4,
|
||||
beforeTurnMove: 5,
|
||||
revivalblessing: 6,
|
||||
|
||||
runUnnerve: 100,
|
||||
runSwitch: 101,
|
||||
// runPrimal: 102, (deprecated)
|
||||
switch: 103,
|
||||
megaEvo: 104,
|
||||
megaEvoX: 104,
|
||||
megaEvoY: 104,
|
||||
runDynamax: 105,
|
||||
terastallize: 106,
|
||||
priorityChargeMove: 107,
|
||||
|
||||
shift: 200,
|
||||
// default is 200 (for moves)
|
||||
|
|
@ -476,12 +494,37 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
pokemon: action.pokemon,
|
||||
}));
|
||||
}
|
||||
if (action.megax && !action.pokemon.isSkyDropped()) {
|
||||
actions.unshift(...this.resolveAction({
|
||||
choice: 'megaEvoX',
|
||||
pokemon: action.pokemon,
|
||||
}));
|
||||
}
|
||||
if (action.megay && !action.pokemon.isSkyDropped()) {
|
||||
actions.unshift(...this.resolveAction({
|
||||
choice: 'megaEvoY',
|
||||
pokemon: action.pokemon,
|
||||
}));
|
||||
}
|
||||
if (action.terastallize && !action.pokemon.terastallized) {
|
||||
actions.unshift(...this.resolveAction({
|
||||
choice: 'terastallize',
|
||||
pokemon: action.pokemon,
|
||||
}));
|
||||
}
|
||||
if (action.maxMove && !action.pokemon.volatiles['dynamax']) {
|
||||
actions.unshift(...this.resolveAction({
|
||||
choice: 'runDynamax',
|
||||
pokemon: action.pokemon,
|
||||
}));
|
||||
}
|
||||
if (!action.maxMove && !action.zmove && action.move.priorityChargeCallback) {
|
||||
actions.unshift(...this.resolveAction({
|
||||
choice: 'priorityChargeMove',
|
||||
pokemon: action.pokemon,
|
||||
move: action.move,
|
||||
}));
|
||||
}
|
||||
action.fractionalPriority = this.battle.runEvent('FractionalPriority', action.pokemon, null, action.move, 0);
|
||||
const linkedMoves: [string, string] = action.pokemon.getLinkedMoves();
|
||||
if (
|
||||
Loading…
Reference in New Issue
Block a user