@pkmn/sim 0.5.13 → 0.5.16
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 +151 -145
- package/build/config/formats.js.map +1 -1
- package/build/data/aliases.js +2 -2
- 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 +3 -3
- package/build/data/formats-data.js.map +1 -1
- package/build/data/items.js +4 -2
- package/build/data/items.js.map +1 -1
- package/build/data/learnsets.js +5 -4
- package/build/data/learnsets.js.map +1 -1
- package/build/data/mods/gen1/formats-data.js +32 -32
- package/build/data/mods/gen1/formats-data.js.map +1 -1
- package/build/data/mods/gen1/scripts.js +1 -1
- package/build/data/mods/gen1/scripts.js.map +1 -1
- package/build/data/mods/gen2/items.js +28 -0
- package/build/data/mods/gen2/items.js.map +1 -1
- package/build/data/mods/gen2/moves.js +2 -5
- package/build/data/mods/gen2/moves.js.map +1 -1
- package/build/data/mods/gen3/items.js +28 -0
- package/build/data/mods/gen3/items.js.map +1 -1
- package/build/data/mods/gen3/moves.js +0 -3
- package/build/data/mods/gen3/moves.js.map +1 -1
- package/build/data/mods/gen4/abilities.js +20 -0
- package/build/data/mods/gen4/abilities.js.map +1 -1
- package/build/data/mods/gen4/items.js +28 -0
- package/build/data/mods/gen4/items.js.map +1 -1
- package/build/data/mods/gen4/moves.js +16 -9
- package/build/data/mods/gen4/moves.js.map +1 -1
- package/build/data/mods/gen5/items.js +0 -4
- package/build/data/mods/gen5/items.js.map +1 -1
- package/build/data/mods/gen6/items.js +24 -0
- package/build/data/mods/gen6/items.js.map +1 -1
- package/build/data/mods/gen7/abilities.js +31 -0
- package/build/data/mods/gen7/abilities.js.map +1 -1
- package/build/data/mods/gen7/items.js +12 -0
- package/build/data/mods/gen7/items.js.map +1 -1
- package/build/data/mods/gen7/moves.js +14 -0
- package/build/data/mods/gen7/moves.js.map +1 -1
- package/build/data/moves.js +45 -20
- package/build/data/moves.js.map +1 -1
- package/build/data/rulesets.js +71 -0
- 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/data/text/moves.js +8 -8
- package/build/data/text/moves.js.map +1 -1
- package/build/sim/battle-actions.js +3 -3
- package/build/sim/battle-actions.js.map +1 -1
- package/build/sim/battle-queue.d.ts +2 -2
- package/build/sim/battle-queue.js +8 -0
- package/build/sim/battle-queue.js.map +1 -1
- package/build/sim/battle.js +46 -6
- package/build/sim/battle.js.map +1 -1
- package/build/sim/dex-conditions.d.ts +2 -2
- package/build/sim/dex-conditions.js.map +1 -1
- package/build/sim/dex-data.js +0 -1
- package/build/sim/dex-data.js.map +1 -1
- package/build/sim/dex-moves.d.ts +2 -1
- package/build/sim/dex-moves.js.map +1 -1
- package/build/sim/pokemon.js +18 -5
- package/build/sim/pokemon.js.map +1 -1
- package/build/sim/team-validator.js +1 -1
- package/build/sim/team-validator.js.map +1 -1
- package/config/formats.ts +156 -150
- package/data/aliases.ts +2 -2
- package/data/conditions.ts +4 -1
- package/data/formats-data.ts +3 -3
- package/data/items.ts +4 -2
- package/data/learnsets.ts +5 -4
- package/data/mods/gen1/formats-data.ts +32 -32
- package/data/mods/gen1/scripts.ts +1 -1
- package/data/mods/gen2/items.ts +28 -0
- package/data/mods/gen2/moves.ts +2 -5
- package/data/mods/gen3/items.ts +28 -0
- package/data/mods/gen3/moves.ts +0 -3
- package/data/mods/gen4/abilities.ts +20 -0
- package/data/mods/gen4/items.ts +28 -0
- package/data/mods/gen4/moves.ts +15 -10
- package/data/mods/gen5/items.ts +0 -4
- package/data/mods/gen6/items.ts +24 -0
- package/data/mods/gen7/abilities.ts +31 -0
- package/data/mods/gen7/items.ts +12 -0
- package/data/mods/gen7/moves.ts +14 -0
- package/data/moves.ts +45 -19
- package/data/rulesets.ts +70 -0
- package/data/tags.ts +3 -3
- package/data/text/moves.ts +8 -8
- package/package.json +2 -2
- package/sim/battle-actions.ts +3 -4
- package/sim/battle-queue.ts +10 -2
- package/sim/battle.ts +43 -6
- package/sim/dex-conditions.ts +6 -2
- package/sim/dex-data.ts +0 -1
- package/sim/dex-moves.ts +2 -1
- package/sim/pokemon.ts +19 -7
- package/sim/team-validator.ts +1 -1
|
@@ -66,6 +66,37 @@ export const Abilities: {[k: string]: ModdedAbilityData} = {
|
|
|
66
66
|
inherit: true,
|
|
67
67
|
onBoost() {},
|
|
68
68
|
},
|
|
69
|
+
slowstart: {
|
|
70
|
+
inherit: true,
|
|
71
|
+
condition: {
|
|
72
|
+
duration: 5,
|
|
73
|
+
onResidualOrder: 28,
|
|
74
|
+
onResidualSubOrder: 2,
|
|
75
|
+
onStart(target) {
|
|
76
|
+
this.add('-start', target, 'ability: Slow Start');
|
|
77
|
+
},
|
|
78
|
+
onModifyAtkPriority: 5,
|
|
79
|
+
onModifyAtk(atk, pokemon, target, move) {
|
|
80
|
+
// This is because the game checks the move's category in data, rather than what it is currently, unlike e.g. Huge Power
|
|
81
|
+
if (this.dex.moves.get(move.id).category === 'Physical') {
|
|
82
|
+
return this.chainModify(0.5);
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
onModifySpAPriority: 5,
|
|
86
|
+
onModifySpA(spa, pokemon, target, move) {
|
|
87
|
+
// Ordinary Z-moves like Breakneck Blitz will halve the user's Special Attack as well
|
|
88
|
+
if (this.dex.moves.get(move.id).category === 'Physical') {
|
|
89
|
+
return this.chainModify(0.5);
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
onModifySpe(spe, pokemon) {
|
|
93
|
+
return this.chainModify(0.5);
|
|
94
|
+
},
|
|
95
|
+
onEnd(target) {
|
|
96
|
+
this.add('-end', target, 'Slow Start');
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
},
|
|
69
100
|
soundproof: {
|
|
70
101
|
inherit: true,
|
|
71
102
|
onTryHit(target, source, move) {
|
package/data/mods/gen7/items.ts
CHANGED
|
@@ -140,6 +140,10 @@ export const Items: {[k: string]: ModdedItemData} = {
|
|
|
140
140
|
inherit: true,
|
|
141
141
|
isNonstandard: null,
|
|
142
142
|
},
|
|
143
|
+
dreamball: {
|
|
144
|
+
inherit: true,
|
|
145
|
+
isNonstandard: "Unobtainable",
|
|
146
|
+
},
|
|
143
147
|
durinberry: {
|
|
144
148
|
inherit: true,
|
|
145
149
|
isNonstandard: "Unobtainable",
|
|
@@ -495,6 +499,10 @@ export const Items: {[k: string]: ModdedItemData} = {
|
|
|
495
499
|
inherit: true,
|
|
496
500
|
isNonstandard: null,
|
|
497
501
|
},
|
|
502
|
+
safariball: {
|
|
503
|
+
inherit: true,
|
|
504
|
+
isNonstandard: "Unobtainable",
|
|
505
|
+
},
|
|
498
506
|
sailfossil: {
|
|
499
507
|
inherit: true,
|
|
500
508
|
isNonstandard: null,
|
|
@@ -547,6 +555,10 @@ export const Items: {[k: string]: ModdedItemData} = {
|
|
|
547
555
|
inherit: true,
|
|
548
556
|
isNonstandard: null,
|
|
549
557
|
},
|
|
558
|
+
sportball: {
|
|
559
|
+
inherit: true,
|
|
560
|
+
isNonstandard: "Unobtainable",
|
|
561
|
+
},
|
|
550
562
|
steelgem: {
|
|
551
563
|
inherit: true,
|
|
552
564
|
isNonstandard: "Unobtainable",
|
package/data/mods/gen7/moves.ts
CHANGED
|
@@ -259,6 +259,20 @@ export const Moves: {[k: string]: ModdedMoveData} = {
|
|
|
259
259
|
return success;
|
|
260
260
|
},
|
|
261
261
|
},
|
|
262
|
+
fly: {
|
|
263
|
+
inherit: true,
|
|
264
|
+
onTryMove(attacker, defender, move) {
|
|
265
|
+
if (attacker.removeVolatile(move.id)) {
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
this.add('-prepare', attacker, move.name);
|
|
269
|
+
if (!this.runEvent('ChargeMove', attacker, defender, move)) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
attacker.addVolatile('twoturnmove', defender);
|
|
273
|
+
return null;
|
|
274
|
+
},
|
|
275
|
+
},
|
|
262
276
|
foresight: {
|
|
263
277
|
inherit: true,
|
|
264
278
|
isNonstandard: null,
|
package/data/moves.ts
CHANGED
|
@@ -1006,6 +1006,13 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
1006
1006
|
pp: 40,
|
|
1007
1007
|
priority: 0,
|
|
1008
1008
|
flags: {},
|
|
1009
|
+
onHit(target) {
|
|
1010
|
+
if (!this.canSwitch(target.side)) {
|
|
1011
|
+
this.attrLastMove('[still]');
|
|
1012
|
+
this.add('-fail', target);
|
|
1013
|
+
return this.NOT_FAIL;
|
|
1014
|
+
}
|
|
1015
|
+
},
|
|
1009
1016
|
self: {
|
|
1010
1017
|
onHit(source) {
|
|
1011
1018
|
source.skipBeforeSwitchOutEventFlag = true;
|
|
@@ -1028,7 +1035,7 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
1028
1035
|
pp: 15,
|
|
1029
1036
|
priority: -3,
|
|
1030
1037
|
flags: {bullet: 1, protect: 1},
|
|
1031
|
-
|
|
1038
|
+
priorityChargeCallback(pokemon) {
|
|
1032
1039
|
pokemon.addVolatile('beakblast');
|
|
1033
1040
|
},
|
|
1034
1041
|
condition: {
|
|
@@ -2633,7 +2640,7 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
2633
2640
|
beforeTurnCallback(pokemon) {
|
|
2634
2641
|
pokemon.addVolatile('counter');
|
|
2635
2642
|
},
|
|
2636
|
-
|
|
2643
|
+
onTry(source) {
|
|
2637
2644
|
if (!source.volatiles['counter']) return false;
|
|
2638
2645
|
if (source.volatiles['counter'].slot === null) return false;
|
|
2639
2646
|
},
|
|
@@ -3085,6 +3092,7 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
3085
3092
|
volatileStatus: 'defensecurl',
|
|
3086
3093
|
condition: {
|
|
3087
3094
|
noCopy: true,
|
|
3095
|
+
onRestart: () => null,
|
|
3088
3096
|
},
|
|
3089
3097
|
secondary: null,
|
|
3090
3098
|
target: "self",
|
|
@@ -4791,7 +4799,6 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
4791
4799
|
pp: 5,
|
|
4792
4800
|
priority: 0,
|
|
4793
4801
|
flags: {protect: 1},
|
|
4794
|
-
selfdestruct: "ifHit",
|
|
4795
4802
|
secondary: null,
|
|
4796
4803
|
target: "normal",
|
|
4797
4804
|
type: "Fighting",
|
|
@@ -5383,6 +5390,17 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
5383
5390
|
if (!this.runEvent('ChargeMove', attacker, defender, move)) {
|
|
5384
5391
|
return;
|
|
5385
5392
|
}
|
|
5393
|
+
|
|
5394
|
+
// In SwSh, Fly's animation leaks the initial target through a camera focus
|
|
5395
|
+
// The animation leak target itself isn't "accurate"; the target it reveals is as if Fly weren't a charge movee
|
|
5396
|
+
// (Fly, like all other charge moves, will actually target slots on its charging turn, relevant for things like Follow Me)
|
|
5397
|
+
// We use a generic single-target move to represent this
|
|
5398
|
+
if (this.gameType === 'doubles' || this.gameType === 'multi') {
|
|
5399
|
+
const animatedTarget = attacker.getMoveTargets(this.dex.getActiveMove('aerialace'), defender).targets[0];
|
|
5400
|
+
if (animatedTarget) {
|
|
5401
|
+
this.hint(`${move.name}'s animation targeted ${animatedTarget.name}`);
|
|
5402
|
+
}
|
|
5403
|
+
}
|
|
5386
5404
|
attacker.addVolatile('twoturnmove', defender);
|
|
5387
5405
|
return null;
|
|
5388
5406
|
},
|
|
@@ -5481,11 +5499,11 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
5481
5499
|
pp: 20,
|
|
5482
5500
|
priority: -3,
|
|
5483
5501
|
flags: {contact: 1, protect: 1, punch: 1},
|
|
5484
|
-
|
|
5502
|
+
priorityChargeCallback(pokemon) {
|
|
5485
5503
|
pokemon.addVolatile('focuspunch');
|
|
5486
5504
|
},
|
|
5487
5505
|
beforeMoveCallback(pokemon) {
|
|
5488
|
-
if (pokemon.volatiles['focuspunch']
|
|
5506
|
+
if (pokemon.volatiles['focuspunch']?.lostFocus) {
|
|
5489
5507
|
this.add('cant', pokemon, 'Focus Punch', 'Focus Punch');
|
|
5490
5508
|
return true;
|
|
5491
5509
|
}
|
|
@@ -5497,7 +5515,7 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
5497
5515
|
},
|
|
5498
5516
|
onHit(pokemon, source, move) {
|
|
5499
5517
|
if (move.category !== 'Status') {
|
|
5500
|
-
|
|
5518
|
+
this.effectState.lostFocus = true;
|
|
5501
5519
|
}
|
|
5502
5520
|
},
|
|
5503
5521
|
onTryAddVolatile(status, pokemon) {
|
|
@@ -7800,10 +7818,12 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
7800
7818
|
pp: 10,
|
|
7801
7819
|
priority: 0,
|
|
7802
7820
|
flags: {snatch: 1, heal: 1},
|
|
7803
|
-
|
|
7804
|
-
if (!this.canSwitch(
|
|
7821
|
+
onHit(target, source, move) {
|
|
7822
|
+
if (!this.canSwitch(source.side)) {
|
|
7805
7823
|
delete move.selfdestruct;
|
|
7806
|
-
|
|
7824
|
+
this.attrLastMove('[still]');
|
|
7825
|
+
this.add('-fail', source);
|
|
7826
|
+
return this.NOT_FAIL;
|
|
7807
7827
|
}
|
|
7808
7828
|
},
|
|
7809
7829
|
selfdestruct: "ifHit",
|
|
@@ -9894,10 +9914,12 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
9894
9914
|
pp: 10,
|
|
9895
9915
|
priority: 0,
|
|
9896
9916
|
flags: {snatch: 1, heal: 1, dance: 1},
|
|
9897
|
-
|
|
9898
|
-
if (!this.canSwitch(
|
|
9917
|
+
onHit(target, source, move) {
|
|
9918
|
+
if (!this.canSwitch(source.side)) {
|
|
9899
9919
|
delete move.selfdestruct;
|
|
9900
|
-
|
|
9920
|
+
this.attrLastMove('[still]');
|
|
9921
|
+
this.add('-fail', source);
|
|
9922
|
+
return this.NOT_FAIL;
|
|
9901
9923
|
}
|
|
9902
9924
|
},
|
|
9903
9925
|
selfdestruct: "ifHit",
|
|
@@ -10914,7 +10936,7 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
10914
10936
|
pp: 10,
|
|
10915
10937
|
priority: 0,
|
|
10916
10938
|
flags: {protect: 1, mirror: 1},
|
|
10917
|
-
|
|
10939
|
+
onTry(source) {
|
|
10918
10940
|
const lastDamagedBy = source.getLastDamagedBy(true);
|
|
10919
10941
|
if (lastDamagedBy === undefined || !lastDamagedBy.thisTurn) return false;
|
|
10920
10942
|
},
|
|
@@ -11176,6 +11198,7 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
11176
11198
|
volatileStatus: 'minimize',
|
|
11177
11199
|
condition: {
|
|
11178
11200
|
noCopy: true,
|
|
11201
|
+
onRestart: () => null,
|
|
11179
11202
|
onSourceModifyDamage(damage, source, target, move) {
|
|
11180
11203
|
const boostedMoves = [
|
|
11181
11204
|
'stomp', 'steamroller', 'bodyslam', 'flyingpress', 'dragonrush', 'heatcrash', 'heavyslam', 'maliciousmoonsault',
|
|
@@ -11253,7 +11276,7 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
11253
11276
|
beforeTurnCallback(pokemon) {
|
|
11254
11277
|
pokemon.addVolatile('mirrorcoat');
|
|
11255
11278
|
},
|
|
11256
|
-
|
|
11279
|
+
onTry(source) {
|
|
11257
11280
|
if (!source.volatiles['mirrorcoat']) return false;
|
|
11258
11281
|
if (source.volatiles['mirrorcoat'].slot === null) return false;
|
|
11259
11282
|
},
|
|
@@ -13467,7 +13490,7 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
13467
13490
|
let alreadyAdded = false;
|
|
13468
13491
|
pokemon.removeVolatile('destinybond');
|
|
13469
13492
|
for (const source of this.effectState.sources) {
|
|
13470
|
-
if (!this.queue.cancelMove(source) || !source.hp) continue;
|
|
13493
|
+
if (!source.isAdjacent(pokemon) || !this.queue.cancelMove(source) || !source.hp) continue;
|
|
13471
13494
|
if (!alreadyAdded) {
|
|
13472
13495
|
this.add('-activate', pokemon, 'move: Pursuit');
|
|
13473
13496
|
alreadyAdded = true;
|
|
@@ -13989,7 +14012,8 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
13989
14012
|
}
|
|
13990
14013
|
},
|
|
13991
14014
|
onHit(target, source, move) {
|
|
13992
|
-
|
|
14015
|
+
const result = target.setStatus('slp', source, move);
|
|
14016
|
+
if (!result) return result;
|
|
13993
14017
|
target.statusState.time = 3;
|
|
13994
14018
|
target.statusState.startTime = 3;
|
|
13995
14019
|
this.heal(target.maxhp); // Aesthetic only as the healing happens after you fall asleep in-game
|
|
@@ -15199,7 +15223,7 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
15199
15223
|
pp: 5,
|
|
15200
15224
|
priority: -3,
|
|
15201
15225
|
flags: {protect: 1},
|
|
15202
|
-
|
|
15226
|
+
priorityChargeCallback(pokemon) {
|
|
15203
15227
|
pokemon.addVolatile('shelltrap');
|
|
15204
15228
|
},
|
|
15205
15229
|
onTryMove(pokemon) {
|
|
@@ -15216,7 +15240,7 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
15216
15240
|
},
|
|
15217
15241
|
onHit(pokemon, source, move) {
|
|
15218
15242
|
if (!pokemon.isAlly(source) && move.category === 'Physical') {
|
|
15219
|
-
|
|
15243
|
+
this.effectState.gotHit = true;
|
|
15220
15244
|
const action = this.queue.willMove(pokemon);
|
|
15221
15245
|
if (action) {
|
|
15222
15246
|
this.queue.prioritizeAction(action);
|
|
@@ -17945,8 +17969,10 @@ export const Moves: {[moveid: string]: MoveData} = {
|
|
|
17945
17969
|
pp: 20,
|
|
17946
17970
|
priority: -6,
|
|
17947
17971
|
flags: {},
|
|
17972
|
+
onTry(source) {
|
|
17973
|
+
return !!this.canSwitch(source.side);
|
|
17974
|
+
},
|
|
17948
17975
|
selfSwitch: true,
|
|
17949
|
-
onTryHit: true,
|
|
17950
17976
|
secondary: null,
|
|
17951
17977
|
target: "self",
|
|
17952
17978
|
type: "Psychic",
|
package/data/rulesets.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Note: These are the rules that formats use
|
|
2
2
|
|
|
3
3
|
import {Utils} from "../lib";
|
|
4
|
+
import {Pokemon} from "../sim/pokemon";
|
|
4
5
|
|
|
5
6
|
// The list of formats is stored in config/formats.js
|
|
6
7
|
export const Rulesets: {[k: string]: FormatData} = {
|
|
@@ -1604,6 +1605,75 @@ export const Rulesets: {[k: string]: FormatData} = {
|
|
|
1604
1605
|
pokemon.trapped = true;
|
|
1605
1606
|
},
|
|
1606
1607
|
},
|
|
1608
|
+
crazyhouserule: {
|
|
1609
|
+
effectType: 'Rule',
|
|
1610
|
+
name: 'Crazyhouse Rule',
|
|
1611
|
+
desc: "Pok\u00e9mon you KO are added to your team and removed from the opponent's, and vice versa.",
|
|
1612
|
+
onValidateRule(value) {
|
|
1613
|
+
if (this.format.gameType === 'doubles' || this.format.gameType === 'triples') {
|
|
1614
|
+
throw new Error(`Crazyhouse Rule currently does not support ${this.format.gameType} battles.`);
|
|
1615
|
+
}
|
|
1616
|
+
const ruleTable = this.ruleTable;
|
|
1617
|
+
const maxTeamSize = ruleTable.pickedTeamSize || ruleTable.maxTeamSize;
|
|
1618
|
+
const numPlayers = (this.format.gameType === 'freeforall' || this.format.gameType === 'multi') ? 4 : 2;
|
|
1619
|
+
const potentialMaxTeamSize = maxTeamSize * numPlayers;
|
|
1620
|
+
if (potentialMaxTeamSize > 24) {
|
|
1621
|
+
throw new Error(`Crazyhouse Rule cannot be added because a team can potentially have ${potentialMaxTeamSize} Pokemon on one team, which is more than the server limit of 24.`);
|
|
1622
|
+
}
|
|
1623
|
+
},
|
|
1624
|
+
// In order to prevent a case of the clones, housekeeping is needed.
|
|
1625
|
+
// This is especially needed to make sure one side doesn't end up with too many Pokemon.
|
|
1626
|
+
onBeforeSwitchIn(pokemon) {
|
|
1627
|
+
if (this.turn < 1 || !pokemon.side.faintedThisTurn) return;
|
|
1628
|
+
pokemon.side.pokemon = pokemon.side.pokemon.filter(x => !(x.fainted && !x.m.outofplay));
|
|
1629
|
+
for (let i = 0; i < pokemon.side.pokemon.length && i < 24; i++) {
|
|
1630
|
+
pokemon.side.pokemon[i].position = i;
|
|
1631
|
+
}
|
|
1632
|
+
},
|
|
1633
|
+
onFaint(target, source, effect) {
|
|
1634
|
+
if (!target.m.numSwaps) {
|
|
1635
|
+
target.m.numSwaps = 0;
|
|
1636
|
+
}
|
|
1637
|
+
target.m.numSwaps++;
|
|
1638
|
+
if (effect && effect.effectType === 'Move' && source.side.pokemon.length < 24 &&
|
|
1639
|
+
source.side !== target.side && target.m.numSwaps < 4) {
|
|
1640
|
+
const hpCost = this.clampIntRange(Math.floor((target.baseMaxhp * target.m.numSwaps) / 4), 1);
|
|
1641
|
+
// Just in case(tm) and for Shedinja
|
|
1642
|
+
if (hpCost === target.baseMaxhp) {
|
|
1643
|
+
target.m.outofplay = true;
|
|
1644
|
+
return;
|
|
1645
|
+
}
|
|
1646
|
+
source.side.pokemonLeft++;
|
|
1647
|
+
source.side.pokemon.length++;
|
|
1648
|
+
|
|
1649
|
+
// A new Pokemon is created and stuff gets aside akin to a deep clone.
|
|
1650
|
+
// This is because deepClone crashes when side is called recursively.
|
|
1651
|
+
// Until a refactor is made to prevent it, this is the best option to prevent crashes.
|
|
1652
|
+
const newPoke = new Pokemon(target.set, source.side);
|
|
1653
|
+
const newPos = source.side.pokemon.length - 1;
|
|
1654
|
+
|
|
1655
|
+
const doNotCarryOver = [
|
|
1656
|
+
'fullname', 'side', 'fainted', 'status', 'hp', 'illusion',
|
|
1657
|
+
'transformed', 'position', 'isActive', 'faintQueued',
|
|
1658
|
+
'subFainted', 'getHealth', 'getDetails', 'moveSlots', 'ability',
|
|
1659
|
+
];
|
|
1660
|
+
for (const [key, value] of Object.entries(target)) {
|
|
1661
|
+
if (doNotCarryOver.includes(key)) continue;
|
|
1662
|
+
// @ts-ignore
|
|
1663
|
+
newPoke[key] = value;
|
|
1664
|
+
}
|
|
1665
|
+
newPoke.maxhp = newPoke.baseMaxhp; // for dynamax
|
|
1666
|
+
newPoke.hp = newPoke.baseMaxhp - hpCost;
|
|
1667
|
+
newPoke.clearVolatile();
|
|
1668
|
+
newPoke.position = newPos;
|
|
1669
|
+
source.side.pokemon[newPos] = newPoke;
|
|
1670
|
+
this.add('poke', source.side.pokemon[newPos].side.id, source.side.pokemon[newPos].details, '');
|
|
1671
|
+
this.add('-message', `${target.name} was captured by ${newPoke.side.name}!`);
|
|
1672
|
+
} else {
|
|
1673
|
+
target.m.outofplay = true;
|
|
1674
|
+
}
|
|
1675
|
+
},
|
|
1676
|
+
},
|
|
1607
1677
|
chimera1v1rule: {
|
|
1608
1678
|
effectType: 'Rule',
|
|
1609
1679
|
name: 'Chimera 1v1 Rule',
|
package/data/tags.ts
CHANGED
|
@@ -198,9 +198,9 @@ export const Tags: {[id: string]: TagData} = {
|
|
|
198
198
|
name: "ND UUBL",
|
|
199
199
|
speciesFilter: species => [
|
|
200
200
|
'Aerodactyl-Mega', 'Alakazam', 'Blacephalon', 'Blaziken', 'Diancie-Mega', 'Gallade-Mega', 'Gardevoir-Mega', 'Gengar', 'Gyarados',
|
|
201
|
-
'Gyarados-Mega', 'Hawlucha', 'Heracross-Mega', 'Hoopa-Unbound', 'Hydreigon', 'Jirachi', 'Latias', 'Latias-Mega', 'Latios',
|
|
202
|
-
'Manaphy', 'Medicham-Mega', 'Mew', 'Pinsir-Mega', 'Sableye-Mega', 'Slowbro-Mega', 'Slowking-Galar',
|
|
203
|
-
'Venusaur-Mega', 'Xurkitree', 'Zapdos-Galar',
|
|
201
|
+
'Gyarados-Mega', 'Hawlucha', 'Heracross-Mega', 'Hoopa-Unbound', 'Hydreigon', 'Jirachi', 'Latias', 'Latias-Mega', 'Latios',
|
|
202
|
+
'Latios-Mega', 'Manaphy', 'Medicham-Mega', 'Melmetal', 'Mew', 'Pinsir-Mega', 'Sableye-Mega', 'Slowbro-Mega', 'Slowking-Galar',
|
|
203
|
+
'Thundurus', 'Thundurus-Therian', 'Venusaur-Mega', 'Xurkitree', 'Zapdos-Galar',
|
|
204
204
|
].includes(species.name),
|
|
205
205
|
},
|
|
206
206
|
|
package/data/text/moves.ts
CHANGED
|
@@ -296,7 +296,7 @@ export const MovesText: {[k: string]: MoveText} = {
|
|
|
296
296
|
},
|
|
297
297
|
banefulbunker: {
|
|
298
298
|
name: "Baneful Bunker",
|
|
299
|
-
desc: "The user is protected from most attacks made by other Pokemon during this turn, and Pokemon making contact with the user become poisoned. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
|
|
299
|
+
desc: "The user is protected from most attacks made by other Pokemon during this turn, and Pokemon making contact with the user become poisoned. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Max Guard, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
|
|
300
300
|
shortDesc: "Protects from moves. Contact: poison.",
|
|
301
301
|
gen7: {
|
|
302
302
|
desc: "The user is protected from most attacks made by other Pokemon during this turn, and Pokemon making contact with the user become poisoned. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
|
|
@@ -1159,7 +1159,7 @@ export const MovesText: {[k: string]: MoveText} = {
|
|
|
1159
1159
|
},
|
|
1160
1160
|
detect: {
|
|
1161
1161
|
name: "Detect",
|
|
1162
|
-
desc: "The user is protected from most attacks made by other Pokemon during this turn. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
|
|
1162
|
+
desc: "The user is protected from most attacks made by other Pokemon during this turn. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Max Guard, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
|
|
1163
1163
|
shortDesc: "Prevents moves from affecting the user this turn.",
|
|
1164
1164
|
gen7: {
|
|
1165
1165
|
desc: "The user is protected from most attacks made by other Pokemon during this turn. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
|
|
@@ -1583,7 +1583,7 @@ export const MovesText: {[k: string]: MoveText} = {
|
|
|
1583
1583
|
},
|
|
1584
1584
|
endure: {
|
|
1585
1585
|
name: "Endure",
|
|
1586
|
-
desc: "The user will survive attacks made by other Pokemon during this turn with at least 1 HP. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
|
|
1586
|
+
desc: "The user will survive attacks made by other Pokemon during this turn with at least 1 HP. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Max Guard, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
|
|
1587
1587
|
shortDesc: "User survives attacks this turn with at least 1 HP.",
|
|
1588
1588
|
gen7: {
|
|
1589
1589
|
desc: "The user will survive attacks made by other Pokemon during this turn with at least 1 HP. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
|
|
@@ -3145,7 +3145,7 @@ export const MovesText: {[k: string]: MoveText} = {
|
|
|
3145
3145
|
},
|
|
3146
3146
|
kingsshield: {
|
|
3147
3147
|
name: "King's Shield",
|
|
3148
|
-
desc: "The user is protected from most attacks made by other Pokemon during this turn, and Pokemon trying to make contact with the user have their Attack lowered by 1 stage. Non-damaging moves go through this protection. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
|
|
3148
|
+
desc: "The user is protected from most attacks made by other Pokemon during this turn, and Pokemon trying to make contact with the user have their Attack lowered by 1 stage. Non-damaging moves go through this protection. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Max Guard, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
|
|
3149
3149
|
shortDesc: "Protects from damaging attacks. Contact: -1 Atk.",
|
|
3150
3150
|
gen7: {
|
|
3151
3151
|
desc: "The user is protected from most attacks made by other Pokemon during this turn, and Pokemon trying to make contact with the user have their Attack lowered by 2 stages. Non-damaging moves go through this protection. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
|
|
@@ -4417,7 +4417,7 @@ export const MovesText: {[k: string]: MoveText} = {
|
|
|
4417
4417
|
},
|
|
4418
4418
|
protect: {
|
|
4419
4419
|
name: "Protect",
|
|
4420
|
-
desc: "The user is protected from most attacks made by other Pokemon during this turn. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
|
|
4420
|
+
desc: "The user is protected from most attacks made by other Pokemon during this turn. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Max Guard, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
|
|
4421
4421
|
shortDesc: "Prevents moves from affecting the user this turn.",
|
|
4422
4422
|
gen7: {
|
|
4423
4423
|
desc: "The user is protected from most attacks made by other Pokemon during this turn. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
|
|
@@ -4570,7 +4570,7 @@ export const MovesText: {[k: string]: MoveText} = {
|
|
|
4570
4570
|
},
|
|
4571
4571
|
quickguard: {
|
|
4572
4572
|
name: "Quick Guard",
|
|
4573
|
-
desc: "The user and its party members are protected from attacks with original or altered priority greater than 0 made by other Pokemon, including allies, during this turn. This move modifies the same 1/X chance of being successful used by other protection moves, where X starts at 1 and triples each time this move is successfully used, but does not use the chance to check for failure. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn or if this move is already in effect for the user's side.",
|
|
4573
|
+
desc: "The user and its party members are protected from attacks with original or altered priority greater than 0 made by other Pokemon, including allies, during this turn. This move modifies the same 1/X chance of being successful used by other protection moves, where X starts at 1 and triples each time this move is successfully used, but does not use the chance to check for failure. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Max Guard, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn or if this move is already in effect for the user's side.",
|
|
4574
4574
|
shortDesc: "Protects allies from priority attacks this turn.",
|
|
4575
4575
|
gen7: {
|
|
4576
4576
|
desc: "The user and its party members are protected from attacks with original or altered priority greater than 0 made by other Pokemon, including allies, during this turn. This move modifies the same 1/X chance of being successful used by other protection moves, where X starts at 1 and triples each time this move is successfully used, but does not use the chance to check for failure. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn or if this move is already in effect for the user's side.",
|
|
@@ -5613,7 +5613,7 @@ export const MovesText: {[k: string]: MoveText} = {
|
|
|
5613
5613
|
},
|
|
5614
5614
|
spikyshield: {
|
|
5615
5615
|
name: "Spiky Shield",
|
|
5616
|
-
desc: "The user is protected from most attacks made by other Pokemon during this turn, and Pokemon making contact with the user lose 1/8 of their maximum HP, rounded down. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
|
|
5616
|
+
desc: "The user is protected from most attacks made by other Pokemon during this turn, and Pokemon making contact with the user lose 1/8 of their maximum HP, rounded down. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Max Guard, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
|
|
5617
5617
|
shortDesc: "Protects from moves. Contact: loses 1/8 max HP.",
|
|
5618
5618
|
gen7: {
|
|
5619
5619
|
desc: "The user is protected from most attacks made by other Pokemon during this turn, and Pokemon making contact with the user lose 1/8 of their maximum HP, rounded down. This move has a 1/X chance of being successful, where X starts at 1 and triples each time this move is successfully used. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn.",
|
|
@@ -6701,7 +6701,7 @@ export const MovesText: {[k: string]: MoveText} = {
|
|
|
6701
6701
|
},
|
|
6702
6702
|
wideguard: {
|
|
6703
6703
|
name: "Wide Guard",
|
|
6704
|
-
desc: "The user and its party members are protected from moves made by other Pokemon, including allies, during this turn that target all adjacent foes or all adjacent Pokemon. This move modifies the same 1/X chance of being successful used by other protection moves, where X starts at 1 and triples each time this move is successfully used, but does not use the chance to check for failure. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn or if this move is already in effect for the user's side.",
|
|
6704
|
+
desc: "The user and its party members are protected from moves made by other Pokemon, including allies, during this turn that target all adjacent foes or all adjacent Pokemon. This move modifies the same 1/X chance of being successful used by other protection moves, where X starts at 1 and triples each time this move is successfully used, but does not use the chance to check for failure. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Max Guard, Obstruct, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn or if this move is already in effect for the user's side.",
|
|
6705
6705
|
shortDesc: "Protects allies from multi-target moves this turn.",
|
|
6706
6706
|
gen7: {
|
|
6707
6707
|
desc: "The user and its party members are protected from moves made by other Pokemon, including allies, during this turn that target all adjacent foes or all adjacent Pokemon. This move modifies the same 1/X chance of being successful used by other protection moves, where X starts at 1 and triples each time this move is successfully used, but does not use the chance to check for failure. X resets to 1 if this move fails, if the user's last move used is not Baneful Bunker, Detect, Endure, King's Shield, Protect, Quick Guard, Spiky Shield, or Wide Guard, or if it was one of those moves and the user's protection was broken. Fails if the user moves last this turn or if this move is already in effect for the user's side.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pkmn/sim",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.16",
|
|
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",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"@pkmn/streams": "^1.0.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"mocha": "^
|
|
34
|
+
"mocha": "^10.0.0"
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
37
|
"compile": "tsc -p .",
|
package/sim/battle-actions.ts
CHANGED
|
@@ -1124,9 +1124,6 @@ export class BattleActions {
|
|
|
1124
1124
|
continue;
|
|
1125
1125
|
}
|
|
1126
1126
|
damage[i] = curDamage;
|
|
1127
|
-
if (move.selfdestruct === 'ifHit') {
|
|
1128
|
-
this.battle.faint(source, source, move);
|
|
1129
|
-
}
|
|
1130
1127
|
}
|
|
1131
1128
|
return damage;
|
|
1132
1129
|
}
|
|
@@ -1230,6 +1227,9 @@ export class BattleActions {
|
|
|
1230
1227
|
}
|
|
1231
1228
|
}
|
|
1232
1229
|
}
|
|
1230
|
+
if (moveData.selfdestruct === 'ifHit' && damage[i] !== false) {
|
|
1231
|
+
this.battle.faint(source, source, move);
|
|
1232
|
+
}
|
|
1233
1233
|
if (moveData.selfSwitch) {
|
|
1234
1234
|
if (this.battle.canSwitch(source.side)) {
|
|
1235
1235
|
didSomething = true;
|
|
@@ -1243,7 +1243,6 @@ export class BattleActions {
|
|
|
1243
1243
|
didAnything = this.combineResults(didAnything, didSomething);
|
|
1244
1244
|
}
|
|
1245
1245
|
|
|
1246
|
-
|
|
1247
1246
|
if (!didAnything && didAnything !== 0 && !moveData.self && !moveData.selfdestruct) {
|
|
1248
1247
|
if (!isSelf && !isSecondary) {
|
|
1249
1248
|
if (didAnything === false) {
|
package/sim/battle-queue.ts
CHANGED
|
@@ -20,8 +20,8 @@ import type {Battle} from './battle';
|
|
|
20
20
|
/** A move action */
|
|
21
21
|
export interface MoveAction {
|
|
22
22
|
/** action type */
|
|
23
|
-
choice: 'move' | 'beforeTurnMove';
|
|
24
|
-
order: 3 | 5 | 200 | 201 | 199;
|
|
23
|
+
choice: 'move' | 'beforeTurnMove' | 'priorityChargeMove';
|
|
24
|
+
order: 3 | 5 | 200 | 201 | 199 | 106;
|
|
25
25
|
/** priority of the action (lower first) */
|
|
26
26
|
priority: number;
|
|
27
27
|
/** fractional priority of the action (lower first) */
|
|
@@ -181,6 +181,7 @@ export class BattleQueue {
|
|
|
181
181
|
switch: 103,
|
|
182
182
|
megaEvo: 104,
|
|
183
183
|
runDynamax: 105,
|
|
184
|
+
priorityChargeMove: 106,
|
|
184
185
|
|
|
185
186
|
shift: 200,
|
|
186
187
|
// default is 200 (for moves)
|
|
@@ -215,6 +216,13 @@ export class BattleQueue {
|
|
|
215
216
|
pokemon: action.pokemon,
|
|
216
217
|
}));
|
|
217
218
|
}
|
|
219
|
+
if (!action.maxMove && !action.zmove && action.move.priorityChargeCallback) {
|
|
220
|
+
actions.unshift(...this.resolveAction({
|
|
221
|
+
choice: 'priorityChargeMove',
|
|
222
|
+
pokemon: action.pokemon,
|
|
223
|
+
move: action.move,
|
|
224
|
+
}));
|
|
225
|
+
}
|
|
218
226
|
action.fractionalPriority = this.battle.runEvent('FractionalPriority', action.pokemon, null, action.move, 0);
|
|
219
227
|
} else if (['switch', 'instaswitch'].includes(action.choice)) {
|
|
220
228
|
if (typeof action.pokemon.switchFlag === 'string') {
|
package/sim/battle.ts
CHANGED
|
@@ -1419,6 +1419,20 @@ export class Battle {
|
|
|
1419
1419
|
this.turn++;
|
|
1420
1420
|
this.lastSuccessfulMoveThisTurn = null;
|
|
1421
1421
|
|
|
1422
|
+
const dynamaxEnding: Pokemon[] = [];
|
|
1423
|
+
for (const pokemon of this.getAllActive()) {
|
|
1424
|
+
if (pokemon.volatiles['dynamax']?.turns === 3) {
|
|
1425
|
+
dynamaxEnding.push(pokemon);
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
if (dynamaxEnding.length > 1) {
|
|
1429
|
+
this.updateSpeed();
|
|
1430
|
+
this.speedSort(dynamaxEnding);
|
|
1431
|
+
}
|
|
1432
|
+
for (const pokemon of dynamaxEnding) {
|
|
1433
|
+
pokemon.removeVolatile('dynamax');
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1422
1436
|
const trappedBySide: boolean[] = [];
|
|
1423
1437
|
const stalenessBySide: ('internal' | 'external' | undefined)[] = [];
|
|
1424
1438
|
for (const side of this.sides) {
|
|
@@ -1548,6 +1562,23 @@ export class Battle {
|
|
|
1548
1562
|
if (this.gen === 2) this.quickClawRoll = this.randomChance(60, 256);
|
|
1549
1563
|
if (this.gen === 3) this.quickClawRoll = this.randomChance(1, 5);
|
|
1550
1564
|
|
|
1565
|
+
// Crazyhouse Progress checker because sidebars has trouble keeping track of Pokemon.
|
|
1566
|
+
// Please remove me once there is client support.
|
|
1567
|
+
if (this.ruleTable.has('crazyhouserule')) {
|
|
1568
|
+
for (const side of this.sides) {
|
|
1569
|
+
let buf = `raw|${side.name}'s team:<br />`;
|
|
1570
|
+
for (const pokemon of side.pokemon) {
|
|
1571
|
+
if (!buf.endsWith('<br />')) buf += '/</span>​';
|
|
1572
|
+
if (pokemon.fainted) {
|
|
1573
|
+
buf += `<span style="white-space:nowrap;"><span style="opacity:.3"><psicon pokemon="${pokemon.species.id}" /></span>`;
|
|
1574
|
+
} else {
|
|
1575
|
+
buf += `<span style="white-space:nowrap"><psicon pokemon="${pokemon.species.id}" />`;
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
this.add(`${buf}</span>`);
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1551
1582
|
this.makeRequest('move');
|
|
1552
1583
|
}
|
|
1553
1584
|
|
|
@@ -2232,11 +2263,11 @@ export class Battle {
|
|
|
2232
2263
|
if (this.activePerHalf > 2) {
|
|
2233
2264
|
if (move.target === 'adjacentFoe' || move.target === 'normal' || move.target === 'randomNormal') {
|
|
2234
2265
|
// even if a move can target an ally, auto-resolution will never make it target an ally
|
|
2235
|
-
// i.e. if both your opponents faint before you use Flamethrower, it will fail instead of targeting your
|
|
2266
|
+
// i.e. if both your opponents faint before you use Flamethrower, it will fail instead of targeting your ally
|
|
2236
2267
|
const adjacentFoes = pokemon.adjacentFoes();
|
|
2237
2268
|
if (adjacentFoes.length) return this.sample(adjacentFoes);
|
|
2238
|
-
// no valid target at all, return
|
|
2239
|
-
return pokemon.side.foe.active[
|
|
2269
|
+
// no valid target at all, return slot directly across for any possible redirection
|
|
2270
|
+
return pokemon.side.foe.active[pokemon.side.foe.active.length - 1 - pokemon.position];
|
|
2240
2271
|
}
|
|
2241
2272
|
}
|
|
2242
2273
|
return pokemon.side.randomFoe() || pokemon.side.foe.active[0];
|
|
@@ -2422,7 +2453,7 @@ export class Battle {
|
|
|
2422
2453
|
action.pokemon.side.dynamaxUsed = true;
|
|
2423
2454
|
if (action.pokemon.side.allySide) action.pokemon.side.allySide.dynamaxUsed = true;
|
|
2424
2455
|
break;
|
|
2425
|
-
case 'beforeTurnMove':
|
|
2456
|
+
case 'beforeTurnMove':
|
|
2426
2457
|
if (!action.pokemon.isActive) return false;
|
|
2427
2458
|
if (action.pokemon.fainted) return false;
|
|
2428
2459
|
this.debug('before turn callback: ' + action.move.id);
|
|
@@ -2431,7 +2462,13 @@ export class Battle {
|
|
|
2431
2462
|
if (!action.move.beforeTurnCallback) throw new Error(`beforeTurnMove has no beforeTurnCallback`);
|
|
2432
2463
|
action.move.beforeTurnCallback.call(this, action.pokemon, target);
|
|
2433
2464
|
break;
|
|
2434
|
-
|
|
2465
|
+
case 'priorityChargeMove':
|
|
2466
|
+
if (!action.pokemon.isActive) return false;
|
|
2467
|
+
if (action.pokemon.fainted) return false;
|
|
2468
|
+
this.debug('priority charge callback: ' + action.move.id);
|
|
2469
|
+
if (!action.move.priorityChargeCallback) throw new Error(`priorityChargeMove has no priorityChargeCallback`);
|
|
2470
|
+
action.move.priorityChargeCallback.call(this, action.pokemon);
|
|
2471
|
+
break;
|
|
2435
2472
|
|
|
2436
2473
|
case 'event':
|
|
2437
2474
|
this.runEvent(action.event!, action.pokemon);
|
|
@@ -2587,7 +2624,7 @@ export class Battle {
|
|
|
2587
2624
|
|
|
2588
2625
|
if (this.gen < 5) this.eachEvent('Update');
|
|
2589
2626
|
|
|
2590
|
-
if (this.gen >= 8 && this.queue.peek()?.choice === 'move') {
|
|
2627
|
+
if (this.gen >= 8 && (this.queue.peek()?.choice === 'move' || this.queue.peek()?.choice === 'runDynamax')) {
|
|
2591
2628
|
// In gen 8, speed is updated dynamically so update the queue's speed properties and sort it.
|
|
2592
2629
|
this.updateSpeed();
|
|
2593
2630
|
for (const queueAction of this.queue.list) {
|
package/sim/dex-conditions.ts
CHANGED
|
@@ -635,8 +635,12 @@ export class Condition extends BasicEffect implements
|
|
|
635
635
|
declare readonly durationCallback?: (this: Battle, target: Pokemon, source: Pokemon, effect: Effect | null) => number;
|
|
636
636
|
declare readonly onCopy?: (this: Battle, pokemon: Pokemon) => void;
|
|
637
637
|
declare readonly onEnd?: (this: Battle, target: Pokemon) => void;
|
|
638
|
-
declare readonly onRestart?: (
|
|
639
|
-
|
|
638
|
+
declare readonly onRestart?: (
|
|
639
|
+
this: Battle, target: Pokemon, source: Pokemon, sourceEffect: Effect
|
|
640
|
+
) => boolean | null | void;
|
|
641
|
+
declare readonly onStart?: (
|
|
642
|
+
this: Battle, target: Pokemon, source: Pokemon, sourceEffect: Effect
|
|
643
|
+
) => boolean | null | void;
|
|
640
644
|
|
|
641
645
|
constructor(data: AnyObject) {
|
|
642
646
|
super(data);
|