@pkmn/sim 0.5.21 → 0.5.24
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/LICENSE +1 -1
- package/build/config/formats.js +412 -419
- package/build/config/formats.js.map +1 -1
- package/build/data/abilities.js +1 -3
- package/build/data/abilities.js.map +1 -1
- package/build/data/aliases.js +4 -4
- package/build/data/aliases.js.map +1 -1
- package/build/data/conditions.js +5 -2
- package/build/data/conditions.js.map +1 -1
- package/build/data/formats-data.js +9 -10
- package/build/data/formats-data.js.map +1 -1
- package/build/data/mods/gen1/conditions.js +3 -0
- package/build/data/mods/gen1/conditions.js.map +1 -1
- package/build/data/mods/gen1/formats-data.js +1 -1
- package/build/data/mods/gen1/formats-data.js.map +1 -1
- package/build/data/mods/gen1/moves.js +5 -2
- package/build/data/mods/gen1/moves.js.map +1 -1
- package/build/data/mods/gen1/scripts.js +4 -2
- package/build/data/mods/gen1/scripts.js.map +1 -1
- package/build/data/mods/gen2/conditions.js +3 -0
- package/build/data/mods/gen2/conditions.js.map +1 -1
- package/build/data/mods/gen3/conditions.js +3 -0
- package/build/data/mods/gen3/conditions.js.map +1 -1
- package/build/data/mods/gen3/formats-data.js +3 -3
- package/build/data/mods/gen3/formats-data.js.map +1 -1
- package/build/data/mods/gen4/abilities.js +1 -1
- package/build/data/mods/gen4/abilities.js.map +1 -1
- package/build/data/mods/gen4/conditions.js +3 -0
- package/build/data/mods/gen4/conditions.js.map +1 -1
- package/build/data/mods/gen4/moves.js +9 -2
- package/build/data/mods/gen4/moves.js.map +1 -1
- package/build/data/mods/gen5/moves.js +4 -7
- package/build/data/mods/gen5/moves.js.map +1 -1
- package/build/data/mods/gen5/pokedex.js +24 -0
- package/build/data/mods/gen5/pokedex.js.map +1 -1
- package/build/data/mods/gen6/formats-data.js +64 -64
- package/build/data/mods/gen6/formats-data.js.map +1 -1
- package/build/data/mods/gen7/abilities.js +8 -0
- package/build/data/mods/gen7/abilities.js.map +1 -1
- package/build/data/mods/gen7/moves.js +2 -2
- package/build/data/mods/gen7/moves.js.map +1 -1
- package/build/data/moves.js +8 -3
- package/build/data/moves.js.map +1 -1
- package/build/data/pokedex.js +1 -1
- package/build/data/rulesets.js +270 -3
- package/build/data/rulesets.js.map +1 -1
- package/build/lib/utils.d.ts +4 -0
- package/build/lib/utils.js +20 -1
- package/build/lib/utils.js.map +1 -1
- package/build/sim/battle-stream.js +3 -0
- package/build/sim/battle-stream.js.map +1 -1
- package/build/sim/exported-global-types.d.ts +2 -0
- package/build/sim/global-types.d.ts +2 -0
- package/build/sim/pokemon.d.ts +1 -0
- package/build/sim/pokemon.js +9 -2
- package/build/sim/pokemon.js.map +1 -1
- package/build/sim/side.js +21 -0
- package/build/sim/side.js.map +1 -1
- package/config/formats.ts +407 -406
- package/data/abilities.ts +1 -3
- package/data/aliases.ts +4 -4
- package/data/conditions.ts +6 -2
- package/data/formats-data.ts +9 -10
- package/data/mods/gen1/conditions.ts +4 -0
- package/data/mods/gen1/formats-data.ts +1 -1
- package/data/mods/gen1/moves.ts +5 -1
- package/data/mods/gen1/scripts.ts +3 -2
- package/data/mods/gen2/conditions.ts +4 -0
- package/data/mods/gen3/conditions.ts +4 -0
- package/data/mods/gen3/formats-data.ts +3 -3
- package/data/mods/gen4/abilities.ts +1 -1
- package/data/mods/gen4/conditions.ts +4 -0
- package/data/mods/gen4/moves.ts +9 -2
- package/data/mods/gen5/moves.ts +4 -7
- package/data/mods/gen5/pokedex.ts +24 -0
- package/data/mods/gen6/formats-data.ts +64 -64
- package/data/mods/gen7/abilities.ts +8 -0
- package/data/mods/gen7/moves.ts +2 -2
- package/data/moves.ts +8 -3
- package/data/pokedex.ts +1 -1
- package/data/rulesets.ts +247 -3
- package/lib/utils.ts +16 -0
- package/package.json +2 -2
- package/sim/battle-stream.ts +3 -0
- package/sim/exported-global-types.ts +2 -0
- package/sim/global-types.ts +2 -0
- package/sim/pokemon.ts +9 -2
- package/sim/side.ts +20 -0
package/data/rulesets.ts
CHANGED
|
@@ -14,7 +14,7 @@ export const Rulesets: {[k: string]: FormatData} = {
|
|
|
14
14
|
name: 'Standard',
|
|
15
15
|
desc: "The standard ruleset for all offical Smogon singles tiers (Ubers, OU, etc.)",
|
|
16
16
|
ruleset: [
|
|
17
|
-
'Obtainable', 'Team Preview', 'Sleep Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod',
|
|
17
|
+
'Obtainable', 'Team Preview', 'Sleep Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Items Clause', 'Evasion Moves Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod',
|
|
18
18
|
],
|
|
19
19
|
},
|
|
20
20
|
standardnext: {
|
|
@@ -71,6 +71,14 @@ export const Rulesets: {[k: string]: FormatData} = {
|
|
|
71
71
|
'Obtainable', 'Team Preview', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'Gravity Sleep Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod',
|
|
72
72
|
],
|
|
73
73
|
},
|
|
74
|
+
standardoms: {
|
|
75
|
+
effectType: 'ValidatorRule',
|
|
76
|
+
name: 'Standard OMs',
|
|
77
|
+
desc: "The standard ruleset for all Smogon OMs (Almost Any Ability, STABmons, etc.)",
|
|
78
|
+
ruleset: [
|
|
79
|
+
'Obtainable', 'Team Preview', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'Endless Battle Clause', 'Dynamax Clause', 'HP Percentage Mod', 'Cancel Mod', 'Overflow Stat Mod',
|
|
80
|
+
],
|
|
81
|
+
},
|
|
74
82
|
standardnatdex: {
|
|
75
83
|
effectType: 'ValidatorRule',
|
|
76
84
|
name: 'Standard NatDex',
|
|
@@ -399,6 +407,29 @@ export const Rulesets: {[k: string]: FormatData} = {
|
|
|
399
407
|
}
|
|
400
408
|
},
|
|
401
409
|
},
|
|
410
|
+
forceselect: {
|
|
411
|
+
effectType: 'ValidatorRule',
|
|
412
|
+
name: 'Force Select',
|
|
413
|
+
desc: `Forces a Pokemon to be on the team and selected at Team Preview. Usage: Force Select = [Pokemon], e.g. "Force Select = Magikarp"`,
|
|
414
|
+
hasValue: true,
|
|
415
|
+
onValidateRule(value) {
|
|
416
|
+
if (!this.dex.species.get(value).exists) throw new Error(`Misspelled Pokemon "${value}"`);
|
|
417
|
+
},
|
|
418
|
+
onValidateTeam(team) {
|
|
419
|
+
let hasSelection = false;
|
|
420
|
+
const species = this.dex.species.get(this.ruleTable.valueRules.get('forceselect'));
|
|
421
|
+
for (const set of team) {
|
|
422
|
+
if (species.name === set.species) {
|
|
423
|
+
hasSelection = true;
|
|
424
|
+
break;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
if (!hasSelection) {
|
|
428
|
+
return [`Your team must contain ${species.name}.`];
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
// hardcoded in sim/side
|
|
432
|
+
},
|
|
402
433
|
evlimits: {
|
|
403
434
|
effectType: 'ValidatorRule',
|
|
404
435
|
name: 'EV Limits',
|
|
@@ -620,6 +651,15 @@ export const Rulesets: {[k: string]: FormatData} = {
|
|
|
620
651
|
return problems;
|
|
621
652
|
},
|
|
622
653
|
},
|
|
654
|
+
evasionclause: {
|
|
655
|
+
effectType: 'ValidatorRule',
|
|
656
|
+
name: 'Evasion Clause',
|
|
657
|
+
desc: "Bans abilities, items, and moves that boost Evasion",
|
|
658
|
+
ruleset: ['Evasion Abilities Clause', 'Evasion Items Clause', 'Evasion Moves Clause'],
|
|
659
|
+
onBegin() {
|
|
660
|
+
this.add('rule', 'Evasion Clause: Evasion abilities, items, and moves are banned');
|
|
661
|
+
},
|
|
662
|
+
},
|
|
623
663
|
evasionabilitiesclause: {
|
|
624
664
|
effectType: 'ValidatorRule',
|
|
625
665
|
name: 'Evasion Abilities Clause',
|
|
@@ -629,6 +669,15 @@ export const Rulesets: {[k: string]: FormatData} = {
|
|
|
629
669
|
this.add('rule', 'Evasion Abilities Clause: Evasion abilities are banned');
|
|
630
670
|
},
|
|
631
671
|
},
|
|
672
|
+
evasionitemsclause: {
|
|
673
|
+
effectType: 'ValidatorRule',
|
|
674
|
+
name: 'Evasion Items Clause',
|
|
675
|
+
desc: "Bans moves that lower the accuracy of moves used against the user",
|
|
676
|
+
banlist: ['Bright Powder', 'Lax Incense'],
|
|
677
|
+
onBegin() {
|
|
678
|
+
this.add('rule', 'Evasion Items Clause: Evasion items are banned');
|
|
679
|
+
},
|
|
680
|
+
},
|
|
632
681
|
evasionmovesclause: {
|
|
633
682
|
effectType: 'ValidatorRule',
|
|
634
683
|
name: 'Evasion Moves Clause',
|
|
@@ -1262,6 +1311,19 @@ export const Rulesets: {[k: string]: FormatData} = {
|
|
|
1262
1311
|
}
|
|
1263
1312
|
},
|
|
1264
1313
|
},
|
|
1314
|
+
gemsclause: {
|
|
1315
|
+
effectType: 'ValidatorRule',
|
|
1316
|
+
name: 'Gems Clause',
|
|
1317
|
+
desc: "Bans all Gems",
|
|
1318
|
+
onValidateSet(set) {
|
|
1319
|
+
if (!set.item) return;
|
|
1320
|
+
const item = this.dex.items.get(set.item);
|
|
1321
|
+
if (item.isGem) {
|
|
1322
|
+
if (this.ruleTable.has(`+item:${item.id}`)) return;
|
|
1323
|
+
return [`${item.name} is banned due to Gems Clause.`];
|
|
1324
|
+
}
|
|
1325
|
+
},
|
|
1326
|
+
},
|
|
1265
1327
|
'sketchgen8moves': {
|
|
1266
1328
|
effectType: 'ValidatorRule',
|
|
1267
1329
|
name: 'Sketch Gen 8 Moves',
|
|
@@ -1833,8 +1895,7 @@ export const Rulesets: {[k: string]: FormatData} = {
|
|
|
1833
1895
|
reevolutionmod: {
|
|
1834
1896
|
effectType: "Rule",
|
|
1835
1897
|
name: "Re-Evolution Mod",
|
|
1836
|
-
desc: "Pokémon gain the
|
|
1837
|
-
ruleset: ['Overflow Stat Mod'],
|
|
1898
|
+
desc: "Pokémon gain the stat changes they would gain from evolving again.",
|
|
1838
1899
|
onBegin() {
|
|
1839
1900
|
this.add('rule', 'Re-Evolution Mod: Pok\u00e9mon gain the boosts they would gain from evolving again');
|
|
1840
1901
|
},
|
|
@@ -1852,4 +1913,187 @@ export const Rulesets: {[k: string]: FormatData} = {
|
|
|
1852
1913
|
return newSpecies;
|
|
1853
1914
|
},
|
|
1854
1915
|
},
|
|
1916
|
+
brokenrecordmod: {
|
|
1917
|
+
effectType: "Rule",
|
|
1918
|
+
name: "Broken Record Mod",
|
|
1919
|
+
desc: `Pokémon can hold a TR to use that move in battle.`,
|
|
1920
|
+
onValidateSet(set) {
|
|
1921
|
+
if (!set.item) return;
|
|
1922
|
+
const item = this.dex.items.get(set.item);
|
|
1923
|
+
if (!/^tr\d\d/i.test(item.name)) return;
|
|
1924
|
+
const moveName = item.desc.split('move ')[1].split('.')[0];
|
|
1925
|
+
if (set.moves.map(this.toID).includes(this.toID(moveName))) {
|
|
1926
|
+
return [
|
|
1927
|
+
`${set.species} can't run ${item.name} (${moveName}) as its item because it already has that move in its moveset.`,
|
|
1928
|
+
];
|
|
1929
|
+
}
|
|
1930
|
+
},
|
|
1931
|
+
onValidateTeam(team) {
|
|
1932
|
+
const trs = new Set<string>();
|
|
1933
|
+
for (const set of team) {
|
|
1934
|
+
if (!set.item) continue;
|
|
1935
|
+
const item = this.dex.items.get(set.item).name;
|
|
1936
|
+
if (!/^tr\d\d/i.test(item)) continue;
|
|
1937
|
+
if (trs.has(item)) {
|
|
1938
|
+
return [`Your team already has a Pok\u00e9mon with ${item}.`];
|
|
1939
|
+
}
|
|
1940
|
+
trs.add(item);
|
|
1941
|
+
}
|
|
1942
|
+
},
|
|
1943
|
+
onTakeItem(item) {
|
|
1944
|
+
return !/^tr\d\d/i.test(item.name);
|
|
1945
|
+
},
|
|
1946
|
+
onModifyMove(move) {
|
|
1947
|
+
if (move.id === 'knockoff') {
|
|
1948
|
+
move.onBasePower = function (basePower, source, target, m) {
|
|
1949
|
+
const item = target.getItem();
|
|
1950
|
+
if (!this.singleEvent('TakeItem', item, target.itemState, target, target, m, item)) return;
|
|
1951
|
+
// Very hardcode but I'd prefer to not make a mod for one damage calculation change
|
|
1952
|
+
if (item.id && !/^tr\d\d/i.test(item.id)) {
|
|
1953
|
+
return this.chainModify(1.5);
|
|
1954
|
+
}
|
|
1955
|
+
};
|
|
1956
|
+
} else if (move.id === 'fling') {
|
|
1957
|
+
move.onPrepareHit = function (target, source, m) {
|
|
1958
|
+
if (source.ignoringItem()) return false;
|
|
1959
|
+
const item = source.getItem();
|
|
1960
|
+
if (!this.singleEvent('TakeItem', item, source.itemState, source, source, m, item)) return false;
|
|
1961
|
+
if (!item.fling) return false;
|
|
1962
|
+
if (/^tr\d\d/i.test(item.id)) return false;
|
|
1963
|
+
m.basePower = item.fling.basePower;
|
|
1964
|
+
if (item.isBerry) {
|
|
1965
|
+
m.onHit = function (foe) {
|
|
1966
|
+
if (this.singleEvent('Eat', item, null, foe, null, null)) {
|
|
1967
|
+
this.runEvent('EatItem', foe, null, null, item);
|
|
1968
|
+
if (item.id === 'leppaberry') foe.staleness = 'external';
|
|
1969
|
+
}
|
|
1970
|
+
if (item.onEat) foe.ateBerry = true;
|
|
1971
|
+
};
|
|
1972
|
+
} else if (item.fling.effect) {
|
|
1973
|
+
m.onHit = item.fling.effect;
|
|
1974
|
+
} else {
|
|
1975
|
+
if (!m.secondaries) m.secondaries = [];
|
|
1976
|
+
if (item.fling.status) {
|
|
1977
|
+
m.secondaries.push({status: item.fling.status});
|
|
1978
|
+
} else if (item.fling.volatileStatus) {
|
|
1979
|
+
m.secondaries.push({volatileStatus: item.fling.volatileStatus});
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
source.addVolatile('fling');
|
|
1983
|
+
};
|
|
1984
|
+
}
|
|
1985
|
+
},
|
|
1986
|
+
onBegin() {
|
|
1987
|
+
for (const pokemon of this.getAllPokemon()) {
|
|
1988
|
+
const item = pokemon.getItem();
|
|
1989
|
+
if (/^tr\d\d/i.test(item.name)) {
|
|
1990
|
+
const move = this.dex.moves.get(item.desc.split('move ')[1].split('.')[0]);
|
|
1991
|
+
pokemon.moveSlots = (pokemon as any).baseMoveSlots = [
|
|
1992
|
+
...pokemon.baseMoveSlots, {
|
|
1993
|
+
id: move.id,
|
|
1994
|
+
move: move.name,
|
|
1995
|
+
pp: move.pp * 8 / 5,
|
|
1996
|
+
maxpp: move.pp * 8 / 5,
|
|
1997
|
+
target: move.target,
|
|
1998
|
+
disabled: false,
|
|
1999
|
+
disabledSource: '',
|
|
2000
|
+
used: false,
|
|
2001
|
+
},
|
|
2002
|
+
];
|
|
2003
|
+
}
|
|
2004
|
+
}
|
|
2005
|
+
},
|
|
2006
|
+
},
|
|
2007
|
+
categoryswapmod: {
|
|
2008
|
+
effectType: 'Rule',
|
|
2009
|
+
name: 'Category Swap Mod',
|
|
2010
|
+
desc: `All physical moves become special, and all special moves become physical.`,
|
|
2011
|
+
onBegin() {
|
|
2012
|
+
this.add('rule', 'Category Swap Mod: All physical moves become special, and vice versa');
|
|
2013
|
+
},
|
|
2014
|
+
onModifyMove(move, pokemon, target) {
|
|
2015
|
+
if (move.category === "Status") return;
|
|
2016
|
+
|
|
2017
|
+
if (move.category === "Physical") {
|
|
2018
|
+
move.category = "Special";
|
|
2019
|
+
} else if (move.category === "Special") {
|
|
2020
|
+
move.category = "Physical";
|
|
2021
|
+
}
|
|
2022
|
+
|
|
2023
|
+
switch (move.id) {
|
|
2024
|
+
case 'doomdesire': {
|
|
2025
|
+
move.onTry = function (source, subtarget) {
|
|
2026
|
+
if (!subtarget.side.addSlotCondition(subtarget, 'futuremove')) return false;
|
|
2027
|
+
Object.assign(subtarget.side.slotConditions[subtarget.position]['futuremove'], {
|
|
2028
|
+
move: 'doomdesire',
|
|
2029
|
+
source: source,
|
|
2030
|
+
moveData: {
|
|
2031
|
+
id: 'doomdesire',
|
|
2032
|
+
name: "Doom Desire",
|
|
2033
|
+
accuracy: 100,
|
|
2034
|
+
basePower: 140,
|
|
2035
|
+
category: "Physical",
|
|
2036
|
+
priority: 0,
|
|
2037
|
+
flags: {},
|
|
2038
|
+
effectType: 'Move',
|
|
2039
|
+
isFutureMove: true,
|
|
2040
|
+
type: 'Steel',
|
|
2041
|
+
},
|
|
2042
|
+
});
|
|
2043
|
+
this.add('-start', source, 'Doom Desire');
|
|
2044
|
+
return this.NOT_FAIL;
|
|
2045
|
+
};
|
|
2046
|
+
break;
|
|
2047
|
+
}
|
|
2048
|
+
case 'futuresight': {
|
|
2049
|
+
move.onTry = function (source, subtarget) {
|
|
2050
|
+
if (!subtarget.side.addSlotCondition(subtarget, 'futuremove')) return false;
|
|
2051
|
+
Object.assign(subtarget.side.slotConditions[subtarget.position]['futuremove'], {
|
|
2052
|
+
duration: 3,
|
|
2053
|
+
move: 'futuresight',
|
|
2054
|
+
source: source,
|
|
2055
|
+
moveData: {
|
|
2056
|
+
id: 'futuresight',
|
|
2057
|
+
name: "Future Sight",
|
|
2058
|
+
accuracy: 100,
|
|
2059
|
+
basePower: 120,
|
|
2060
|
+
category: "Physical",
|
|
2061
|
+
priority: 0,
|
|
2062
|
+
flags: {},
|
|
2063
|
+
ignoreImmunity: false,
|
|
2064
|
+
effectType: 'Move',
|
|
2065
|
+
isFutureMove: true,
|
|
2066
|
+
type: 'Psychic',
|
|
2067
|
+
},
|
|
2068
|
+
});
|
|
2069
|
+
this.add('-start', source, 'move: Future Sight');
|
|
2070
|
+
return this.NOT_FAIL;
|
|
2071
|
+
};
|
|
2072
|
+
break;
|
|
2073
|
+
}
|
|
2074
|
+
// Moves with dynamic categories will always be physical if not special-cased
|
|
2075
|
+
case 'lightthatburnsthesky':
|
|
2076
|
+
case 'photongeyser': {
|
|
2077
|
+
move.category = 'Special';
|
|
2078
|
+
if (pokemon.getStat('atk', false, true) > pokemon.getStat('spa', false, true)) move.category = 'Physical';
|
|
2079
|
+
break;
|
|
2080
|
+
}
|
|
2081
|
+
case 'shellsidearm': {
|
|
2082
|
+
if (!target) return;
|
|
2083
|
+
move.category = 'Special';
|
|
2084
|
+
const atk = pokemon.getStat('atk', false, true);
|
|
2085
|
+
const spa = pokemon.getStat('spa', false, true);
|
|
2086
|
+
const def = target.getStat('def', false, true);
|
|
2087
|
+
const spd = target.getStat('spd', false, true);
|
|
2088
|
+
const physical = Math.floor(Math.floor(Math.floor(Math.floor(2 * pokemon.level / 5 + 2) * 90 * atk) / def) / 50);
|
|
2089
|
+
const special = Math.floor(Math.floor(Math.floor(Math.floor(2 * pokemon.level / 5 + 2) * 90 * spa) / spd) / 50);
|
|
2090
|
+
if (physical > special || (physical === special && this.random(2) === 0)) {
|
|
2091
|
+
move.category = 'Physical';
|
|
2092
|
+
move.flags.contact = 1;
|
|
2093
|
+
}
|
|
2094
|
+
break;
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
},
|
|
2098
|
+
},
|
|
1855
2099
|
};
|
package/lib/utils.ts
CHANGED
|
@@ -63,6 +63,22 @@ export function stripHTML(htmlContent: string) {
|
|
|
63
63
|
return htmlContent.replace(/<[^>]*>/g, '');
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
/**
|
|
67
|
+
* Maps numbers to their ordinal string.
|
|
68
|
+
*/
|
|
69
|
+
export function formatOrder(place: number) {
|
|
70
|
+
// anything between 10 and 20 should always end with -th
|
|
71
|
+
let remainder = place % 100;
|
|
72
|
+
if (remainder >= 10 && remainder <= 20) return place + 'th';
|
|
73
|
+
|
|
74
|
+
// follow standard rules with -st, -nd, -rd, and -th
|
|
75
|
+
remainder = place % 10;
|
|
76
|
+
if (remainder === 1) return place + 'st';
|
|
77
|
+
if (remainder === 2) return place + 'nd';
|
|
78
|
+
if (remainder === 3) return place + 'rd';
|
|
79
|
+
return place + 'th';
|
|
80
|
+
}
|
|
81
|
+
|
|
66
82
|
/**
|
|
67
83
|
* Visualizes eval output in a slightly more readable form
|
|
68
84
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pkmn/sim",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.24",
|
|
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,7 @@
|
|
|
27
27
|
"sim"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@pkmn/sets": "^3.
|
|
30
|
+
"@pkmn/sets": "^3.1.0",
|
|
31
31
|
"@pkmn/streams": "^1.0.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
package/sim/battle-stream.ts
CHANGED
|
@@ -211,6 +211,9 @@ export class BattleStream extends Streams.ObjectReadWriteStream<string> {
|
|
|
211
211
|
case 'requestlog':
|
|
212
212
|
this.push(`requesteddata\n${this.battle!.inputLog.join('\n')}`);
|
|
213
213
|
break;
|
|
214
|
+
case 'requestexport':
|
|
215
|
+
this.push(`requesteddata\n${this.battle!.prngSeed}\n${this.battle!.inputLog.join('\n')}`);
|
|
216
|
+
break;
|
|
214
217
|
case 'requestteam':
|
|
215
218
|
message = message.trim();
|
|
216
219
|
const slotNum = parseInt(message.slice(1)) - 1;
|
|
@@ -515,6 +515,7 @@ export namespace RandomTeamsTypes {
|
|
|
515
515
|
shiny: boolean;
|
|
516
516
|
nature?: string;
|
|
517
517
|
happiness?: number;
|
|
518
|
+
dynamaxLevel?: number;
|
|
518
519
|
gigantamax?: boolean;
|
|
519
520
|
}
|
|
520
521
|
export interface RandomFactorySet {
|
|
@@ -530,6 +531,7 @@ export namespace RandomTeamsTypes {
|
|
|
530
531
|
ivs: SparseStatsTable;
|
|
531
532
|
nature: string;
|
|
532
533
|
moves: string[];
|
|
534
|
+
dynamaxLevel?: number;
|
|
533
535
|
gigantamax?: boolean;
|
|
534
536
|
}
|
|
535
537
|
}
|
package/sim/global-types.ts
CHANGED
|
@@ -515,6 +515,7 @@ namespace RandomTeamsTypes {
|
|
|
515
515
|
shiny: boolean;
|
|
516
516
|
nature?: string;
|
|
517
517
|
happiness?: number;
|
|
518
|
+
dynamaxLevel?: number;
|
|
518
519
|
gigantamax?: boolean;
|
|
519
520
|
}
|
|
520
521
|
export interface RandomFactorySet {
|
|
@@ -530,6 +531,7 @@ namespace RandomTeamsTypes {
|
|
|
530
531
|
ivs: SparseStatsTable;
|
|
531
532
|
nature: string;
|
|
532
533
|
moves: string[];
|
|
534
|
+
dynamaxLevel?: number;
|
|
533
535
|
gigantamax?: boolean;
|
|
534
536
|
}
|
|
535
537
|
}
|
package/sim/pokemon.ts
CHANGED
|
@@ -77,6 +77,7 @@ export class Pokemon {
|
|
|
77
77
|
readonly gender: GenderName;
|
|
78
78
|
readonly happiness: number;
|
|
79
79
|
readonly pokeball: string;
|
|
80
|
+
readonly dynamaxLevel: number;
|
|
80
81
|
readonly gigantamax: boolean;
|
|
81
82
|
|
|
82
83
|
/** Transform keeps the original pre-transformed Hidden Power in Gen 2-4. */
|
|
@@ -326,6 +327,7 @@ export class Pokemon {
|
|
|
326
327
|
if (this.gender === 'N') this.gender = '';
|
|
327
328
|
this.happiness = typeof set.happiness === 'number' ? this.battle.clampIntRange(set.happiness, 0, 255) : 255;
|
|
328
329
|
this.pokeball = this.set.pokeball || 'pokeball';
|
|
330
|
+
this.dynamaxLevel = typeof set.dynamaxLevel === 'number' ? this.battle.clampIntRange(set.dynamaxLevel, 0, 10) : 10;
|
|
329
331
|
this.gigantamax = this.set.gigantamax || false;
|
|
330
332
|
|
|
331
333
|
this.baseMoveSlots = [];
|
|
@@ -1522,7 +1524,7 @@ export class Pokemon {
|
|
|
1522
1524
|
cureStatus(silent = false) {
|
|
1523
1525
|
if (!this.hp || !this.status) return false;
|
|
1524
1526
|
this.battle.add('-curestatus', this, this.status, silent ? '[silent]' : '[msg]');
|
|
1525
|
-
if (this.status === 'slp' &&
|
|
1527
|
+
if (this.status === 'slp' && this.removeVolatile('nightmare')) {
|
|
1526
1528
|
this.battle.add('-end', this, 'Nightmare', '[silent]');
|
|
1527
1529
|
}
|
|
1528
1530
|
this.setStatus('');
|
|
@@ -1599,7 +1601,12 @@ export class Pokemon {
|
|
|
1599
1601
|
* Unlike cureStatus, does not give cure message
|
|
1600
1602
|
*/
|
|
1601
1603
|
clearStatus() {
|
|
1602
|
-
|
|
1604
|
+
if (!this.hp || !this.status) return false;
|
|
1605
|
+
if (this.status === 'slp' && this.removeVolatile('nightmare')) {
|
|
1606
|
+
this.battle.add('-end', this, 'Nightmare', '[silent]');
|
|
1607
|
+
}
|
|
1608
|
+
this.setStatus('');
|
|
1609
|
+
return true;
|
|
1603
1610
|
}
|
|
1604
1611
|
|
|
1605
1612
|
getStatus() {
|
package/sim/side.ts
CHANGED
|
@@ -796,6 +796,26 @@ export class Side {
|
|
|
796
796
|
}
|
|
797
797
|
}
|
|
798
798
|
}
|
|
799
|
+
if (ruleTable.valueRules.has('forceselect')) {
|
|
800
|
+
const species = this.battle.dex.species.get(ruleTable.valueRules.get('forceselect'));
|
|
801
|
+
if (!data) {
|
|
802
|
+
// autoChoose
|
|
803
|
+
positions = [...this.pokemon.keys()].filter(pos => this.pokemon[pos].species.name === species.name)
|
|
804
|
+
.concat([...this.pokemon.keys()].filter(pos => this.pokemon[pos].species.name !== species.name))
|
|
805
|
+
.slice(0, pickedTeamSize);
|
|
806
|
+
} else {
|
|
807
|
+
let hasSelection = false;
|
|
808
|
+
for (const pos of positions) {
|
|
809
|
+
if (this.pokemon[pos].species.name === species.name) {
|
|
810
|
+
hasSelection = true;
|
|
811
|
+
break;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
if (!hasSelection) {
|
|
815
|
+
return this.emitChoiceError(`You must bring ${species.name} to the battle.`);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
}
|
|
799
819
|
for (const [index, pos] of positions.entries()) {
|
|
800
820
|
this.choice.switchIns.add(pos);
|
|
801
821
|
this.choice.actions.push({
|