@pkmn/sim 0.5.28 → 0.6.2
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/README.md +3 -2
- package/build/config/formats.js +72 -105
- package/build/config/formats.js.map +1 -1
- package/build/data/abilities.js +4 -0
- package/build/data/abilities.js.map +1 -1
- package/build/data/aliases.js +2 -2
- package/build/data/aliases.js.map +1 -1
- package/build/data/formats-data.js +111 -115
- package/build/data/formats-data.js.map +1 -1
- package/build/data/items.js +7 -1
- package/build/data/items.js.map +1 -1
- package/build/data/learnsets.js +3 -2
- package/build/data/learnsets.js.map +1 -1
- package/build/data/mods/gen1/moves.js +0 -10
- package/build/data/mods/gen1/moves.js.map +1 -1
- package/build/data/mods/gen1/scripts.js +15 -14
- package/build/data/mods/gen1/scripts.js.map +1 -1
- package/build/data/mods/gen2/formats-data.js +2 -2
- package/build/data/mods/gen2/formats-data.js.map +1 -1
- package/build/data/mods/gen2/moves.js +0 -1
- package/build/data/mods/gen2/moves.js.map +1 -1
- package/build/data/moves.js +44 -25
- package/build/data/moves.js.map +1 -1
- package/build/data/pokedex.js +1 -1
- package/build/sim/dex-conditions.d.ts +1 -0
- package/build/sim/dex-conditions.js.map +1 -1
- package/build/sim/dex.js +2 -2
- package/build/sim/dex.js.map +1 -1
- package/build/sim/field.js +1 -0
- package/build/sim/field.js.map +1 -1
- package/build/sim/pokemon.js +2 -10
- package/build/sim/pokemon.js.map +1 -1
- package/build/sim/team-validator.d.ts +2 -2
- package/build/sim/team-validator.js +19 -14
- package/build/sim/team-validator.js.map +1 -1
- package/config/formats.ts +75 -110
- package/data/abilities.ts +4 -0
- package/data/aliases.ts +2 -2
- package/data/formats-data.ts +111 -115
- package/data/items.ts +7 -1
- package/data/learnsets.ts +3 -2
- package/data/mods/gen1/moves.ts +0 -10
- package/data/mods/gen1/scripts.ts +14 -14
- package/data/mods/gen2/formats-data.ts +2 -2
- package/data/mods/gen2/moves.ts +0 -1
- package/data/moves.ts +43 -23
- package/data/pokedex.ts +1 -1
- package/package.json +3 -3
- package/sim/dex-conditions.ts +1 -0
- package/sim/dex.ts +1 -1
- package/sim/field.ts +1 -0
- package/sim/pokemon.ts +1 -8
- package/sim/team-validator.ts +27 -15
package/data/items.ts
CHANGED
|
@@ -4576,7 +4576,13 @@ export const Items: {[itemid: string]: ItemData} = {
|
|
|
4576
4576
|
fling: {
|
|
4577
4577
|
basePower: 100,
|
|
4578
4578
|
},
|
|
4579
|
-
|
|
4579
|
+
onStart(pokemon) {
|
|
4580
|
+
if (!pokemon.ignoringItem() && this.field.getPseudoWeather('trickroom')) {
|
|
4581
|
+
pokemon.useItem();
|
|
4582
|
+
}
|
|
4583
|
+
},
|
|
4584
|
+
onAnyPseudoWeatherStart() {
|
|
4585
|
+
const pokemon = this.effectState.target;
|
|
4580
4586
|
if (this.field.getPseudoWeather('trickroom')) {
|
|
4581
4587
|
pokemon.useItem();
|
|
4582
4588
|
}
|
package/data/learnsets.ts
CHANGED
|
@@ -79223,7 +79223,7 @@ export const Learnsets: {[speciesid: string]: LearnsetData} = {
|
|
|
79223
79223
|
blizzard: ["8M"],
|
|
79224
79224
|
bodyslam: ["8M"],
|
|
79225
79225
|
boomburst: ["8L75"],
|
|
79226
|
-
calmmind: ["8M"
|
|
79226
|
+
calmmind: ["8M"],
|
|
79227
79227
|
charm: ["8M"],
|
|
79228
79228
|
crunch: ["8M", "8L35"],
|
|
79229
79229
|
darkpulse: ["8M", "8S0"],
|
|
@@ -79271,6 +79271,7 @@ export const Learnsets: {[speciesid: string]: LearnsetData} = {
|
|
|
79271
79271
|
stompingtantrum: ["8M", "8L30"],
|
|
79272
79272
|
substitute: ["8M"],
|
|
79273
79273
|
sunnyday: ["8M"],
|
|
79274
|
+
switcheroo: ["8S0"],
|
|
79274
79275
|
taunt: ["8M"],
|
|
79275
79276
|
thief: ["8M"],
|
|
79276
79277
|
thunder: ["8M"],
|
|
@@ -79283,7 +79284,7 @@ export const Learnsets: {[speciesid: string]: LearnsetData} = {
|
|
|
79283
79284
|
wideguard: ["8L50"],
|
|
79284
79285
|
},
|
|
79285
79286
|
eventData: [
|
|
79286
|
-
{generation: 8, level: 50, moves: ["recover", "
|
|
79287
|
+
{generation: 8, level: 50, moves: ["recover", "switcheroo", "darkpulse", "belch"], pokeball: "cherishball"},
|
|
79287
79288
|
],
|
|
79288
79289
|
},
|
|
79289
79290
|
syclant: {
|
package/data/mods/gen1/moves.ts
CHANGED
|
@@ -884,16 +884,6 @@ export const Moves: {[k: string]: ModdedMoveData} = {
|
|
|
884
884
|
status: 'par',
|
|
885
885
|
},
|
|
886
886
|
},
|
|
887
|
-
thunderwave: {
|
|
888
|
-
inherit: true,
|
|
889
|
-
accuracy: 100,
|
|
890
|
-
onTryHit(target) {
|
|
891
|
-
if (target.hasType('Ground')) {
|
|
892
|
-
this.add('-immune', target);
|
|
893
|
-
return null;
|
|
894
|
-
}
|
|
895
|
-
},
|
|
896
|
-
},
|
|
897
887
|
triattack: {
|
|
898
888
|
inherit: true,
|
|
899
889
|
onHit() {},
|
|
@@ -18,7 +18,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|
|
18
18
|
getStat(statName, unmodified) {
|
|
19
19
|
// @ts-ignore - type checking prevents 'hp' from being passed, but we're paranoid
|
|
20
20
|
if (statName === 'hp') throw new Error("Please read `maxhp` directly");
|
|
21
|
-
if (unmodified) return this.
|
|
21
|
+
if (unmodified) return this.baseStoredStats[statName];
|
|
22
22
|
return this.modifiedStats![statName];
|
|
23
23
|
},
|
|
24
24
|
// Gen 1 function to apply a stat modification that is only active until the stat is recalculated or mon switched.
|
|
@@ -46,9 +46,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|
|
46
46
|
changed = true;
|
|
47
47
|
// Recalculate the modified stat
|
|
48
48
|
if (i === 'evasion' || i === 'accuracy') continue;
|
|
49
|
-
|
|
50
|
-
stat = Math.floor(Math.floor(2 * stat + this.set.ivs[i] + Math.floor(this.set.evs[i] / 4)) * this.level / 100 + 5);
|
|
51
|
-
this.modifiedStats![i] = this.storedStats[i] = Math.floor(stat);
|
|
49
|
+
this.modifiedStats![i] = this.storedStats[i];
|
|
52
50
|
if (this.boosts[i] >= 0) {
|
|
53
51
|
this.modifyStat!(i, [1, 1.5, 2, 2.5, 3, 3.5, 4][this.boosts[i]]);
|
|
54
52
|
} else {
|
|
@@ -63,9 +61,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|
|
63
61
|
this.boosts[i] = 0;
|
|
64
62
|
// Recalculate the modified stat
|
|
65
63
|
if (i === 'evasion' || i === 'accuracy') continue;
|
|
66
|
-
|
|
67
|
-
stat = Math.floor(Math.floor(2 * stat + this.set.ivs[i] + Math.floor(this.set.evs[i] / 4)) * this.level / 100 + 5);
|
|
68
|
-
this.modifiedStats![i] = this.storedStats[i] = Math.floor(stat);
|
|
64
|
+
this.modifiedStats![i] = this.storedStats[i];
|
|
69
65
|
}
|
|
70
66
|
},
|
|
71
67
|
},
|
|
@@ -334,6 +330,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|
|
334
330
|
let i: number;
|
|
335
331
|
for (i = 0; i < hits && target.hp && pokemon.hp; i++) {
|
|
336
332
|
move.hit = i + 1;
|
|
333
|
+
if (move.hit === hits) move.lastHit = true;
|
|
337
334
|
moveDamage = this.moveHit(target, pokemon, move);
|
|
338
335
|
if (moveDamage === false) break;
|
|
339
336
|
damage = (moveDamage || 0);
|
|
@@ -573,13 +570,16 @@ export const Scripts: ModdedBattleScriptsData = {
|
|
|
573
570
|
// Apply move secondaries.
|
|
574
571
|
if (moveData.secondaries) {
|
|
575
572
|
for (const secondary of moveData.secondaries) {
|
|
576
|
-
//
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
573
|
+
// Multi-hit moves only roll for status once
|
|
574
|
+
if (!move.multihit || move.lastHit) {
|
|
575
|
+
// We check here whether to negate the probable secondary status if it's para, burn, or freeze.
|
|
576
|
+
// In the game, this is checked and if true, the random number generator is not called.
|
|
577
|
+
// That means that a move that does not share the type of the target can status it.
|
|
578
|
+
// If a move that was not fire-type would exist on Gen 1, it could burn a Pokémon.
|
|
579
|
+
if (!(secondary.status && ['par', 'brn', 'frz'].includes(secondary.status) && target && target.hasType(move.type))) {
|
|
580
|
+
if (secondary.chance === undefined || this.battle.randomChance(Math.ceil(secondary.chance * 256 / 100), 256)) {
|
|
581
|
+
this.moveHit(target, pokemon, move, secondary, true, isSelf);
|
|
582
|
+
}
|
|
583
583
|
}
|
|
584
584
|
}
|
|
585
585
|
}
|
|
@@ -162,7 +162,7 @@ export const FormatsData: {[k: string]: ModdedSpeciesFormatsData} = {
|
|
|
162
162
|
tier: "NU",
|
|
163
163
|
},
|
|
164
164
|
vileplume: {
|
|
165
|
-
randomBattleMoves: ["
|
|
165
|
+
randomBattleMoves: ["hiddenpowergrass", "moonlight", "sleeppowder", "sludgebomb", "stunspore", "swordsdance"],
|
|
166
166
|
tier: "UU",
|
|
167
167
|
},
|
|
168
168
|
bellossom: {
|
|
@@ -889,7 +889,7 @@ export const FormatsData: {[k: string]: ModdedSpeciesFormatsData} = {
|
|
|
889
889
|
tier: "Uber",
|
|
890
890
|
},
|
|
891
891
|
celebi: {
|
|
892
|
-
randomBattleMoves: ["
|
|
892
|
+
randomBattleMoves: ["hiddenpowergrass", "healbell", "leechseed", "psychic", "recover", "toxic"],
|
|
893
893
|
tier: "Uber",
|
|
894
894
|
},
|
|
895
895
|
};
|
package/data/mods/gen2/moves.ts
CHANGED
package/data/moves.ts
CHANGED
|
@@ -8707,10 +8707,16 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
8707
8707
|
basePower: 30,
|
|
8708
8708
|
basePowerCallback(pokemon, target, move) {
|
|
8709
8709
|
let bp = move.basePower;
|
|
8710
|
-
|
|
8711
|
-
|
|
8710
|
+
const iceballData = pokemon.volatiles['iceball'];
|
|
8711
|
+
if (iceballData?.hitCount) {
|
|
8712
|
+
bp *= Math.pow(2, iceballData.hitCount);
|
|
8713
|
+
}
|
|
8714
|
+
if (iceballData && pokemon.status !== 'slp') {
|
|
8715
|
+
iceballData.hitCount++;
|
|
8716
|
+
if (iceballData.hitCount < 5) {
|
|
8717
|
+
iceballData.duration = 2;
|
|
8718
|
+
}
|
|
8712
8719
|
}
|
|
8713
|
-
if (pokemon.status !== 'slp') pokemon.addVolatile('iceball');
|
|
8714
8720
|
if (pokemon.volatiles['defensecurl']) {
|
|
8715
8721
|
bp *= 2;
|
|
8716
8722
|
}
|
|
@@ -8723,17 +8729,19 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
8723
8729
|
pp: 20,
|
|
8724
8730
|
priority: 0,
|
|
8725
8731
|
flags: {bullet: 1, contact: 1, protect: 1, mirror: 1},
|
|
8732
|
+
onModifyMove(move, pokemon, target) {
|
|
8733
|
+
if (pokemon.volatiles['iceball'] || pokemon.status === 'slp' || !target) return;
|
|
8734
|
+
pokemon.addVolatile('iceball');
|
|
8735
|
+
// @ts-ignore
|
|
8736
|
+
// TS thinks pokemon.volatiles['iceball'] doesn't exist because of the condition on the return above
|
|
8737
|
+
// but it does exist now because addVolatile created it
|
|
8738
|
+
pokemon.volatiles['iceball'].targetSlot = move.sourceEffect ? pokemon.lastMoveTargetLoc : pokemon.getLocOf(target);
|
|
8739
|
+
},
|
|
8726
8740
|
condition: {
|
|
8727
|
-
duration:
|
|
8741
|
+
duration: 1,
|
|
8728
8742
|
onLockMove: 'iceball',
|
|
8729
8743
|
onStart() {
|
|
8730
|
-
this.effectState.hitCount =
|
|
8731
|
-
},
|
|
8732
|
-
onRestart() {
|
|
8733
|
-
this.effectState.hitCount++;
|
|
8734
|
-
if (this.effectState.hitCount < 5) {
|
|
8735
|
-
this.effectState.duration = 2;
|
|
8736
|
-
}
|
|
8744
|
+
this.effectState.hitCount = 0;
|
|
8737
8745
|
},
|
|
8738
8746
|
onResidual(target) {
|
|
8739
8747
|
if (target.lastMove && target.lastMove.id === 'struggle') {
|
|
@@ -13434,7 +13442,11 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
13434
13442
|
priority: 0,
|
|
13435
13443
|
flags: {protect: 1, reflectable: 1, heal: 1},
|
|
13436
13444
|
onHit(target, source) {
|
|
13437
|
-
if (!target.cureStatus())
|
|
13445
|
+
if (!target.cureStatus()) {
|
|
13446
|
+
this.add('-fail', source);
|
|
13447
|
+
this.attrLastMove('[still]');
|
|
13448
|
+
return this.NOT_FAIL;
|
|
13449
|
+
}
|
|
13438
13450
|
this.heal(Math.ceil(source.maxhp * 0.5), source);
|
|
13439
13451
|
},
|
|
13440
13452
|
secondary: null,
|
|
@@ -14390,10 +14402,16 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
14390
14402
|
basePower: 30,
|
|
14391
14403
|
basePowerCallback(pokemon, target, move) {
|
|
14392
14404
|
let bp = move.basePower;
|
|
14393
|
-
|
|
14394
|
-
|
|
14405
|
+
const rolloutData = pokemon.volatiles['rollout'];
|
|
14406
|
+
if (rolloutData?.hitCount) {
|
|
14407
|
+
bp *= Math.pow(2, rolloutData.hitCount);
|
|
14408
|
+
}
|
|
14409
|
+
if (rolloutData && pokemon.status !== 'slp') {
|
|
14410
|
+
rolloutData.hitCount++;
|
|
14411
|
+
if (rolloutData.hitCount < 5) {
|
|
14412
|
+
rolloutData.duration = 2;
|
|
14413
|
+
}
|
|
14395
14414
|
}
|
|
14396
|
-
if (pokemon.status !== 'slp') pokemon.addVolatile('rollout');
|
|
14397
14415
|
if (pokemon.volatiles['defensecurl']) {
|
|
14398
14416
|
bp *= 2;
|
|
14399
14417
|
}
|
|
@@ -14405,17 +14423,19 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
14405
14423
|
pp: 20,
|
|
14406
14424
|
priority: 0,
|
|
14407
14425
|
flags: {contact: 1, protect: 1, mirror: 1},
|
|
14426
|
+
onModifyMove(move, pokemon, target) {
|
|
14427
|
+
if (pokemon.volatiles['rollout'] || pokemon.status === 'slp' || !target) return;
|
|
14428
|
+
pokemon.addVolatile('rollout');
|
|
14429
|
+
// @ts-ignore
|
|
14430
|
+
// TS thinks pokemon.volatiles['rollout'] doesn't exist because of the condition on the return above
|
|
14431
|
+
// but it does exist now because addVolatile created it
|
|
14432
|
+
pokemon.volatiles['rollout'].targetSlot = move.sourceEffect ? pokemon.lastMoveTargetLoc : pokemon.getLocOf(target);
|
|
14433
|
+
},
|
|
14408
14434
|
condition: {
|
|
14409
|
-
duration:
|
|
14435
|
+
duration: 1,
|
|
14410
14436
|
onLockMove: 'rollout',
|
|
14411
14437
|
onStart() {
|
|
14412
|
-
this.effectState.hitCount =
|
|
14413
|
-
},
|
|
14414
|
-
onRestart() {
|
|
14415
|
-
this.effectState.hitCount++;
|
|
14416
|
-
if (this.effectState.hitCount < 5) {
|
|
14417
|
-
this.effectState.duration = 2;
|
|
14418
|
-
}
|
|
14438
|
+
this.effectState.hitCount = 0;
|
|
14419
14439
|
},
|
|
14420
14440
|
onResidual(target) {
|
|
14421
14441
|
if (target.lastMove && target.lastMove.id === 'struggle') {
|
package/data/pokedex.ts
CHANGED
|
@@ -17309,7 +17309,7 @@ export const Pokedex: {[speciesid: string]: SpeciesData} = {
|
|
|
17309
17309
|
chromera: {
|
|
17310
17310
|
num: -60,
|
|
17311
17311
|
name: "Chromera",
|
|
17312
|
-
types: ["Dark", "
|
|
17312
|
+
types: ["Dark", "Normal"],
|
|
17313
17313
|
gender: "N",
|
|
17314
17314
|
baseStats: {hp: 85, atk: 85, def: 115, spa: 115, spd: 100, spe: 100},
|
|
17315
17315
|
abilities: {0: "Color Change"},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pkmn/sim",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "An automatically generated extraction of just the simulator portion of Pokémon Showdown",
|
|
5
5
|
"homepage": "https://psim.us",
|
|
6
6
|
"main": "build/sim/index.js",
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
"sim"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@pkmn/sets": "^
|
|
30
|
+
"@pkmn/sets": "^4.0.0",
|
|
31
31
|
"@pkmn/streams": "^1.0.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"mocha": "^10.
|
|
34
|
+
"mocha": "^10.1.0"
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
37
|
"compile": "tsc -p .",
|
package/sim/dex-conditions.ts
CHANGED
|
@@ -390,6 +390,7 @@ export interface EventMethods {
|
|
|
390
390
|
onAnyNegateImmunity?: ((this: Battle, pokemon: Pokemon, type: string) => boolean | void) | boolean;
|
|
391
391
|
onAnyOverrideAction?: (this: Battle, pokemon: Pokemon, target: Pokemon, move: ActiveMove) => string | void;
|
|
392
392
|
onAnyPrepareHit?: CommonHandlers['ResultSourceMove'];
|
|
393
|
+
onAnyPseudoWeatherStart?: (this: Battle, target: Pokemon, source: Pokemon, pseudoWeather: Condition) => void;
|
|
393
394
|
onAnyRedirectTarget?: (
|
|
394
395
|
this: Battle, target: Pokemon, source: Pokemon, source2: Effect, move: ActiveMove
|
|
395
396
|
) => Pokemon | void;
|
package/sim/dex.ts
CHANGED
package/sim/field.ts
CHANGED
package/sim/pokemon.ts
CHANGED
|
@@ -1180,6 +1180,7 @@ export class Pokemon {
|
|
|
1180
1180
|
let statName: StatIDExceptHP;
|
|
1181
1181
|
for (statName in this.storedStats) {
|
|
1182
1182
|
this.storedStats[statName] = pokemon.storedStats[statName];
|
|
1183
|
+
if (this.modifiedStats) this.modifiedStats[statName] = pokemon.modifiedStats![statName]; // Gen 1: Copy modified stats.
|
|
1183
1184
|
}
|
|
1184
1185
|
this.moveSlots = [];
|
|
1185
1186
|
this.set.ivs = (this.battle.gen >= 5 ? this.set.ivs : pokemon.set.ivs);
|
|
@@ -1204,14 +1205,6 @@ export class Pokemon {
|
|
|
1204
1205
|
let boostName: BoostID;
|
|
1205
1206
|
for (boostName in pokemon.boosts) {
|
|
1206
1207
|
this.boosts[boostName] = pokemon.boosts[boostName];
|
|
1207
|
-
if (this.battle.gen <= 1) {
|
|
1208
|
-
if (boostName === 'evasion' || boostName === 'accuracy') continue;
|
|
1209
|
-
if (this.boosts[boostName] >= 0) {
|
|
1210
|
-
this.modifyStat!(boostName, [1, 1.5, 2, 2.5, 3, 3.5, 4][this.boosts[boostName]]);
|
|
1211
|
-
} else {
|
|
1212
|
-
this.modifyStat!(boostName, [100, 66, 50, 40, 33, 28, 25][-this.boosts[boostName]] / 100);
|
|
1213
|
-
}
|
|
1214
|
-
}
|
|
1215
1208
|
}
|
|
1216
1209
|
if (this.battle.gen >= 6) {
|
|
1217
1210
|
const volatilesToCopy = ['focusenergy', 'gmaxchistrike', 'laserfocus'];
|
package/sim/team-validator.ts
CHANGED
|
@@ -687,7 +687,7 @@ export class TeamValidator {
|
|
|
687
687
|
const {species: eventSpecies, eventData} = eventOnlyData;
|
|
688
688
|
let legal = false;
|
|
689
689
|
for (const event of eventData) {
|
|
690
|
-
if (this.validateEvent(set, event, eventSpecies)) continue;
|
|
690
|
+
if (this.validateEvent(set, setSources, event, eventSpecies)) continue;
|
|
691
691
|
legal = true;
|
|
692
692
|
break;
|
|
693
693
|
}
|
|
@@ -698,20 +698,19 @@ export class TeamValidator {
|
|
|
698
698
|
if (eventData.length === 1) {
|
|
699
699
|
problems.push(`${species.name} is only obtainable from an event - it needs to match its event:`);
|
|
700
700
|
} else {
|
|
701
|
-
problems.push(`${species.name} is only obtainable from events - it needs to match one of its events
|
|
701
|
+
problems.push(`${species.name} is only obtainable from events - it needs to match one of its events:`);
|
|
702
702
|
}
|
|
703
|
-
let eventInfo = eventData[0];
|
|
704
|
-
let eventNum = 1;
|
|
705
703
|
for (const [i, event] of eventData.entries()) {
|
|
706
704
|
if (event.generation <= dex.gen && event.generation >= this.minSourceGen) {
|
|
707
|
-
eventInfo = event;
|
|
708
|
-
eventNum = i + 1;
|
|
709
|
-
|
|
705
|
+
const eventInfo = event;
|
|
706
|
+
const eventNum = i + 1;
|
|
707
|
+
const eventName = eventData.length > 1 ? ` #${eventNum}` : ``;
|
|
708
|
+
const eventProblems = this.validateEvent(
|
|
709
|
+
set, setSources, eventInfo, eventSpecies, ` to be`, `from its event${eventName}`
|
|
710
|
+
);
|
|
711
|
+
if (eventProblems) problems.push(...eventProblems);
|
|
710
712
|
}
|
|
711
713
|
}
|
|
712
|
-
const eventName = eventData.length > 1 ? ` #${eventNum}` : ``;
|
|
713
|
-
const eventProblems = this.validateEvent(set, eventInfo, eventSpecies, ` to be`, `from its event${eventName}`);
|
|
714
|
-
if (eventProblems) problems.push(...eventProblems);
|
|
715
714
|
}
|
|
716
715
|
}
|
|
717
716
|
|
|
@@ -1102,7 +1101,7 @@ export class TeamValidator {
|
|
|
1102
1101
|
}
|
|
1103
1102
|
|
|
1104
1103
|
// complicated fancy return signature
|
|
1105
|
-
return this.validateEvent(set, eventData, eventSpecies, because as any) as any;
|
|
1104
|
+
return this.validateEvent(set, setSources, eventData, eventSpecies, because as any) as any;
|
|
1106
1105
|
}
|
|
1107
1106
|
|
|
1108
1107
|
findEggMoveFathers(source: PokemonSource, species: Species, setSources: PokemonSources): boolean;
|
|
@@ -1674,16 +1673,22 @@ export class TeamValidator {
|
|
|
1674
1673
|
return null;
|
|
1675
1674
|
}
|
|
1676
1675
|
|
|
1677
|
-
validateEvent(set: PokemonSet, eventData: EventInfo, eventSpecies: Species): true | undefined;
|
|
1678
1676
|
validateEvent(
|
|
1679
|
-
set: PokemonSet, eventData: EventInfo, eventSpecies: Species
|
|
1677
|
+
set: PokemonSet, setSources: PokemonSources, eventData: EventInfo, eventSpecies: Species
|
|
1678
|
+
): true | undefined;
|
|
1679
|
+
validateEvent(
|
|
1680
|
+
set: PokemonSet, setSources: PokemonSources, eventData: EventInfo, eventSpecies: Species,
|
|
1681
|
+
because: string, from?: string
|
|
1680
1682
|
): string[] | undefined;
|
|
1681
1683
|
/**
|
|
1682
1684
|
* Returns array of error messages if invalid, undefined if valid
|
|
1683
1685
|
*
|
|
1684
1686
|
* If `because` is not passed, instead returns true if invalid.
|
|
1685
1687
|
*/
|
|
1686
|
-
validateEvent(
|
|
1688
|
+
validateEvent(
|
|
1689
|
+
set: PokemonSet, setSources: PokemonSources, eventData: EventInfo, eventSpecies: Species,
|
|
1690
|
+
because = ``, from = `from an event`
|
|
1691
|
+
) {
|
|
1687
1692
|
const dex = this.dex;
|
|
1688
1693
|
let name = set.species;
|
|
1689
1694
|
const species = dex.species.get(set.species);
|
|
@@ -1784,8 +1789,15 @@ export class TeamValidator {
|
|
|
1784
1789
|
problems.push(`${name} can only use Hidden Power Dark/Dragon/Electric/Steel/Ice because it must have at least 5 perfect IVs${etc}.`);
|
|
1785
1790
|
}
|
|
1786
1791
|
}
|
|
1787
|
-
// Event-related ability restrictions only matter if we care about illegal abilities
|
|
1788
1792
|
const ruleTable = this.ruleTable;
|
|
1793
|
+
if (ruleTable.has('obtainablemoves')) {
|
|
1794
|
+
const ssMaxSourceGen = setSources.maxSourceGen();
|
|
1795
|
+
const tradebackEligible = dex.gen === 2 && species.gen === 1;
|
|
1796
|
+
if (ssMaxSourceGen && eventData.generation > ssMaxSourceGen && !tradebackEligible) {
|
|
1797
|
+
if (fastReturn) return true;
|
|
1798
|
+
problems.push(`${name} must not have moves only learnable in gen ${ssMaxSourceGen}${etc}.`);
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1789
1801
|
if (ruleTable.has('obtainableabilities')) {
|
|
1790
1802
|
if (dex.gen <= 5 && eventData.abilities && eventData.abilities.length === 1 && !eventData.isHidden) {
|
|
1791
1803
|
if (species.name === eventSpecies.name) {
|