@pkmn/sim 0.4.19 → 0.4.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/config/formats.js +752 -743
- package/build/config/formats.js.map +1 -1
- package/build/data/aliases.js +4 -4
- package/build/data/aliases.js.map +1 -1
- package/build/data/conditions.js +4 -1
- package/build/data/conditions.js.map +1 -1
- package/build/data/formats-data.js +27 -27
- package/build/data/formats-data.js.map +1 -1
- package/build/data/learnsets.js +10 -10
- package/build/data/learnsets.js.map +1 -1
- package/build/data/mods/gen1/moves.js +1 -1
- package/build/data/mods/gen1/moves.js.map +1 -1
- package/build/data/mods/gen1/scripts.js +18 -22
- package/build/data/mods/gen1/scripts.js.map +1 -1
- package/build/data/mods/gen2/scripts.js +16 -23
- package/build/data/mods/gen2/scripts.js.map +1 -1
- package/build/data/mods/gen3/moves.js +2 -1
- package/build/data/mods/gen3/moves.js.map +1 -1
- package/build/data/mods/gen4/conditions.js +6 -0
- package/build/data/mods/gen4/conditions.js.map +1 -1
- package/build/data/mods/gen4/moves.js +2 -1
- package/build/data/mods/gen4/moves.js.map +1 -1
- package/build/data/mods/gen4/scripts.js +2 -1
- package/build/data/mods/gen4/scripts.js.map +1 -1
- package/build/data/mods/gen6/conditions.js +4 -1
- package/build/data/mods/gen6/conditions.js.map +1 -1
- package/build/data/mods/gen7/formats-data.js +2 -2
- package/build/data/mods/gen7/formats-data.js.map +1 -1
- package/build/data/mods/gen7/moves.js +8 -0
- package/build/data/mods/gen7/moves.js.map +1 -1
- package/build/data/moves.js +26 -14
- package/build/data/moves.js.map +1 -1
- package/build/data/rulesets.js +258 -16
- package/build/data/rulesets.js.map +1 -1
- package/build/data/tags.js +3 -3
- package/build/data/tags.js.map +1 -1
- package/build/lib/streams.d.ts +1 -199
- package/build/lib/streams.js +11 -772
- package/build/lib/streams.js.map +1 -1
- package/build/sim/battle-actions.d.ts +1 -1
- package/build/sim/battle-actions.js +18 -42
- package/build/sim/battle-actions.js.map +1 -1
- package/build/sim/battle.d.ts +1 -0
- package/build/sim/battle.js +5 -0
- package/build/sim/battle.js.map +1 -1
- package/build/sim/dex-moves.d.ts +31 -11
- package/build/sim/dex-moves.js +4 -3
- package/build/sim/dex-moves.js.map +1 -1
- package/build/sim/dex-species.js +11 -1
- package/build/sim/dex-species.js.map +1 -1
- package/build/sim/exported-global-types.d.ts +4 -0
- package/build/sim/global-types.d.ts +4 -0
- package/build/sim/pokemon.js +1 -1
- package/build/sim/pokemon.js.map +1 -1
- package/build/sim/side.js +2 -2
- package/build/sim/side.js.map +1 -1
- package/build/sim/team-validator.d.ts +4 -0
- package/build/sim/team-validator.js +37 -11
- package/build/sim/team-validator.js.map +1 -1
- package/config/formats.ts +649 -630
- package/data/aliases.ts +4 -4
- package/data/conditions.ts +4 -1
- package/data/formats-data.ts +27 -27
- package/data/learnsets.ts +10 -10
- package/data/mods/gen1/moves.ts +1 -1
- package/data/mods/gen1/scripts.ts +23 -19
- package/data/mods/gen2/scripts.ts +20 -19
- package/data/mods/gen3/moves.ts +2 -1
- package/data/mods/gen4/conditions.ts +6 -0
- package/data/mods/gen4/moves.ts +2 -1
- package/data/mods/gen4/scripts.ts +1 -1
- package/data/mods/gen6/conditions.ts +4 -1
- package/data/mods/gen7/formats-data.ts +2 -2
- package/data/mods/gen7/moves.ts +8 -0
- package/data/moves.ts +23 -14
- package/data/rulesets.ts +235 -16
- package/data/tags.ts +3 -3
- package/lib/streams.ts +1 -874
- package/package.json +4 -3
- package/sim/battle-actions.ts +19 -40
- package/sim/battle.ts +6 -0
- package/sim/dex-moves.ts +35 -13
- package/sim/dex-species.ts +10 -1
- package/sim/exported-global-types.ts +4 -0
- package/sim/global-types.ts +4 -0
- package/sim/pokemon.ts +1 -1
- package/sim/side.ts +2 -2
- package/sim/team-validator.ts +41 -10
|
@@ -8,9 +8,12 @@ export const Conditions: {[k: string]: ModdedConditionData} = {
|
|
|
8
8
|
par: {
|
|
9
9
|
inherit: true,
|
|
10
10
|
onModifySpe(spe, pokemon) {
|
|
11
|
+
// Paralysis occurs after all other Speed modifiers, so evaluate all modifiers up to this point first
|
|
12
|
+
spe = this.finalModify(spe);
|
|
11
13
|
if (!pokemon.hasAbility('quickfeet')) {
|
|
12
|
-
|
|
14
|
+
spe = Math.floor(spe * 25 / 100);
|
|
13
15
|
}
|
|
16
|
+
return spe;
|
|
14
17
|
},
|
|
15
18
|
},
|
|
16
19
|
confusion: {
|
|
@@ -529,7 +529,7 @@ export const FormatsData: {[k: string]: ModdedSpeciesFormatsData} = {
|
|
|
529
529
|
doublesTier: "(DUU)",
|
|
530
530
|
},
|
|
531
531
|
farfetchd: {
|
|
532
|
-
randomBattleMoves: ["bravebird", "knockoff", "leafblade", "return", "
|
|
532
|
+
randomBattleMoves: ["bravebird", "knockoff", "leafblade", "return", "swordsdance"],
|
|
533
533
|
randomDoubleBattleMoves: ["bravebird", "knockoff", "leafblade", "protect", "return", "swordsdance"],
|
|
534
534
|
tier: "(PU)",
|
|
535
535
|
doublesTier: "(DUU)",
|
|
@@ -2486,7 +2486,7 @@ export const FormatsData: {[k: string]: ModdedSpeciesFormatsData} = {
|
|
|
2486
2486
|
tier: "LC",
|
|
2487
2487
|
},
|
|
2488
2488
|
gastrodon: {
|
|
2489
|
-
randomBattleMoves: ["
|
|
2489
|
+
randomBattleMoves: ["earthquake", "icebeam", "recover", "scald", "toxic"],
|
|
2490
2490
|
randomDoubleBattleMoves: ["earthpower", "icywind", "muddywater", "protect", "recover", "scald"],
|
|
2491
2491
|
tier: "PU",
|
|
2492
2492
|
doublesTier: "DOU",
|
package/data/mods/gen7/moves.ts
CHANGED
|
@@ -151,6 +151,10 @@ export const Moves: {[k: string]: ModdedMoveData} = {
|
|
|
151
151
|
inherit: true,
|
|
152
152
|
isNonstandard: null,
|
|
153
153
|
},
|
|
154
|
+
dive: {
|
|
155
|
+
inherit: true,
|
|
156
|
+
flags: {contact: 1, charge: 1, protect: 1, mirror: 1, nonsky: 1},
|
|
157
|
+
},
|
|
154
158
|
dizzypunch: {
|
|
155
159
|
inherit: true,
|
|
156
160
|
isNonstandard: null,
|
|
@@ -644,6 +648,10 @@ export const Moves: {[k: string]: ModdedMoveData} = {
|
|
|
644
648
|
inherit: true,
|
|
645
649
|
isNonstandard: null,
|
|
646
650
|
},
|
|
651
|
+
pollenpuff: {
|
|
652
|
+
inherit: true,
|
|
653
|
+
flags: {bullet: 1, protect: 1, mirror: 1},
|
|
654
|
+
},
|
|
647
655
|
powder: {
|
|
648
656
|
inherit: true,
|
|
649
657
|
isNonstandard: null,
|
package/data/moves.ts
CHANGED
|
@@ -1399,7 +1399,7 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
1399
1399
|
pp: 10,
|
|
1400
1400
|
priority: 0,
|
|
1401
1401
|
flags: {contact: 1, protect: 1, mirror: 1},
|
|
1402
|
-
|
|
1402
|
+
overrideOffensiveStat: 'def',
|
|
1403
1403
|
secondary: null,
|
|
1404
1404
|
target: "normal",
|
|
1405
1405
|
type: "Fighting",
|
|
@@ -2282,7 +2282,7 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
2282
2282
|
name: "Coaching",
|
|
2283
2283
|
pp: 10,
|
|
2284
2284
|
priority: 0,
|
|
2285
|
-
flags: {bypasssub: 1},
|
|
2285
|
+
flags: {bypasssub: 1, allyanim: 1},
|
|
2286
2286
|
secondary: null,
|
|
2287
2287
|
boosts: {
|
|
2288
2288
|
atk: 1,
|
|
@@ -3387,7 +3387,7 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
3387
3387
|
name: "Dive",
|
|
3388
3388
|
pp: 10,
|
|
3389
3389
|
priority: 0,
|
|
3390
|
-
flags: {contact: 1, charge: 1, protect: 1, mirror: 1, nonsky: 1},
|
|
3390
|
+
flags: {contact: 1, charge: 1, protect: 1, mirror: 1, nonsky: 1, allyanim: 1},
|
|
3391
3391
|
onTryMove(attacker, defender, move) {
|
|
3392
3392
|
if (attacker.removeVolatile(move.id)) {
|
|
3393
3393
|
return;
|
|
@@ -5621,7 +5621,7 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
5621
5621
|
pp: 15,
|
|
5622
5622
|
priority: 0,
|
|
5623
5623
|
flags: {contact: 1, protect: 1, mirror: 1},
|
|
5624
|
-
|
|
5624
|
+
overrideOffensivePokemon: 'target',
|
|
5625
5625
|
secondary: null,
|
|
5626
5626
|
target: "normal",
|
|
5627
5627
|
type: "Dark",
|
|
@@ -6509,9 +6509,9 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
6509
6509
|
flags: {},
|
|
6510
6510
|
isMax: "Melmetal",
|
|
6511
6511
|
self: {
|
|
6512
|
-
onHit(source) {
|
|
6512
|
+
onHit(source, target, effect) {
|
|
6513
6513
|
for (const pokemon of source.foes()) {
|
|
6514
|
-
if (!pokemon.volatiles['dynamax']) pokemon.addVolatile('torment');
|
|
6514
|
+
if (!pokemon.volatiles['dynamax']) pokemon.addVolatile('torment', source, effect);
|
|
6515
6515
|
}
|
|
6516
6516
|
},
|
|
6517
6517
|
},
|
|
@@ -7148,7 +7148,7 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
7148
7148
|
name: "Grassy Glide",
|
|
7149
7149
|
pp: 20,
|
|
7150
7150
|
priority: 0,
|
|
7151
|
-
flags: {contact: 1, protect: 1
|
|
7151
|
+
flags: {contact: 1, protect: 1},
|
|
7152
7152
|
onModifyPriority(priority, source, target, move) {
|
|
7153
7153
|
if (this.field.isTerrain('grassyterrain') && source.isGrounded()) {
|
|
7154
7154
|
return priority + 1;
|
|
@@ -10423,7 +10423,7 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
10423
10423
|
if (['gmaxoneblow', 'gmaxrapidflow'].includes(move.id)) return;
|
|
10424
10424
|
/** moves blocked by Max Guard but not Protect */
|
|
10425
10425
|
const overrideBypassProtect = [
|
|
10426
|
-
'block', 'flowershield', 'gearup', 'magneticflux', 'phantomforce', 'psychup', 'shadowforce', 'teatime', 'transform',
|
|
10426
|
+
'block', 'flowershield', 'gearup', 'magneticflux', 'phantomforce', 'psychup', 'shadowforce', 'teatime', 'transform', 'whirlwind',
|
|
10427
10427
|
];
|
|
10428
10428
|
const blockedByMaxGuard = (this.dex.moves.get(move.id).flags['protect'] ||
|
|
10429
10429
|
move.isZ || move.isMax || overrideBypassProtect.includes(move.id));
|
|
@@ -12727,7 +12727,7 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
12727
12727
|
name: "Pollen Puff",
|
|
12728
12728
|
pp: 15,
|
|
12729
12729
|
priority: 0,
|
|
12730
|
-
flags: {bullet: 1, protect: 1, mirror: 1},
|
|
12730
|
+
flags: {bullet: 1, protect: 1, mirror: 1, allyanim: 1},
|
|
12731
12731
|
onTryHit(target, source, move) {
|
|
12732
12732
|
if (source.isAlly(target)) {
|
|
12733
12733
|
move.basePower = 0;
|
|
@@ -13309,7 +13309,7 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
13309
13309
|
accuracy: 100,
|
|
13310
13310
|
basePower: 80,
|
|
13311
13311
|
category: "Special",
|
|
13312
|
-
|
|
13312
|
+
overrideDefensiveStat: 'def',
|
|
13313
13313
|
name: "Psyshock",
|
|
13314
13314
|
pp: 10,
|
|
13315
13315
|
priority: 0,
|
|
@@ -13324,7 +13324,7 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
13324
13324
|
accuracy: 100,
|
|
13325
13325
|
basePower: 100,
|
|
13326
13326
|
category: "Special",
|
|
13327
|
-
|
|
13327
|
+
overrideDefensiveStat: 'def',
|
|
13328
13328
|
name: "Psystrike",
|
|
13329
13329
|
pp: 10,
|
|
13330
13330
|
priority: 0,
|
|
@@ -14852,7 +14852,7 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
14852
14852
|
accuracy: 100,
|
|
14853
14853
|
basePower: 85,
|
|
14854
14854
|
category: "Special",
|
|
14855
|
-
|
|
14855
|
+
overrideDefensiveStat: 'def',
|
|
14856
14856
|
name: "Secret Sword",
|
|
14857
14857
|
pp: 10,
|
|
14858
14858
|
priority: 0,
|
|
@@ -18312,11 +18312,12 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
18312
18312
|
volatileStatus: 'torment',
|
|
18313
18313
|
condition: {
|
|
18314
18314
|
noCopy: true,
|
|
18315
|
-
onStart(pokemon) {
|
|
18315
|
+
onStart(pokemon, source, effect) {
|
|
18316
18316
|
if (pokemon.volatiles['dynamax']) {
|
|
18317
18317
|
delete pokemon.volatiles['torment'];
|
|
18318
18318
|
return false;
|
|
18319
18319
|
}
|
|
18320
|
+
if (effect?.id === 'gmaxmeltdown') this.effectState.duration = 3;
|
|
18320
18321
|
this.add('-start', pokemon, 'Torment');
|
|
18321
18322
|
},
|
|
18322
18323
|
onEnd(pokemon) {
|
|
@@ -19436,13 +19437,21 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
19436
19437
|
}
|
|
19437
19438
|
return 5;
|
|
19438
19439
|
},
|
|
19440
|
+
onModifyMove(move, source, target) {
|
|
19441
|
+
// This code is for moves that use defensive stats as the attacking stat; see below for most of the implementation
|
|
19442
|
+
if (!move.overrideOffensiveStat) return;
|
|
19443
|
+
const statAndBoosts = move.overrideOffensiveStat;
|
|
19444
|
+
if (!['def', 'spd'].includes(statAndBoosts)) return;
|
|
19445
|
+
move.overrideOffensiveStat = statAndBoosts === 'def' ? 'spd' : 'def';
|
|
19446
|
+
this.hint(`${move.name} uses ${statAndBoosts === 'def' ? '' : 'Sp. '}Def boosts when Wonder Room is active.`);
|
|
19447
|
+
},
|
|
19439
19448
|
onFieldStart(field, source) {
|
|
19440
19449
|
this.add('-fieldstart', 'move: Wonder Room', '[of] ' + source);
|
|
19441
19450
|
},
|
|
19442
19451
|
onFieldRestart(target, source) {
|
|
19443
19452
|
this.field.removePseudoWeather('wonderroom');
|
|
19444
19453
|
},
|
|
19445
|
-
// Swapping defenses implemented in sim/pokemon.js:Pokemon#calculateStat and Pokemon#getStat
|
|
19454
|
+
// Swapping defenses partially implemented in sim/pokemon.js:Pokemon#calculateStat and Pokemon#getStat
|
|
19446
19455
|
onFieldResidualOrder: 27,
|
|
19447
19456
|
onFieldResidualSubOrder: 5,
|
|
19448
19457
|
onFieldEnd() {
|
package/data/rulesets.ts
CHANGED
|
@@ -75,7 +75,7 @@ export const Rulesets: {[k: string]: FormatData} = {
|
|
|
75
75
|
name: 'Standard NatDex',
|
|
76
76
|
desc: "The standard ruleset for all National Dex tiers",
|
|
77
77
|
ruleset: [
|
|
78
|
-
'Obtainable', '+Unobtainable', '+Past', 'Team Preview', 'Nickname Clause', 'HP Percentage Mod', 'Cancel Mod', 'Endless Battle Clause',
|
|
78
|
+
'Obtainable', '+Unobtainable', '+Past', 'Sketch Gen 8 Moves', 'Team Preview', 'Nickname Clause', 'HP Percentage Mod', 'Cancel Mod', 'Endless Battle Clause',
|
|
79
79
|
],
|
|
80
80
|
onValidateSet(set) {
|
|
81
81
|
// These Pokemon are still unobtainable
|
|
@@ -280,9 +280,25 @@ export const Rulesets: {[k: string]: FormatData} = {
|
|
|
280
280
|
}
|
|
281
281
|
},
|
|
282
282
|
},
|
|
283
|
-
|
|
283
|
+
oldalolapokedex: {
|
|
284
284
|
effectType: 'ValidatorRule',
|
|
285
|
-
name: 'Alola Pokedex',
|
|
285
|
+
name: 'Old Alola Pokedex',
|
|
286
|
+
desc: "Only allows Pokémon native to the Alola region (SUMO)",
|
|
287
|
+
banlist: ['Pikachu-Partner', 'Marowak-Alola-Totem', 'Ribombee-Totem', 'Araquanid-Totem', 'Lycanroc-Dusk', 'Necrozma-Dusk-Mane', 'Necrozma-Dawn-Wings'],
|
|
288
|
+
onValidateSet(set, format) {
|
|
289
|
+
const alolaDex = [
|
|
290
|
+
"Rowlet", "Dartrix", "Decidueye", "Litten", "Torracat", "Incineroar", "Popplio", "Brionne", "Primarina", "Pikipek", "Trumbeak", "Toucannon", "Yungoos", "Gumshoos", "Rattata-Alola", "Raticate-Alola", "Caterpie", "Metapod", "Butterfree", "Ledyba", "Ledian", "Spinarak", "Ariados", "Pichu", "Pikachu", "Raichu-Alola", "Grubbin", "Charjabug", "Vikavolt", "Bonsly", "Sudowoodo", "Happiny", "Chansey", "Blissey", "Munchlax", "Snorlax", "Slowpoke", "Slowbro", "Slowking", "Wingull", "Pelipper", "Abra", "Kadabra", "Alakazam", "Meowth-Alola", "Persian-Alola", "Magnemite", "Magneton", "Magnezone", "Grimer-Alola", "Muk-Alola", "Growlithe", "Arcanine", "Drowzee", "Hypno", "Makuhita", "Hariyama", "Smeargle", "Crabrawler", "Crabominable", "Gastly", "Haunter", "Gengar", "Drifloon", "Drifblim", "Misdreavus", "Mismagius", "Zubat", "Golbat", "Crobat", "Diglett-Alola", "Dugtrio-Alola", "Spearow", "Fearow", "Rufflet", "Braviary", "Vullaby", "Mandibuzz", "Mankey", "Primeape", "Delibird", "Oricorio", "Cutiefly", "Ribombee", "Petilil", "Lilligant", "Cottonee", "Whimsicott", "Psyduck", "Golduck", "Magikarp", "Gyarados", "Barboach", "Whiscash", "Machop", "Machoke", "Machamp", "Roggenrola", "Boldore", "Gigalith", "Carbink", "Sableye", "Rockruff", "Lycanroc", "Spinda", "Tentacool", "Tentacruel", "Finneon", "Lumineon", "Wishiwashi", "Luvdisc", "Corsola", "Mareanie", "Toxapex", "Shellder", "Cloyster", "Bagon", "Shelgon", "Salamence", "Lillipup", "Herdier", "Stoutland", "Eevee", "Vaporeon", "Jolteon", "Flareon", "Espeon", "Umbreon", "Leafeon", "Glaceon", "Sylveon", "Mudbray", "Mudsdale", "Igglybuff", "Jigglypuff", "Wigglytuff", "Tauros", "Miltank", "Surskit", "Masquerain", "Dewpider", "Araquanid", "Fomantis", "Lurantis", "Morelull", "Shiinotic", "Paras", "Parasect", "Poliwag", "Poliwhirl", "Poliwrath", "Politoed", "Goldeen", "Seaking", "Feebas", "Milotic", "Alomomola", "Fletchling", "Fletchinder", "Talonflame", "Salandit", "Salazzle", "Cubone", "Marowak-Alola", "Kangaskhan", "Magby", "Magmar", "Magmortar", "Stufful", "Bewear", "Bounsweet", "Steenee", "Tsareena", "Comfey", "Pinsir", "Oranguru", "Passimian", "Goomy", "Sliggoo", "Goodra", "Castform", "Wimpod", "Golisopod", "Staryu", "Starmie", "Sandygast", "Palossand", "Cranidos", "Rampardos", "Shieldon", "Bastiodon", "Archen", "Archeops", "Tirtouga", "Carracosta", "Phantump", "Trevenant", "Nosepass", "Probopass", "Pyukumuku", "Chinchou", "Lanturn", "Type: Null", "Silvally", "Zygarde", "Trubbish", "Garbodor", "Skarmory", "Ditto", "Cleffa", "Clefairy", "Clefable", "Minior", "Beldum", "Metang", "Metagross", "Porygon", "Porygon2", "Porygon-Z", "Pancham", "Pangoro", "Komala", "Torkoal", "Turtonator", "Togedemaru", "Elekid", "Electabuzz", "Electivire", "Geodude-Alola", "Graveler-Alola", "Golem-Alola", "Sandile", "Krokorok", "Krookodile", "Trapinch", "Vibrava", "Flygon", "Gible", "Gabite", "Garchomp", "Klefki", "Mimikyu", "Bruxish", "Drampa", "Absol", "Snorunt", "Glalie", "Froslass", "Sneasel", "Weavile", "Sandshrew-Alola", "Sandslash-Alola", "Vulpix-Alola", "Ninetales-Alola", "Vanillite", "Vanillish", "Vanilluxe", "Snubbull", "Granbull", "Shellos", "Gastrodon", "Relicanth", "Dhelmise", "Carvanha", "Sharpedo", "Wailmer", "Wailord", "Lapras", "Exeggcute", "Exeggutor-Alola", "Jangmo-o", "Hakamo-o", "Kommo-o", "Emolga", "Scyther", "Scizor", "Murkrow", "Honchkrow", "Riolu", "Lucario", "Dratini", "Dragonair", "Dragonite", "Aerodactyl", "Tapu Koko", "Tapu Lele", "Tapu Bulu", "Tapu Fini", "Cosmog", "Cosmoem", "Solgaleo", "Lunala", "Nihilego", "Buzzwole", "Pheromosa", "Xurkitree", "Celesteela", "Kartana", "Guzzlord", "Necrozma", "Magearna", "Marshadow",
|
|
291
|
+
];
|
|
292
|
+
const species = this.dex.species.get(set.species || set.name);
|
|
293
|
+
if (!alolaDex.includes(species.baseSpecies) && !alolaDex.includes(species.name) &&
|
|
294
|
+
!this.ruleTable.has('+' + species.id)) {
|
|
295
|
+
return [`${species.baseSpecies} is not in the Old Alola Pokédex.`];
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
newalolapokedex: {
|
|
300
|
+
effectType: 'ValidatorRule',
|
|
301
|
+
name: 'New Alola Pokedex',
|
|
286
302
|
desc: "Only allows Pokémon native to the Alola region (US/UM)",
|
|
287
303
|
onValidateSet(set, format) {
|
|
288
304
|
const alolaDex = [
|
|
@@ -291,7 +307,7 @@ export const Rulesets: {[k: string]: FormatData} = {
|
|
|
291
307
|
const species = this.dex.species.get(set.species || set.name);
|
|
292
308
|
if (!alolaDex.includes(species.baseSpecies) && !alolaDex.includes(species.name) &&
|
|
293
309
|
!this.ruleTable.has('+' + species.id)) {
|
|
294
|
-
return [`${species.baseSpecies} is not in the Alola Pokédex.`];
|
|
310
|
+
return [`${species.baseSpecies} is not in the New Alola Pokédex.`];
|
|
295
311
|
}
|
|
296
312
|
},
|
|
297
313
|
},
|
|
@@ -550,6 +566,7 @@ export const Rulesets: {[k: string]: FormatData} = {
|
|
|
550
566
|
this.add('rule', '2 Ability Clause: Limit two of each ability');
|
|
551
567
|
},
|
|
552
568
|
onValidateTeam(team) {
|
|
569
|
+
if (this.format.id === 'gen8multibility') return;
|
|
553
570
|
const abilityTable = new Map<string, number>();
|
|
554
571
|
const base: {[k: string]: string} = {
|
|
555
572
|
airlock: 'cloudnine',
|
|
@@ -960,16 +977,14 @@ export const Rulesets: {[k: string]: FormatData} = {
|
|
|
960
977
|
} else {
|
|
961
978
|
typeTable = typeTable.filter(type => species.types.includes(type));
|
|
962
979
|
}
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
typeTable = typeTable.filter(type => species.types.includes(type));
|
|
972
|
-
}
|
|
980
|
+
const item = this.dex.items.get(set.item);
|
|
981
|
+
if (item.megaStone && species.baseSpecies === item.megaEvolves) {
|
|
982
|
+
species = this.dex.species.get(item.megaStone);
|
|
983
|
+
typeTable = typeTable.filter(type => species.types.includes(type));
|
|
984
|
+
}
|
|
985
|
+
if (item.id === "ultranecroziumz" && species.baseSpecies === "Necrozma") {
|
|
986
|
+
species = this.dex.species.get("Necrozma-Ultra");
|
|
987
|
+
typeTable = typeTable.filter(type => species.types.includes(type));
|
|
973
988
|
}
|
|
974
989
|
if (!typeTable.length) return [`Your team must share a type.`];
|
|
975
990
|
}
|
|
@@ -1074,7 +1089,9 @@ export const Rulesets: {[k: string]: FormatData} = {
|
|
|
1074
1089
|
if (!nonstandard && !move.isZ && !move.isMax && !this.ruleTable.isRestricted(`move:${move.id}`)) {
|
|
1075
1090
|
const speciesTypes: string[] = [];
|
|
1076
1091
|
const moveTypes: string[] = [];
|
|
1077
|
-
|
|
1092
|
+
// BDSP can't import Pokemon from Home, so it shouldn't grant moves from archaic species types
|
|
1093
|
+
const minObtainableSpeciesGen = this.dex.currentMod === 'gen8bdsp' ? this.dex.gen : species.gen;
|
|
1094
|
+
for (let i = this.dex.gen; i >= minObtainableSpeciesGen && i >= move.gen; i--) {
|
|
1078
1095
|
const dex = this.dex.forGen(i);
|
|
1079
1096
|
moveTypes.push(dex.moves.get(move.name).type);
|
|
1080
1097
|
|
|
@@ -1188,6 +1205,12 @@ export const Rulesets: {[k: string]: FormatData} = {
|
|
|
1188
1205
|
}
|
|
1189
1206
|
},
|
|
1190
1207
|
},
|
|
1208
|
+
'sketchgen8moves': {
|
|
1209
|
+
effectType: 'ValidatorRule',
|
|
1210
|
+
name: 'Sketch Gen 8 Moves',
|
|
1211
|
+
desc: "Allows Pokémon who learn Sketch to learn any Gen 8 move (normally, Sketch is not usable in Gen 8).",
|
|
1212
|
+
// Implemented in sim/team-validator.ts
|
|
1213
|
+
},
|
|
1191
1214
|
mimicglitch: {
|
|
1192
1215
|
effectType: 'ValidatorRule',
|
|
1193
1216
|
name: 'Mimic Glitch',
|
|
@@ -1371,7 +1394,7 @@ export const Rulesets: {[k: string]: FormatData} = {
|
|
|
1371
1394
|
hasValue: 'positive-integer',
|
|
1372
1395
|
// hardcoded in sim/side
|
|
1373
1396
|
onValidateRule() {
|
|
1374
|
-
if (!this.ruleTable.has('teampreview')) {
|
|
1397
|
+
if (!(this.ruleTable.has('teampreview') || this.ruleTable.has('teamtypepreview'))) {
|
|
1375
1398
|
throw new Error(`The "Picked Team Size" rule${this.ruleTable.blame('pickedteamsize')} requires Team Preview.`);
|
|
1376
1399
|
}
|
|
1377
1400
|
},
|
|
@@ -1603,4 +1626,200 @@ export const Rulesets: {[k: string]: FormatData} = {
|
|
|
1603
1626
|
this.lose(target.side);
|
|
1604
1627
|
},
|
|
1605
1628
|
},
|
|
1629
|
+
tiershiftmod: {
|
|
1630
|
+
effectType: "Rule",
|
|
1631
|
+
name: "Tier Shift Mod",
|
|
1632
|
+
desc: `Pokémon below OU get their stats, excluding HP, boosted. UU/RUBL get +10, RU/NUBL get +20, NU/PUBL get +30, and PU or lower get +40.`,
|
|
1633
|
+
ruleset: ['Overflow Stat Mod'],
|
|
1634
|
+
onBegin() {
|
|
1635
|
+
this.add('rule', 'Tier Shift Mod: Pok\u00e9mon get stat buffs depending on their tier, excluding HP.');
|
|
1636
|
+
},
|
|
1637
|
+
onModifySpecies(species, target, source, effect) {
|
|
1638
|
+
if (!species.baseStats) return;
|
|
1639
|
+
const boosts: {[tier: string]: number} = {
|
|
1640
|
+
uu: 10,
|
|
1641
|
+
rubl: 10,
|
|
1642
|
+
ru: 20,
|
|
1643
|
+
nubl: 20,
|
|
1644
|
+
nu: 30,
|
|
1645
|
+
publ: 30,
|
|
1646
|
+
pu: 40,
|
|
1647
|
+
nfe: 40,
|
|
1648
|
+
lc: 40,
|
|
1649
|
+
};
|
|
1650
|
+
let tier: string = this.toID(species.tier);
|
|
1651
|
+
if (!(tier in boosts)) return;
|
|
1652
|
+
// Non-Pokemon bans in lower tiers
|
|
1653
|
+
if (target) {
|
|
1654
|
+
if (target.set.item === 'lightclay') return;
|
|
1655
|
+
if (['drizzle', 'drought', 'snowwarning'].includes(target.set.ability) && boosts[tier] > 20) tier = 'nubl';
|
|
1656
|
+
}
|
|
1657
|
+
const pokemon = this.dex.deepClone(species);
|
|
1658
|
+
pokemon.bst = pokemon.baseStats['hp'];
|
|
1659
|
+
const boost = boosts[tier];
|
|
1660
|
+
let statName: StatID;
|
|
1661
|
+
for (statName in pokemon.baseStats as StatsTable) {
|
|
1662
|
+
if (statName === 'hp') continue;
|
|
1663
|
+
pokemon.baseStats[statName] = this.clampIntRange(pokemon.baseStats[statName] + boost, 1, 255);
|
|
1664
|
+
pokemon.bst += pokemon.baseStats[statName];
|
|
1665
|
+
}
|
|
1666
|
+
return pokemon;
|
|
1667
|
+
},
|
|
1668
|
+
},
|
|
1669
|
+
crossevolutionmod: {
|
|
1670
|
+
effectType: "Rule",
|
|
1671
|
+
name: "Cross Evolution Mod",
|
|
1672
|
+
desc: "Give a Pokémon a Pokémon name of the next evolution stage as a nickname to inherit stat changes, typing, abilities, and up to 2 moves from the next stage Pokémon.",
|
|
1673
|
+
ruleset: ['Overflow Stat Mod'],
|
|
1674
|
+
onValidateTeam(team) {
|
|
1675
|
+
const names = new Set<ID>();
|
|
1676
|
+
for (const set of team) {
|
|
1677
|
+
const name = set.name;
|
|
1678
|
+
if (names.has(this.dex.toID(name))) {
|
|
1679
|
+
return [
|
|
1680
|
+
`Your Pok\u00e9mon must have different nicknames.`,
|
|
1681
|
+
`(You have more than one Pok\u00e9mon named '${name}')`,
|
|
1682
|
+
];
|
|
1683
|
+
}
|
|
1684
|
+
names.add(this.dex.toID(name));
|
|
1685
|
+
}
|
|
1686
|
+
if (!names.size) {
|
|
1687
|
+
return [
|
|
1688
|
+
`${this.format.name} works using nicknames; your team has 0 nicknamed Pok\u00e9mon.`,
|
|
1689
|
+
`(If this was intentional, add a nickname to one Pok\u00e9mon that isn't the name of a Pok\u00e9mon species.)`,
|
|
1690
|
+
];
|
|
1691
|
+
}
|
|
1692
|
+
},
|
|
1693
|
+
checkCanLearn(move, species, lsetData, set) {
|
|
1694
|
+
// @ts-ignore
|
|
1695
|
+
if (!set.sp?.exists || !set.crossSpecies?.exists) {
|
|
1696
|
+
return this.checkCanLearn(move, species, lsetData, set);
|
|
1697
|
+
}
|
|
1698
|
+
// @ts-ignore
|
|
1699
|
+
const problem = this.checkCanLearn(move, set.sp);
|
|
1700
|
+
if (!problem) return null;
|
|
1701
|
+
// @ts-ignore
|
|
1702
|
+
if (!set.crossMovesLeft) return problem;
|
|
1703
|
+
// @ts-ignore
|
|
1704
|
+
if (this.checkCanLearn(move, set.crossSpecies)) return problem;
|
|
1705
|
+
// @ts-ignore
|
|
1706
|
+
set.crossMovesLeft--;
|
|
1707
|
+
return null;
|
|
1708
|
+
},
|
|
1709
|
+
validateSet(set, teamHas) {
|
|
1710
|
+
const crossSpecies = this.dex.species.get(set.name);
|
|
1711
|
+
const onChangeSet = this.dex.formats.get('Pokemon').onChangeSet;
|
|
1712
|
+
let problems = onChangeSet?.call(this, set, this.format) || null;
|
|
1713
|
+
if (Array.isArray(problems) && problems.length) return problems;
|
|
1714
|
+
const crossNonstandard = !this.ruleTable.has('standardnatdex') && crossSpecies.isNonstandard === 'Past';
|
|
1715
|
+
const crossIsCap = !this.ruleTable.has('+pokemontag:cap') && crossSpecies.isNonstandard === 'CAP';
|
|
1716
|
+
if (!crossSpecies.exists || crossNonstandard || crossIsCap) return this.validateSet(set, teamHas);
|
|
1717
|
+
const species = this.dex.species.get(set.species);
|
|
1718
|
+
const check = this.checkSpecies(set, species, species, {});
|
|
1719
|
+
if (check) return [check];
|
|
1720
|
+
const nonstandard = !this.ruleTable.has('standardnatdex') && species.isNonstandard === 'Past';
|
|
1721
|
+
const isCap = !this.ruleTable.has('+pokemontag:cap') && species.isNonstandard === 'CAP';
|
|
1722
|
+
if (!species.exists || nonstandard || isCap || species === crossSpecies) return this.validateSet(set, teamHas);
|
|
1723
|
+
if (!species.nfe) return [`${species.name} cannot cross evolve because it doesn't evolve.`];
|
|
1724
|
+
const crossIsUnreleased = (crossSpecies.tier === "Unreleased" && crossSpecies.isNonstandard === "Unobtainable");
|
|
1725
|
+
if (crossSpecies.battleOnly || crossIsUnreleased || !crossSpecies.prevo) {
|
|
1726
|
+
return [`${species.name} cannot cross evolve into ${crossSpecies.name} because it isn't an evolution.`];
|
|
1727
|
+
}
|
|
1728
|
+
if (this.ruleTable.isRestrictedSpecies(crossSpecies)) {
|
|
1729
|
+
return [`${species.name} cannot cross evolve into ${crossSpecies.name} because it is banned.`];
|
|
1730
|
+
}
|
|
1731
|
+
const crossPrevoSpecies = this.dex.species.get(crossSpecies.prevo);
|
|
1732
|
+
if (!crossPrevoSpecies.prevo !== !species.prevo) {
|
|
1733
|
+
return [
|
|
1734
|
+
`${species.name} cannot cross evolve into ${crossSpecies.name} because they are not consecutive evolution stages.`,
|
|
1735
|
+
];
|
|
1736
|
+
}
|
|
1737
|
+
const ability = this.dex.abilities.get(set.ability);
|
|
1738
|
+
if (!this.ruleTable.isRestricted(`ability:${ability.id}`) || Object.values(species.abilities).includes(ability.name)) {
|
|
1739
|
+
set.species = crossSpecies.name;
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
// @ts-ignore
|
|
1743
|
+
set.sp = species;
|
|
1744
|
+
// @ts-ignore
|
|
1745
|
+
set.crossSpecies = crossSpecies;
|
|
1746
|
+
// @ts-ignore
|
|
1747
|
+
set.crossMovesLeft = 2;
|
|
1748
|
+
problems = this.validateSet(set, teamHas);
|
|
1749
|
+
set.name = crossSpecies.name;
|
|
1750
|
+
set.species = species.name;
|
|
1751
|
+
return problems;
|
|
1752
|
+
},
|
|
1753
|
+
onModifySpecies(species, target, source, effect) {
|
|
1754
|
+
if (!target) return; // chat
|
|
1755
|
+
if (effect && ['imposter', 'transform'].includes(effect.id)) return;
|
|
1756
|
+
if (target.set.name === target.set.species) return;
|
|
1757
|
+
const crossSpecies = this.dex.species.get(target.set.name);
|
|
1758
|
+
if (!crossSpecies.exists) return;
|
|
1759
|
+
if (species.battleOnly || !species.nfe) return;
|
|
1760
|
+
const crossIsUnreleased = (crossSpecies.tier === "Unreleased" && crossSpecies.isNonstandard === "Unobtainable");
|
|
1761
|
+
if (crossSpecies.battleOnly || crossIsUnreleased || !crossSpecies.prevo) return;
|
|
1762
|
+
const crossPrevoSpecies = this.dex.species.get(crossSpecies.prevo);
|
|
1763
|
+
if (!crossPrevoSpecies.prevo !== !species.prevo) return;
|
|
1764
|
+
|
|
1765
|
+
const mixedSpecies = this.dex.deepClone(species);
|
|
1766
|
+
mixedSpecies.baseSpecies = mixedSpecies.name = `${species.name}-${crossSpecies.name}`;
|
|
1767
|
+
mixedSpecies.weightkg =
|
|
1768
|
+
Math.max(0.1, +(species.weightkg + crossSpecies.weightkg - crossPrevoSpecies.weightkg)).toFixed(1);
|
|
1769
|
+
mixedSpecies.nfe = false;
|
|
1770
|
+
mixedSpecies.evos = [];
|
|
1771
|
+
mixedSpecies.eggGroups = crossSpecies.eggGroups;
|
|
1772
|
+
mixedSpecies.abilities = crossSpecies.abilities;
|
|
1773
|
+
mixedSpecies.bst = 0;
|
|
1774
|
+
let i: StatID;
|
|
1775
|
+
for (i in species.baseStats) {
|
|
1776
|
+
const statChange = crossSpecies.baseStats[i] - crossPrevoSpecies.baseStats[i];
|
|
1777
|
+
mixedSpecies.baseStats[i] = this.clampIntRange(species.baseStats[i] + statChange, 1, 255);
|
|
1778
|
+
mixedSpecies.bst += mixedSpecies.baseStats[i];
|
|
1779
|
+
}
|
|
1780
|
+
if (crossSpecies.types[0] !== crossPrevoSpecies.types[0]) mixedSpecies.types[0] = crossSpecies.types[0];
|
|
1781
|
+
if (crossSpecies.types[1] !== crossPrevoSpecies.types[1]) {
|
|
1782
|
+
mixedSpecies.types[1] = crossSpecies.types[1] || crossSpecies.types[0];
|
|
1783
|
+
}
|
|
1784
|
+
if (mixedSpecies.types[0] === mixedSpecies.types[1]) mixedSpecies.types = [mixedSpecies.types[0]];
|
|
1785
|
+
|
|
1786
|
+
return mixedSpecies;
|
|
1787
|
+
},
|
|
1788
|
+
onBegin() {
|
|
1789
|
+
for (const pokemon of this.getAllPokemon()) {
|
|
1790
|
+
pokemon.baseSpecies = pokemon.species;
|
|
1791
|
+
}
|
|
1792
|
+
},
|
|
1793
|
+
},
|
|
1794
|
+
revelationmonsmod: {
|
|
1795
|
+
effectType: "Rule",
|
|
1796
|
+
name: "Revelationmons Mod",
|
|
1797
|
+
desc: `The moves in the first slot(s) of a Pokémon's set have their types changed to match the Pokémon's type(s).`,
|
|
1798
|
+
onBegin() {
|
|
1799
|
+
this.add('rule', 'Revelationmons Mod: The first moveslots have their types changed to match the Pokémon\'s types');
|
|
1800
|
+
},
|
|
1801
|
+
onValidateSet(set) {
|
|
1802
|
+
const species = this.dex.species.get(set.species);
|
|
1803
|
+
const slotIndex = species.types.length - 1;
|
|
1804
|
+
const problems = [];
|
|
1805
|
+
for (const [i, moveid] of set.moves.entries()) {
|
|
1806
|
+
const move = this.dex.moves.get(moveid);
|
|
1807
|
+
if (!this.ruleTable.isRestricted(`move:${move.id}`)) continue;
|
|
1808
|
+
if (i <= slotIndex) {
|
|
1809
|
+
problems.push(`${move.name} can't be in moveslot ${i + 1} because it's restricted from being in the first ${slotIndex + 1 > 1 ? `${slotIndex + 1} slots` : 'slot'}.`);
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
return problems;
|
|
1813
|
+
},
|
|
1814
|
+
onModifyMove(move, pokemon, target) {
|
|
1815
|
+
const types = pokemon.getTypes(true);
|
|
1816
|
+
const noModifyType = [
|
|
1817
|
+
'judgment', 'multiattack', 'naturalgift', 'revelationdance', 'technoblast', 'terrainpulse', 'weatherball',
|
|
1818
|
+
];
|
|
1819
|
+
if (noModifyType.includes(move.id)) return;
|
|
1820
|
+
for (const [i, type] of types.entries()) {
|
|
1821
|
+
if (pokemon.moveSlots[i] && move.id === pokemon.moveSlots[i].id) move.type = type;
|
|
1822
|
+
}
|
|
1823
|
+
},
|
|
1824
|
+
},
|
|
1606
1825
|
};
|
package/data/tags.ts
CHANGED
|
@@ -196,8 +196,8 @@ export const Tags: {[id: string]: TagData} = {
|
|
|
196
196
|
name: "ND UUBL",
|
|
197
197
|
speciesFilter: species => [
|
|
198
198
|
'Aerodactyl-Mega', 'Azumarill', 'Blacephalon', 'Diancie-Mega', 'Gallade-Mega', 'Gardevoir-Mega', 'Gengar', 'Gyarados', 'Gyarados-Mega',
|
|
199
|
-
'Hawlucha', 'Heracross-Mega', 'Hoopa-Unbound', 'Hydreigon', 'Jirachi', 'Latias', 'Latias-Mega', 'Latios', 'Latios-Mega', 'Manaphy',
|
|
200
|
-
'Pinsir-Mega', 'Sableye-Mega', 'Slowbro-Mega', 'Thundurus', 'Thundurus-Therian', 'Venusaur-Mega', 'Xurkitree', 'Zapdos-Galar',
|
|
199
|
+
'Hawlucha', 'Heracross-Mega', 'Hoopa-Unbound', 'Hydreigon', 'Jirachi', 'Latias', 'Latias-Mega', 'Latios', 'Latios-Mega', 'Manaphy', 'Mew',
|
|
200
|
+
'Pinsir-Mega', 'Sableye-Mega', 'Slowbro-Mega', 'Slowking-Galar', 'Thundurus', 'Thundurus-Therian', 'Venusaur-Mega', 'Xurkitree', 'Zapdos-Galar',
|
|
201
201
|
].includes(species.name),
|
|
202
202
|
},
|
|
203
203
|
|
|
@@ -209,7 +209,7 @@ export const Tags: {[id: string]: TagData} = {
|
|
|
209
209
|
},
|
|
210
210
|
dou: {
|
|
211
211
|
name: "DOU",
|
|
212
|
-
speciesFilter: species => species.doublesTier === 'DOU',
|
|
212
|
+
speciesFilter: species => species.doublesTier === 'DOU' || species.doublesTier === '(DOU)',
|
|
213
213
|
},
|
|
214
214
|
dbl: {
|
|
215
215
|
name: "DBL",
|