@pkmn/sim 0.4.21 → 0.4.25
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 +198 -136
- package/build/config/formats.js.map +1 -1
- package/build/data/aliases.js +5 -3
- package/build/data/aliases.js.map +1 -1
- package/build/data/conditions.js +5 -1
- package/build/data/conditions.js.map +1 -1
- package/build/data/formats-data.js +16 -16
- package/build/data/formats-data.js.map +1 -1
- package/build/data/mods/gen1/scripts.js +17 -20
- package/build/data/mods/gen1/scripts.js.map +1 -1
- package/build/data/mods/gen2/scripts.js +15 -21
- package/build/data/mods/gen2/scripts.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/gen6/conditions.js +4 -1
- package/build/data/mods/gen6/conditions.js.map +1 -1
- package/build/data/mods/gen6/pokedex.js +17 -17
- package/build/data/mods/gen6/pokedex.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/moves.js +22 -9
- package/build/data/moves.js.map +1 -1
- package/build/data/rulesets.js +3 -1
- package/build/data/rulesets.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 +19 -43
- 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 +1 -0
- package/build/sim/global-types.d.ts +1 -0
- package/build/sim/side.js +2 -2
- package/build/sim/side.js.map +1 -1
- package/build/sim/team-validator.js +1 -1
- package/build/sim/team-validator.js.map +1 -1
- package/build/sim/tools/runner.d.ts +1 -6
- package/build/sim/tools/runner.js +6 -6
- package/build/sim/tools/runner.js.map +1 -1
- package/config/formats.ts +210 -141
- package/data/aliases.ts +5 -3
- package/data/conditions.ts +5 -1
- package/data/formats-data.ts +16 -16
- package/data/mods/gen1/scripts.ts +22 -18
- package/data/mods/gen2/scripts.ts +19 -18
- package/data/mods/gen4/conditions.ts +6 -0
- package/data/mods/gen6/conditions.ts +4 -1
- package/data/mods/gen6/pokedex.ts +17 -17
- package/data/mods/gen7/formats-data.ts +2 -2
- package/data/moves.ts +19 -9
- package/data/rulesets.ts +3 -1
- package/lib/streams.ts +1 -874
- package/package.json +3 -2
- package/sim/battle-actions.ts +20 -41
- 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 +1 -0
- package/sim/global-types.ts +1 -0
- package/sim/side.ts +2 -2
- package/sim/team-validator.ts +1 -1
- package/sim/tools/runner.ts +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pkmn/sim",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.25",
|
|
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,7 +27,8 @@
|
|
|
27
27
|
"sim"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@pkmn/sets": "^2.0.0"
|
|
30
|
+
"@pkmn/sets": "^2.0.0",
|
|
31
|
+
"@pkmn/streams": "^1.0.0"
|
|
31
32
|
},
|
|
32
33
|
"devDependencies": {
|
|
33
34
|
"mocha": "^9.1.3"
|
package/sim/battle-actions.ts
CHANGED
|
@@ -549,7 +549,7 @@ export class BattleActions {
|
|
|
549
549
|
[moveSteps[2], moveSteps[4]] = [moveSteps[4], moveSteps[2]];
|
|
550
550
|
}
|
|
551
551
|
|
|
552
|
-
if (
|
|
552
|
+
if (notActive) this.battle.setActiveMove(move, pokemon, targets[0]);
|
|
553
553
|
|
|
554
554
|
const hitResult = this.battle.singleEvent('Try', move, null, pokemon, targets[0], move) &&
|
|
555
555
|
this.battle.singleEvent('PrepareHit', move, {}, targets[0], pokemon, move) &&
|
|
@@ -1505,7 +1505,7 @@ export class BattleActions {
|
|
|
1505
1505
|
* undefined = success, null = silent failure, false = loud failure
|
|
1506
1506
|
*/
|
|
1507
1507
|
getDamage(
|
|
1508
|
-
|
|
1508
|
+
source: Pokemon, target: Pokemon, move: string | number | ActiveMove,
|
|
1509
1509
|
suppressMessages = false
|
|
1510
1510
|
): number | undefined | null | false {
|
|
1511
1511
|
if (typeof move === 'string') move = this.dex.getActiveMove(move);
|
|
@@ -1528,25 +1528,24 @@ export class BattleActions {
|
|
|
1528
1528
|
}
|
|
1529
1529
|
|
|
1530
1530
|
if (move.ohko) return target.maxhp;
|
|
1531
|
-
if (move.damageCallback) return move.damageCallback.call(this.battle,
|
|
1531
|
+
if (move.damageCallback) return move.damageCallback.call(this.battle, source, target);
|
|
1532
1532
|
if (move.damage === 'level') {
|
|
1533
|
-
return
|
|
1533
|
+
return source.level;
|
|
1534
1534
|
} else if (move.damage) {
|
|
1535
1535
|
return move.damage;
|
|
1536
1536
|
}
|
|
1537
1537
|
|
|
1538
1538
|
const category = this.battle.getCategory(move);
|
|
1539
|
-
const defensiveCategory = move.defensiveCategory || category;
|
|
1540
1539
|
|
|
1541
1540
|
let basePower: number | false | null = move.basePower;
|
|
1542
1541
|
if (move.basePowerCallback) {
|
|
1543
|
-
basePower = move.basePowerCallback.call(this.battle,
|
|
1542
|
+
basePower = move.basePowerCallback.call(this.battle, source, target, move);
|
|
1544
1543
|
}
|
|
1545
1544
|
if (!basePower) return basePower === 0 ? undefined : basePower;
|
|
1546
1545
|
basePower = this.battle.clampIntRange(basePower, 1);
|
|
1547
1546
|
|
|
1548
1547
|
let critMult;
|
|
1549
|
-
let critRatio = this.battle.runEvent('ModifyCritRatio',
|
|
1548
|
+
let critRatio = this.battle.runEvent('ModifyCritRatio', source, target, move, move.critRatio || 0);
|
|
1550
1549
|
if (this.battle.gen <= 5) {
|
|
1551
1550
|
critRatio = this.battle.clampIntRange(critRatio, 0, 5);
|
|
1552
1551
|
critMult = [0, 16, 8, 4, 3, 2];
|
|
@@ -1572,39 +1571,23 @@ export class BattleActions {
|
|
|
1572
1571
|
}
|
|
1573
1572
|
|
|
1574
1573
|
// happens after crit calculation
|
|
1575
|
-
basePower = this.battle.runEvent('BasePower',
|
|
1574
|
+
basePower = this.battle.runEvent('BasePower', source, target, move, basePower, true);
|
|
1576
1575
|
|
|
1577
1576
|
if (!basePower) return 0;
|
|
1578
1577
|
basePower = this.battle.clampIntRange(basePower, 1);
|
|
1579
1578
|
|
|
1580
|
-
const level =
|
|
1579
|
+
const level = source.level;
|
|
1581
1580
|
|
|
1582
|
-
const attacker =
|
|
1583
|
-
const defender = target;
|
|
1584
|
-
|
|
1585
|
-
const
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
// Body press really wants to use the def stat,
|
|
1589
|
-
// so it switches stats to compensate for Wonder Room.
|
|
1590
|
-
// Of course, the game thus miscalculates the boosts...
|
|
1591
|
-
if ('wonderroom' in this.battle.field.pseudoWeather) {
|
|
1592
|
-
if (attackStat === 'def') {
|
|
1593
|
-
attackStat = 'spd';
|
|
1594
|
-
} else if (attackStat === 'spd') {
|
|
1595
|
-
attackStat = 'def';
|
|
1596
|
-
}
|
|
1597
|
-
if (attacker.boosts['def'] || attacker.boosts['spd']) {
|
|
1598
|
-
this.battle.hint("Body Press uses Sp. Def boosts when Wonder Room is active.");
|
|
1599
|
-
}
|
|
1600
|
-
}
|
|
1601
|
-
}
|
|
1581
|
+
const attacker = move.overrideOffensivePokemon === 'target' ? target : source;
|
|
1582
|
+
const defender = move.overrideDefensivePokemon === 'source' ? source : target;
|
|
1583
|
+
|
|
1584
|
+
const isPhysical = move.category === 'Physical';
|
|
1585
|
+
let attackStat: StatIDExceptHP = move.overrideOffensiveStat || (isPhysical ? 'atk' : 'spa');
|
|
1586
|
+
const defenseStat: StatIDExceptHP = move.overrideDefensiveStat || (isPhysical ? 'def' : 'spd');
|
|
1602
1587
|
|
|
1603
1588
|
const statTable = {atk: 'Atk', def: 'Def', spa: 'SpA', spd: 'SpD', spe: 'Spe'};
|
|
1604
|
-
let attack;
|
|
1605
|
-
let defense;
|
|
1606
1589
|
|
|
1607
|
-
let atkBoosts =
|
|
1590
|
+
let atkBoosts = attacker.boosts[attackStat];
|
|
1608
1591
|
let defBoosts = defender.boosts[defenseStat];
|
|
1609
1592
|
|
|
1610
1593
|
let ignoreNegativeOffensive = !!move.ignoreNegativeOffensive;
|
|
@@ -1626,18 +1609,14 @@ export class BattleActions {
|
|
|
1626
1609
|
defBoosts = 0;
|
|
1627
1610
|
}
|
|
1628
1611
|
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
} else {
|
|
1632
|
-
attack = attacker.calculateStat(attackStat, atkBoosts);
|
|
1633
|
-
}
|
|
1612
|
+
let attack = attacker.calculateStat(attackStat, atkBoosts);
|
|
1613
|
+
let defense = defender.calculateStat(defenseStat, defBoosts);
|
|
1634
1614
|
|
|
1635
1615
|
attackStat = (category === 'Physical' ? 'atk' : 'spa');
|
|
1636
|
-
defense = defender.calculateStat(defenseStat, defBoosts);
|
|
1637
1616
|
|
|
1638
1617
|
// Apply Stat Modifiers
|
|
1639
|
-
attack = this.battle.runEvent('Modify' + statTable[attackStat],
|
|
1640
|
-
defense = this.battle.runEvent('Modify' + statTable[defenseStat],
|
|
1618
|
+
attack = this.battle.runEvent('Modify' + statTable[attackStat], source, target, move, attack);
|
|
1619
|
+
defense = this.battle.runEvent('Modify' + statTable[defenseStat], target, source, move, defense);
|
|
1641
1620
|
|
|
1642
1621
|
if (this.battle.gen <= 4 && ['explosion', 'selfdestruct'].includes(move.id) && defenseStat === 'def') {
|
|
1643
1622
|
defense = this.battle.clampIntRange(Math.floor(defense / 2), 1);
|
|
@@ -1649,7 +1628,7 @@ export class BattleActions {
|
|
|
1649
1628
|
const baseDamage = tr(tr(tr(tr(2 * level / 5 + 2) * basePower * attack) / defense) / 50);
|
|
1650
1629
|
|
|
1651
1630
|
// Calculate damage modifiers separately (order differs between generations)
|
|
1652
|
-
return this.modifyDamage(baseDamage,
|
|
1631
|
+
return this.modifyDamage(baseDamage, source, target, move, suppressMessages);
|
|
1653
1632
|
}
|
|
1654
1633
|
|
|
1655
1634
|
modifyDamage(
|
package/sim/battle.ts
CHANGED
|
@@ -2102,6 +2102,12 @@ export class Battle {
|
|
|
2102
2102
|
return stats;
|
|
2103
2103
|
}
|
|
2104
2104
|
|
|
2105
|
+
finalModify(relayVar: number) {
|
|
2106
|
+
relayVar = this.modify(relayVar, this.event.modifier);
|
|
2107
|
+
this.event.modifier = 1;
|
|
2108
|
+
return relayVar;
|
|
2109
|
+
}
|
|
2110
|
+
|
|
2105
2111
|
getCategory(move: string | Move): Move['category'] {
|
|
2106
2112
|
return this.dex.moves.get(move).category || 'Physical';
|
|
2107
2113
|
}
|
package/sim/dex-moves.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
Pokemon,
|
|
12
12
|
Side,
|
|
13
13
|
SparseBoostsTable,
|
|
14
|
+
StatIDExceptHP,
|
|
14
15
|
} from './exported-global-types';
|
|
15
16
|
|
|
16
17
|
import {Utils} from '../lib';
|
|
@@ -218,7 +219,22 @@ export interface MoveData extends EffectData, MoveEventMethods, HitEffect {
|
|
|
218
219
|
basePowerModifier?: number;
|
|
219
220
|
critModifier?: number;
|
|
220
221
|
critRatio?: number;
|
|
221
|
-
|
|
222
|
+
/**
|
|
223
|
+
* Pokemon for the attack stat. Ability and Item damage modifiers still come from the real attacker.
|
|
224
|
+
*/
|
|
225
|
+
overrideOffensivePokemon?: 'target' | 'source';
|
|
226
|
+
/**
|
|
227
|
+
* Physical moves use attack stat modifiers, special moves use special attack stat modifiers.
|
|
228
|
+
*/
|
|
229
|
+
overrideOffensiveStat?: StatIDExceptHP;
|
|
230
|
+
/**
|
|
231
|
+
* Pokemon for the defense stat. Ability and Item damage modifiers still come from the real defender.
|
|
232
|
+
*/
|
|
233
|
+
overrideDefensivePokemon?: 'target' | 'source';
|
|
234
|
+
/**
|
|
235
|
+
* uses modifiers that match the new stat
|
|
236
|
+
*/
|
|
237
|
+
overrideDefensiveStat?: StatIDExceptHP;
|
|
222
238
|
forceSTAB?: boolean;
|
|
223
239
|
ignoreAbility?: boolean;
|
|
224
240
|
ignoreAccuracy?: boolean;
|
|
@@ -246,8 +262,6 @@ export interface MoveData extends EffectData, MoveEventMethods, HitEffect {
|
|
|
246
262
|
* situations, rather than just targeting a slot. (Stalwart, Snipe Shot)
|
|
247
263
|
*/
|
|
248
264
|
tracksTarget?: boolean;
|
|
249
|
-
useTargetOffensive?: boolean;
|
|
250
|
-
useSourceDefensiveAsOffensive?: boolean;
|
|
251
265
|
willCrit?: boolean;
|
|
252
266
|
|
|
253
267
|
// Mechanics flags
|
|
@@ -375,14 +389,21 @@ export class DataMove extends BasicEffect implements Readonly<BasicEffect & Move
|
|
|
375
389
|
/** Move category. */
|
|
376
390
|
readonly category: MoveCategory;
|
|
377
391
|
/**
|
|
378
|
-
*
|
|
379
|
-
|
|
392
|
+
* Pokemon for the attack stat. Ability and Item damage modifiers still come from the real attacker.
|
|
393
|
+
*/
|
|
394
|
+
readonly overrideOffensivePokemon?: 'target' | 'source';
|
|
395
|
+
/**
|
|
396
|
+
* Physical moves use attack stat modifiers, special moves use special attack stat modifiers.
|
|
397
|
+
*/
|
|
398
|
+
readonly overrideOffensiveStat?: StatIDExceptHP;
|
|
399
|
+
/**
|
|
400
|
+
* Pokemon for the defense stat. Ability and Item damage modifiers still come from the real defender.
|
|
401
|
+
*/
|
|
402
|
+
readonly overrideDefensivePokemon?: 'target' | 'source';
|
|
403
|
+
/**
|
|
404
|
+
* uses modifiers that match the new stat
|
|
380
405
|
*/
|
|
381
|
-
|
|
382
|
-
/** Uses the target's Atk/SpA as the attacking stat, instead of the user's. */
|
|
383
|
-
readonly useTargetOffensive: boolean;
|
|
384
|
-
/** Use the user's Def/SpD as the attacking stat, instead of Atk/SpA. */
|
|
385
|
-
readonly useSourceDefensiveAsOffensive: boolean;
|
|
406
|
+
readonly overrideDefensiveStat?: StatIDExceptHP;
|
|
386
407
|
/** Whether or not this move ignores negative attack boosts. */
|
|
387
408
|
readonly ignoreNegativeOffensive: boolean;
|
|
388
409
|
/** Whether or not this move ignores positive defense boosts. */
|
|
@@ -463,9 +484,10 @@ export class DataMove extends BasicEffect implements Readonly<BasicEffect & Move
|
|
|
463
484
|
this.secondaries = data.secondaries || (this.secondary && [this.secondary]) || null;
|
|
464
485
|
this.priority = Number(data.priority) || 0;
|
|
465
486
|
this.category = data.category!;
|
|
466
|
-
this.
|
|
467
|
-
this.
|
|
468
|
-
this.
|
|
487
|
+
this.overrideOffensiveStat = data.overrideOffensiveStat || undefined;
|
|
488
|
+
this.overrideOffensivePokemon = data.overrideOffensivePokemon || undefined;
|
|
489
|
+
this.overrideDefensiveStat = data.overrideDefensiveStat || undefined;
|
|
490
|
+
this.overrideDefensivePokemon = data.overrideDefensivePokemon || undefined;
|
|
469
491
|
this.ignoreNegativeOffensive = !!data.ignoreNegativeOffensive;
|
|
470
492
|
this.ignorePositiveDefensive = !!data.ignorePositiveDefensive;
|
|
471
493
|
this.ignoreOffensive = !!data.ignoreOffensive;
|
package/sim/dex-species.ts
CHANGED
|
@@ -479,15 +479,24 @@ export class DexSpecies {
|
|
|
479
479
|
if (this.dex.currentMod === 'gen7letsgo' && !species.isNonstandard) {
|
|
480
480
|
const isLetsGo = (
|
|
481
481
|
(species.num <= 151 || ['Meltan', 'Melmetal'].includes(species.name)) &&
|
|
482
|
-
(!species.forme || ['Alola', 'Mega', 'Mega-X', 'Mega-Y', 'Starter'].includes(species.forme)
|
|
482
|
+
(!species.forme || ['Alola', 'Mega', 'Mega-X', 'Mega-Y', 'Starter'].includes(species.forme) &&
|
|
483
|
+
species.name !== 'Pikachu-Alola')
|
|
483
484
|
);
|
|
484
485
|
if (!isLetsGo) species.isNonstandard = 'Past';
|
|
485
486
|
}
|
|
487
|
+
if (this.dex.currentMod === 'gen8bdsp' &&
|
|
488
|
+
(!species.isNonstandard || species.isNonstandard === "Gigantamax")) {
|
|
489
|
+
if (species.gen > 4 || species.num < 1 || species.id === 'pichuspikyeared') {
|
|
490
|
+
species.isNonstandard = 'Past';
|
|
491
|
+
species.tier = species.doublesTier = 'Illegal';
|
|
492
|
+
}
|
|
493
|
+
}
|
|
486
494
|
species.nfe = !!(species.evos.length && this.get(species.evos[0]).gen <= this.dex.gen);
|
|
487
495
|
species.canHatch = species.canHatch ||
|
|
488
496
|
(!['Ditto', 'Undiscovered'].includes(species.eggGroups[0]) && !species.prevo && species.name !== 'Manaphy');
|
|
489
497
|
if (this.dex.gen === 1) species.bst -= species.baseStats.spd;
|
|
490
498
|
if (this.dex.gen < 5) delete species.abilities['H'];
|
|
499
|
+
if (this.dex.gen === 3 && this.dex.abilities.get(species.abilities['1']).gen === 4) delete species.abilities['1'];
|
|
491
500
|
} else {
|
|
492
501
|
species = new Species({
|
|
493
502
|
id, name: id,
|
package/sim/global-types.ts
CHANGED
package/sim/side.ts
CHANGED
|
@@ -255,14 +255,14 @@ export class Side {
|
|
|
255
255
|
allies(all?: boolean) {
|
|
256
256
|
// called during the first switch-in, so `active` can still contain nulls at this point
|
|
257
257
|
let allies = this.activeTeam().filter(ally => ally);
|
|
258
|
-
if (!all) allies = allies.filter(ally =>
|
|
258
|
+
if (!all) allies = allies.filter(ally => !!ally.hp);
|
|
259
259
|
|
|
260
260
|
return allies;
|
|
261
261
|
}
|
|
262
262
|
foes(all?: boolean) {
|
|
263
263
|
if (this.battle.gameType === 'freeforall') {
|
|
264
264
|
return this.battle.sides.map(side => side.active[0])
|
|
265
|
-
.filter(pokemon => pokemon && pokemon.side !== this && (all ||
|
|
265
|
+
.filter(pokemon => pokemon && pokemon.side !== this && (all || !!pokemon.hp));
|
|
266
266
|
}
|
|
267
267
|
return this.foe.allies(all);
|
|
268
268
|
}
|
package/sim/team-validator.ts
CHANGED
|
@@ -1910,7 +1910,7 @@ export class TeamValidator {
|
|
|
1910
1910
|
/**
|
|
1911
1911
|
* The format allows Sketch to copy moves in Gen 8
|
|
1912
1912
|
*/
|
|
1913
|
-
const canSketchGen8Moves = ruleTable.has('sketchgen8moves');
|
|
1913
|
+
const canSketchGen8Moves = ruleTable.has('sketchgen8moves') || this.dex.currentMod === 'gen8bdsp';
|
|
1914
1914
|
|
|
1915
1915
|
let tradebackEligible = false;
|
|
1916
1916
|
while (species?.name && !alreadyChecked[species.id]) {
|