mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-04-26 18:57:15 -05:00
Compare commits
1193 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae12146317 | ||
|
|
a53ce5ebfc | ||
|
|
82f476388b | ||
|
|
f9e37e22c8 | ||
|
|
6ddd3e5cea | ||
|
|
1d2258d087 | ||
|
|
f4c2c03d75 | ||
|
|
4f12cc3daa | ||
|
|
9df652be21 | ||
|
|
6224d3ba15 | ||
|
|
7e2d55f209 | ||
|
|
f8cfbda668 | ||
|
|
d2a2beec42 | ||
|
|
a82ba07ca1 | ||
|
|
472faf4962 | ||
|
|
d4ba2e66ae | ||
|
|
91672eacea | ||
|
|
fc741472f4 | ||
|
|
bd2443ca3e | ||
|
|
2d1bd7ad2f | ||
|
|
39526ae29b | ||
|
|
bae84aa65b | ||
|
|
2abcf80e6d | ||
|
|
90c73e5665 | ||
|
|
94ade49e0e | ||
|
|
664c3012bf | ||
|
|
6e4ef513f5 | ||
|
|
31ec3498f7 | ||
|
|
6226ccf635 | ||
|
|
0c32d260b5 | ||
|
|
f76228a135 | ||
|
|
3a485e8a68 | ||
|
|
29cafd520d | ||
|
|
f0ad97f35f | ||
|
|
00da5788d8 | ||
|
|
af7bc6b6f2 | ||
|
|
a520011ce7 | ||
|
|
64800d8e2d | ||
|
|
b76b0499cd | ||
|
|
f6796331e4 | ||
|
|
e888dbb2c8 | ||
|
|
27e4ef0af2 | ||
|
|
c46fc5b7df | ||
|
|
7580f76d71 | ||
|
|
2f66b84955 | ||
|
|
dca9202136 | ||
|
|
40f614db6a | ||
|
|
6e71625b9e | ||
|
|
f5bbea09f6 | ||
|
|
72b341ec5e | ||
|
|
7fc9597193 | ||
|
|
5ec8a0311f | ||
|
|
96871d0fc9 | ||
|
|
b1e754ecb8 | ||
|
|
29944af64a | ||
|
|
e6de3f60c4 | ||
|
|
c1950e3256 | ||
|
|
67ee00f975 | ||
|
|
b86dd3ae5c | ||
|
|
d5c5f4e414 | ||
|
|
e03a832594 | ||
|
|
55725c3ade | ||
|
|
e778a05d69 | ||
|
|
51e701b212 | ||
|
|
0855a80287 | ||
|
|
98bf26a3f5 | ||
|
|
9493eeb7d6 | ||
|
|
013f2b0cad | ||
|
|
d31a3e8ba2 | ||
|
|
871e13646c | ||
|
|
322a3161a0 | ||
|
|
00d8fc0afd | ||
|
|
26f8b4ecce | ||
|
|
03d7ac6bcf | ||
|
|
d509ca3230 | ||
|
|
420def6e1b | ||
|
|
fdb08bf19f | ||
|
|
e3a67c9789 | ||
|
|
367e1c3ff8 | ||
|
|
b0b9f9932a | ||
|
|
cbd8d39cd9 | ||
|
|
cd0c18a14e | ||
|
|
d2db2bdb66 | ||
|
|
3d1a4f20e9 | ||
|
|
b555f4d8ce | ||
|
|
f53616001a | ||
|
|
94639756a6 | ||
|
|
839d46bfb3 | ||
|
|
9ca5a16af2 | ||
|
|
1e2048e2a4 | ||
|
|
cfbffd0339 | ||
|
|
dd3e9bf64b | ||
|
|
f2ebeac6c3 | ||
|
|
68df315d27 | ||
|
|
6c1aeba4b2 | ||
|
|
479c4c5162 | ||
|
|
78cdce345a | ||
|
|
856002f191 | ||
|
|
efe5a68778 | ||
|
|
fed5bee42d | ||
|
|
200aa0d944 | ||
|
|
dae827f7c7 | ||
|
|
0a1029243c | ||
|
|
61d354e7f4 | ||
|
|
9fa739c1e6 | ||
|
|
1cb9d96b1f | ||
|
|
3278858017 | ||
|
|
3006a64f40 | ||
|
|
d596c03d62 | ||
|
|
d63de4f826 | ||
|
|
0045ef6732 | ||
|
|
0c22331b1e | ||
|
|
9e14d688c4 | ||
|
|
db808096eb | ||
|
|
ba3ed7bce2 | ||
|
|
f94a826fea | ||
|
|
bfc061eb44 | ||
|
|
32a2a39741 | ||
|
|
d8f06fe26c | ||
|
|
f1294f2773 | ||
|
|
d9f5e2a560 | ||
|
|
d1b3406335 | ||
|
|
7b841a13f8 | ||
|
|
60f74aa00c | ||
|
|
03fcdad5c0 | ||
|
|
ca6228da03 | ||
|
|
da0643cd46 | ||
|
|
202ecc8e48 | ||
|
|
441e6677d3 | ||
|
|
7ae9bc6d4c | ||
|
|
7cc114ad4c | ||
|
|
ae608f5fcf | ||
|
|
7d769eaaf7 | ||
|
|
91628f0b68 | ||
|
|
ee0cf5e37d | ||
|
|
0effd41ff7 | ||
|
|
e813cf649c | ||
|
|
2d66d56524 | ||
|
|
0e66fb4fc3 | ||
|
|
54ac918828 | ||
|
|
815b5f260a | ||
|
|
2dfe57c13a | ||
|
|
6938f1f807 | ||
|
|
e57a806630 | ||
|
|
e7b13b7df3 | ||
|
|
307b84fe4c | ||
|
|
9e270bebe4 | ||
|
|
c7717be292 | ||
|
|
79483f6616 | ||
|
|
1832b39b7b | ||
|
|
84f6e93478 | ||
|
|
2b55cb90fc | ||
|
|
f01268f26c | ||
|
|
c0c337ec45 | ||
|
|
0c78853bc6 | ||
|
|
4ceb02536c | ||
|
|
6bd082af47 | ||
|
|
be33fc1ee6 | ||
|
|
bf6e6efbe7 | ||
|
|
3b326cfa83 | ||
|
|
2742d9dd47 | ||
|
|
c4d659391a | ||
|
|
400a7c54bc | ||
|
|
834cca8b8e | ||
|
|
4a736e5af1 | ||
|
|
03fc6de00e | ||
|
|
c6504627ec | ||
|
|
e5c7fe52ed | ||
|
|
8d87bb5a9c | ||
|
|
cc68e3e967 | ||
|
|
b809f86f09 | ||
|
|
7af1d0e48f | ||
|
|
3f071d4b8a | ||
|
|
8539330f7e | ||
|
|
802c1c1d99 | ||
|
|
d57d100065 | ||
|
|
e78411f6e7 | ||
|
|
55f9e85172 | ||
|
|
b36a3ea036 | ||
|
|
cb47056b1b | ||
|
|
59709dba6c | ||
|
|
04a026782d | ||
|
|
4415c0ffbe | ||
|
|
f494d48434 | ||
|
|
cf8cbd8f5d | ||
|
|
dd60398eac | ||
|
|
50ad403c5c | ||
|
|
7bd04f470c | ||
|
|
59529d79e0 | ||
|
|
5f698aaf74 | ||
|
|
4c8c7cbdef | ||
|
|
6545c74486 | ||
|
|
bf612bf9ee | ||
|
|
e4801e992a | ||
|
|
65e046529c | ||
|
|
8ce95e4a2c | ||
|
|
c9f530f412 | ||
|
|
e8bd7a5905 | ||
|
|
746d3ddf62 | ||
|
|
3a3c6739f2 | ||
|
|
c8ed448422 | ||
|
|
16675b07bc | ||
|
|
eaff3cf2a8 | ||
|
|
376da145ff | ||
|
|
1d8968acdf | ||
|
|
261dcddca6 | ||
|
|
be25932aff | ||
|
|
8a0685b03f | ||
|
|
76eb3eb3bf | ||
|
|
c30261be77 | ||
|
|
3ad40b4a5c | ||
|
|
95aad7df02 | ||
|
|
1091524b94 | ||
|
|
f4889cac74 | ||
|
|
42f591a330 | ||
|
|
a66fecae31 | ||
|
|
9cfe6c1333 | ||
|
|
686819e5e1 | ||
|
|
6b5cf272d6 | ||
|
|
a7f286ee0d | ||
|
|
c448db8692 | ||
|
|
7a55285dd1 | ||
|
|
ae43883ed1 | ||
|
|
2ad682ce28 | ||
|
|
84df91ed10 | ||
|
|
32f8ffecaa | ||
|
|
c55e84f7cb | ||
|
|
737a8095ac | ||
|
|
b9caaaa927 | ||
|
|
8f8c96915d | ||
|
|
f75c7e4ef8 | ||
|
|
df367633bc | ||
|
|
af4f85a33c | ||
|
|
2ca5d0f3ca | ||
|
|
0fd2b67850 | ||
|
|
08562488b0 | ||
|
|
a6c45ecb45 | ||
|
|
e847960a1b | ||
|
|
1cbbf9bf65 | ||
|
|
d769756639 | ||
|
|
ccdc32dd7c | ||
|
|
95416b29dc | ||
|
|
fcd41c87a1 | ||
|
|
d3f6885435 | ||
|
|
5f1667c2f4 | ||
|
|
d6cae36487 | ||
|
|
aa592f2742 | ||
|
|
4cb7ecf998 | ||
|
|
2180a5c998 | ||
|
|
12bb66810e | ||
|
|
42ceec9a6b | ||
|
|
117cb69c89 | ||
|
|
fc70a34fd3 | ||
|
|
faa549e02f | ||
|
|
550a9ad2a9 | ||
|
|
2b02955fdc | ||
|
|
b0dc94f196 | ||
|
|
712867050c | ||
|
|
b99ff0165a | ||
|
|
cd653397db | ||
|
|
feed5acb9c | ||
|
|
7a560fae3f | ||
|
|
973e1e0b96 | ||
|
|
daddd5793a | ||
|
|
dd3d52b838 | ||
|
|
ea160e1059 | ||
|
|
3619ad8eef | ||
|
|
cc37f4c724 | ||
|
|
56faffd46c | ||
|
|
3bd1a1e329 | ||
|
|
0e435f9887 | ||
|
|
7e557b7cf5 | ||
|
|
8ac23313bb | ||
|
|
5dfa67e248 | ||
|
|
ea822f8863 | ||
|
|
fe37e47d54 | ||
|
|
b5514e03af | ||
|
|
a86abb2b6b | ||
|
|
f5011b81ec | ||
|
|
9fd696977c | ||
|
|
f2883557ca | ||
|
|
6bcb0f7f32 | ||
|
|
275fc63851 | ||
|
|
d547152057 | ||
|
|
28fd76a151 | ||
|
|
2c13c40578 | ||
|
|
dd421f7466 | ||
|
|
684150d9d7 | ||
|
|
ee77cf98ae | ||
|
|
020da8412f | ||
|
|
35e871e1d1 | ||
|
|
6d9a1cd20f | ||
|
|
537afeea76 | ||
|
|
7a3f4dbbe2 | ||
|
|
c671f43d50 | ||
|
|
acdbd55ee5 | ||
|
|
1a18b3dd55 | ||
|
|
f5483a18d0 | ||
|
|
1b3275a22f | ||
|
|
de0358b763 | ||
|
|
c735c99724 | ||
|
|
cf82bac342 | ||
|
|
6304bec9dc | ||
|
|
cb910c6973 | ||
|
|
7fabf3ab4b | ||
|
|
190940fc58 | ||
|
|
d71eae4fc3 | ||
|
|
cec4772767 | ||
|
|
51eae1b871 | ||
|
|
df32a5f5bb | ||
|
|
a77084b6d5 | ||
|
|
02828be7b6 | ||
|
|
f2f5bb9786 | ||
|
|
0cf3933f8a | ||
|
|
4a6196f310 | ||
|
|
b7d8dee113 | ||
|
|
b7e25e9a09 | ||
|
|
5062101622 | ||
|
|
48727c319d | ||
|
|
ad9d7add4b | ||
|
|
61a7a3a675 | ||
|
|
6a2b1ad82e | ||
|
|
305fff4049 | ||
|
|
63bdcb392b | ||
|
|
cacd9a80bb | ||
|
|
ee8568588a | ||
|
|
b636814279 | ||
|
|
af4110abee | ||
|
|
021acd4c4c | ||
|
|
156ef64700 | ||
|
|
f10c7af9e5 | ||
|
|
07469afc59 | ||
|
|
e54906fe2c | ||
|
|
40efc83fa0 | ||
|
|
0abc64a1a6 | ||
|
|
16c2c7e90b | ||
|
|
7d2de8779e | ||
|
|
03f76488f4 | ||
|
|
d99280a578 | ||
|
|
29627552e8 | ||
|
|
66a6eec955 | ||
|
|
5b88ce0556 | ||
|
|
43cedf4025 | ||
|
|
2ed92845c9 | ||
|
|
2c58b396cb | ||
|
|
5a02f59339 | ||
|
|
fa3b107c95 | ||
|
|
11458b1bd3 | ||
|
|
0fc4e743bb | ||
|
|
9df62c450e | ||
|
|
9c6d0bf25d | ||
|
|
3498499a7f | ||
|
|
8e999f3c51 | ||
|
|
f245f28c83 | ||
|
|
cd95a13a78 | ||
|
|
39c43fc8b1 | ||
|
|
27ecc9e7d1 | ||
|
|
ce3cff6168 | ||
|
|
236833b92f | ||
|
|
4990f0a65e | ||
|
|
9df07a958d | ||
|
|
56a4b2a747 | ||
|
|
e13942b721 | ||
|
|
be5057c9e8 | ||
|
|
6f9b1e6213 | ||
|
|
30ff784f2c | ||
|
|
7828ec3220 | ||
|
|
13aa6355af | ||
|
|
787fd585e6 | ||
|
|
96904095bf | ||
|
|
533de76f4e | ||
|
|
5b3f2a121e | ||
|
|
3b8813e3a2 | ||
|
|
2f948d7a5d | ||
|
|
0faca2ef1d | ||
|
|
7112ed9564 | ||
|
|
df6ec6faa1 | ||
|
|
c6028d6458 | ||
|
|
b27e545e94 | ||
|
|
b2b885d68c | ||
|
|
3a5828895d | ||
|
|
fba466c13d | ||
|
|
7c154118e5 | ||
|
|
bccddf3975 | ||
|
|
9fae1b8a01 | ||
|
|
08bcb39912 | ||
|
|
526f4f17d5 | ||
|
|
aa1ff9fbe5 | ||
|
|
972f89fa28 | ||
|
|
e94ba6a848 | ||
|
|
f66eef5271 | ||
|
|
be4f2bd6ab | ||
|
|
8bae904193 | ||
|
|
1ee0986f67 | ||
|
|
5390fc1d20 | ||
|
|
5e542aae99 | ||
|
|
6b2b9e18ba | ||
|
|
c919f52630 | ||
|
|
8ebb431d6c | ||
|
|
90020fbf67 | ||
|
|
e8eda2446f | ||
|
|
c1e7db7735 | ||
|
|
a75e0b49e9 | ||
|
|
69081ea829 | ||
|
|
ba85377563 | ||
|
|
af7e9dbb3c | ||
|
|
b971dd072e | ||
|
|
ad3b40f1c9 | ||
|
|
ca306027fa | ||
|
|
039ee5a8ae | ||
|
|
bc580f98af | ||
|
|
bbad9183f2 | ||
|
|
0f4a8bd0c2 | ||
|
|
e06072ed8b | ||
|
|
9b9112c227 | ||
|
|
0e41bcfc6e | ||
|
|
59318c3f96 | ||
|
|
97c7a70bfd | ||
|
|
0005dd6a40 | ||
|
|
5421909ffc | ||
|
|
6e5e42e1d3 | ||
|
|
00fe920ec0 | ||
|
|
874aa6f73c | ||
|
|
7b0158b4ab | ||
|
|
e1eae4b88d | ||
|
|
142d2bb6c3 | ||
|
|
ae832da721 | ||
|
|
27f2a9d3b9 | ||
|
|
ac406bb3aa | ||
|
|
4737bb273f | ||
|
|
8fb533e4b9 | ||
|
|
c33bfbd004 | ||
|
|
bc044e3037 | ||
|
|
46980af8ce | ||
|
|
87a0f0fcde | ||
|
|
87dfb36c5c | ||
|
|
b6902782ab | ||
|
|
54d7abae08 | ||
|
|
963d49aa93 | ||
|
|
b2a85d2559 | ||
|
|
2f2e193dad | ||
|
|
31b555ee3f | ||
|
|
fd782a300b | ||
|
|
1aaa8137e6 | ||
|
|
caf0b9b9d3 | ||
|
|
f7e10ad94a | ||
|
|
85bfc60fe8 | ||
|
|
af9af342e1 | ||
|
|
44ded79364 | ||
|
|
0ef2d38ac3 | ||
|
|
6cfb5cfc98 | ||
|
|
34bd4c5d71 | ||
|
|
e8ecbc0518 | ||
|
|
cd23d6ff53 | ||
|
|
6b354689ca | ||
|
|
9562cec389 | ||
|
|
9e6f71c175 | ||
|
|
31d94e6d1e | ||
|
|
16bf2213c0 | ||
|
|
68596ed027 | ||
|
|
f083a5b45d | ||
|
|
7600085fc0 | ||
|
|
f532e74000 | ||
|
|
fcddb7fe21 | ||
|
|
5b5adadd66 | ||
|
|
332093b59e | ||
|
|
6d4985c51e | ||
|
|
0a2112b19b | ||
|
|
64a0978b8a | ||
|
|
93e8759892 | ||
|
|
f69ebf7fed | ||
|
|
b3374fb2e5 | ||
|
|
851acf73ba | ||
|
|
0c69a1f7e3 | ||
|
|
65c3bf81c6 | ||
|
|
1bc2d58eec | ||
|
|
debd7bebc3 | ||
|
|
5bef393f6f | ||
|
|
4b8c6a4d6d | ||
|
|
d0d1eab7b7 | ||
|
|
b7c444cee5 | ||
|
|
8a75295b1b | ||
|
|
558a799c81 | ||
|
|
f159beb578 | ||
|
|
051a404478 | ||
|
|
612707d654 | ||
|
|
c4cd55e397 | ||
|
|
0d555b62f4 | ||
|
|
dc48d8234e | ||
|
|
f1adacf0ee | ||
|
|
805b17ba3e | ||
|
|
ef70c3193a | ||
|
|
e3854f06e8 | ||
|
|
5ead2874eb | ||
|
|
c2162bd442 | ||
|
|
4425ec2719 | ||
|
|
c7bd8da8b6 | ||
|
|
afbe769358 | ||
|
|
4db305f846 | ||
|
|
859e6dcaa9 | ||
|
|
8890d95d61 | ||
|
|
57d62f664a | ||
|
|
d4e84d80d7 | ||
|
|
2f0fb74325 | ||
|
|
2dc477f9d8 | ||
|
|
03cf977b12 | ||
|
|
6dc97b208c | ||
|
|
912a4c1388 | ||
|
|
c75fe52753 | ||
|
|
05aa26d108 | ||
|
|
45e4f2e882 | ||
|
|
9292dd4546 | ||
|
|
f52bc482bb | ||
|
|
8f75a35759 | ||
|
|
f34f220a66 | ||
|
|
7554287821 | ||
|
|
ef80a83683 | ||
|
|
2dbd3e8772 | ||
|
|
b1192c40e5 | ||
|
|
1731cf159e | ||
|
|
fbe978a9c9 | ||
|
|
1d741a1209 | ||
|
|
42861c0c9b | ||
|
|
6f21617d42 | ||
|
|
343839efa0 | ||
|
|
2145f582c9 | ||
|
|
9b631af072 | ||
|
|
ae49cc9c66 | ||
|
|
96233e6576 | ||
|
|
16f3718c39 | ||
|
|
875eed575c | ||
|
|
f6120ffe4f | ||
|
|
7ad9c45191 | ||
|
|
658cb99fac | ||
|
|
3c1cb0912f | ||
|
|
7eca4741ab | ||
|
|
68c6f9aa35 | ||
|
|
1423bb6904 | ||
|
|
c164f85009 | ||
|
|
bd5fdfc68e | ||
|
|
a6d2c8cda5 | ||
|
|
6bf169523d | ||
|
|
def592aba0 | ||
|
|
ee81fdcca9 | ||
|
|
be2ea86180 | ||
|
|
ab4d6742d8 | ||
|
|
a157e3db0e | ||
|
|
56b9561219 | ||
|
|
ae6d677edc | ||
|
|
8af9d9cfab | ||
|
|
dbb10a22d3 | ||
|
|
42294611bb | ||
|
|
f20c0403bc | ||
|
|
9c52db4321 | ||
|
|
ac2d14a299 | ||
|
|
b8a526d479 | ||
|
|
1b2e721a37 | ||
|
|
84409bf462 | ||
|
|
32ce74568d | ||
|
|
10e3a12d4e | ||
|
|
02b461c848 | ||
|
|
336f1d58f1 | ||
|
|
4495da1c15 | ||
|
|
2eca53c782 | ||
|
|
79a073e2d8 | ||
|
|
8b37edc5ea | ||
|
|
3d4f34e784 | ||
|
|
8584c3cf50 | ||
|
|
421d35113c | ||
|
|
ad36e04327 | ||
|
|
e18740c70a | ||
|
|
da359b0d8f | ||
|
|
ce510af51f | ||
|
|
e4998fa279 | ||
|
|
318bc27ed2 | ||
|
|
de10d91321 | ||
|
|
af1833b74a | ||
|
|
743d259186 | ||
|
|
7255086287 | ||
|
|
f480b8c442 | ||
|
|
8b1efe7e45 | ||
|
|
f4a7f092f6 | ||
|
|
fde7a7962a | ||
|
|
7357f0fa8f | ||
|
|
c3e0bbd61d | ||
|
|
8797d4628c | ||
|
|
5fb1a1dd85 | ||
|
|
f50dc0f836 | ||
|
|
d2591ecc75 | ||
|
|
cec4e42f02 | ||
|
|
9c4a4277fb | ||
|
|
a35198aca7 | ||
|
|
2acecdb7bb | ||
|
|
62a399b347 | ||
|
|
919135f432 | ||
|
|
9f0e3584de | ||
|
|
38228cf1be | ||
|
|
139e57e56a | ||
|
|
c339b13ca6 | ||
|
|
79885b011a | ||
|
|
b27ddb4ae2 | ||
|
|
d0696157a3 | ||
|
|
7561ae90a9 | ||
|
|
0cda843116 | ||
|
|
2abd5c12d5 | ||
|
|
29612dd396 | ||
|
|
51c5cc594b | ||
|
|
2bc7166d4e | ||
|
|
2ece981dae | ||
|
|
c1b536d2f3 | ||
|
|
5f9ef6e4cb | ||
|
|
df1567a51a | ||
|
|
5205be2c5a | ||
|
|
73558a31f4 | ||
|
|
06325a0b57 | ||
|
|
16765c31f7 | ||
|
|
3ac9aa1121 | ||
|
|
ac20e7c438 | ||
|
|
ffe2f3111b | ||
|
|
f420a8ee12 | ||
|
|
3468744364 | ||
|
|
7143879536 | ||
|
|
9e13a9eec3 | ||
|
|
321c7bd112 | ||
|
|
60a4698695 | ||
|
|
643d650c03 | ||
|
|
3a67660d9e | ||
|
|
1ee9efa2c8 | ||
|
|
99c0799376 | ||
|
|
478faeeb69 | ||
|
|
a3932e114e | ||
|
|
368419d7d4 | ||
|
|
ace0df5c23 | ||
|
|
c1e292bf2a | ||
|
|
f1055d9c1c | ||
|
|
2ceb8375b6 | ||
|
|
4980b7c36c | ||
|
|
04454f58ac | ||
|
|
fdffa2abdd | ||
|
|
d1efa30cf4 | ||
|
|
73bf84e9b4 | ||
|
|
0d9a9f3ef8 | ||
|
|
b106dde6c0 | ||
|
|
5e2fb9b0a0 | ||
|
|
2e977534d4 | ||
|
|
9d85f6e687 | ||
|
|
ee5c3cee62 | ||
|
|
928ed14f07 | ||
|
|
7e6cea3605 | ||
|
|
c7c2f81ab2 | ||
|
|
dbdb492557 | ||
|
|
799d2e1f45 | ||
|
|
fcdefab367 | ||
|
|
ea3a0579bc | ||
|
|
ccd9b5cae7 | ||
|
|
2b834af990 | ||
|
|
b5d398e6d7 | ||
|
|
018ea4abef | ||
|
|
f891287bac | ||
|
|
7f1c827c28 | ||
|
|
21495a92f1 | ||
|
|
49676c06f7 | ||
|
|
2f03ce912d | ||
|
|
2586a8f39b | ||
|
|
f770b255f3 | ||
|
|
4a8341586a | ||
|
|
932350d503 | ||
|
|
a341d3c566 | ||
|
|
d32ad3dc98 | ||
|
|
70f9725113 | ||
|
|
18cdce9803 | ||
|
|
db07049c6c | ||
|
|
31a4289cc6 | ||
|
|
f753dbfdf0 | ||
|
|
15c2716034 | ||
|
|
3a82310b30 | ||
|
|
e473be87d1 | ||
|
|
7b8acfeadb | ||
|
|
3b5e0b558b | ||
|
|
d51d959669 | ||
|
|
5eee238838 | ||
|
|
9ae55bad0e | ||
|
|
bd0d0ebedb | ||
|
|
5fafd91d24 | ||
|
|
8d75112e4a | ||
|
|
1931b23006 | ||
|
|
936f9e4680 | ||
|
|
525d72e6fe | ||
|
|
6c053abea9 | ||
|
|
9873c3f32e | ||
|
|
d24a41bcca | ||
|
|
01286250cb | ||
|
|
8cc6743a47 | ||
|
|
03e1fb6dff | ||
|
|
503030c0d8 | ||
|
|
005d98993f | ||
|
|
c135ecdce8 | ||
|
|
20e5727112 | ||
|
|
a718a33227 | ||
|
|
3f0c9fe991 | ||
|
|
43bb532f48 | ||
|
|
909c8c51f1 | ||
|
|
f24d648c8a | ||
|
|
d757e52be0 | ||
|
|
aa2f2a306f | ||
|
|
e27ae66ec6 | ||
|
|
7f58261221 | ||
|
|
cd0b071a3e | ||
|
|
e716ef1aba | ||
|
|
4cd2f90abf | ||
|
|
455546c69f | ||
|
|
2467596832 | ||
|
|
8691ace824 | ||
|
|
6e2ca2b3ff | ||
|
|
7a9e535e35 | ||
|
|
1487d52db0 | ||
|
|
05de0574b7 | ||
|
|
ac3c06daf0 | ||
|
|
ef56c668d2 | ||
|
|
d97b176082 | ||
|
|
4d634394f5 | ||
|
|
fd21559ba8 | ||
|
|
f74586f765 | ||
|
|
99af09ba7c | ||
|
|
0899c4b7b3 | ||
|
|
46d77d4b06 | ||
|
|
48316b5864 | ||
|
|
33673d88bc | ||
|
|
b019954f68 | ||
|
|
9ca1b0c35f | ||
|
|
e9fd0b76dd | ||
|
|
3823ec2471 | ||
|
|
546dfd07ff | ||
|
|
4d314e3f5e | ||
|
|
67ca3b04eb | ||
|
|
ad3cedc8ad | ||
|
|
0c4298d29d | ||
|
|
c4a6e8de1f | ||
|
|
4012a4b532 | ||
|
|
2b7e1d48b5 | ||
|
|
4d4c541a57 | ||
|
|
20072695c1 | ||
|
|
fa5295db23 | ||
|
|
88726667a1 | ||
|
|
e81d70440e | ||
|
|
5f31e2efe3 | ||
|
|
29f0455878 | ||
|
|
450528489c | ||
|
|
19d279c9b5 | ||
|
|
38b0d9475e | ||
|
|
324966b811 | ||
|
|
53fe99a6ff | ||
|
|
6cf20d2101 | ||
|
|
c12111b5a8 | ||
|
|
beed07db0b | ||
|
|
b11d29db70 | ||
|
|
63c36a1dca | ||
|
|
eb6d580a90 | ||
|
|
85d60cefe6 | ||
|
|
fddbf8adb5 | ||
|
|
7d8f01f849 | ||
|
|
0b6c1dbeec | ||
|
|
3b7b1d2864 | ||
|
|
14f8677565 | ||
|
|
b3fd853052 | ||
|
|
613613b6b6 | ||
|
|
07b90b13cf | ||
|
|
3b6af0dd6d | ||
|
|
fccf112a61 | ||
|
|
e589a90ed5 | ||
|
|
0ad85d4127 | ||
|
|
2b32c8f57c | ||
|
|
9bcca73a33 | ||
|
|
2857a7b5ee | ||
|
|
014c77353e | ||
|
|
0bd2f3e778 | ||
|
|
481c3d14b7 | ||
|
|
ff8cc48ba2 | ||
|
|
eb550ea05c | ||
|
|
3bab394e1b | ||
|
|
6fc4ef4c45 | ||
|
|
2fffb4a3ca | ||
|
|
f92b63cc1a | ||
|
|
07a2820cf2 | ||
|
|
9ba1623c03 | ||
|
|
f8f08443ac | ||
|
|
4edd58a832 | ||
|
|
377838ccc0 | ||
|
|
f4380feffe | ||
|
|
2ce41f17f3 | ||
|
|
baf2ea69ac | ||
|
|
c49644c295 | ||
|
|
696811790c | ||
|
|
88d53617d6 | ||
|
|
a097a4265a | ||
|
|
a8794d47fb | ||
|
|
6733e2fc10 | ||
|
|
17e16863aa | ||
|
|
def62ad205 | ||
|
|
6a416d3cb2 | ||
|
|
99242d57bb | ||
|
|
6a44ac42b9 | ||
|
|
4e1b6e1d7f | ||
|
|
5771f65626 | ||
|
|
862f409e57 | ||
|
|
ac19dbb9e5 | ||
|
|
6397bfddb3 | ||
|
|
92482df250 | ||
|
|
d3d834c91a | ||
|
|
bc832df368 | ||
|
|
6533311382 | ||
|
|
c969dcb4e7 | ||
|
|
3b825333ea | ||
|
|
babf4f6576 | ||
|
|
8bcd2c2960 | ||
|
|
6e41ce15e3 | ||
|
|
5a4c785ec4 | ||
|
|
9cd93f2a0c | ||
|
|
c03510f909 | ||
|
|
687b1c4ae0 | ||
|
|
4979f9f91c | ||
|
|
5e65007240 | ||
|
|
063a19e6c1 | ||
|
|
a512048ae8 | ||
|
|
fdbe0e3b5b | ||
|
|
aab6b728cb | ||
|
|
3b4a2c9bf5 | ||
|
|
f795b5d750 | ||
|
|
e0ccfa1532 | ||
|
|
b598355b66 | ||
|
|
e982385e54 | ||
|
|
20717b7c67 | ||
|
|
dc7294ed6e | ||
|
|
7835b015d9 | ||
|
|
f68b7e94c4 | ||
|
|
d6e98c21fb | ||
|
|
36ae30160c | ||
|
|
1c28a150e7 | ||
|
|
08305c7497 | ||
|
|
1bbb8ec800 | ||
|
|
6903a2e2e7 | ||
|
|
e7b2be606a | ||
|
|
f8a4a61874 | ||
|
|
4536eee620 | ||
|
|
73a8b3188b | ||
|
|
4435fc48b8 | ||
|
|
acf0fb8a2e | ||
|
|
c73803efe7 | ||
|
|
0b6d2aa399 | ||
|
|
b5304c68b5 | ||
|
|
6007bdc0b9 | ||
|
|
2b027d9d5a | ||
|
|
f3c17bcf75 | ||
|
|
92f5871309 | ||
|
|
5e61465955 | ||
|
|
71041ecfe1 | ||
|
|
92ed7a4243 | ||
|
|
dd96c0de95 | ||
|
|
edd2068e23 | ||
|
|
48ba18608b | ||
|
|
5c9ccae9a0 | ||
|
|
6522f7987b | ||
|
|
9560f87ebd | ||
|
|
9f8e8acd53 | ||
|
|
8b6964f060 | ||
|
|
e26eadfa4c | ||
|
|
7f69e2893d | ||
|
|
bde88764cb | ||
|
|
9a2c4739b0 | ||
|
|
561fe5e375 | ||
|
|
a94972bbd2 | ||
|
|
6d1337ad0a | ||
|
|
fd1c2f1738 | ||
|
|
80996b1a3b | ||
|
|
db6107b462 | ||
|
|
de1d24e4eb | ||
|
|
2815ce3d62 | ||
|
|
5aca342e2f | ||
|
|
8dfed1fa21 | ||
|
|
a3a822d564 | ||
|
|
e1fb179e9c | ||
|
|
cf11f04043 | ||
|
|
372d05e49c | ||
|
|
af908a36b8 | ||
|
|
eb3c1f6a39 | ||
|
|
3e9d498805 | ||
|
|
909aefddbf | ||
|
|
085a67ee3a | ||
|
|
dbb7dcff8c | ||
|
|
64b80ca9f5 | ||
|
|
4ccaa1598d | ||
|
|
adbb32c71e | ||
|
|
6a8e18ec96 | ||
|
|
6513f4b18a | ||
|
|
a2f2f14ada | ||
|
|
d67f64d00e | ||
|
|
466be38a53 | ||
|
|
0bde1a1103 | ||
|
|
2b05770780 | ||
|
|
ee3d1805c9 | ||
|
|
fa88abb5d6 | ||
|
|
9c857973a2 | ||
|
|
da9a5c4d8d | ||
|
|
233c618f97 | ||
|
|
cf03724b91 | ||
|
|
0187007de5 | ||
|
|
10a58c0e16 | ||
|
|
13578bce64 | ||
|
|
cd20be423f | ||
|
|
66018a56b8 | ||
|
|
859f5f5be8 | ||
|
|
e08bc7abdf | ||
|
|
f616e48196 | ||
|
|
4b2ac032d6 | ||
|
|
17f8fbc46a | ||
|
|
a260a5f026 | ||
|
|
cb8381e2b9 | ||
|
|
0f663cd46f | ||
|
|
14b3c117b3 | ||
|
|
b81ff9a69a | ||
|
|
5669abc8c5 | ||
|
|
57dec7aa5e | ||
|
|
e07080ce5c | ||
|
|
8f57aa50bf | ||
|
|
d972d8e21b | ||
|
|
f94b419caa | ||
|
|
34295c1f6b | ||
|
|
99ff2921e5 | ||
|
|
df8a236c16 | ||
|
|
803be601e6 | ||
|
|
fc3ab2cf61 | ||
|
|
a58e184872 | ||
|
|
a87a05fc7f | ||
|
|
f54a9ed5e1 | ||
|
|
417a9183f8 | ||
|
|
99c69509ad | ||
|
|
7f51282b16 | ||
|
|
ef9e1d23e2 | ||
|
|
c4e1a4b154 | ||
|
|
5e9d392c28 | ||
|
|
0ee3291761 | ||
|
|
9b6bb90cb5 | ||
|
|
f09476998e | ||
|
|
337c3ed4dd | ||
|
|
7f4f4fe584 | ||
|
|
c5e63f84ab | ||
|
|
a7f7e9049c | ||
|
|
f13fe4495b | ||
|
|
9af6808163 | ||
|
|
c5ef8ea3e5 | ||
|
|
8158284427 | ||
|
|
ca3e6faaae | ||
|
|
27f55f7116 | ||
|
|
091241f1bb | ||
|
|
3db46c58eb | ||
|
|
4f270fa968 | ||
|
|
ec15de7e79 | ||
|
|
0e2a8001ff | ||
|
|
a4fbc8619b | ||
|
|
f23c953273 | ||
|
|
be76e2a686 | ||
|
|
d25aba9aff | ||
|
|
72d7d38568 | ||
|
|
012b6716fb | ||
|
|
fe45b7d1bf | ||
|
|
80c1460db8 | ||
|
|
48d4a386b7 | ||
|
|
ab3e4f4c50 | ||
|
|
a7489f0995 | ||
|
|
d044cd7bc5 | ||
|
|
a7e9d9883b | ||
|
|
fb65a43ced | ||
|
|
33f7b41d03 | ||
|
|
f2c7891775 | ||
|
|
b979451e76 | ||
|
|
23c387f4a0 | ||
|
|
9a670548fa | ||
|
|
d25ab4b4b3 | ||
|
|
548f6911e9 | ||
|
|
a01bb7d4a3 | ||
|
|
906cc41d41 | ||
|
|
42d52e36e0 | ||
|
|
a1e9066f9e | ||
|
|
79fd439fcd | ||
|
|
a8b794b1a7 | ||
|
|
ce7f05e240 | ||
|
|
8835f8b73d | ||
|
|
6d7778167d | ||
|
|
31e7e9bab5 | ||
|
|
9bd91a6dae | ||
|
|
751ac04a21 | ||
|
|
4ff71c51e0 | ||
|
|
1c805b8049 | ||
|
|
671f4edfad | ||
|
|
e015dc78e9 | ||
|
|
1f7d2a26f1 | ||
|
|
dcd7f2d8df | ||
|
|
a4d35be1f0 | ||
|
|
cabcc8d419 | ||
|
|
ed30b21165 | ||
|
|
2ea0348b66 | ||
|
|
9fac6d66cc | ||
|
|
4d227e26dc | ||
|
|
0f60b6458e | ||
|
|
fb1b7d040c | ||
|
|
78247527fd | ||
|
|
6668106730 | ||
|
|
7135b1d196 | ||
|
|
2dab03e2c0 | ||
|
|
0d07a671f2 | ||
|
|
4e188f3dd7 | ||
|
|
d6d74a3b8e | ||
|
|
591a83cd63 | ||
|
|
8167652d11 | ||
|
|
71759c417a | ||
|
|
58711d3511 | ||
|
|
e00df54850 | ||
|
|
e7c5f126da | ||
|
|
f2290ced37 | ||
|
|
3c2a45c68c | ||
|
|
60786853de | ||
|
|
db8576e2b3 | ||
|
|
78bd34e2d9 | ||
|
|
5a3e33257e | ||
|
|
f86f08cb9a | ||
|
|
6d455ab03e | ||
|
|
427e2deb6b | ||
|
|
36fb26649a | ||
|
|
6b3d0eefbd | ||
|
|
c273081062 | ||
|
|
6d98dfa237 | ||
|
|
74d9c773c2 | ||
|
|
9c1457ee9b | ||
|
|
3a08216317 | ||
|
|
33f2e8ffa3 | ||
|
|
0fcbe9fcec | ||
|
|
f3ed0ee66d | ||
|
|
793fee5467 | ||
|
|
535657e766 | ||
|
|
57380ae0b5 | ||
|
|
d249e388e4 | ||
|
|
6793b8a6ab | ||
|
|
cc1f5c043f | ||
|
|
a251474697 | ||
|
|
71f784c180 | ||
|
|
fa4cc97fa1 | ||
|
|
32f62518f7 | ||
|
|
777ce4d38a | ||
|
|
77d0732af3 | ||
|
|
ed9764bc23 | ||
|
|
49d81ab318 | ||
|
|
fc23103de1 | ||
|
|
789456572d | ||
|
|
61d5684b4d | ||
|
|
2186bc919f | ||
|
|
14ec078746 | ||
|
|
4079fe7846 | ||
|
|
2990bc79e2 | ||
|
|
0f8a31252b | ||
|
|
0cd19ed250 | ||
|
|
d758c21c64 | ||
|
|
ae542f3e0c | ||
|
|
c4a5ed50e4 | ||
|
|
89b976fe70 | ||
|
|
01d1ed0624 | ||
|
|
7d989abe8e | ||
|
|
81b3471cae | ||
|
|
0f64804714 | ||
|
|
9ff1398c69 | ||
|
|
40f4915925 | ||
|
|
60fad5523d | ||
|
|
8e1888b463 | ||
|
|
3bbdb4e00e | ||
|
|
5fdf220101 | ||
|
|
b7acdf9d3c | ||
|
|
291636a807 | ||
|
|
dc156eaff5 | ||
|
|
06d8a8963b | ||
|
|
c63f633f32 | ||
|
|
b48abbf09e | ||
|
|
cb81863dc5 | ||
|
|
7979ef12cc | ||
|
|
1a9d691493 | ||
|
|
6f1cd87732 | ||
|
|
65b08549d7 | ||
|
|
319d8060b7 | ||
|
|
cf7826be73 | ||
|
|
c654d83a0c | ||
|
|
991cc727f7 | ||
|
|
07cbce7ce0 | ||
|
|
d8fa1532f4 | ||
|
|
e9caabaec1 | ||
|
|
0c659c658c | ||
|
|
95e935b6af | ||
|
|
de52e37ac9 | ||
|
|
eccd7efd4c | ||
|
|
9ba3752d50 | ||
|
|
18b96a8d03 | ||
|
|
dba4211641 | ||
|
|
46b2ab79b4 | ||
|
|
87e6f20664 | ||
|
|
09facb8cbb | ||
|
|
152e7eed93 | ||
|
|
1a0953ffb6 | ||
|
|
dd5c134603 | ||
|
|
ef5ea9f0ff | ||
|
|
5383667f2c | ||
|
|
3dd18fdfa5 | ||
|
|
d7bfa16a36 | ||
|
|
e6658f6768 | ||
|
|
58ce1e6dfa | ||
|
|
26f3952930 | ||
|
|
c04e8118bc | ||
|
|
7e1622dc19 | ||
|
|
ff32395a86 | ||
|
|
a56b9801cf | ||
|
|
a337f2b4b4 | ||
|
|
415ae6be39 | ||
|
|
f5fffca889 | ||
|
|
e288deabc9 | ||
|
|
40b44b04ab | ||
|
|
4e6355837d | ||
|
|
bdeb19f26a | ||
|
|
c06500fbef | ||
|
|
673f5e11dd | ||
|
|
945f130e66 | ||
|
|
2f0ce9c423 | ||
|
|
8ff6033077 | ||
|
|
9b04fd7073 | ||
|
|
d0e3531e8b | ||
|
|
7279f81cc3 | ||
|
|
0f3eaaf2f1 | ||
|
|
0fe2067c9b | ||
|
|
243ca8b294 | ||
|
|
f6ccab5e83 | ||
|
|
f53e9995b7 | ||
|
|
ae22234ed0 | ||
|
|
75533cca60 | ||
|
|
dbf5830353 | ||
|
|
a5ae0ee42b | ||
|
|
232af5c19f | ||
|
|
e251645e11 | ||
|
|
eb3c7d1d61 | ||
|
|
39f90f25fd | ||
|
|
4cb442e33d | ||
|
|
ab1f7a2952 | ||
|
|
f2736e1a3f | ||
|
|
4346e3d34c | ||
|
|
7bf04ad1e1 | ||
|
|
f1ba8179c0 | ||
|
|
917bb0dd32 | ||
|
|
ae626838bf | ||
|
|
64b033a8c9 | ||
|
|
ef4029ce57 | ||
|
|
18ca337e13 | ||
|
|
6280f3366c | ||
|
|
10c692b174 | ||
|
|
f9a74915d3 | ||
|
|
c280cca53b | ||
|
|
d6e17ebc9e | ||
|
|
c90643efd0 | ||
|
|
99ea179aaa | ||
|
|
d9557375a0 | ||
|
|
c5b8ff7e47 | ||
|
|
285cf9e2e6 | ||
|
|
94f049ce19 | ||
|
|
b10f385d40 | ||
|
|
36aa7462af | ||
|
|
23c0ec34d2 | ||
|
|
74aa072bfb | ||
|
|
d5f4cbf053 | ||
|
|
c0b088f8e5 | ||
|
|
46ab6455c9 | ||
|
|
6e66cd2fff | ||
|
|
0cb51158aa | ||
|
|
7b32d0f8c7 | ||
|
|
95d6547739 | ||
|
|
5424ef069f | ||
|
|
2d4eecf5c4 | ||
|
|
af4ae79fa6 | ||
|
|
6200a86c3e | ||
|
|
cc1fa09b47 | ||
|
|
61b2544477 | ||
|
|
91198ac2c7 | ||
|
|
674defa1b1 | ||
|
|
719bc1a87f | ||
|
|
2a88d42831 | ||
|
|
21b368a88f | ||
|
|
be518c5025 | ||
|
|
557ed5008b | ||
|
|
d8a051e364 | ||
|
|
c0fcb03f4c | ||
|
|
d4fc262f7f |
12
.github/workflows/publish.yml
vendored
12
.github/workflows/publish.yml
vendored
|
|
@ -15,23 +15,23 @@ jobs:
|
|||
last_version: ${{ steps.last_version.outputs.version }}
|
||||
token_exists: ${{ steps.check_token.outputs.token }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 50
|
||||
# Check if the package.json version field has changed since the last push
|
||||
- name: Get current version from package.json
|
||||
id: current_version
|
||||
run: |
|
||||
echo "version=$(jq -r .version package.json)" >> $GITHUB_OUTPUT
|
||||
echo "version=$(jq -r .version package.json)" >> "$GITHUB_OUTPUT"
|
||||
- name: Get the version from the last push
|
||||
id: last_version
|
||||
run: |
|
||||
git checkout ${{ github.event.before }}
|
||||
echo "version=$(jq -r .version package.json)" >> $GITHUB_OUTPUT
|
||||
echo "version=$(jq -r .version package.json)" >> "$GITHUB_OUTPUT"
|
||||
- name: Check if NPM_TOKEN exists
|
||||
id: check_token
|
||||
run: |
|
||||
echo "token=$(if [ -n "${{ secrets.NPM_TOKEN }}" ]; then echo true; else echo false; fi)" >> $GITHUB_OUTPUT
|
||||
echo "token=$(if [ -n "${{ secrets.NPM_TOKEN }}" ]; then echo true; else echo false; fi)" >> "$GITHUB_OUTPUT"
|
||||
npm-publish:
|
||||
needs:
|
||||
- test
|
||||
|
|
@ -40,8 +40,8 @@ jobs:
|
|||
# We only want to publish if the package.json version field has changed
|
||||
if: needs.get-version.outputs.current_version != needs.get-version.outputs.last_version && needs.get-version.outputs.token_exists == 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 18
|
||||
cache: 'npm'
|
||||
|
|
|
|||
20
.github/workflows/test.yml
vendored
20
.github/workflows/test.yml
vendored
|
|
@ -17,15 +17,23 @@ jobs:
|
|||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [18.x]
|
||||
# Testing multiple Node versions makes CI take forever, and basically
|
||||
# never actually finds anything we care about. Testing one is enough.
|
||||
#
|
||||
# This number should be left at the oldest Node LTS version capable of
|
||||
# running Node without errors (it doesn't matter if it's unsupported).
|
||||
# Please freely bump this version (and the check in `pokemon-showdown`
|
||||
# and `server/index.ts`) if you want to use features from newer versions;
|
||||
# this is purely for our own reference, not to constrain programmers.
|
||||
node-version: ['18.x']
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 100 # assumes PR/push to master is no larger than 100 commits. Other solutions are needlessly complex.
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v3
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'npm'
|
||||
|
|
@ -35,7 +43,7 @@ jobs:
|
|||
- name: Determine which files to lint (if pull request)
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
id: changed-files
|
||||
uses: tj-actions/changed-files@v35
|
||||
uses: tj-actions/changed-files@v47
|
||||
with:
|
||||
files: |
|
||||
./config/*.ts
|
||||
|
|
@ -58,14 +66,14 @@ jobs:
|
|||
- name: Determine whether test/sim or test/random-battles need to run (if pull request)
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
id: changed-directories
|
||||
uses: tj-actions/changed-files@v35
|
||||
uses: tj-actions/changed-files@v47
|
||||
with:
|
||||
files: |
|
||||
config/formats.ts
|
||||
data/**
|
||||
sim/**
|
||||
|
||||
- name: Run selective lint & neccessary tests (if pull request)
|
||||
- name: Run selective lint & necessary tests (if pull request)
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
run: npm run full-test-ci
|
||||
env:
|
||||
|
|
|
|||
29
.github/workflows/update_version.yml
vendored
29
.github/workflows/update_version.yml
vendored
|
|
@ -3,12 +3,12 @@ name: Update the npm package version
|
|||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
required: true
|
||||
type: choice
|
||||
description: Version type
|
||||
default: patch
|
||||
options:
|
||||
version:
|
||||
required: true
|
||||
type: choice
|
||||
description: Version type
|
||||
default: patch
|
||||
options:
|
||||
- major
|
||||
- minor
|
||||
- patch
|
||||
|
|
@ -16,27 +16,30 @@ on:
|
|||
- preminor
|
||||
- prepatch
|
||||
- prerelease
|
||||
|
||||
jobs:
|
||||
update_version:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 18
|
||||
cache: 'npm'
|
||||
|
||||
- id: bump_version
|
||||
run: |
|
||||
echo "old_version=$(jq -r .version package.json)" >> $GITHUB_OUTPUT
|
||||
echo "old_version=$(jq -r .version package.json)" >> "$GITHUB_OUTPUT"
|
||||
npm version ${{ github.event.inputs.version }} --no-git-tag-version
|
||||
echo "new_version=$(jq -r .version package.json)" >> $GITHUB_OUTPUT
|
||||
echo "new_version=$(jq -r .version package.json)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- uses: peter-evans/create-pull-request@v4
|
||||
- uses: peter-evans/create-pull-request@v8
|
||||
with:
|
||||
title: Bump package.json version to v${{ steps.bump_version.outputs.new_version }}}
|
||||
title: Bump package.json version to v${{ steps.bump_version.outputs.new_version }}
|
||||
body: |
|
||||
Bump package.json version from `v${{ steps.bump_version.outputs.old_version }}` to `v${{ steps.bump_version.outputs.new_version }}`
|
||||
commit-message: Bump package.json version to v${{ steps.bump_version.outputs.new_version }}
|
||||
branch: npm-version-bump
|
||||
base: master
|
||||
|
||||
|
||||
|
|
|
|||
10
CODEOWNERS
10
CODEOWNERS
|
|
@ -1,25 +1,25 @@
|
|||
config/formats.ts @KrisXV @Marty-D
|
||||
data/mods/*/random-teams.ts @AnnikaCodes
|
||||
data/mods/gen9ssb/ @HoeenCoder @HisuianZoroark @KrisXV
|
||||
data/random-sets.json @MathyFurret @ACakeWearingAHat @livid-washed @adrivrie
|
||||
data/random-teams.ts @AnnikaCodes @KrisXV @MathyFurret @ACakeWearingAHat @livid-washed @adrivrie
|
||||
data/random-battles/ @KrisXV @MathyFurret @ACakeWearingAHat @livid-washed @adrivrie
|
||||
data/text/ @Marty-D
|
||||
databases/ @monsanto
|
||||
lib/sql.ts @mia-pi-git
|
||||
server/artemis/* @mia-pi-git
|
||||
server/chat-plugins/random-battles/ @KrisXV @AnnikaCodes
|
||||
server/chat-plugins/abuse-monitor.ts @mia-pi-git
|
||||
server/chat-plugins/auction.ts @Karthik99999
|
||||
server/chat-plugins/datasearch.ts @KrisXV
|
||||
server/chat-plugins/friends.ts @mia-pi-git
|
||||
server/chat-plugins/github.ts @mia-pi-git
|
||||
server/chat-plugins/hosts.ts @AnnikaCodes
|
||||
server/chat-plugins/helptickets*.ts @mia-pi-git
|
||||
server/chat-plugins/laddertours.ts @mia-pi-git
|
||||
server/chat-plugins/mafia.ts @HoeenCoder
|
||||
server/chat-plugins/othermetas.ts @KrisXV
|
||||
server/chat-plugins/permalocks.ts @mia-pi-git
|
||||
server/chat-plugins/quotes.ts @mia-pi-git @KrisXV
|
||||
server/chat-plugins/random-battles.ts @KrisXV @AnnikaCodes
|
||||
server/chat-plugins/repeats.ts @AnnikaCodes
|
||||
server/chat-plugins/responder.ts @mia-pi-git
|
||||
server/chat-plugins/rock-paper-scissors.ts @mia-pi-git
|
||||
server/chat-plugins/sample-teams.ts @KrisXV
|
||||
server/chat-plugins/scavenger*.ts @xfix @sparkychildcharlie @PartMan7
|
||||
sever/chat-plugins/teams.ts @mia-pi-git
|
||||
|
|
|
|||
|
|
@ -301,13 +301,13 @@ In general, we prefer modern ways of writing things as long as they're supported
|
|||
|
||||
- Multiline template strings: A frequent source of bugs (and also weird for readability), so we prefer to explicitly use `\n` and concatenate over multiple lines.
|
||||
|
||||
- `async`/`await`: We prefer it for readability, but in certain cases we use raw Promises or even callbacks for performance. Don't worry about it too much; we usually won't nitpick code that uses any async implementation (although we might insist on `async`/`await` if the readability difference is huge).
|
||||
- `async`/`await`: We prefer it for readability, but in certain cases we use raw Promises or even callbacks for performance. Don't worry about it too much; we usually won't nitpick code that uses either async implementation (although we might insist on `async`/`await` if the readability difference is huge).
|
||||
|
||||
- getters/setters/`Proxy`: We are generally very anti-magic. There are certain places in the code we do use magic where it's massively DRYer (or for historical reasons), but we prefer to explicitly mark that setting a variable is actually running a function with many and varied side effects. Please have a better reason than "`.foo` is less visual clutter than `.getFoo()`".
|
||||
|
||||
- Constant Enums: Don't use; we prefer constant union types, like `type Category = 'Physical' | 'Special' | 'Status'`
|
||||
|
||||
- Default Properties: Mediocre performance when compiled with `sucrase`. This is fine for objects that are rarely created, but prefer setting properties directly in a constructor, for objects created in inner loops.
|
||||
- Default Properties: Use.
|
||||
|
||||
|
||||
Dependencies
|
||||
|
|
|
|||
2
LICENSE
2
LICENSE
|
|
@ -1,6 +1,6 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2011-2024 Guangcong Luo and other contributors http://pokemonshowdown.com/
|
||||
Copyright (c) 2011-2026 Guangcong Luo and other contributors http://pokemonshowdown.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
|
|
|
|||
12
PROTOCOL.md
12
PROTOCOL.md
|
|
@ -7,9 +7,9 @@ Pokémon Showdown is implemented in SockJS. SockJS is a compatibility
|
|||
layer over raw WebSocket, so you can actually connect to Pokémon
|
||||
Showdown directly using WebSocket:
|
||||
|
||||
ws://sim.smogon.com:8000/showdown/websocket
|
||||
or
|
||||
wss://sim3.psim.us/showdown/websocket
|
||||
or
|
||||
ws://sim3.psim.us:8000/showdown/websocket
|
||||
|
||||
Client implementations you might want to look at for reference include:
|
||||
|
||||
|
|
@ -144,7 +144,7 @@ represented by a space), and the rest of the string being their username.
|
|||
|
||||
`|uhtml|NAME|HTML`
|
||||
|
||||
> We recieved an HTML message (NAME) that can change what it's displaying,
|
||||
> We received an HTML message (NAME) that can change what it's displaying,
|
||||
> this is used in things like our Polls system, for example.
|
||||
|
||||
`|uhtmlchange|NAME|HTML`
|
||||
|
|
@ -305,7 +305,7 @@ represented by a space), and the rest of the string being their username.
|
|||
`|tournament|update|JSON`
|
||||
|
||||
> `JSON` is a JSON object representing the changes in the tournament
|
||||
> since the last update you recieved or the start of the tournament.
|
||||
> since the last update you received or the start of the tournament.
|
||||
> These include:
|
||||
>
|
||||
format: the tournament's custom name or the format being used
|
||||
|
|
@ -478,7 +478,9 @@ If the challenge is accepted, you will receive a room initialization message.
|
|||
`JSON.searching` will be an array of format IDs you're currently searching for
|
||||
games in.
|
||||
|
||||
`JSON.games` will be a `{roomid: title}` table of games you're currently in.
|
||||
`JSON.games` will be a `{roomid: title}` table of games you're currently in,
|
||||
or `null` if you're in no games.
|
||||
|
||||
Note that this includes ALL games, so `|updatesearch|` will be sent when you
|
||||
start/end challenge battles, and even non-Pokémon games like Mafia.
|
||||
|
||||
|
|
|
|||
17
build
17
build
|
|
@ -2,10 +2,12 @@
|
|||
"use strict";
|
||||
|
||||
try {
|
||||
// technically this was introduced in Node 17, but we'll ask for the most recent LTS with it to be safe
|
||||
structuredClone({});
|
||||
// fetch was introduced in Node 18, which is EOL,
|
||||
// so we'll ask for the most recent "Active LTS" with it to be safe
|
||||
// https://nodejs.org/en/about/previous-releases
|
||||
fetch;
|
||||
} catch (e) {
|
||||
console.log("We require Node.js version 18 or later; you're using " + process.version);
|
||||
console.error("We require Node.js version 22 or later; you're using " + process.version);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
|
@ -22,13 +24,10 @@ function shell(cmd) {
|
|||
|
||||
// Check to make sure the most recently added or updated dependency is installed at the correct version
|
||||
try {
|
||||
var version = require('esbuild').version.split('.');
|
||||
if (parseInt(version[1]) < 16) {
|
||||
throw new Error("esbuild version too old");
|
||||
}
|
||||
require.resolve('ts-chacha20');
|
||||
} catch (e) {
|
||||
console.log('Installing dependencies...');
|
||||
shell('npm install');
|
||||
shell('npm ci');
|
||||
}
|
||||
|
||||
// Make sure config.js exists. If not, copy it over synchronously from
|
||||
|
|
@ -48,7 +47,5 @@ try {
|
|||
// for some reason, esbuild won't be requirable until a tick has passed
|
||||
// see https://stackoverflow.com/questions/53270058/node-cant-find-certain-modules-after-synchronous-install
|
||||
setImmediate(() => {
|
||||
// npm package, don't rebuild
|
||||
if (process.argv[2] === 'postinstall' && fs.existsSync('dist')) return;
|
||||
require('./tools/build-utils').transpile(force, decl);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ Bans are just a `-` followed by the thing you want to ban.
|
|||
|
||||
`- Future` - ban things that only appears in a future generation (such as Arceus in Gen 1)
|
||||
|
||||
`- Custom` - ban made-up things other than CAP (such as Magikarp's Revenge, or Staff Bros moves)
|
||||
`- Custom` - (DEPRECATED) ban miscellaneous other things
|
||||
|
||||
`- Nonexistent` - catch-all to ban all nonexistent Pokémon, items, etc. Includes: `- CAP, - Past, - Future, - LGPE`
|
||||
|
||||
|
|
@ -83,10 +83,20 @@ Syntax is identical to bans, just replace `-` with `+`, like:
|
|||
|
||||
More specific always trumps less specific:
|
||||
|
||||
`- all Pokemon, + Uber, - Giratina, + Giratina-Altered` - allow only Ubers other than Giratina-Origin
|
||||
`- all pokemon, + Uber, - Giratina, + Giratina-Altered` - allow only Ubers other than Giratina-Origin
|
||||
|
||||
`- all pokemon, + Giratina-Altered, - Giratina, + Uber` - allow only Ubers other than Giratina-Origin
|
||||
|
||||
`- Nonexistent, + Necturna` - don't allow anything from outside the game, except the CAP Necturna
|
||||
|
||||
Except `all pokemon`, which removes all bans/unbans of pokemon before it:
|
||||
|
||||
`- all pokemon, + Pikachu, + Raichu` - allow Pikachu and Raichu
|
||||
|
||||
`+ Pikachu, - all pokemon, + Raichu` - allow only Raichu
|
||||
|
||||
(Note that `all pokemon` does not affect obtainability rules. `+ all pokemon` will not allow CAPs or anything like that.)
|
||||
|
||||
For equally specific rules, the last rule wins:
|
||||
|
||||
`- Pikachu, - Pikachu, + Pikachu` - allow Pikachu
|
||||
|
|
@ -128,7 +138,7 @@ Whitelisting
|
|||
|
||||
Instead of a banlist, you can have a list of allowed things:
|
||||
|
||||
`- all Pokemon, + Charmander, + Squirtle, + Bulbasaur` - allow only Kanto starters
|
||||
`- all pokemon, + Charmander, + Squirtle, + Bulbasaur` - allow only Kanto starters
|
||||
|
||||
`- all moves, + move: Metronome` - allow only the move Metronome
|
||||
|
||||
|
|
|
|||
|
|
@ -15,23 +15,6 @@ exports.port = 8000;
|
|||
*/
|
||||
exports.bindaddress = '0.0.0.0';
|
||||
|
||||
/**
|
||||
* workers - the number of networking child processes to spawn
|
||||
* This should be no greater than the number of threads available on your
|
||||
* server's CPU. If you're not sure how many you have, you can check from a
|
||||
* terminal by running:
|
||||
*
|
||||
* $ node -e "console.log(require('os').cpus().length)"
|
||||
*
|
||||
* Using more workers than there are available threads will cause performance
|
||||
* issues. Keeping a couple threads available for use for OS-related work and
|
||||
* other PS processes will likely give you the best performance, if your
|
||||
* server's CPU is capable of multithreading. If you don't know what any of
|
||||
* this means or you are unfamiliar with PS' networking code, leave this set
|
||||
* to 1.
|
||||
*/
|
||||
exports.workers = 1;
|
||||
|
||||
/**
|
||||
* wsdeflate - compresses WebSocket messages
|
||||
* Toggles use of the Sec-WebSocket-Extension permessage-deflate extension.
|
||||
|
|
@ -42,6 +25,15 @@ exports.workers = 1;
|
|||
*/
|
||||
exports.wsdeflate = null;
|
||||
|
||||
/**
|
||||
* lazysockets - disables eager initialization of network services
|
||||
* Turn this on if you'd prefer to manually connect Showdown to the network,
|
||||
* or you intend to run it offline.
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
exports.lazysockets = false;
|
||||
|
||||
/*
|
||||
// example:
|
||||
exports.wsdeflate = {
|
||||
|
|
@ -92,6 +84,50 @@ Main's SSL deploy script from Let's Encrypt looks like:
|
|||
*/
|
||||
exports.proxyip = false;
|
||||
|
||||
// subprocesses - the number of child processes to use for various tasks.
|
||||
// Can be set to `0` instead of `{...}` to stop using subprocesses, if you're running out of RAM.
|
||||
exports.subprocesses = {
|
||||
/**
|
||||
* network - the number of networking child processes to spawn
|
||||
* This should be no greater than the number of threads available on your
|
||||
* server's CPU. If you're not sure how many you have, you can check from a
|
||||
* terminal by running:
|
||||
*
|
||||
* $ node -e "console.log(require('os').cpus().length)"
|
||||
*
|
||||
* Using more workers than there are available threads will cause performance
|
||||
* issues. Keeping a couple threads available for use for OS-related work and
|
||||
* other PS processes will likely give you the best performance, if your
|
||||
* server's CPU is capable of multithreading. If you don't know what any of
|
||||
* this means or you are unfamiliar with PS' networking code, leave this set
|
||||
* to 1.
|
||||
*/
|
||||
network: 1,
|
||||
/**
|
||||
* for simulating battles
|
||||
* You should leave this at 1 unless your server has a very large
|
||||
* amount of traffic (i.e. hundreds of concurrent battles).
|
||||
*/
|
||||
simulator: 1,
|
||||
|
||||
// beyond this point, it'd be very weird if you needed more than one of each of these
|
||||
|
||||
/** for validating teams */
|
||||
validator: 1,
|
||||
/** for user authentication */
|
||||
verifier: 1,
|
||||
localartemis: 1,
|
||||
remoteartemis: 1,
|
||||
friends: 1,
|
||||
chatdb: 1,
|
||||
modlog: 1,
|
||||
pm: 1,
|
||||
/** for the battlesearch chat plugin */
|
||||
battlesearch: 1,
|
||||
/** datasearch - for the datasearch chat plugin */
|
||||
datasearch: 1,
|
||||
};
|
||||
|
||||
/**
|
||||
* Various debug options
|
||||
*
|
||||
|
|
@ -401,15 +437,6 @@ exports.logchallenges = false;
|
|||
*/
|
||||
exports.loguserstats = 1000 * 60 * 10; // 10 minutes
|
||||
|
||||
/**
|
||||
* validatorprocesses - the number of processes to use for validating teams
|
||||
* simulatorprocesses - the number of processes to use for handling battles
|
||||
* You should leave both of these at 1 unless your server has a very large
|
||||
* amount of traffic (i.e. hundreds of concurrent battles).
|
||||
*/
|
||||
exports.validatorprocesses = 1;
|
||||
exports.simulatorprocesses = 1;
|
||||
|
||||
/**
|
||||
* inactiveuserthreshold - how long a user must be inactive before being pruned
|
||||
* from the `users` array. The default is 1 hour.
|
||||
|
|
@ -500,7 +527,7 @@ exports.lastfmkey = '';
|
|||
exports.chatlogreader = 'fs';
|
||||
/**
|
||||
* permissions and groups:
|
||||
* Each entry in `grouplist` is a seperate group. Some of the members are "special"
|
||||
* Each entry in `grouplist` is a separate group. Some of the members are "special"
|
||||
* while the rest is just a normal permission.
|
||||
* The order of the groups determines their ranking.
|
||||
* The special members are as follows:
|
||||
|
|
|
|||
2912
config/formats.ts
2912
config/formats.ts
File diff suppressed because it is too large
Load Diff
|
|
@ -127,6 +127,7 @@ List of all in-battle forme changes:
|
|||
- Darmanitan (Zen Mode)
|
||||
- Meloetta (Relic Song)
|
||||
- Shaymin-Sky (Frozen status)
|
||||
- Ramnarok (Polar Flare)
|
||||
- Mega evolutions
|
||||
- Primal reversions
|
||||
- Ultra Burst
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
const noModifyType = [
|
||||
'judgment', 'multiattack', 'naturalgift', 'revelationdance', 'technoblast', 'terrainpulse', 'weatherball',
|
||||
];
|
||||
if (move.type === 'Normal' && !noModifyType.includes(move.id) &&
|
||||
if (move.type === 'Normal' && (!noModifyType.includes(move.id) || this.activeMove?.isMax) &&
|
||||
!(move.isZ && move.category !== 'Status') && !(move.name === 'Tera Blast' && pokemon.terastallized)) {
|
||||
move.type = 'Flying';
|
||||
move.typeChangerBoosted = this.effect;
|
||||
|
|
@ -142,15 +142,10 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
},
|
||||
angershell: {
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (
|
||||
effect.effectType === "Move" &&
|
||||
!effect.multihit &&
|
||||
(!effect.negateSecondary && !(effect.hasSheerForce && source.hasAbility('sheerforce')))
|
||||
) {
|
||||
this.effectState.checkedAngerShell = false;
|
||||
} else {
|
||||
this.effectState.checkedAngerShell = true;
|
||||
}
|
||||
this.effectState.checkedAngerShell = !(
|
||||
effect.effectType === "Move" && !effect.multihit &&
|
||||
!(effect.hasSheerForce && source.hasAbility('sheerforce'))
|
||||
);
|
||||
},
|
||||
onTryEatItem(item) {
|
||||
const healingItems = [
|
||||
|
|
@ -301,7 +296,6 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
},
|
||||
aurabreak: {
|
||||
onStart(pokemon) {
|
||||
if (this.suppressingAbility(pokemon)) return;
|
||||
this.add('-ability', pokemon, 'Aura Break');
|
||||
},
|
||||
onAnyTryPrimaryHit(target, source, move) {
|
||||
|
|
@ -357,12 +351,19 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
},
|
||||
battlebond: {
|
||||
onSourceAfterFaint(length, target, source, effect) {
|
||||
if (source.bondTriggered) return;
|
||||
if (effect?.effectType !== 'Move') return;
|
||||
if (source.abilityState.battleBondTriggered) return;
|
||||
if (source.species.id === 'greninjabond' && source.hp && !source.transformed && source.side.foePokemonLeft()) {
|
||||
this.boost({ atk: 1, spa: 1, spe: 1 }, source, source, this.effect);
|
||||
this.add('-activate', source, 'ability: Battle Bond');
|
||||
source.abilityState.battleBondTriggered = true;
|
||||
source.bondTriggered = true;
|
||||
}
|
||||
},
|
||||
onModifyMovePriority: -1,
|
||||
onModifyMove(move, attacker) {
|
||||
if (move.id === 'watershuriken' && attacker.species.name === 'Greninja-Ash' &&
|
||||
!attacker.transformed) {
|
||||
move.multihit = 3;
|
||||
}
|
||||
},
|
||||
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, cantsuppress: 1 },
|
||||
|
|
@ -402,15 +403,10 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
},
|
||||
berserk: {
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (
|
||||
effect.effectType === "Move" &&
|
||||
!effect.multihit &&
|
||||
(!effect.negateSecondary && !(effect.hasSheerForce && source.hasAbility('sheerforce')))
|
||||
) {
|
||||
this.effectState.checkedBerserk = false;
|
||||
} else {
|
||||
this.effectState.checkedBerserk = true;
|
||||
}
|
||||
this.effectState.checkedBerserk = !(
|
||||
effect.effectType === "Move" && !effect.multihit &&
|
||||
!(effect.hasSheerForce && source.hasAbility('sheerforce'))
|
||||
);
|
||||
},
|
||||
onTryEatItem(item) {
|
||||
const healingItems = [
|
||||
|
|
@ -734,33 +730,29 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
num: 238,
|
||||
},
|
||||
cudchew: {
|
||||
onEatItem(item, pokemon) {
|
||||
if (item.isBerry && pokemon.addVolatile('cudchew')) {
|
||||
pokemon.volatiles['cudchew'].berry = item;
|
||||
onEatItem(item, pokemon, source, effect) {
|
||||
if (item.isBerry && (!effect || !['bugbite', 'pluck'].includes(effect.id))) {
|
||||
this.effectState.berry = item;
|
||||
this.effectState.counter = 2;
|
||||
// This is needed in case the berry was eaten during residuals, preventing the timer from decreasing this turn
|
||||
if (!this.queue.peek()) this.effectState.counter--;
|
||||
}
|
||||
},
|
||||
onEnd(pokemon) {
|
||||
delete pokemon.volatiles['cudchew'];
|
||||
},
|
||||
condition: {
|
||||
noCopy: true,
|
||||
duration: 2,
|
||||
onRestart() {
|
||||
this.effectState.duration = 2;
|
||||
},
|
||||
onResidualOrder: 28,
|
||||
onResidualSubOrder: 2,
|
||||
onEnd(pokemon) {
|
||||
if (pokemon.hp) {
|
||||
const item = this.effectState.berry;
|
||||
this.add('-activate', pokemon, 'ability: Cud Chew');
|
||||
this.add('-enditem', pokemon, item.name, '[eat]');
|
||||
if (this.singleEvent('Eat', item, null, pokemon, null, null)) {
|
||||
this.runEvent('EatItem', pokemon, null, null, item);
|
||||
}
|
||||
if (item.onEat) pokemon.ateBerry = true;
|
||||
onResidualOrder: 28,
|
||||
onResidualSubOrder: 2,
|
||||
onResidual(pokemon) {
|
||||
if (!this.effectState.berry || !pokemon.hp) return;
|
||||
if (--this.effectState.counter <= 0) {
|
||||
const item = this.effectState.berry;
|
||||
this.add('-activate', pokemon, 'ability: Cud Chew');
|
||||
this.add('-enditem', pokemon, item.name, '[eat]');
|
||||
if (this.singleEvent('Eat', item, null, pokemon, null, null)) {
|
||||
this.runEvent('EatItem', pokemon, null, null, item);
|
||||
}
|
||||
},
|
||||
if (item.onEat) pokemon.ateBerry = true;
|
||||
delete this.effectState.berry;
|
||||
delete this.effectState.counter;
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Cud Chew",
|
||||
|
|
@ -982,7 +974,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
const hitSub = target.volatiles['substitute'] && !move.flags['bypasssub'] && !(move.infiltrates && this.gen >= 6);
|
||||
if (hitSub) return;
|
||||
|
||||
if (!target.runImmunity(move.type)) return;
|
||||
if (!target.runImmunity(move)) return;
|
||||
return false;
|
||||
},
|
||||
onEffectiveness(typeMod, target, type, move) {
|
||||
|
|
@ -994,7 +986,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
const hitSub = target.volatiles['substitute'] && !move.flags['bypasssub'] && !(move.infiltrates && this.gen >= 6);
|
||||
if (hitSub) return;
|
||||
|
||||
if (!target.runImmunity(move.type)) return;
|
||||
if (!target.runImmunity(move)) return;
|
||||
return 0;
|
||||
},
|
||||
onUpdate(pokemon) {
|
||||
|
|
@ -1031,6 +1023,28 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
rating: 3.5,
|
||||
num: 88,
|
||||
},
|
||||
dragonize: {
|
||||
isNonstandard: "Future",
|
||||
onModifyTypePriority: -1,
|
||||
onModifyType(move, pokemon) {
|
||||
const noModifyType = [
|
||||
'judgment', 'multiattack', 'naturalgift', 'revelationdance', 'technoblast', 'terrainpulse', 'weatherball',
|
||||
];
|
||||
if (move.type === 'Normal' && (!noModifyType.includes(move.id) || this.activeMove?.isMax) &&
|
||||
!(move.isZ && move.category !== 'Status') && !(move.name === 'Tera Blast' && pokemon.terastallized)) {
|
||||
move.type = 'Dragon';
|
||||
move.typeChangerBoosted = this.effect;
|
||||
}
|
||||
},
|
||||
onBasePowerPriority: 23,
|
||||
onBasePower(basePower, pokemon, target, move) {
|
||||
if (move.typeChangerBoosted === this.effect) return this.chainModify([4915, 4096]);
|
||||
},
|
||||
flags: {},
|
||||
name: "Dragonize",
|
||||
rating: 4,
|
||||
num: 312,
|
||||
},
|
||||
dragonsmaw: {
|
||||
onModifyAtkPriority: 5,
|
||||
onModifyAtk(atk, attacker, defender, move) {
|
||||
|
|
@ -1087,7 +1101,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
}
|
||||
},
|
||||
onWeather(target, source, effect) {
|
||||
if (target.hasItem('utilityumbrella')) return;
|
||||
if (target.effectiveWeather() !== effect.id) return;
|
||||
if (effect.id === 'raindance' || effect.id === 'primordialsea') {
|
||||
this.heal(target.baseMaxhp / 8);
|
||||
} else if (effect.id === 'sunnyday' || effect.id === 'desolateland') {
|
||||
|
|
@ -1122,14 +1136,14 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
},
|
||||
effectspore: {
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (this.checkMoveMakesContact(move, source, target) && !source.status && source.runStatusImmunity('powder')) {
|
||||
if (this.checkMoveMakesContact(move, source, target) && source.runStatusImmunity('powder')) {
|
||||
const r = this.random(100);
|
||||
if (r < 11) {
|
||||
source.setStatus('slp', target);
|
||||
source.trySetStatus('slp', target);
|
||||
} else if (r < 21) {
|
||||
source.setStatus('par', target);
|
||||
source.trySetStatus('par', target);
|
||||
} else if (r < 30) {
|
||||
source.setStatus('psn', target);
|
||||
source.trySetStatus('psn', target);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -1159,9 +1173,9 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
},
|
||||
embodyaspectcornerstone: {
|
||||
onStart(pokemon) {
|
||||
if (pokemon.baseSpecies.name === 'Ogerpon-Cornerstone-Tera' &&
|
||||
this.effectState.embodied !== pokemon.previouslySwitchedIn) {
|
||||
this.effectState.embodied = pokemon.previouslySwitchedIn;
|
||||
if (pokemon.baseSpecies.name === 'Ogerpon-Cornerstone-Tera' && pokemon.terastallized &&
|
||||
!this.effectState.embodied) {
|
||||
this.effectState.embodied = true;
|
||||
this.boost({ def: 1 }, pokemon);
|
||||
}
|
||||
},
|
||||
|
|
@ -1172,9 +1186,9 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
},
|
||||
embodyaspecthearthflame: {
|
||||
onStart(pokemon) {
|
||||
if (pokemon.baseSpecies.name === 'Ogerpon-Hearthflame-Tera' &&
|
||||
this.effectState.embodied !== pokemon.previouslySwitchedIn) {
|
||||
this.effectState.embodied = pokemon.previouslySwitchedIn;
|
||||
if (pokemon.baseSpecies.name === 'Ogerpon-Hearthflame-Tera' && pokemon.terastallized &&
|
||||
!this.effectState.embodied) {
|
||||
this.effectState.embodied = true;
|
||||
this.boost({ atk: 1 }, pokemon);
|
||||
}
|
||||
},
|
||||
|
|
@ -1185,9 +1199,9 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
},
|
||||
embodyaspectteal: {
|
||||
onStart(pokemon) {
|
||||
if (pokemon.baseSpecies.name === 'Ogerpon-Teal-Tera' &&
|
||||
this.effectState.embodied !== pokemon.previouslySwitchedIn) {
|
||||
this.effectState.embodied = pokemon.previouslySwitchedIn;
|
||||
if (pokemon.baseSpecies.name === 'Ogerpon-Teal-Tera' && pokemon.terastallized &&
|
||||
!this.effectState.embodied) {
|
||||
this.effectState.embodied = true;
|
||||
this.boost({ spe: 1 }, pokemon);
|
||||
}
|
||||
},
|
||||
|
|
@ -1198,9 +1212,9 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
},
|
||||
embodyaspectwellspring: {
|
||||
onStart(pokemon) {
|
||||
if (pokemon.baseSpecies.name === 'Ogerpon-Wellspring-Tera' &&
|
||||
this.effectState.embodied !== pokemon.previouslySwitchedIn) {
|
||||
this.effectState.embodied = pokemon.previouslySwitchedIn;
|
||||
if (pokemon.baseSpecies.name === 'Ogerpon-Wellspring-Tera' && pokemon.terastallized &&
|
||||
!this.effectState.embodied) {
|
||||
this.effectState.embodied = true;
|
||||
this.boost({ spd: 1 }, pokemon);
|
||||
}
|
||||
},
|
||||
|
|
@ -1541,7 +1555,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
const noModifyType = [
|
||||
'judgment', 'multiattack', 'naturalgift', 'revelationdance', 'technoblast', 'terrainpulse', 'weatherball',
|
||||
];
|
||||
if (move.type === 'Normal' && !noModifyType.includes(move.id) &&
|
||||
if (move.type === 'Normal' && (!noModifyType.includes(move.id) || this.activeMove?.isMax) &&
|
||||
!(move.isZ && move.category !== 'Status') && !(move.name === 'Tera Blast' && pokemon.terastallized)) {
|
||||
move.type = 'Electric';
|
||||
move.typeChangerBoosted = this.effect;
|
||||
|
|
@ -1928,7 +1942,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
if (!target) return;
|
||||
if (move.category !== 'Physical' || target.species.id !== 'eiscue') return;
|
||||
if (target.volatiles['substitute'] && !(move.flags['bypasssub'] || move.infiltrates)) return;
|
||||
if (!target.runImmunity(move.type)) return;
|
||||
if (!target.runImmunity(move)) return;
|
||||
return false;
|
||||
},
|
||||
onEffectiveness(typeMod, target, type, move) {
|
||||
|
|
@ -1938,7 +1952,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
const hitSub = target.volatiles['substitute'] && !move.flags['bypasssub'] && !(move.infiltrates && this.gen >= 6);
|
||||
if (hitSub) return;
|
||||
|
||||
if (!target.runImmunity(move.type)) return;
|
||||
if (!target.runImmunity(move)) return;
|
||||
return 0;
|
||||
},
|
||||
onUpdate(pokemon) {
|
||||
|
|
@ -2002,7 +2016,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
if (!possibleTarget.fainted) {
|
||||
// If Ogerpon is in the last slot while the Illusion Pokemon is Terastallized
|
||||
// Illusion will not disguise as anything
|
||||
if (!pokemon.terastallized || possibleTarget.species.baseSpecies !== 'Ogerpon') {
|
||||
if (!pokemon.terastallized || !['Ogerpon', 'Terapagos'].includes(possibleTarget.species.baseSpecies)) {
|
||||
pokemon.illusion = possibleTarget;
|
||||
}
|
||||
break;
|
||||
|
|
@ -2015,7 +2029,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
}
|
||||
},
|
||||
onEnd(pokemon) {
|
||||
if (pokemon.illusion) {
|
||||
if (pokemon.illusion && !pokemon.beingCalledBack) {
|
||||
this.debug('illusion cleared');
|
||||
pokemon.illusion = null;
|
||||
const details = pokemon.getUpdatedDetails();
|
||||
|
|
@ -2082,6 +2096,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
onDamagingHitOrder: 1,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (!target.hp) {
|
||||
if (!move.smartTarget) damage += Number(move.totalDamage);
|
||||
this.damage(target.getUndynamaxedHP(damage), source, target);
|
||||
}
|
||||
},
|
||||
|
|
@ -2257,12 +2272,12 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
},
|
||||
libero: {
|
||||
onPrepareHit(source, target, move) {
|
||||
if (this.effectState.libero === source.previouslySwitchedIn) return;
|
||||
if (this.effectState.libero) return;
|
||||
if (move.hasBounced || move.flags['futuremove'] || move.sourceEffect === 'snatch' || move.callsMove) return;
|
||||
const type = move.type;
|
||||
if (type && type !== '???' && source.getTypes().join() !== type) {
|
||||
if (!source.setType(type)) return;
|
||||
this.effectState.libero = source.previouslySwitchedIn;
|
||||
this.effectState.libero = true;
|
||||
this.add('-start', source, 'typechange', type, '[from] ability: Libero');
|
||||
}
|
||||
},
|
||||
|
|
@ -2331,10 +2346,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
return;
|
||||
}
|
||||
if (this.checkMoveMakesContact(move, source, target, !source.isAlly(target))) {
|
||||
const oldAbility = source.setAbility('lingeringaroma', target);
|
||||
if (oldAbility) {
|
||||
this.add('-activate', target, 'ability: Lingering Aroma', this.dex.abilities.get(oldAbility).name, `[of] ${source}`);
|
||||
}
|
||||
source.setAbility('lingeringaroma', target);
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
|
|
@ -2397,11 +2409,9 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
newMove.hasBounced = true;
|
||||
newMove.pranksterBoosted = false;
|
||||
this.actions.useMove(newMove, this.effectState.target, { target: source });
|
||||
move.hasBounced = true; // only bounce once in free-for-all battles
|
||||
return null;
|
||||
},
|
||||
condition: {
|
||||
duration: 1,
|
||||
},
|
||||
flags: { breakable: 1 },
|
||||
name: "Magic Bounce",
|
||||
rating: 4,
|
||||
|
|
@ -2421,16 +2431,21 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
},
|
||||
magician: {
|
||||
onAfterMoveSecondarySelf(source, target, move) {
|
||||
if (!move || !target || source.switchFlag === true) return;
|
||||
if (target !== source && move.category !== 'Status') {
|
||||
if (source.item || source.volatiles['gem'] || move.id === 'fling') return;
|
||||
const yourItem = target.takeItem(source);
|
||||
if (!yourItem) return;
|
||||
if (!source.setItem(yourItem)) {
|
||||
target.item = yourItem.id; // bypass setItem so we don't break choicelock or anything
|
||||
if (!move || source.switchFlag === true || !move.hitTargets || source.item || source.volatiles['gem'] ||
|
||||
move.id === 'fling' || move.category === 'Status') return;
|
||||
const hitTargets = move.hitTargets;
|
||||
this.speedSort(hitTargets);
|
||||
for (const pokemon of hitTargets) {
|
||||
if (pokemon !== source) {
|
||||
const yourItem = pokemon.takeItem(source);
|
||||
if (!yourItem) continue;
|
||||
if (!source.setItem(yourItem)) {
|
||||
pokemon.item = yourItem.id; // bypass setItem so we don't break choicelock or anything
|
||||
continue;
|
||||
}
|
||||
this.add('-item', source, yourItem, '[from] ability: Magician', `[of] ${pokemon}`);
|
||||
return;
|
||||
}
|
||||
this.add('-item', source, yourItem, '[from] ability: Magician', `[of] ${target}`);
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
|
|
@ -2495,6 +2510,20 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
rating: 3,
|
||||
num: 178,
|
||||
},
|
||||
megasol: {
|
||||
isNonstandard: "Future",
|
||||
onWeatherModifyDamage(damage, attacker, defender, move) {
|
||||
if (this.field.weather !== 'sunnyday') {
|
||||
(this.dex.conditions.getByID('sunnyday' as ID) as any).onWeatherModifyDamage
|
||||
.call(this, damage, attacker, defender, move);
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Mega Sol",
|
||||
rating: 3,
|
||||
num: 315,
|
||||
// Partially implemented in Pokemon.effectiveWeather() in sim/pokemon.ts
|
||||
},
|
||||
merciless: {
|
||||
onModifyCritRatio(critRatio, source, target) {
|
||||
if (target && ['psn', 'tox'].includes(target.status)) return 5;
|
||||
|
|
@ -2709,10 +2738,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
return;
|
||||
}
|
||||
if (this.checkMoveMakesContact(move, source, target, !source.isAlly(target))) {
|
||||
const oldAbility = source.setAbility('mummy', target);
|
||||
if (oldAbility) {
|
||||
this.add('-activate', target, 'ability: Mummy', this.dex.abilities.get(oldAbility).name, `[of] ${source}`);
|
||||
}
|
||||
source.setAbility('mummy', target);
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
|
|
@ -2808,7 +2834,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
// is known
|
||||
if (pokemon.showCure === undefined) pokemon.showCure = true;
|
||||
|
||||
if (pokemon.showCure) this.add('-curestatus', pokemon, pokemon.status, '[from] ability: Natural Cure');
|
||||
if (pokemon.showCure) this.add('-curestatus', pokemon, pokemon.status, '[from] ability: Natural Cure', '[silent]');
|
||||
pokemon.clearStatus();
|
||||
|
||||
// only reset .showCure if it's false
|
||||
|
|
@ -2918,9 +2944,9 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
const noModifyType = [
|
||||
'hiddenpower', 'judgment', 'multiattack', 'naturalgift', 'revelationdance', 'struggle', 'technoblast', 'terrainpulse', 'weatherball',
|
||||
];
|
||||
if (!(move.isZ && move.category !== 'Status') && !noModifyType.includes(move.id) &&
|
||||
if (!(move.isZ && move.category !== 'Status') &&
|
||||
// TODO: Figure out actual interaction
|
||||
!(move.name === 'Tera Blast' && pokemon.terastallized)) {
|
||||
(!noModifyType.includes(move.id) || this.activeMove?.isMax) && !(move.name === 'Tera Blast' && pokemon.terastallized)) {
|
||||
move.type = 'Normal';
|
||||
move.typeChangerBoosted = this.effect;
|
||||
}
|
||||
|
|
@ -2985,6 +3011,16 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
this.boost(this.effectState.boosts, this.effectState.target);
|
||||
delete this.effectState.boosts;
|
||||
},
|
||||
onAnyAfterMega() {
|
||||
if (!this.effectState.boosts) return;
|
||||
this.boost(this.effectState.boosts, this.effectState.target);
|
||||
delete this.effectState.boosts;
|
||||
},
|
||||
onAnyAfterTerastallization() {
|
||||
if (!this.effectState.boosts) return;
|
||||
this.boost(this.effectState.boosts, this.effectState.target);
|
||||
delete this.effectState.boosts;
|
||||
},
|
||||
onAnyAfterMove() {
|
||||
if (!this.effectState.boosts) return;
|
||||
this.boost(this.effectState.boosts, this.effectState.target);
|
||||
|
|
@ -3198,13 +3234,27 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
rating: 0.5,
|
||||
num: 53,
|
||||
},
|
||||
piercingdrill: {
|
||||
isNonstandard: "Future",
|
||||
onHitProtect(source, target, move) {
|
||||
if (move.flags['contact']) {
|
||||
target.getMoveHitData(move).bypassProtect = this.effect;
|
||||
return false;
|
||||
}
|
||||
},
|
||||
// breaking protect handled in Battle#checkMoveBypassesProtect()
|
||||
flags: {},
|
||||
name: "Piercing Drill",
|
||||
rating: 1,
|
||||
num: 311,
|
||||
},
|
||||
pixilate: {
|
||||
onModifyTypePriority: -1,
|
||||
onModifyType(move, pokemon) {
|
||||
const noModifyType = [
|
||||
'judgment', 'multiattack', 'naturalgift', 'revelationdance', 'technoblast', 'terrainpulse', 'weatherball',
|
||||
];
|
||||
if (move.type === 'Normal' && !noModifyType.includes(move.id) &&
|
||||
if (move.type === 'Normal' && (!noModifyType.includes(move.id) || this.activeMove?.isMax) &&
|
||||
!(move.isZ && move.category !== 'Status') && !(move.name === 'Tera Blast' && pokemon.terastallized)) {
|
||||
move.type = 'Fairy';
|
||||
move.typeChangerBoosted = this.effect;
|
||||
|
|
@ -3294,13 +3344,8 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
if (pokemon.species.id === 'zygardecomplete' || pokemon.hp > pokemon.maxhp / 2) return;
|
||||
this.add('-activate', pokemon, 'ability: Power Construct');
|
||||
pokemon.formeChange('Zygarde-Complete', this.effect, true);
|
||||
pokemon.baseMaxhp = Math.floor(Math.floor(
|
||||
2 * pokemon.species.baseStats['hp'] + pokemon.set.ivs['hp'] + Math.floor(pokemon.set.evs['hp'] / 4) + 100
|
||||
) * pokemon.level / 100 + 10);
|
||||
const newMaxHP = pokemon.volatiles['dynamax'] ? (2 * pokemon.baseMaxhp) : pokemon.baseMaxhp;
|
||||
pokemon.hp = newMaxHP - (pokemon.maxhp - pokemon.hp);
|
||||
pokemon.maxhp = newMaxHP;
|
||||
this.add('-heal', pokemon, pokemon.getHealth, '[silent]');
|
||||
pokemon.canMegaEvo = pokemon.canMegaEvo === false ? false : this.actions.canMegaEvo(pokemon);
|
||||
pokemon.formeRegression = true;
|
||||
},
|
||||
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, cantsuppress: 1 },
|
||||
name: "Power Construct",
|
||||
|
|
@ -3312,9 +3357,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
if (!this.effectState.target.hp) return;
|
||||
const ability = target.getAbility();
|
||||
if (ability.flags['noreceiver'] || ability.id === 'noability') return;
|
||||
if (this.effectState.target.setAbility(ability)) {
|
||||
this.add('-ability', this.effectState.target, ability, '[from] ability: Power of Alchemy', `[of] ${target}`);
|
||||
}
|
||||
this.effectState.target.setAbility(ability, target);
|
||||
},
|
||||
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1 },
|
||||
name: "Power of Alchemy",
|
||||
|
|
@ -3408,12 +3451,12 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
},
|
||||
protean: {
|
||||
onPrepareHit(source, target, move) {
|
||||
if (this.effectState.protean === source.previouslySwitchedIn) return;
|
||||
if (this.effectState.protean) return;
|
||||
if (move.hasBounced || move.flags['futuremove'] || move.sourceEffect === 'snatch' || move.callsMove) return;
|
||||
const type = move.type;
|
||||
if (type && type !== '???' && source.getTypes().join() !== type) {
|
||||
if (!source.setType(type)) return;
|
||||
this.effectState.protean = source.previouslySwitchedIn;
|
||||
this.effectState.protean = true;
|
||||
this.add('-start', source, 'typechange', type, '[from] ability: Protean');
|
||||
}
|
||||
},
|
||||
|
|
@ -3670,7 +3713,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
},
|
||||
raindish: {
|
||||
onWeather(target, source, effect) {
|
||||
if (target.hasItem('utilityumbrella')) return;
|
||||
if (target.effectiveWeather() !== effect.id) return;
|
||||
if (effect.id === 'raindance' || effect.id === 'primordialsea') {
|
||||
this.heal(target.baseMaxhp / 16);
|
||||
}
|
||||
|
|
@ -3701,9 +3744,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
if (!this.effectState.target.hp) return;
|
||||
const ability = target.getAbility();
|
||||
if (ability.flags['noreceiver'] || ability.id === 'noability') return;
|
||||
if (this.effectState.target.setAbility(ability)) {
|
||||
this.add('-ability', this.effectState.target, ability, '[from] ability: Receiver', `[of] ${target}`);
|
||||
}
|
||||
this.effectState.target.setAbility(ability, target);
|
||||
},
|
||||
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1 },
|
||||
name: "Receiver",
|
||||
|
|
@ -3729,7 +3770,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
const noModifyType = [
|
||||
'judgment', 'multiattack', 'naturalgift', 'revelationdance', 'technoblast', 'terrainpulse', 'weatherball',
|
||||
];
|
||||
if (move.type === 'Normal' && !noModifyType.includes(move.id) &&
|
||||
if (move.type === 'Normal' && (!noModifyType.includes(move.id) || this.activeMove?.isMax) &&
|
||||
!(move.isZ && move.category !== 'Status') && !(move.name === 'Tera Blast' && pokemon.terastallized)) {
|
||||
move.type = 'Ice';
|
||||
move.typeChangerBoosted = this.effect;
|
||||
|
|
@ -4115,7 +4156,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
},
|
||||
sheerforce: {
|
||||
onModifyMove(move, pokemon) {
|
||||
if (move.secondaries) {
|
||||
if (move.secondaries && !move.hasSheerForceBoost) {
|
||||
delete move.secondaries;
|
||||
// Technically not a secondary effect, but it is negated
|
||||
delete move.self;
|
||||
|
|
@ -4126,7 +4167,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
},
|
||||
onBasePowerPriority: 21,
|
||||
onBasePower(basePower, pokemon, target, move) {
|
||||
if (move.hasSheerForce) return this.chainModify([5325, 4096]);
|
||||
if (move.hasSheerForce || move.hasSheerForceBoost) return this.chainModify([5325, 4096]);
|
||||
},
|
||||
flags: {},
|
||||
name: "Sheer Force",
|
||||
|
|
@ -4143,7 +4184,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
shielddust: {
|
||||
onModifySecondaries(secondaries) {
|
||||
this.debug('Shield Dust prevent secondary');
|
||||
return secondaries.filter(effect => !!(effect.self || effect.dustproof));
|
||||
return secondaries.filter(effect => !!effect.self);
|
||||
},
|
||||
flags: { breakable: 1 },
|
||||
name: "Shield Dust",
|
||||
|
|
@ -4224,35 +4265,35 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
},
|
||||
slowstart: {
|
||||
onStart(pokemon) {
|
||||
pokemon.addVolatile('slowstart');
|
||||
this.add('-start', pokemon, 'ability: Slow Start');
|
||||
this.effectState.counter = 5;
|
||||
},
|
||||
onResidualOrder: 28,
|
||||
onResidualSubOrder: 2,
|
||||
onResidual(pokemon) {
|
||||
if (pokemon.activeTurns && this.effectState.counter) {
|
||||
this.effectState.counter--;
|
||||
if (!this.effectState.counter) {
|
||||
this.add('-end', pokemon, 'Slow Start');
|
||||
delete this.effectState.counter;
|
||||
}
|
||||
}
|
||||
},
|
||||
onModifyAtkPriority: 5,
|
||||
onModifyAtk(atk, pokemon) {
|
||||
if (this.effectState.counter) {
|
||||
return this.chainModify(0.5);
|
||||
}
|
||||
},
|
||||
onModifySpe(spe, pokemon) {
|
||||
if (this.effectState.counter) {
|
||||
return this.chainModify(0.5);
|
||||
}
|
||||
},
|
||||
onEnd(pokemon) {
|
||||
delete pokemon.volatiles['slowstart'];
|
||||
if (pokemon.beingCalledBack) return;
|
||||
this.add('-end', pokemon, 'Slow Start', '[silent]');
|
||||
},
|
||||
condition: {
|
||||
duration: 5,
|
||||
onResidualOrder: 28,
|
||||
onResidualSubOrder: 2,
|
||||
onStart(target) {
|
||||
this.add('-start', target, 'ability: Slow Start');
|
||||
},
|
||||
onResidual(pokemon) {
|
||||
if (!pokemon.activeTurns) {
|
||||
this.effectState.duration! += 1;
|
||||
}
|
||||
},
|
||||
onModifyAtkPriority: 5,
|
||||
onModifyAtk(atk, pokemon) {
|
||||
return this.chainModify(0.5);
|
||||
},
|
||||
onModifySpe(spe, pokemon) {
|
||||
return this.chainModify(0.5);
|
||||
},
|
||||
onEnd(target) {
|
||||
this.add('-end', target, 'Slow Start');
|
||||
},
|
||||
},
|
||||
flags: {},
|
||||
name: "Slow Start",
|
||||
rating: -1,
|
||||
|
|
@ -4315,7 +4356,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
}
|
||||
},
|
||||
onWeather(target, source, effect) {
|
||||
if (target.hasItem('utilityumbrella')) return;
|
||||
if (target.effectiveWeather() !== effect.id) return;
|
||||
if (effect.id === 'sunnyday' || effect.id === 'desolateland') {
|
||||
this.damage(target.baseMaxhp / 8, target, target);
|
||||
}
|
||||
|
|
@ -4377,6 +4418,16 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
rating: 4.5,
|
||||
num: 3,
|
||||
},
|
||||
spicyspray: {
|
||||
isNonstandard: "Future",
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
source.trySetStatus('brn', target);
|
||||
},
|
||||
flags: {},
|
||||
name: "Spicy Spray",
|
||||
rating: 3,
|
||||
num: 318,
|
||||
},
|
||||
stakeout: {
|
||||
onModifyAtkPriority: 5,
|
||||
onModifyAtk(atk, attacker, defender) {
|
||||
|
|
@ -4720,6 +4771,24 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
rating: 3,
|
||||
num: 33,
|
||||
},
|
||||
swordofruin: {
|
||||
onStart(pokemon) {
|
||||
if (this.suppressingAbility(pokemon)) return;
|
||||
this.add('-ability', pokemon, 'Sword of Ruin');
|
||||
},
|
||||
onAnyModifyDef(def, target, source, move) {
|
||||
const abilityHolder = this.effectState.target;
|
||||
if (target.hasAbility('Sword of Ruin')) return;
|
||||
if (!move.ruinedDef?.hasAbility('Sword of Ruin')) move.ruinedDef = abilityHolder;
|
||||
if (move.ruinedDef !== abilityHolder) return;
|
||||
this.debug('Sword of Ruin Def drop');
|
||||
return this.chainModify(0.75);
|
||||
},
|
||||
flags: {},
|
||||
name: "Sword of Ruin",
|
||||
rating: 4.5,
|
||||
num: 285,
|
||||
},
|
||||
symbiosis: {
|
||||
onAllyAfterUseItem(item, pokemon) {
|
||||
if (pokemon.switchFlag) return;
|
||||
|
|
@ -4755,24 +4824,6 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
rating: 2,
|
||||
num: 28,
|
||||
},
|
||||
swordofruin: {
|
||||
onStart(pokemon) {
|
||||
if (this.suppressingAbility(pokemon)) return;
|
||||
this.add('-ability', pokemon, 'Sword of Ruin');
|
||||
},
|
||||
onAnyModifyDef(def, target, source, move) {
|
||||
const abilityHolder = this.effectState.target;
|
||||
if (target.hasAbility('Sword of Ruin')) return;
|
||||
if (!move.ruinedDef?.hasAbility('Sword of Ruin')) move.ruinedDef = abilityHolder;
|
||||
if (move.ruinedDef !== abilityHolder) return;
|
||||
this.debug('Sword of Ruin Def drop');
|
||||
return this.chainModify(0.75);
|
||||
},
|
||||
flags: {},
|
||||
name: "Sword of Ruin",
|
||||
rating: 4.5,
|
||||
num: 285,
|
||||
},
|
||||
tabletsofruin: {
|
||||
onStart(pokemon) {
|
||||
if (this.suppressingAbility(pokemon)) return;
|
||||
|
|
@ -4860,13 +4911,6 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
},
|
||||
terashell: {
|
||||
// effectiveness implemented in sim/pokemon.ts:Pokemon#runEffectiveness
|
||||
// needs two checks to reset between regular moves and future attacks
|
||||
onAnyBeforeMove() {
|
||||
delete this.effectState.resisted;
|
||||
},
|
||||
onAnyAfterMove() {
|
||||
delete this.effectState.resisted;
|
||||
},
|
||||
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, breakable: 1 },
|
||||
name: "Tera Shell",
|
||||
rating: 3.5,
|
||||
|
|
@ -4879,14 +4923,6 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
if (pokemon.species.forme !== 'Terastal') {
|
||||
this.add('-activate', pokemon, 'ability: Tera Shift');
|
||||
pokemon.formeChange('Terapagos-Terastal', this.effect, true);
|
||||
pokemon.regressionForme = false;
|
||||
pokemon.baseMaxhp = Math.floor(Math.floor(
|
||||
2 * pokemon.species.baseStats['hp'] + pokemon.set.ivs['hp'] + Math.floor(pokemon.set.evs['hp'] / 4) + 100
|
||||
) * pokemon.level / 100 + 10);
|
||||
const newMaxHP = pokemon.baseMaxhp;
|
||||
pokemon.hp = newMaxHP - (pokemon.maxhp - pokemon.hp);
|
||||
pokemon.maxhp = newMaxHP;
|
||||
this.add('-heal', pokemon, pokemon.getHealth, '[silent]');
|
||||
}
|
||||
},
|
||||
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, cantsuppress: 1, notransform: 1 },
|
||||
|
|
@ -5061,9 +5097,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
|
||||
const target = this.sample(possibleTargets);
|
||||
const ability = target.getAbility();
|
||||
if (pokemon.setAbility(ability)) {
|
||||
this.add('-ability', pokemon, ability, '[from] ability: Trace', `[of] ${target}`);
|
||||
}
|
||||
pokemon.setAbility(ability, target);
|
||||
},
|
||||
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1 },
|
||||
name: "Trace",
|
||||
|
|
@ -5274,20 +5308,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
},
|
||||
wanderingspirit: {
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (source.getAbility().flags['failskillswap'] || target.volatiles['dynamax']) return;
|
||||
|
||||
if (this.checkMoveMakesContact(move, source, target)) {
|
||||
const targetCanBeSet = this.runEvent('SetAbility', target, source, this.effect, source.ability);
|
||||
if (!targetCanBeSet) return targetCanBeSet;
|
||||
const sourceAbility = source.setAbility('wanderingspirit', target);
|
||||
if (!sourceAbility) return;
|
||||
if (target.isAlly(source)) {
|
||||
this.add('-activate', target, 'Skill Swap', '', '', `[of] ${source}`);
|
||||
} else {
|
||||
this.add('-activate', target, 'ability: Wandering Spirit', this.dex.abilities.get(sourceAbility).name, 'Wandering Spirit', `[of] ${source}`);
|
||||
}
|
||||
target.setAbility(sourceAbility);
|
||||
}
|
||||
if (this.checkMoveMakesContact(move, source, target)) this.skillSwap(source, target);
|
||||
},
|
||||
flags: {},
|
||||
name: "Wandering Spirit",
|
||||
|
|
@ -5447,7 +5468,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
target.addVolatile('charge');
|
||||
}
|
||||
},
|
||||
onAllySideConditionStart(target, source, sideCondition) {
|
||||
onSideConditionStart(side, source, sideCondition) {
|
||||
const pokemon = this.effectState.target;
|
||||
if (sideCondition.id === 'tailwind') {
|
||||
pokemon.addVolatile('charge');
|
||||
|
|
@ -5472,7 +5493,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
return null;
|
||||
}
|
||||
},
|
||||
onAllySideConditionStart(target, source, sideCondition) {
|
||||
onSideConditionStart(side, source, sideCondition) {
|
||||
const pokemon = this.effectState.target;
|
||||
if (sideCondition.id === 'tailwind') {
|
||||
this.boost({ atk: 1 }, pokemon, pokemon);
|
||||
|
|
@ -5486,10 +5507,10 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
},
|
||||
wonderguard: {
|
||||
onTryHit(target, source, move) {
|
||||
if (target === source || move.category === 'Status' || move.type === '???' || move.id === 'struggle') return;
|
||||
if (target === source || move.category === 'Status' || move.id === 'struggle') return;
|
||||
if (move.id === 'skydrop' && !source.volatiles['skydrop']) return;
|
||||
this.debug('Wonder Guard immunity: ' + move.id);
|
||||
if (target.runEffectiveness(move) <= 0) {
|
||||
if (target.runEffectiveness(move) <= 0 || !target.runImmunity(move)) {
|
||||
if (move.smartTarget) {
|
||||
move.smartTarget = false;
|
||||
} else {
|
||||
|
|
@ -5561,14 +5582,14 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
if (pokemon.baseSpecies.baseSpecies !== 'Palafin') return;
|
||||
if (pokemon.species.forme !== 'Hero') {
|
||||
pokemon.formeChange('Palafin-Hero', this.effect, true);
|
||||
pokemon.regressionForme = false;
|
||||
pokemon.heroMessageDisplayed = false;
|
||||
}
|
||||
},
|
||||
onSwitchIn(pokemon) {
|
||||
if (pokemon.baseSpecies.baseSpecies !== 'Palafin') return;
|
||||
if (!this.effectState.heroMessageDisplayed && pokemon.species.forme === 'Hero') {
|
||||
if (!pokemon.heroMessageDisplayed && pokemon.species.forme === 'Hero') {
|
||||
this.add('-activate', pokemon, 'ability: Zero to Hero');
|
||||
this.effectState.heroMessageDisplayed = true;
|
||||
pokemon.heroMessageDisplayed = true;
|
||||
}
|
||||
},
|
||||
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, cantsuppress: 1, notransform: 1 },
|
||||
|
|
@ -5594,7 +5615,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
flags: { breakable: 1 },
|
||||
name: "Mountaineer",
|
||||
rating: 3,
|
||||
num: -2,
|
||||
num: -1,
|
||||
},
|
||||
rebound: {
|
||||
isNonstandard: "CAP",
|
||||
|
|
@ -5602,32 +5623,32 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
onTryHit(target, source, move) {
|
||||
if (this.effectState.target.activeTurns) return;
|
||||
|
||||
if (target === source || move.hasBounced || !move.flags['reflectable']) {
|
||||
if (target === source || move.hasBounced || !move.flags['reflectable'] || target.isSemiInvulnerable()) {
|
||||
return;
|
||||
}
|
||||
const newMove = this.dex.getActiveMove(move.id);
|
||||
newMove.hasBounced = true;
|
||||
newMove.pranksterBoosted = false;
|
||||
this.actions.useMove(newMove, target, { target: source });
|
||||
return null;
|
||||
},
|
||||
onAllyTryHitSide(target, source, move) {
|
||||
if (this.effectState.target.activeTurns) return;
|
||||
|
||||
if (target.isAlly(source) || move.hasBounced || !move.flags['reflectable']) {
|
||||
if (target.isAlly(source) || move.hasBounced || !move.flags['reflectable'] || target.isSemiInvulnerable()) {
|
||||
return;
|
||||
}
|
||||
const newMove = this.dex.getActiveMove(move.id);
|
||||
newMove.hasBounced = true;
|
||||
newMove.pranksterBoosted = false;
|
||||
this.actions.useMove(newMove, this.effectState.target, { target: source });
|
||||
move.hasBounced = true; // only bounce once in free-for-all battles
|
||||
return null;
|
||||
},
|
||||
condition: {
|
||||
duration: 1,
|
||||
},
|
||||
flags: { breakable: 1 },
|
||||
name: "Rebound",
|
||||
rating: 3,
|
||||
num: -3,
|
||||
num: -2,
|
||||
},
|
||||
persistent: {
|
||||
isNonstandard: "CAP",
|
||||
|
|
@ -5635,6 +5656,6 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
|
|||
flags: {},
|
||||
name: "Persistent",
|
||||
rating: 3,
|
||||
num: -4,
|
||||
num: -3,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
1787
data/aliases.ts
1787
data/aliases.ts
File diff suppressed because it is too large
Load Diff
|
|
@ -1,78 +0,0 @@
|
|||
// Data for computer-generated teams
|
||||
|
||||
export const MOVE_PAIRINGS: { [moveID: IDEntry]: IDEntry } = {
|
||||
rest: 'sleeptalk',
|
||||
sleeptalk: 'rest',
|
||||
};
|
||||
|
||||
// Bonuses to move ratings by ability
|
||||
export const ABILITY_MOVE_BONUSES: { [abilityID: IDEntry]: { [moveID: IDEntry]: number } } = {
|
||||
contrary: { terablast: 2 },
|
||||
drought: { sunnyday: 0.2, solarbeam: 2 },
|
||||
drizzle: { raindance: 0.2, solarbeam: 0.2, hurricane: 2 },
|
||||
};
|
||||
// Bonuses to move ratings by move type
|
||||
export const ABILITY_MOVE_TYPE_BONUSES: { [abilityID: IDEntry]: { [typeName: string]: number } } = {
|
||||
darkaura: { Dark: 1.33 },
|
||||
dragonsmaw: { Dragon: 1.5 },
|
||||
fairyaura: { Fairy: 1.33 },
|
||||
steelworker: { Steel: 1.5 },
|
||||
steelyspirit: { Steel: 1.5 },
|
||||
transistor: { Electric: 1.3 },
|
||||
|
||||
// -ate moves
|
||||
pixilate: { Normal: 1.5 * 1.2 },
|
||||
refrigerate: { Normal: 1.5 * 1.2 },
|
||||
aerilate: { Normal: 1.5 * 1.2 },
|
||||
normalize: { Normal: 1.2 },
|
||||
|
||||
// weather
|
||||
drizzle: { Water: 1.4, Fire: 0.6 },
|
||||
drought: { Fire: 1.4, Water: 0.6 },
|
||||
};
|
||||
// For moves whose quality isn't obvious from data
|
||||
// USE SPARINGLY!
|
||||
export const HARDCODED_MOVE_WEIGHTS: { [moveID: IDEntry]: number } = {
|
||||
// Fails unless user is asleep
|
||||
snore: 0,
|
||||
// Hard to use
|
||||
lastresort: 0.1, dreameater: 0.1,
|
||||
// Useless without Berry + sucks even then
|
||||
belch: 0.2,
|
||||
|
||||
// Power increases in conditions out of our control that may occur
|
||||
avalanche: 1.2,
|
||||
ficklebeam: 1.3,
|
||||
hex: 1.2,
|
||||
stompingtantrum: 1.2,
|
||||
temperflare: 1.2,
|
||||
|
||||
// Attacks that set hazards on hit
|
||||
// We REALLY like hazards
|
||||
stoneaxe: 16,
|
||||
ceaselessedge: 16,
|
||||
|
||||
// screens
|
||||
lightscreen: 3, reflect: 3, auroraveil: 3, // TODO: make sure AVeil always gets Snow?
|
||||
tailwind: 2,
|
||||
|
||||
// mess with the opponent
|
||||
taunt: 2, disable: 2, encore: 3,
|
||||
|
||||
// healing moves
|
||||
// TODO: should healing moves be more common on bulkier pokemon?
|
||||
// 25%
|
||||
junglehealing: 3, lifedew: 3,
|
||||
// 50%
|
||||
milkdrink: 5, moonlight: 5, morningsun: 5, recover: 5, roost: 5,
|
||||
shoreup: 5, slackoff: 5, softboiled: 5, synthesis: 5,
|
||||
// delayed/consequence
|
||||
rest: 3, // has sleeptalk potential
|
||||
wish: 2,
|
||||
|
||||
// requires terrain
|
||||
steelroller: 0.1,
|
||||
};
|
||||
|
||||
export const WEIGHT_BASED_MOVES = ['heatcrash', 'heavyslam', 'lowkick', 'grassknot'];
|
||||
export const TARGET_HP_BASED_MOVES = ['crushgrip', 'hardpress'];
|
||||
1098
data/cg-teams.ts
1098
data/cg-teams.ts
File diff suppressed because it is too large
Load Diff
|
|
@ -91,12 +91,11 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
}
|
||||
if (target.species.name === 'Shaymin-Sky' && target.baseSpecies.baseSpecies === 'Shaymin') {
|
||||
target.formeChange('Shaymin', this.effect, true);
|
||||
target.regressionForme = false;
|
||||
}
|
||||
},
|
||||
onBeforeMovePriority: 10,
|
||||
onBeforeMove(pokemon, target, move) {
|
||||
if (move.flags['defrost']) return;
|
||||
if (move.flags['defrost'] && !(move.id === 'burnup' && !pokemon.hasType('Fire'))) return;
|
||||
if (this.randomChance(1, 5)) {
|
||||
pokemon.cureStatus();
|
||||
return;
|
||||
|
|
@ -116,7 +115,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
}
|
||||
},
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (move.type === 'Fire' && move.category !== 'Status') {
|
||||
if (move.type === 'Fire' && move.category !== 'Status' && move.id !== 'polarflare') {
|
||||
target.cureStatus();
|
||||
}
|
||||
},
|
||||
|
|
@ -271,6 +270,11 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
this.effectState.duration = 2;
|
||||
}
|
||||
},
|
||||
onAfterMove(pokemon) {
|
||||
if (this.effectState.duration === 1) {
|
||||
pokemon.removeVolatile('lockedmove');
|
||||
}
|
||||
},
|
||||
onEnd(target) {
|
||||
if (this.effectState.trueDuration > 1) return;
|
||||
target.addVolatile('confusion');
|
||||
|
|
@ -480,7 +484,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
return 5;
|
||||
},
|
||||
onWeatherModifyDamage(damage, attacker, defender, move) {
|
||||
if (defender.hasItem('utilityumbrella')) return;
|
||||
if (defender.effectiveWeather() !== 'raindance') return;
|
||||
if (move.type === 'Water') {
|
||||
this.debug('rain water boost');
|
||||
return this.chainModify(1.5);
|
||||
|
|
@ -521,7 +525,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
}
|
||||
},
|
||||
onWeatherModifyDamage(damage, attacker, defender, move) {
|
||||
if (defender.hasItem('utilityumbrella')) return;
|
||||
if (defender.effectiveWeather() !== 'primordialsea') return;
|
||||
if (move.type === 'Water') {
|
||||
this.debug('Rain water boost');
|
||||
return this.chainModify(1.5);
|
||||
|
|
@ -550,11 +554,11 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
return 5;
|
||||
},
|
||||
onWeatherModifyDamage(damage, attacker, defender, move) {
|
||||
if (move.id === 'hydrosteam' && !attacker.hasItem('utilityumbrella')) {
|
||||
if (move.id === 'hydrosteam' && attacker.effectiveWeather() === 'sunnyday') {
|
||||
this.debug('Sunny Day Hydro Steam boost');
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
if (defender.hasItem('utilityumbrella')) return;
|
||||
if (defender.effectiveWeather() !== 'sunnyday') return;
|
||||
if (move.type === 'Fire') {
|
||||
this.debug('Sunny Day fire boost');
|
||||
return this.chainModify(1.5);
|
||||
|
|
@ -573,7 +577,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
}
|
||||
},
|
||||
onImmunity(type, pokemon) {
|
||||
if (pokemon.hasItem('utilityumbrella')) return;
|
||||
if (pokemon.effectiveWeather() !== 'sunnyday') return;
|
||||
if (type === 'frz') return false;
|
||||
},
|
||||
onFieldResidualOrder: 1,
|
||||
|
|
@ -599,9 +603,9 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
}
|
||||
},
|
||||
onWeatherModifyDamage(damage, attacker, defender, move) {
|
||||
if (defender.hasItem('utilityumbrella')) return;
|
||||
if (defender.effectiveWeather() !== 'desolateland') return;
|
||||
if (move.type === 'Fire') {
|
||||
this.debug('Sunny Day fire boost');
|
||||
this.debug('Desolate Land fire boost');
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
},
|
||||
|
|
@ -609,7 +613,7 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
this.add('-weather', 'DesolateLand', '[from] ability: ' + effect.name, `[of] ${source}`);
|
||||
},
|
||||
onImmunity(type, pokemon) {
|
||||
if (pokemon.hasItem('utilityumbrella')) return;
|
||||
if (pokemon.effectiveWeather() !== 'desolateland') return;
|
||||
if (type === 'frz') return false;
|
||||
},
|
||||
onFieldResidualOrder: 1,
|
||||
|
|
@ -875,6 +879,67 @@ export const Conditions: import('../sim/dex-conditions').ConditionDataTable = {
|
|||
return [type];
|
||||
},
|
||||
},
|
||||
zacian: {
|
||||
name: 'Zacian',
|
||||
onBattleStart(pokemon) {
|
||||
if (pokemon.item !== 'rustedsword') return;
|
||||
const rawSpecies = this.dex.species.get('Zacian-Crowned');
|
||||
const species = pokemon.setSpecies(rawSpecies);
|
||||
if (!species) return;
|
||||
pokemon.baseSpecies = rawSpecies;
|
||||
pokemon.details = pokemon.getUpdatedDetails();
|
||||
pokemon.setAbility(species.abilities['0'], null, null, true);
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
|
||||
const ironHeadIndex = pokemon.baseMoves.indexOf('ironhead');
|
||||
if (ironHeadIndex >= 0) {
|
||||
const move = this.dex.moves.get('behemothblade');
|
||||
const pp = this.calculatePP(move, pokemon.ppUps[ironHeadIndex]);
|
||||
pokemon.baseMoveSlots[ironHeadIndex] = {
|
||||
move: move.name,
|
||||
id: move.id,
|
||||
pp,
|
||||
maxpp: pp,
|
||||
target: move.target,
|
||||
disabled: false,
|
||||
disabledSource: '',
|
||||
used: false,
|
||||
};
|
||||
pokemon.moveSlots = pokemon.baseMoveSlots.slice();
|
||||
}
|
||||
},
|
||||
},
|
||||
zamazenta: {
|
||||
name: 'Zamazenta',
|
||||
onBattleStart(pokemon) {
|
||||
if (pokemon.item !== 'rustedshield') return;
|
||||
const rawSpecies = this.dex.species.get('Zamazenta-Crowned');
|
||||
const species = pokemon.setSpecies(rawSpecies);
|
||||
if (!species) return;
|
||||
pokemon.baseSpecies = rawSpecies;
|
||||
pokemon.details = pokemon.getUpdatedDetails();
|
||||
pokemon.setAbility(species.abilities['0'], null, null, true);
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
|
||||
const ironHeadIndex = pokemon.baseMoves.indexOf('ironhead');
|
||||
if (ironHeadIndex >= 0) {
|
||||
const move = this.dex.moves.get('behemothbash');
|
||||
const pp = this.calculatePP(move, pokemon.ppUps[ironHeadIndex]);
|
||||
pokemon.baseMoveSlots[ironHeadIndex] = {
|
||||
move: move.name,
|
||||
id: move.id,
|
||||
pp,
|
||||
maxpp: pp,
|
||||
target: move.target,
|
||||
disabled: false,
|
||||
disabledSource: '',
|
||||
used: false,
|
||||
};
|
||||
pokemon.moveSlots = pokemon.baseMoveSlots.slice();
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
rolloutstorage: {
|
||||
name: 'rolloutstorage',
|
||||
duration: 2,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
1273
data/items.ts
1273
data/items.ts
File diff suppressed because it is too large
Load Diff
1105
data/learnsets.ts
1105
data/learnsets.ts
File diff suppressed because it is too large
Load Diff
231
data/mods/afd/abilities.ts
Normal file
231
data/mods/afd/abilities.ts
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTable = {
|
||||
chaossaliva: {
|
||||
onSourceDamagingHit(damage, target, source, move) {
|
||||
// Despite not being a secondary, Shield Dust / Covert Cloak block Poison Touch's effect
|
||||
if (target.hasAbility('shielddust') || target.hasItem('covertcloak')) return;
|
||||
if (this.checkMoveMakesContact(move, target, source)) {
|
||||
if (this.randomChance(2, 10)) {
|
||||
target.trySetStatus('par', source);
|
||||
}
|
||||
if (this.randomChance(2, 10)) {
|
||||
target.addVolatile('confusion', source);
|
||||
}
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Chaos Saliva",
|
||||
gen: 9,
|
||||
shortDesc: "Contact moves have a 20% chance to paralyze and a 20% chance to confuse.",
|
||||
},
|
||||
faststart: {
|
||||
onStart(pokemon) {
|
||||
this.add('-start', pokemon, 'ability: Fast Start');
|
||||
this.effectState.counter = 5;
|
||||
},
|
||||
onResidualOrder: 28,
|
||||
onResidualSubOrder: 2,
|
||||
onResidual(pokemon) {
|
||||
if (pokemon.activeTurns && this.effectState.counter) {
|
||||
this.effectState.counter--;
|
||||
if (!this.effectState.counter) {
|
||||
this.add('-end', pokemon, 'Fast Start');
|
||||
delete this.effectState.counter;
|
||||
}
|
||||
}
|
||||
},
|
||||
onModifyAtkPriority: 5,
|
||||
onModifyAtk(atk, pokemon) {
|
||||
if (this.effectState.counter) {
|
||||
return this.chainModify(2);
|
||||
}
|
||||
},
|
||||
onModifySpe(spe, pokemon) {
|
||||
if (this.effectState.counter) {
|
||||
return this.chainModify(2);
|
||||
}
|
||||
},
|
||||
onEnd(pokemon) {
|
||||
if (pokemon.beingCalledBack) return;
|
||||
this.add('-end', pokemon, 'Fast Start', '[silent]');
|
||||
},
|
||||
flags: {},
|
||||
name: "Fast Start",
|
||||
rating: -1,
|
||||
gen: 9,
|
||||
},
|
||||
ironfist: {
|
||||
inherit: true,
|
||||
onBasePower(basePower, attacker, defender, move) {
|
||||
if (move.flags['punch']) {
|
||||
this.debug('Iron Fist boost');
|
||||
return this.chainModify([8192, 4096]);
|
||||
}
|
||||
},
|
||||
},
|
||||
supermegalauncher: {
|
||||
onBasePowerPriority: 19,
|
||||
onBasePower(basePower, attacker, defender, move) {
|
||||
if (move.flags['pulse']) {
|
||||
return this.chainModify(4);
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Mega Launcher",
|
||||
desc: "This Pokemon's pulse moves have their power multiplied by 4. Heal Pulse restores 8/4 of a target's maximum HP, rounded half down.",
|
||||
shortDesc: "This Pokemon's pulse moves have 4x power. Heal Pulse heals 8/4 target's max HP.",
|
||||
rating: 3,
|
||||
gen: 9,
|
||||
},
|
||||
discourage: {
|
||||
onStart(pokemon) {
|
||||
let activated = false;
|
||||
for (const target of pokemon.adjacentFoes()) {
|
||||
if (!activated) {
|
||||
this.add('-ability', pokemon, 'Discourage', 'boost');
|
||||
activated = true;
|
||||
}
|
||||
if (target.volatiles['substitute']) {
|
||||
this.add('-immune', target);
|
||||
} else {
|
||||
this.boost({ spa: -1 }, target, pokemon, null, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Discourage",
|
||||
rating: 3.5,
|
||||
num: 999,
|
||||
gen: 9,
|
||||
},
|
||||
adaptability: {
|
||||
inherit: true,
|
||||
onModifySTAB(stab, source, target, move) {
|
||||
if (move.forceSTAB || source.hasType(move.type)) {
|
||||
const types = source.getTypes();
|
||||
if (types[0] === move.type) return 2.3;
|
||||
if (types[1] && types[1] === move.type) return 1.6;
|
||||
if (stab === 2.3) {
|
||||
return 2.55;
|
||||
}
|
||||
return 2.7;
|
||||
}
|
||||
},
|
||||
},
|
||||
icebody: {
|
||||
inherit: true,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (this.checkMoveMakesContact(move, source, target)) {
|
||||
if (this.randomChance(1, 10)) {
|
||||
source.trySetStatus('frz', target);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
noretreat: {
|
||||
onStart(target) {
|
||||
this.add('-start', target, 'move: No Retreat');
|
||||
},
|
||||
onFoeBeforeSwitchOut(pokemon) {
|
||||
if (!pokemon || pokemon.fainted || pokemon.hp <= 0 || pokemon.hasAbility('noretreat')) return;
|
||||
const success = !!this.damage(pokemon.maxhp / 4, pokemon, this.effectState.target);
|
||||
if (success) {
|
||||
pokemon.tryTrap();
|
||||
}
|
||||
},
|
||||
name: "No Retreat",
|
||||
flags: { breakable: 1 },
|
||||
},
|
||||
itsexcadrillintime: {
|
||||
onModifySpe(spe, pokemon) {
|
||||
if (this.field.isWeather('sandstorm')) {
|
||||
return this.chainModify(2);
|
||||
}
|
||||
},
|
||||
onImmunity(type, pokemon) {
|
||||
if (type === 'sandstorm') return false;
|
||||
},
|
||||
onBasePowerPriority: 21,
|
||||
onBasePower(basePower, attacker, defender, move) {
|
||||
if (this.field.isWeather('sandstorm')) {
|
||||
if (move.type === 'Rock' || move.type === 'Ground' || move.type === 'Steel') {
|
||||
this.debug('Sand Force boost');
|
||||
return this.chainModify([5325, 4096]);
|
||||
}
|
||||
}
|
||||
},
|
||||
name: "It's Excadrillin' Time!",
|
||||
flags: {},
|
||||
},
|
||||
goodasgold: {
|
||||
inherit: true,
|
||||
onTryHit(target, source, move) {
|
||||
if (move.category !== 'Special' && target !== source) {
|
||||
this.add('-immune', target, '[from] ability: Good as Gold');
|
||||
return null;
|
||||
}
|
||||
},
|
||||
},
|
||||
intimidate2: {
|
||||
onStart(pokemon) {
|
||||
let activated = false;
|
||||
let timesActivated = 0;
|
||||
for (const target of pokemon.adjacentFoes()) {
|
||||
if (!activated) {
|
||||
this.add('-ability', pokemon, 'Intimidate 2', 'boost');
|
||||
activated = true;
|
||||
}
|
||||
if (target.volatiles['substitute']) {
|
||||
this.add('-immune', target);
|
||||
} else {
|
||||
this.boost({ atk: -1 }, target, pokemon, null, true);
|
||||
timesActivated++;
|
||||
}
|
||||
}
|
||||
if (timesActivated > 0) {
|
||||
for (let i = 0; i < timesActivated; i++) {
|
||||
this.boost({ atk: 1 }, pokemon, pokemon, null, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Intimidate 2",
|
||||
rating: 3.5,
|
||||
num: 22,
|
||||
},
|
||||
asonemonarch: {
|
||||
onSwitchInPriority: 1,
|
||||
onStart(pokemon) {
|
||||
if (this.effectState.unnerved) return;
|
||||
this.add('-ability', pokemon, 'As One');
|
||||
this.add('-ability', pokemon, 'Unnerve');
|
||||
this.effectState.unnerved = true;
|
||||
},
|
||||
onEnd() {
|
||||
this.effectState.unnerved = false;
|
||||
},
|
||||
onFoeTryEatItem() {
|
||||
return !this.effectState.unnerved;
|
||||
},
|
||||
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, cantsuppress: 1 },
|
||||
name: "As One (Monarch)",
|
||||
rating: 3.5,
|
||||
num: 266,
|
||||
},
|
||||
intimidate: {
|
||||
inherit: true,
|
||||
onStart(pokemon) {
|
||||
let activated = false;
|
||||
for (const target of pokemon.adjacentFoes()) {
|
||||
if (!activated) {
|
||||
this.add('-ability', pokemon, 'Intimidate', 'boost');
|
||||
activated = true;
|
||||
}
|
||||
if (target.volatiles['substitute']) {
|
||||
this.add('-immune', target);
|
||||
} else {
|
||||
this.boost({ atk: -2 }, target, pokemon, null, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
22
data/mods/afd/conditions.ts
Normal file
22
data/mods/afd/conditions.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDataTable = {
|
||||
sandstorm: {
|
||||
inherit: true,
|
||||
onWeatherModifyDamage(damage, attacker, defender, move) {
|
||||
if (defender.hasItem('utilityumbrella')) return;
|
||||
if (move.type === 'Rock') {
|
||||
this.debug('Sandstorm rock boost');
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
},
|
||||
},
|
||||
snowscape: {
|
||||
inherit: true,
|
||||
onModifySpePriority: 10,
|
||||
onModifySpe(spe, pokemon) {
|
||||
if (!pokemon.getTypes(false, true).includes('Ice') && !pokemon.getTypes(false, true).includes('Steel') &&
|
||||
!pokemon.hasAbility(['slushrush', 'snowcloak', 'iceface', 'icebody']) && pokemon.effectiveWeather() === 'snowscape') {
|
||||
return this.modify(spe, 0.5);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
93
data/mods/afd/items.ts
Normal file
93
data/mods/afd/items.ts
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
||||
hoots: {
|
||||
name: "Hoots",
|
||||
spritenum: 715,
|
||||
fling: {
|
||||
basePower: 80,
|
||||
},
|
||||
num: 1120,
|
||||
gen: 8,
|
||||
// Hazard Immunity implemented in moves.ts
|
||||
},
|
||||
luckycharm: {
|
||||
name: "Lucky Charm",
|
||||
onModifyMovePriority: -2,
|
||||
onModifyMove(move, pokemon, target) {
|
||||
let trigger = false;
|
||||
if (move.secondaries) {
|
||||
this.debug('doubling secondary chance');
|
||||
for (const secondary of move.secondaries) {
|
||||
if (secondary.chance && secondary.chance < 100) {
|
||||
secondary.chance = 100;
|
||||
if (!trigger) trigger = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (move.self?.chance) {
|
||||
move.self.chance = 100;
|
||||
trigger = true;
|
||||
}
|
||||
if (trigger) {
|
||||
pokemon.useItem();
|
||||
}
|
||||
},
|
||||
spritenum: 707,
|
||||
fling: {
|
||||
basePower: 120,
|
||||
},
|
||||
num: 9999,
|
||||
gen: 9,
|
||||
},
|
||||
onikaburger: {
|
||||
name: "Onika Burger",
|
||||
desc: "PP and damage of every move is halved. Gain 25% max HP at the end of each turn.",
|
||||
shortDesc: "PP and damage of every move is halved. Gain 25% max HP at the end of each turn.",
|
||||
onStart(target) {
|
||||
if (target.m.onikaBurger) return;
|
||||
target.m.onikaBurger = true;
|
||||
for (const moveSlot of target.moveSlots) {
|
||||
const deductPP = target.deductPP(moveSlot.id, moveSlot.maxpp / 2, target);
|
||||
if (!deductPP) continue;
|
||||
this.add('-activate', target, 'item: Onika Burger', moveSlot.move, deductPP);
|
||||
}
|
||||
},
|
||||
onModifyDamage() {
|
||||
return this.chainModify(0.5);
|
||||
},
|
||||
onResidualOrder: 5,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
this.heal(pokemon.baseMaxhp / 4);
|
||||
},
|
||||
},
|
||||
wardtag: {
|
||||
name: "Ward Tag",
|
||||
desc: "Reflects back 125% of the damage that would've been dealt. One-time use.",
|
||||
shortDesc: "Reflects back 125% of the damage that would've been dealt. One-time use.",
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (source && target !== source && effect?.effectType === 'Move' && target.useItem()) {
|
||||
this.add('-activate', target, 'item: Ward Tag');
|
||||
this.damage(damage * 5 / 4, source, target);
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
},
|
||||
strengthpolicy: {
|
||||
name: "Strength Policy",
|
||||
spritenum: 609,
|
||||
fling: {
|
||||
basePower: 80,
|
||||
},
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (!move.damage && !move.damageCallback && target.getMoveHitData(move).typeMod < 0) {
|
||||
target.useItem();
|
||||
}
|
||||
},
|
||||
boosts: {
|
||||
def: 2,
|
||||
spd: 2,
|
||||
},
|
||||
num: 639,
|
||||
gen: 6,
|
||||
},
|
||||
};
|
||||
599
data/mods/afd/moves.ts
Normal file
599
data/mods/afd/moves.ts
Normal file
|
|
@ -0,0 +1,599 @@
|
|||
export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
||||
banefulbunker: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
onTryHit(target, source, move) {
|
||||
if (this.checkMoveBypassesProtect(move, source, target)) return;
|
||||
if (move.smartTarget) {
|
||||
move.smartTarget = false;
|
||||
} else {
|
||||
if (!this.randomChance(2, 10)) {
|
||||
this.add('-activate', target, 'move: Protect');
|
||||
if (move.basePower >= 100) {
|
||||
this.add('message', '**BWUAHAAUAAAANGGGGGG**');
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const lockedmove = source.getVolatile('lockedmove');
|
||||
if (lockedmove) {
|
||||
// Outrage counter is reset
|
||||
if (source.volatiles['lockedmove'].duration === 2) {
|
||||
delete source.volatiles['lockedmove'];
|
||||
}
|
||||
}
|
||||
if (this.checkMoveMakesContact(move, source, target)) {
|
||||
source.trySetStatus('psn', target);
|
||||
}
|
||||
return this.NOT_FAIL;
|
||||
},
|
||||
},
|
||||
},
|
||||
burningbulwark: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
onTryHit(target, source, move) {
|
||||
if (this.checkMoveBypassesProtect(move, source, target, false)) return;
|
||||
if (move.smartTarget) {
|
||||
move.smartTarget = false;
|
||||
} else {
|
||||
if (!this.randomChance(2, 10)) {
|
||||
this.add('-activate', target, 'move: Protect');
|
||||
if (move.basePower >= 100) {
|
||||
this.add('message', '**BWUAHAAUAAAANGGGGGG**');
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const lockedmove = source.getVolatile('lockedmove');
|
||||
if (lockedmove) {
|
||||
// Outrage counter is reset
|
||||
if (source.volatiles['lockedmove'].duration === 2) {
|
||||
delete source.volatiles['lockedmove'];
|
||||
}
|
||||
}
|
||||
if (this.checkMoveMakesContact(move, source, target)) {
|
||||
source.trySetStatus('brn', target);
|
||||
}
|
||||
return this.NOT_FAIL;
|
||||
},
|
||||
},
|
||||
},
|
||||
kingsshield: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
onTryHit(target, source, move) {
|
||||
if (this.checkMoveBypassesProtect(move, source, target, false)) return;
|
||||
if (move.smartTarget) {
|
||||
move.smartTarget = false;
|
||||
} else {
|
||||
if (!this.randomChance(2, 10)) {
|
||||
this.add('-activate', target, 'move: Protect');
|
||||
if (move.basePower >= 100) {
|
||||
this.add('message', '**BWUAHAAUAAAANGGGGGG**');
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const lockedmove = source.getVolatile('lockedmove');
|
||||
if (lockedmove) {
|
||||
// Outrage counter is reset
|
||||
if (source.volatiles['lockedmove'].duration === 2) {
|
||||
delete source.volatiles['lockedmove'];
|
||||
}
|
||||
}
|
||||
if (this.checkMoveMakesContact(move, source, target)) {
|
||||
this.boost({ atk: -1 }, source, target, this.dex.getActiveMove("King's Shield"));
|
||||
}
|
||||
return this.NOT_FAIL;
|
||||
},
|
||||
},
|
||||
},
|
||||
maxguard: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
onTryHit(target, source, move) {
|
||||
const bypassesMaxGuard = [
|
||||
'acupressure', 'afteryou', 'allyswitch', 'aromatherapy', 'aromaticmist', 'coaching', 'confide', 'copycat', 'curse', 'decorate', 'doomdesire', 'feint', 'futuresight', 'gmaxoneblow', 'gmaxrapidflow', 'healbell', 'holdhands', 'howl', 'junglehealing', 'lifedew', 'meanlook', 'perishsong', 'playnice', 'powertrick', 'roar', 'roleplay', 'tearfullook',
|
||||
];
|
||||
if (bypassesMaxGuard.includes(move.id)) return;
|
||||
if (move.smartTarget) {
|
||||
move.smartTarget = false;
|
||||
} else {
|
||||
if (!this.randomChance(2, 10)) {
|
||||
this.add('-activate', target, 'move: Protect');
|
||||
if (move.basePower >= 100) {
|
||||
this.add('message', '**BWUAHAAUAAAANGGGGGG**');
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const lockedmove = source.getVolatile('lockedmove');
|
||||
if (lockedmove) {
|
||||
// Outrage counter is reset
|
||||
if (source.volatiles['lockedmove'].duration === 2) {
|
||||
delete source.volatiles['lockedmove'];
|
||||
}
|
||||
}
|
||||
return this.NOT_FAIL;
|
||||
},
|
||||
},
|
||||
},
|
||||
meteorbeam: {
|
||||
inherit: true,
|
||||
onTryMove(attacker, defender, move) {
|
||||
if (attacker.removeVolatile(move.id)) {
|
||||
return;
|
||||
}
|
||||
this.add('-prepare', attacker, move.name);
|
||||
this.boost({ spa: 1 }, attacker, attacker, move);
|
||||
if (['sandstorm'].includes(attacker.effectiveWeather())) {
|
||||
this.attrLastMove('[still]');
|
||||
this.addMove('-anim', attacker, move.name, defender);
|
||||
return;
|
||||
}
|
||||
if (!this.runEvent('ChargeMove', attacker, defender, move)) {
|
||||
return;
|
||||
}
|
||||
attacker.addVolatile('twoturnmove', defender);
|
||||
return null;
|
||||
},
|
||||
},
|
||||
obstruct: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
onTryHit(target, source, move) {
|
||||
if (this.checkMoveBypassesProtect(move, source, target, false)) return;
|
||||
if (move.smartTarget) {
|
||||
move.smartTarget = false;
|
||||
} else {
|
||||
if (!this.randomChance(2, 10)) {
|
||||
this.add('-activate', target, 'move: Protect');
|
||||
if (move.basePower >= 100) {
|
||||
this.add('message', '**BWUAHAAUAAAANGGGGGG**');
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const lockedmove = source.getVolatile('lockedmove');
|
||||
if (lockedmove) {
|
||||
// Outrage counter is reset
|
||||
if (source.volatiles['lockedmove'].duration === 2) {
|
||||
delete source.volatiles['lockedmove'];
|
||||
}
|
||||
}
|
||||
if (this.checkMoveMakesContact(move, source, target)) {
|
||||
this.boost({ def: -2 }, source, target, this.dex.getActiveMove("Obstruct"));
|
||||
}
|
||||
return this.NOT_FAIL;
|
||||
},
|
||||
},
|
||||
},
|
||||
protect: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
onTryHit(target, source, move) {
|
||||
if (this.checkMoveBypassesProtect(move, source, target)) return;
|
||||
if (move.smartTarget) {
|
||||
move.smartTarget = false;
|
||||
} else {
|
||||
if (!this.randomChance(2, 10)) {
|
||||
this.add('-activate', target, 'move: Protect');
|
||||
if (move.basePower >= 100) {
|
||||
this.add('message', '**BWUAHAAUAAAANGGGGGG**');
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const lockedmove = source.getVolatile('lockedmove');
|
||||
if (lockedmove) {
|
||||
// Outrage counter is reset
|
||||
if (source.volatiles['lockedmove'].duration === 2) {
|
||||
delete source.volatiles['lockedmove'];
|
||||
}
|
||||
}
|
||||
return this.NOT_FAIL;
|
||||
},
|
||||
},
|
||||
},
|
||||
silktrap: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
onTryHit(target, source, move) {
|
||||
if (this.checkMoveBypassesProtect(move, source, target, false)) return;
|
||||
if (move.smartTarget) {
|
||||
move.smartTarget = false;
|
||||
} else {
|
||||
if (!this.randomChance(2, 10)) {
|
||||
this.add('-activate', target, 'move: Protect');
|
||||
if (move.basePower >= 100) {
|
||||
this.add('message', '**BWUAHAAUAAAANGGGGGG**');
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const lockedmove = source.getVolatile('lockedmove');
|
||||
if (lockedmove) {
|
||||
// Outrage counter is reset
|
||||
if (source.volatiles['lockedmove'].duration === 2) {
|
||||
delete source.volatiles['lockedmove'];
|
||||
}
|
||||
}
|
||||
if (this.checkMoveMakesContact(move, source, target)) {
|
||||
this.boost({ spe: -1 }, source, target, this.dex.getActiveMove("Silk Trap"));
|
||||
}
|
||||
return this.NOT_FAIL;
|
||||
},
|
||||
},
|
||||
},
|
||||
spikyshield: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
onTryHit(target, source, move) {
|
||||
if (this.checkMoveBypassesProtect(move, source, target)) return;
|
||||
if (move.smartTarget) {
|
||||
move.smartTarget = false;
|
||||
} else {
|
||||
if (!this.randomChance(2, 10)) {
|
||||
this.add('-activate', target, 'move: Protect');
|
||||
if (move.basePower >= 100) {
|
||||
this.add('message', '**BWUAHAAUAAAANGGGGGG**');
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const lockedmove = source.getVolatile('lockedmove');
|
||||
if (lockedmove) {
|
||||
// Outrage counter is reset
|
||||
if (source.volatiles['lockedmove'].duration === 2) {
|
||||
delete source.volatiles['lockedmove'];
|
||||
}
|
||||
}
|
||||
if (this.checkMoveMakesContact(move, source, target)) {
|
||||
this.damage(source.baseMaxhp / 8, source, target);
|
||||
}
|
||||
return this.NOT_FAIL;
|
||||
},
|
||||
},
|
||||
},
|
||||
stealthrock: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
onSideStart(side) {
|
||||
this.add('-sidestart', side, 'Stealth Rock');
|
||||
this.effectState.layers = 1;
|
||||
},
|
||||
onSideRestart(side) {
|
||||
if (this.effectState.layers >= 5) return false;
|
||||
this.add('-sidestart', side, 'Stealth Rock');
|
||||
this.effectState.layers++;
|
||||
},
|
||||
onSwitchIn(pokemon) {
|
||||
if (pokemon.hasItem(['heavydutyboots', 'hoots'])) return;
|
||||
const typeMod = this.clampIntRange(pokemon.runEffectiveness(this.dex.getActiveMove('stealthrock')), -6, 6);
|
||||
const damageAmounts = [0, 1, 2, 3, 4, 5]; // 2 ** typeMod / 8
|
||||
this.damage((damageAmounts[this.effectState.layers] / 5) * pokemon.maxhp * ((2 ** typeMod) / 8));
|
||||
},
|
||||
},
|
||||
},
|
||||
gmaxsteelsurge: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
onSideStart(side) {
|
||||
this.add('-sidestart', side, 'G-Max Steelsurge');
|
||||
this.effectState.layers = 1;
|
||||
},
|
||||
onSideRestart(side) {
|
||||
if (this.effectState.layers >= 5) return false;
|
||||
this.add('-sidestart', side, 'G-Max Steelsurge');
|
||||
this.effectState.layers++;
|
||||
},
|
||||
onSwitchIn(pokemon) {
|
||||
if (pokemon.hasItem(['heavydutyboots', 'hoots'])) return;
|
||||
const steelHazard = this.dex.getActiveMove('Stealth Rock');
|
||||
steelHazard.type = 'Steel';
|
||||
const typeMod = this.clampIntRange(pokemon.runEffectiveness(steelHazard), -6, 6);
|
||||
const damageAmounts = [0, 1, 2, 3, 4, 5]; // 2 ** typeMod / 8
|
||||
this.damage((damageAmounts[this.effectState.layers] / 5) * pokemon.maxhp * ((2 ** typeMod) / 8));
|
||||
},
|
||||
},
|
||||
},
|
||||
spikes: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
onSwitchIn(pokemon) {
|
||||
if (!pokemon.isGrounded() || pokemon.hasItem(['heavydutyboots', 'hoots'])) return;
|
||||
const damageAmounts = [0, 3, 4, 6]; // 1/8, 1/6, 1/4
|
||||
this.damage(damageAmounts[this.effectState.layers] * pokemon.maxhp / 24);
|
||||
},
|
||||
},
|
||||
},
|
||||
stickyweb: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
onSwitchIn(pokemon) {
|
||||
if (!pokemon.isGrounded() || pokemon.hasItem(['heavydutyboots', 'hoots'])) return;
|
||||
this.add('-activate', pokemon, 'move: Sticky Web');
|
||||
this.boost({ spe: -1 }, pokemon, pokemon.side.foe.active[0], this.dex.getActiveMove('stickyweb'));
|
||||
},
|
||||
},
|
||||
},
|
||||
toxicspikes: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
onSwitchIn(pokemon) {
|
||||
if (!pokemon.isGrounded()) return;
|
||||
if (pokemon.hasType('Poison')) {
|
||||
this.add('-sideend', pokemon.side, 'move: Toxic Spikes', `[of] ${pokemon}`);
|
||||
pokemon.side.removeSideCondition('toxicspikes');
|
||||
} else if (pokemon.hasType('Steel') || pokemon.hasItem(['heavydutyboots', 'hoots'])) {
|
||||
// do nothing
|
||||
} else if (this.effectState.layers >= 2) {
|
||||
pokemon.trySetStatus('tox', pokemon.side.foe.active[0]);
|
||||
} else {
|
||||
pokemon.trySetStatus('psn', pokemon.side.foe.active[0]);
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
suckerpunch: {
|
||||
inherit: true,
|
||||
onTry() { },
|
||||
onModifyPriority(priority, source, target, move) {
|
||||
if (!target) return priority - 1;
|
||||
const action = this.queue.willMove(target);
|
||||
const aMove = action?.choice === 'move' ? action.move : null;
|
||||
if (!aMove || (aMove.category === 'Status' && aMove.id !== 'mefirst') || target.volatiles['mustrecharge']) {
|
||||
return priority - 1;
|
||||
}
|
||||
return priority;
|
||||
},
|
||||
},
|
||||
thousandarrows: {
|
||||
inherit: true,
|
||||
basePower: 120,
|
||||
},
|
||||
healpulse: {
|
||||
inherit: true,
|
||||
onHit(target, source) {
|
||||
let success = false;
|
||||
if (source.hasAbility('supermegalauncher')) {
|
||||
success = !!this.heal(this.modify(target.baseMaxhp, 2));
|
||||
} else if (source.hasAbility('megalauncher')) {
|
||||
success = !!this.heal(this.modify(target.baseMaxhp, 0.75));
|
||||
} else {
|
||||
success = !!this.heal(Math.ceil(target.baseMaxhp * 0.5));
|
||||
}
|
||||
if (success && !target.isAlly(source)) {
|
||||
target.staleness = 'external';
|
||||
}
|
||||
if (!success) {
|
||||
this.add('-fail', target, 'heal');
|
||||
return this.NOT_FAIL;
|
||||
}
|
||||
return success;
|
||||
},
|
||||
},
|
||||
headsmash: {
|
||||
inherit: true,
|
||||
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1, heal: 1 },
|
||||
secondary: {
|
||||
chance: 100,
|
||||
onHit(target, source, move) {
|
||||
if (!this.heal(this.modify(target.baseMaxhp, 0.25))) {
|
||||
return this.NOT_FAIL;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
knockoff: {
|
||||
inherit: true,
|
||||
accuracy: 90,
|
||||
},
|
||||
shitpulse: {
|
||||
num: -400,
|
||||
gen: 9,
|
||||
accuracy: 100,
|
||||
basePower: 75,
|
||||
category: "Special",
|
||||
name: "Shit Pulse",
|
||||
pp: 15,
|
||||
priority: 0,
|
||||
flags: { protect: 1, mirror: 1, distance: 1, metronome: 1, pulse: 1 },
|
||||
secondary: {
|
||||
chance: 30,
|
||||
boosts: {
|
||||
accuracy: -2,
|
||||
},
|
||||
},
|
||||
target: "any",
|
||||
type: "Poison",
|
||||
shortDesc: "30% chance to lower foe's accuracy by 2.",
|
||||
},
|
||||
solarflare: {
|
||||
num: -4324534,
|
||||
gen: 9,
|
||||
accuracy: 100,
|
||||
basePower: 75,
|
||||
category: "Special",
|
||||
name: "Solar Flare",
|
||||
pp: 15,
|
||||
priority: 0,
|
||||
flags: { protect: 1, mirror: 1, metronome: 1 },
|
||||
secondary: {
|
||||
chance: 50,
|
||||
onHit(target, source, move) {
|
||||
if (!['sunnyday', 'desolateland'].includes(target.effectiveWeather())) return;
|
||||
target.trySetStatus('brn', source, move);
|
||||
},
|
||||
},
|
||||
target: "normal",
|
||||
type: "Fire",
|
||||
shortDesc: "Sun active: 50% chance to burn.",
|
||||
},
|
||||
onslaught: {
|
||||
num: -3023,
|
||||
gen: 9,
|
||||
accuracy: 100,
|
||||
basePower: 100,
|
||||
category: "Physical",
|
||||
name: "Onslaught",
|
||||
pp: 5,
|
||||
priority: 0,
|
||||
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
|
||||
self: {
|
||||
boosts: {
|
||||
atk: -1,
|
||||
def: -1,
|
||||
},
|
||||
},
|
||||
target: "normal",
|
||||
type: "Dark",
|
||||
},
|
||||
scald: {
|
||||
inherit: true,
|
||||
onEffectiveness(typeMod, target, type) {
|
||||
if (type === 'Steel') return 1;
|
||||
},
|
||||
secondary: undefined,
|
||||
secondaries: [{
|
||||
chance: 30,
|
||||
status: 'brn',
|
||||
}, {
|
||||
chance: 100,
|
||||
onHit(target, source, move) {
|
||||
if (target.hasType(['Normal', 'Fairy'])) {
|
||||
target.trySetStatus('brn', source, move);
|
||||
}
|
||||
},
|
||||
}],
|
||||
},
|
||||
explosion: {
|
||||
inherit: true,
|
||||
onAfterMove(pokemon, target, move) {
|
||||
if (target && target.hp <= 0) {
|
||||
delete move.selfdestruct;
|
||||
return;
|
||||
}
|
||||
},
|
||||
},
|
||||
selfdestruct: {
|
||||
inherit: true,
|
||||
onAfterMove(pokemon, target, move) {
|
||||
if (target && target.hp <= 0) {
|
||||
delete move.selfdestruct;
|
||||
return;
|
||||
}
|
||||
},
|
||||
},
|
||||
mistyexplosion: {
|
||||
inherit: true,
|
||||
onAfterMove(pokemon, target, move) {
|
||||
if (target && target.hp <= 0) {
|
||||
delete move.selfdestruct;
|
||||
return;
|
||||
}
|
||||
},
|
||||
},
|
||||
moonblast: {
|
||||
inherit: true,
|
||||
basePower: 90,
|
||||
accuracy: 90,
|
||||
secondary: {
|
||||
chance: 10,
|
||||
boosts: {
|
||||
atk: -1,
|
||||
},
|
||||
},
|
||||
category: "Physical",
|
||||
},
|
||||
noretreat: {
|
||||
name: "No Retreat",
|
||||
// @ts-expect-error
|
||||
exists: false,
|
||||
},
|
||||
blastiodon: {
|
||||
num: -306345534534523,
|
||||
gen: 9,
|
||||
accuracy: 100,
|
||||
basePower: 0,
|
||||
basePowerCallback(pokemon, target) {
|
||||
const targetDef = target.getStat('def', false, true);
|
||||
const pokemonDef = pokemon.getStat('def', false, true);
|
||||
let bp;
|
||||
if (pokemonDef >= targetDef * 5) {
|
||||
bp = 150;
|
||||
} else if (pokemonDef >= targetDef * 4) {
|
||||
bp = 125;
|
||||
} else if (pokemonDef >= targetDef * 3) {
|
||||
bp = 100;
|
||||
} else if (pokemonDef >= targetDef * 2) {
|
||||
bp = 75;
|
||||
} else {
|
||||
bp = 50;
|
||||
}
|
||||
this.debug(`BP: ${bp}`);
|
||||
return bp;
|
||||
},
|
||||
category: "Physical",
|
||||
name: "Blastiodon",
|
||||
pp: 15,
|
||||
priority: 0,
|
||||
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1 },
|
||||
overrideOffensiveStat: 'def',
|
||||
secondary: {
|
||||
chance: 50,
|
||||
boosts: {
|
||||
def: -1,
|
||||
},
|
||||
},
|
||||
target: "normal",
|
||||
type: "Rock",
|
||||
shortDesc: "Higher user Def than target Def = higher BP.",
|
||||
},
|
||||
focusblast: {
|
||||
inherit: true,
|
||||
accuracy: 100,
|
||||
recoil: [1, 4],
|
||||
category: "Physical",
|
||||
},
|
||||
darkvoid: {
|
||||
inherit: true,
|
||||
onModifyMove(move, pokemon, target) {
|
||||
if (pokemon.species.baseSpecies === 'Calyrex') {
|
||||
move.accuracy = 80;
|
||||
}
|
||||
},
|
||||
onTry(source, target, move) {
|
||||
if (source.species.baseSpecies === 'Darkrai' || source.species.baseSpecies === 'Calyrex' || move.hasBounced) {
|
||||
return;
|
||||
}
|
||||
this.add('-fail', source, 'move: Dark Void');
|
||||
this.hint("Only a Pokemon whose form is Darkrai can use this move.");
|
||||
return null;
|
||||
},
|
||||
},
|
||||
rapidspin: {
|
||||
inherit: true,
|
||||
type: "Dark",
|
||||
},
|
||||
};
|
||||
329
data/mods/afd/pokedex.ts
Normal file
329
data/mods/afd/pokedex.ts
Normal file
|
|
@ -0,0 +1,329 @@
|
|||
export const Pokedex: import('../../../sim/dex-species').ModdedSpeciesDataTable = {
|
||||
seaking: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 80, atk: 92, def: 65, spa: 65, spd: 80, spe: 98 },
|
||||
},
|
||||
clefablemega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Regenerator" },
|
||||
},
|
||||
victreebelmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Regenerator" },
|
||||
},
|
||||
starmiemega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Huge Power" },
|
||||
},
|
||||
skarmorymega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Huge Power" },
|
||||
},
|
||||
scolipedemega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Huge Power" },
|
||||
},
|
||||
scraftymega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Huge Power" },
|
||||
},
|
||||
emboarmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Regenerator" },
|
||||
},
|
||||
eelektrossmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Regenerator" },
|
||||
},
|
||||
chesnaughtmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Regenerator" },
|
||||
},
|
||||
delphoxmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Regenerator" },
|
||||
},
|
||||
greninjamega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Regenerator" },
|
||||
},
|
||||
pyroarmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Regenerator" },
|
||||
},
|
||||
barbaraclemega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Huge Power" },
|
||||
},
|
||||
hawluchamega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Huge Power" },
|
||||
},
|
||||
raichumegax: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Huge Power" },
|
||||
},
|
||||
chimechomega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Regenerator" },
|
||||
},
|
||||
baxcaliburmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Huge Power" },
|
||||
},
|
||||
zeraoramega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Huge Power" },
|
||||
},
|
||||
absolmegaz: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Huge Power" },
|
||||
},
|
||||
staraptormega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Huge Power" },
|
||||
},
|
||||
golisopodmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Huge Power" },
|
||||
},
|
||||
meowsticfmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Regenerator" },
|
||||
},
|
||||
crabominablemega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Huge Power" },
|
||||
},
|
||||
golurkmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Huge Power" },
|
||||
},
|
||||
garchompmegaz: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Huge Power" },
|
||||
},
|
||||
lucariomegaz: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Regenerator" },
|
||||
},
|
||||
raichumegay: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Regenerator" },
|
||||
},
|
||||
falinksmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "No Retreat" },
|
||||
},
|
||||
drampamega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Regenerator" },
|
||||
},
|
||||
zygardemega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Regenerator" },
|
||||
},
|
||||
dragalgemega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Regenerator" },
|
||||
},
|
||||
darkraimega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Regenerator" },
|
||||
},
|
||||
heatranmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Regenerator" },
|
||||
},
|
||||
floettemega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Regenerator" },
|
||||
},
|
||||
chandeluremega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Shadow Tag" },
|
||||
},
|
||||
lickitung: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Own Tempo", 1: "Oblivious", H: "Chaos Saliva" },
|
||||
},
|
||||
mewtwo: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Pressure", 1: "Neuroforce", H: "Unnerve" },
|
||||
},
|
||||
scovillainmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Contrary" },
|
||||
},
|
||||
mew: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Synchronize", 1: "Neuroforce" },
|
||||
},
|
||||
smeargle: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Own Tempo", 1: "Prankster", H: "Moody" },
|
||||
},
|
||||
swampert: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Torrent", 1: "Sap Sipper", H: "Damp" },
|
||||
},
|
||||
bibarel: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 159, atk: 85, def: 60, spa: 55, spd: 60, spe: 151 },
|
||||
},
|
||||
skuntank: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 103, atk: 93, def: 67, spa: 106, spd: 61, spe: 84 },
|
||||
abilities: { 0: "Stench", 1: "Aftermath", H: "Mega Launcher" },
|
||||
},
|
||||
rampardos: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 97, atk: 225, def: 30, spa: 65, spd: 30, spe: 58 },
|
||||
abilities: { 0: "Rocky Payload", H: "Sheer Force" },
|
||||
},
|
||||
gallademega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Sharpness" },
|
||||
},
|
||||
garchompmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Sand Rush" },
|
||||
},
|
||||
dusknoir: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Damp" },
|
||||
},
|
||||
lickilicky: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Own Tempo", 1: "Oblivious", H: "Chaos Saliva" },
|
||||
},
|
||||
regigigas: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Slow Start", H: "Fast Start" },
|
||||
},
|
||||
serperior: {
|
||||
inherit: true,
|
||||
types: ['Grass', 'Dragon'],
|
||||
baseStats: { hp: 75, atk: 75, def: 95, spa: 105, spd: 95, spe: 113 },
|
||||
},
|
||||
simisage: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 120, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 },
|
||||
},
|
||||
excadrillmega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "It's Excadrillin' Time!" },
|
||||
},
|
||||
chandelure: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Flash Fire", 1: "Flame Body", H: "Shadow Tag" },
|
||||
},
|
||||
delphox: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Blaze", H: "Discourage" },
|
||||
},
|
||||
clawitzer: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Super Mega Launcher" },
|
||||
},
|
||||
malamar: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 101, atk: 112, def: 88, spa: 68, spd: 75, spe: 73 },
|
||||
},
|
||||
malamarmega: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 101, atk: 122, def: 88, spa: 98, spd: 120, spe: 88 },
|
||||
abilities: { 0: "Contrary" },
|
||||
},
|
||||
incineroar: {
|
||||
inherit: true,
|
||||
types: ['Fire', 'Fighting'],
|
||||
},
|
||||
incineroar2: {
|
||||
num: 2000,
|
||||
name: "Incineroar 2",
|
||||
types: ["Ghost", "Steel"],
|
||||
genderRatio: { M: 0.875, F: 0.125 },
|
||||
baseStats: { hp: 95, atk: 115, def: 90, spa: 80, spd: 90, spe: 60 },
|
||||
abilities: { 0: "Intimidate 2" },
|
||||
heightm: 1.8,
|
||||
weightkg: 83,
|
||||
color: "Red",
|
||||
eggGroups: ["Field"],
|
||||
},
|
||||
celesteela: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 5, atk: 5, def: 5, spa: 5, spd: 5, spe: 5 },
|
||||
},
|
||||
hatterene: {
|
||||
inherit: true,
|
||||
types: ['Psychic', 'Dark'],
|
||||
},
|
||||
glimmora: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 106, atk: 150, def: 70, spa: 194, spd: 120, spe: 140 },
|
||||
},
|
||||
glimmoramega: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 106, atk: 185, def: 85, spa: 214, spd: 145, spe: 155 },
|
||||
abilities: { 0: "Regenerator" },
|
||||
},
|
||||
tatsugiri: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Commander", 1: "Parental Bond", H: "Storm Drain" },
|
||||
},
|
||||
tatsugiridroopy: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Commander", 1: "Parental Bond", H: "Storm Drain" },
|
||||
},
|
||||
tatsugiristretchy: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Commander", 1: "Parental Bond", H: "Storm Drain" },
|
||||
},
|
||||
tatsugiricurlymega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Parental Bond" },
|
||||
},
|
||||
tatsugiridroopymega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Parental Bond" },
|
||||
},
|
||||
tatsugiristretchymega: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Parental Bond" },
|
||||
},
|
||||
calyrex: {
|
||||
num: 898,
|
||||
name: "Calyrex",
|
||||
types: ["Psychic", "Grass"],
|
||||
gender: "N",
|
||||
baseStats: { hp: 100, atk: 80, def: 80, spa: 80, spd: 80, spe: 80 },
|
||||
abilities: { 0: "Unnerve" },
|
||||
heightm: 1.1,
|
||||
weightkg: 7.7,
|
||||
color: "Green",
|
||||
eggGroups: ["Undiscovered"],
|
||||
tags: ["Restricted Legendary"],
|
||||
otherFormes: ["Calyrex-Ice", "Calyrex-Shadow", "Calyrex-Monarch"],
|
||||
formeOrder: ["Calyrex", "Calyrex-Ice", "Calyrex-Shadow", "Calyrex-Monarch"],
|
||||
},
|
||||
calyrexmonarch: {
|
||||
num: 898,
|
||||
name: "Calyrex-Monarch",
|
||||
baseSpecies: "Calyrex",
|
||||
forme: "Monarch",
|
||||
types: ["Psychic", "Grass"],
|
||||
gender: "N",
|
||||
baseStats: { hp: 200, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 },
|
||||
abilities: { 0: "As One (Calyrex)" },
|
||||
heightm: 2.2,
|
||||
weightkg: 15.4,
|
||||
color: "Green",
|
||||
eggGroups: ["Undiscovered"],
|
||||
changesFrom: "Calyrex",
|
||||
},
|
||||
spidops: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 100, atk: 100, def: 100, spa: 100, spd: 100, spe: 0 },
|
||||
},
|
||||
};
|
||||
788
data/mods/afd/random-teams.ts
Normal file
788
data/mods/afd/random-teams.ts
Normal file
|
|
@ -0,0 +1,788 @@
|
|||
import { Utils } from '../../../lib';
|
||||
import RandomTeams from '../../random-battles/gen9/teams';
|
||||
import { toID } from '../../../sim/dex';
|
||||
|
||||
export interface TeamData {
|
||||
typeCount: { [k: string]: number };
|
||||
typeComboCount: { [k: string]: number };
|
||||
baseFormes: { [k: string]: number };
|
||||
megaCount?: number;
|
||||
zCount?: number;
|
||||
wantsTeraCount?: number;
|
||||
has: { [k: string]: number };
|
||||
forceResult: boolean;
|
||||
weaknesses: { [k: string]: number };
|
||||
resistances: { [k: string]: number };
|
||||
weather?: string;
|
||||
eeveeLimCount?: number;
|
||||
gigantamax?: boolean;
|
||||
}
|
||||
export interface BattleFactorySpecies {
|
||||
sets: BattleFactorySet[];
|
||||
weight: number;
|
||||
}
|
||||
interface BattleFactorySet {
|
||||
species: string;
|
||||
weight: number;
|
||||
item: string[];
|
||||
ability: string[];
|
||||
nature: string[];
|
||||
moves: string[][];
|
||||
teraType: string[];
|
||||
gender?: string;
|
||||
wantsTera?: boolean;
|
||||
evs?: Partial<StatsTable>;
|
||||
ivs?: Partial<StatsTable>;
|
||||
shiny?: boolean;
|
||||
level?: number;
|
||||
}
|
||||
export class MoveCounter extends Utils.Multiset<string> {
|
||||
damagingMoves: Set<Move>;
|
||||
basePowerMoves: Set<Move>;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.damagingMoves = new Set();
|
||||
this.basePowerMoves = new Set();
|
||||
}
|
||||
}
|
||||
// Moves that switch the user out
|
||||
const PIVOT_MOVES = [
|
||||
'chillyreception', 'flipturn', 'partingshot', 'shedtail', 'teleport', 'uturn', 'voltswitch',
|
||||
];
|
||||
|
||||
/** Pokemon who should never be in the lead slot */
|
||||
const NO_LEAD_POKEMON = [
|
||||
'Zacian', 'Zamazenta',
|
||||
];
|
||||
|
||||
const DEFENSIVE_TERA_BLAST_USERS = [
|
||||
'alcremie', 'bellossom', 'comfey', 'fezandipiti', 'florges',
|
||||
];
|
||||
|
||||
export class RandomAFDTeams extends RandomTeams {
|
||||
override shouldCullAbility(
|
||||
ability: string,
|
||||
types: string[],
|
||||
moves: Set<string>,
|
||||
abilities: string[],
|
||||
counter: MoveCounter,
|
||||
teamDetails: RandomTeamsTypes.TeamDetails,
|
||||
species: Species,
|
||||
isLead: boolean,
|
||||
isDoubles: boolean,
|
||||
teraType: string,
|
||||
role: RandomTeamsTypes.Role,
|
||||
): boolean {
|
||||
switch (ability) {
|
||||
// Abilities which are primarily useful for certain moves or with team support
|
||||
case 'Chlorophyll': case 'Solar Power':
|
||||
return !teamDetails.sun;
|
||||
case 'Defiant':
|
||||
return (species.id === 'thundurus' && !!counter.get('Status'));
|
||||
case 'Hydration': case 'Swift Swim':
|
||||
return !teamDetails.rain;
|
||||
case 'Iron Fist': case 'Skill Link':
|
||||
return !counter.get(toID(ability));
|
||||
case 'Overgrow':
|
||||
return !counter.get('Grass');
|
||||
case 'Prankster':
|
||||
return !counter.get('Status');
|
||||
case 'Sand Force': case 'Sand Rush': case 'It\'s Excadrillin\' Time!':
|
||||
return !teamDetails.sand;
|
||||
case 'Slush Rush':
|
||||
return !teamDetails.snow;
|
||||
case 'Swarm':
|
||||
return !counter.get('Bug');
|
||||
case 'Torrent':
|
||||
return (!counter.get('Water') && !moves.has('flipturn'));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
override getAbility(
|
||||
types: string[],
|
||||
moves: Set<string>,
|
||||
abilities: string[],
|
||||
counter: MoveCounter,
|
||||
teamDetails: RandomTeamsTypes.TeamDetails,
|
||||
species: Species,
|
||||
isLead: boolean,
|
||||
isDoubles: boolean,
|
||||
teraType: string,
|
||||
role: RandomTeamsTypes.Role,
|
||||
): string {
|
||||
if (abilities.length <= 1) return abilities[0];
|
||||
|
||||
// Hard-code abilities here
|
||||
if (species.id === 'drifblim') return moves.has('defog') ? 'Aftermath' : 'Unburden';
|
||||
if (abilities.includes('Flash Fire') && this.dex.getEffectiveness('Fire', teraType) >= 1) return 'Flash Fire';
|
||||
if ((species.id === 'thundurus' || species.id === 'tornadus') && !counter.get('Physical')) return 'Prankster';
|
||||
if (species.id === 'toucannon' && counter.get('skilllink')) return 'Skill Link';
|
||||
if (abilities.includes('Slush Rush') && moves.has('snowscape')) return 'Slush Rush';
|
||||
if (species.id === 'golduck' && teamDetails.rain) return 'Swift Swim';
|
||||
|
||||
const abilityAllowed: string[] = [];
|
||||
// Obtain a list of abilities that are allowed (not culled)
|
||||
for (const ability of abilities) {
|
||||
if (!this.shouldCullAbility(
|
||||
ability, types, moves, abilities, counter, teamDetails, species, isLead, isDoubles, teraType, role
|
||||
)) {
|
||||
abilityAllowed.push(ability);
|
||||
}
|
||||
}
|
||||
|
||||
// Pick a random allowed ability
|
||||
if (abilityAllowed.length >= 1) return this.sample(abilityAllowed);
|
||||
|
||||
// If all abilities are rejected, prioritize weather abilities over non-weather abilities
|
||||
if (!abilityAllowed.length) {
|
||||
const weatherAbilities = abilities.filter(
|
||||
a => ['Chlorophyll', 'Hydration', 'Sand Force', 'Sand Rush', 'Slush Rush', 'Solar Power', 'Swift Swim'].includes(a)
|
||||
);
|
||||
if (weatherAbilities.length) return this.sample(weatherAbilities);
|
||||
}
|
||||
|
||||
// Pick a random ability
|
||||
return this.sample(abilities);
|
||||
}
|
||||
|
||||
override getPriorityItem(
|
||||
ability: string,
|
||||
types: string[],
|
||||
moves: Set<string>,
|
||||
counter: MoveCounter,
|
||||
teamDetails: RandomTeamsTypes.TeamDetails,
|
||||
species: Species,
|
||||
isLead: boolean,
|
||||
isDoubles: boolean,
|
||||
teraType: string,
|
||||
role: RandomTeamsTypes.Role,
|
||||
) {
|
||||
if (role === 'Fast Bulky Setup' && (ability === 'Quark Drive' || ability === 'Protosynthesis')) {
|
||||
return 'Booster Energy';
|
||||
}
|
||||
if (species.id === 'lokix') {
|
||||
return (role === 'Fast Attacker') ? 'Silver Powder' : 'Life Orb';
|
||||
}
|
||||
if (species.requiredItems && species.baseSpecies !== 'Magearna') {
|
||||
// Z-Crystals aren't available in Gen 9, so require Plates
|
||||
if (species.baseSpecies === 'Arceus') {
|
||||
return species.requiredItems[0];
|
||||
}
|
||||
return this.sample(species.requiredItems);
|
||||
}
|
||||
if (species.id === 'pikachu') return 'Light Ball';
|
||||
if (role === 'AV Pivot') return 'Assault Vest';
|
||||
if (species.id === 'regieleki') return 'Magnet';
|
||||
if (types.includes('Normal') && moves.has('doubleedge') && moves.has('fakeout')) return 'Silk Scarf';
|
||||
if (
|
||||
species.id === 'froslass' || moves.has('populationbomb') ||
|
||||
(ability === 'Hustle' && counter.get('setup') && !isDoubles && this.randomChance(1, 2))
|
||||
) return 'Wide Lens';
|
||||
if (species.id === 'smeargle') return 'Focus Sash';
|
||||
if (moves.has('clangoroussoul') || (species.id === 'toxtricity' && moves.has('shiftgear'))) return 'Throat Spray';
|
||||
if (
|
||||
(species.baseSpecies === 'Magearna' && role === 'Tera Blast user') ||
|
||||
((species.id === 'calyrexice' || species.id === 'necrozmaduskmane') && isDoubles)
|
||||
) return 'Weakness Policy';
|
||||
if (['dragonenergy', 'lastrespects', 'waterspout'].some(m => moves.has(m))) return 'Choice Scarf';
|
||||
if (
|
||||
!isDoubles && (ability === 'Imposter' || (species.id === 'magnezone' && role === 'Fast Attacker'))
|
||||
) return 'Choice Scarf';
|
||||
if (species.id === 'rampardos' && (role === 'Fast Attacker' || isDoubles)) return 'Choice Scarf';
|
||||
if (species.id === 'palkia' && counter.get('Status')) return 'Lustrous Orb';
|
||||
if (
|
||||
moves.has('courtchange') ||
|
||||
!isDoubles && (species.id === 'luvdisc' || (species.id === 'terapagos' && !moves.has('rest')))
|
||||
) return 'Hoots';
|
||||
if (['Cheek Pouch', 'Cud Chew', 'Harvest', 'Ripen'].some(m => ability === m)) {
|
||||
return 'Sitrus Berry';
|
||||
}
|
||||
if (moves.has('bellydrum') || moves.has('filletaway')) return 'Ward Tag';
|
||||
if (['healingwish', 'switcheroo', 'trick'].some(m => moves.has(m))) {
|
||||
if (
|
||||
species.baseStats.spe >= 60 && species.baseStats.spe <= 108 &&
|
||||
role !== 'Wallbreaker' && role !== 'Doubles Wallbreaker' && !counter.get('priority')
|
||||
) {
|
||||
return 'Choice Scarf';
|
||||
} else {
|
||||
return (counter.get('Physical') > counter.get('Special')) ? 'Choice Band' : 'Choice Specs';
|
||||
}
|
||||
}
|
||||
if (counter.get('Status') && (species.name === 'Latias' || species.name === 'Latios')) return 'Soul Dew';
|
||||
if (species.id === 'scyther' && !isDoubles) return (isLead && !moves.has('uturn')) ? 'Eviolite' : 'Hoots';
|
||||
if (ability === 'Poison Heal' || ability === 'Quick Feet') return 'Toxic Orb';
|
||||
if (species.nfe) return 'Eviolite';
|
||||
if ((ability === 'Guts' || moves.has('facade')) && !moves.has('sleeptalk')) {
|
||||
return (types.includes('Fire') || ability === 'Toxic Boost') ? 'Toxic Orb' : 'Flame Orb';
|
||||
}
|
||||
if (ability === 'Magic Guard' || (ability === 'Sheer Force' && counter.get('sheerforce'))) return 'Life Orb';
|
||||
if (ability === 'Anger Shell') return this.sample(['Expert Belt', 'Lum Berry', 'Scope Lens', 'Sitrus Berry']);
|
||||
if (moves.has('dragondance') && isDoubles) return 'Clear Amulet';
|
||||
if (counter.get('skilllink') && ability !== 'Skill Link' && species.id !== 'breloom') return 'Loaded Dice';
|
||||
if (ability === 'Unburden') {
|
||||
return (moves.has('closecombat') || moves.has('leafstorm')) ? 'White Herb' : 'Sitrus Berry';
|
||||
}
|
||||
if (moves.has('shellsmash') && ability !== 'Weak Armor') return 'White Herb';
|
||||
if (moves.has('meteorbeam') || (moves.has('electroshot') && !teamDetails.rain)) return 'Power Herb';
|
||||
if (moves.has('acrobatics') && ability !== 'Protosynthesis') return '';
|
||||
if (moves.has('auroraveil') || moves.has('lightscreen') && moves.has('reflect')) return 'Light Clay';
|
||||
if (ability === 'Gluttony') return `${this.sample(['Aguav', 'Figy', 'Iapapa', 'Mago', 'Wiki'])} Berry`;
|
||||
if (species.id === 'giratina' && !isDoubles && moves.has('rest') && !moves.has('sleeptalk')) return 'Leftovers';
|
||||
if (
|
||||
moves.has('rest') && !moves.has('sleeptalk') &&
|
||||
ability !== 'Natural Cure' && ability !== 'Shed Skin'
|
||||
) {
|
||||
return 'Chesto Berry';
|
||||
}
|
||||
if (
|
||||
species.id !== 'yanmega' &&
|
||||
this.dex.getEffectiveness('Rock', species) >= 2 && (!types.includes('Flying') || !isDoubles)
|
||||
) return 'Hoots';
|
||||
}
|
||||
|
||||
override getItem(
|
||||
ability: string,
|
||||
types: string[],
|
||||
moves: Set<string>,
|
||||
counter: MoveCounter,
|
||||
teamDetails: RandomTeamsTypes.TeamDetails,
|
||||
species: Species,
|
||||
isLead: boolean,
|
||||
teraType: string,
|
||||
role: RandomTeamsTypes.Role,
|
||||
): string {
|
||||
const lifeOrbReqs = ['flamecharge', 'nuzzle', 'rapidspin'].every(m => !moves.has(m));
|
||||
|
||||
if (
|
||||
species.id !== 'jirachi' && (counter.get('Physical') >= moves.size) &&
|
||||
['dragontail', 'fakeout', 'firstimpression', 'flamecharge', 'rapidspin', 'trailblaze'].every(m => !moves.has(m))
|
||||
) {
|
||||
const scarfReqs = (
|
||||
role !== 'Wallbreaker' &&
|
||||
(species.baseStats.atk >= 100 || ability === 'Huge Power' || ability === 'Pure Power') &&
|
||||
species.baseStats.spe >= 60 && species.baseStats.spe <= 108 &&
|
||||
ability !== 'Speed Boost' && !counter.get('priority')
|
||||
);
|
||||
return (scarfReqs && this.randomChance(1, 2)) ? 'Choice Scarf' : 'Choice Band';
|
||||
}
|
||||
if (
|
||||
(counter.get('Special') >= moves.size) ||
|
||||
(counter.get('Special') >= moves.size - 1 && ['flipturn', 'uturn'].some(m => moves.has(m)))
|
||||
) {
|
||||
const scarfReqs = (
|
||||
role !== 'Wallbreaker' &&
|
||||
species.baseStats.spa >= 100 &&
|
||||
species.baseStats.spe >= 60 && species.baseStats.spe <= 108 &&
|
||||
ability !== 'Speed Boost' && ability !== 'Tinted Lens' && !moves.has('uturn') && !counter.get('priority')
|
||||
);
|
||||
return (scarfReqs && this.randomChance(1, 2)) ? 'Choice Scarf' : 'Choice Specs';
|
||||
}
|
||||
if (counter.get('speedsetup') && !counter.get('physicalsetup') && role === 'Bulky Setup') return 'Weakness Policy';
|
||||
if (
|
||||
!counter.get('Status') &&
|
||||
!['Fast Attacker', 'Wallbreaker', 'Tera Blast user'].includes(role)
|
||||
) {
|
||||
return 'Assault Vest';
|
||||
}
|
||||
if (species.id === 'golem') return (counter.get('speedsetup')) ? 'Weakness Policy' : 'Custap Berry';
|
||||
if (moves.has('substitute')) return 'Leftovers';
|
||||
if (
|
||||
moves.has('stickyweb') && isLead &&
|
||||
(species.baseStats.hp + species.baseStats.def + species.baseStats.spd) <= 235
|
||||
) return 'Focus Sash';
|
||||
if (this.dex.getEffectiveness('Rock', species) >= 1) return 'Hoots';
|
||||
if (
|
||||
(moves.has('chillyreception') || (
|
||||
role === 'Fast Support' &&
|
||||
[...PIVOT_MOVES, 'defog', 'mortalspin', 'rapidspin'].some(m => moves.has(m)) &&
|
||||
!types.includes('Flying') && ability !== 'Levitate'
|
||||
))
|
||||
) return 'Hoots';
|
||||
|
||||
// Low Priority
|
||||
if (moves.has('dragondance') && role === 'Bulky Setup') return 'Weakness Policy';
|
||||
if (
|
||||
ability === 'Rough Skin' || (
|
||||
ability === 'Regenerator' && (role === 'Bulky Support' || role === 'Bulky Attacker') &&
|
||||
(species.baseStats.hp + species.baseStats.def) >= 180 && this.randomChance(1, 2)
|
||||
) || (
|
||||
ability !== 'Regenerator' && !counter.get('setup') && counter.get('recovery') &&
|
||||
this.dex.getEffectiveness('Fighting', species) < 1 &&
|
||||
(species.baseStats.hp + species.baseStats.def) > 200 && this.randomChance(1, 2)
|
||||
)
|
||||
) return 'Rocky Helmet';
|
||||
if (role === 'Bulky Support') return 'Onika Burger';
|
||||
if (moves.has('outrage') && counter.get('setup')) return 'Lum Berry';
|
||||
if (moves.has('protect') && ability !== 'Speed Boost') return 'Leftovers';
|
||||
if (
|
||||
role === 'Fast Support' && isLead && !counter.get('recovery') && !counter.get('recoil') &&
|
||||
(counter.get('hazards') || counter.get('setup')) &&
|
||||
(species.baseStats.hp + species.baseStats.def + species.baseStats.spd) < 258
|
||||
) return 'Focus Sash';
|
||||
if (
|
||||
!counter.get('setup') && ability !== 'Levitate' && this.dex.getEffectiveness('Ground', species) >= 2
|
||||
) return 'Air Balloon';
|
||||
if (['Bulky Attacker', 'Bulky Setup'].some(m => role === (m))) return 'Leftovers';
|
||||
if (species.id === 'pawmot' && moves.has('nuzzle')) return 'Leppa Berry';
|
||||
if (role === 'Fast Support' || role === 'Fast Bulky Setup') {
|
||||
return (
|
||||
counter.get('Physical') + counter.get('Special') > counter.get('Status') && lifeOrbReqs
|
||||
) ? 'Life Orb' : 'Leftovers';
|
||||
}
|
||||
if (role === 'Tera Blast user' && DEFENSIVE_TERA_BLAST_USERS.includes(species.id)) return 'Leftovers';
|
||||
if (
|
||||
lifeOrbReqs && ['Fast Attacker', 'Setup Sweeper', 'Tera Blast user', 'Wallbreaker'].some(m => role === (m))
|
||||
) return 'Life Orb';
|
||||
return 'Leftovers';
|
||||
}
|
||||
|
||||
override getLevel(species: Species): number {
|
||||
if (this.adjustLevel) return this.adjustLevel;
|
||||
const file = this.randomAFDSets[species.id] || this.randomSets[species.id];
|
||||
if (file["level"]) return file["level"];
|
||||
// Default to tier-based levelling
|
||||
const tier = species.tier;
|
||||
const tierScale: Partial<Record<Species['tier'], number>> = {
|
||||
Uber: 76,
|
||||
OU: 80,
|
||||
UUBL: 81,
|
||||
UU: 82,
|
||||
RUBL: 83,
|
||||
RU: 84,
|
||||
NUBL: 85,
|
||||
NU: 86,
|
||||
PUBL: 87,
|
||||
PU: 88, "(PU)": 88, NFE: 88,
|
||||
};
|
||||
return tierScale[tier] || 80;
|
||||
}
|
||||
|
||||
override getForme(species: Species): string {
|
||||
if (typeof species.battleOnly === 'string') {
|
||||
// Only change the forme. The species has custom moves, and may have different typing and requirements.
|
||||
return species.battleOnly;
|
||||
}
|
||||
if (species.cosmeticFormes) return this.sample([species.name].concat(species.cosmeticFormes));
|
||||
|
||||
// Consolidate mostly-cosmetic formes, at least for the purposes of Random Battles
|
||||
if (['Dudunsparce', 'Maushold', 'Polteageist', 'Sinistcha', 'Zarude'].includes(species.baseSpecies)) {
|
||||
return this.sample([species.name].concat(species.otherFormes!));
|
||||
}
|
||||
if (species.baseSpecies === 'Basculin') return 'Basculin' + this.sample(['', '-Blue-Striped']);
|
||||
if (species.baseSpecies === 'Magearna') return 'Magearna' + this.sample(['', '-Original']);
|
||||
if (species.baseSpecies === 'Pikachu') {
|
||||
return 'Pikachu' + this.sample(
|
||||
['', '-Original', '-Hoenn', '-Sinnoh', '-Unova', '-Kalos', '-Alola', '-Partner', '-World']
|
||||
);
|
||||
}
|
||||
return species.name;
|
||||
}
|
||||
|
||||
randomAFDSet(
|
||||
s: string | Species,
|
||||
teamDetails: RandomTeamsTypes.TeamDetails = {},
|
||||
isLead = false,
|
||||
isDoubles = false
|
||||
): RandomTeamsTypes.RandomSet {
|
||||
const species = this.dex.species.get(s);
|
||||
const forme = this.getForme(species);
|
||||
if (!this.randomAFDSets[species.id]) return this.randomSet(species, teamDetails, isLead, isDoubles);
|
||||
const sets = this.randomAFDSets[species.id]["sets"];
|
||||
const possibleSets: RandomTeamsTypes.RandomSetData[] = [];
|
||||
|
||||
const ruleTable = this.dex.formats.getRuleTable(this.format);
|
||||
|
||||
for (const set of sets) {
|
||||
// Prevent Fast Bulky Setup on lead Paradox Pokemon, since it generates Booster Energy.
|
||||
const abilities = set.abilities!;
|
||||
if (
|
||||
isLead && (abilities.includes('Protosynthesis') || abilities.includes('Quark Drive')) &&
|
||||
set.role === 'Fast Bulky Setup'
|
||||
) continue;
|
||||
// Prevent Tera Blast user if the team already has one, or if Terastallizion is prevented.
|
||||
if ((teamDetails.teraBlast || ruleTable.has('terastalclause')) && set.role === 'Tera Blast user') {
|
||||
continue;
|
||||
}
|
||||
possibleSets.push(set);
|
||||
}
|
||||
const set = this.sampleIfArray(possibleSets);
|
||||
const role = set.role;
|
||||
const movePool: string[] = [];
|
||||
for (const movename of set.movepool) {
|
||||
movePool.push(this.dex.moves.get(movename).id);
|
||||
}
|
||||
const teraTypes = set.teraTypes!;
|
||||
let teraType = this.sampleIfArray(teraTypes);
|
||||
|
||||
let ability = '';
|
||||
let item = undefined;
|
||||
|
||||
const evs = { hp: 85, atk: 85, def: 85, spa: 85, spd: 85, spe: 85 };
|
||||
const ivs = { hp: 31, atk: 31, def: 31, spa: 31, spd: 31, spe: 31 };
|
||||
|
||||
const types = species.types;
|
||||
const abilities = set.abilities!;
|
||||
|
||||
// Get moves
|
||||
const moves = this.randomMoveset(types, abilities, teamDetails, species, isLead, isDoubles, movePool, teraType, role);
|
||||
const counter = this.queryMoves(moves, species, teraType, abilities);
|
||||
|
||||
// Get ability
|
||||
ability = this.getAbility(types, moves, abilities, counter, teamDetails, species, isLead, isDoubles, teraType, role);
|
||||
|
||||
// Get items
|
||||
// First, the priority items
|
||||
item = this.getPriorityItem(ability, types, moves, counter, teamDetails, species, isLead, isDoubles, teraType, role);
|
||||
if (item === undefined) {
|
||||
item = this.getItem(ability, types, moves, counter, teamDetails, species, isLead, teraType, role);
|
||||
}
|
||||
|
||||
// Get level
|
||||
const level = this.getLevel(species);
|
||||
|
||||
// Prepare optimal HP
|
||||
const srImmunity = ability === 'Magic Guard' || item === 'Heavy-Duty Boots' || item === 'Hoots';
|
||||
let srWeakness = srImmunity ? 0 : this.dex.getEffectiveness('Rock', species);
|
||||
// Crash damage move users want an odd HP to survive two misses
|
||||
if (['axekick', 'highjumpkick', 'jumpkick', 'supercellslam'].some(m => moves.has(m))) srWeakness = 2;
|
||||
while (evs.hp > 1) {
|
||||
const hp = Math.floor(Math.floor(2 * species.baseStats.hp + ivs.hp + Math.floor(evs.hp / 4) + 100) * level / 100 + 10);
|
||||
if ((moves.has('substitute') && ['Sitrus Berry'].includes(item)) || species.id === 'minior') {
|
||||
// Two Substitutes should activate Sitrus Berry. Two switch-ins to Stealth Rock should activate Shields Down on Minior.
|
||||
if (hp % 4 === 0) break;
|
||||
} else if (
|
||||
(moves.has('bellydrum') || moves.has('filletaway') || moves.has('shedtail')) &&
|
||||
(item === 'Sitrus Berry' || ability === 'Gluttony')
|
||||
) {
|
||||
// Belly Drum should activate Sitrus Berry
|
||||
if (hp % 2 === 0) break;
|
||||
} else if (moves.has('substitute') && moves.has('endeavor')) {
|
||||
// Luvdisc should be able to Substitute down to very low HP
|
||||
if (hp % 4 > 0) break;
|
||||
} else {
|
||||
// Maximize number of Stealth Rock switch-ins in singles
|
||||
if (isDoubles) break;
|
||||
if (srWeakness <= 0 || ability === 'Regenerator' || ['Leftovers', 'Life Orb'].includes(item)) break;
|
||||
if (item !== 'Sitrus Berry' && hp % (4 / srWeakness) > 0) break;
|
||||
// Minimise number of Stealth Rock switch-ins to activate Sitrus Berry
|
||||
if (item === 'Sitrus Berry' && hp % (4 / srWeakness) === 0) break;
|
||||
}
|
||||
evs.hp -= 4;
|
||||
}
|
||||
|
||||
// Minimize confusion damage
|
||||
const noAttackStatMoves = [...moves].every(m => {
|
||||
const move = this.dex.moves.get(m);
|
||||
if (move.damageCallback || move.damage) return true;
|
||||
if (move.id === 'shellsidearm') return false;
|
||||
// Physical Tera Blast
|
||||
if (
|
||||
move.id === 'terablast' && (species.id === 'porygon2' || ['Contrary', 'Defiant'].includes(ability) ||
|
||||
moves.has('shiftgear') || species.baseStats.atk > species.baseStats.spa)
|
||||
) return false;
|
||||
return move.category !== 'Physical' || move.id === 'bodypress' || move.id === 'foulplay';
|
||||
});
|
||||
if (
|
||||
noAttackStatMoves && !moves.has('transform') && this.format.mod !== 'partnersincrime' &&
|
||||
!ruleTable.has('forceofthefallenmod')
|
||||
) {
|
||||
evs.atk = 0;
|
||||
ivs.atk = 0;
|
||||
}
|
||||
|
||||
if (moves.has('gyroball') || moves.has('trickroom')) {
|
||||
evs.spe = 0;
|
||||
ivs.spe = 0;
|
||||
}
|
||||
|
||||
// Enforce Tera Type after all set generation is done to prevent infinite generation
|
||||
if (this.forceTeraType) teraType = this.forceTeraType;
|
||||
|
||||
// shuffle moves to add more randomness to camomons
|
||||
const shuffledMoves = Array.from(moves);
|
||||
this.prng.shuffle(shuffledMoves);
|
||||
let name = species.baseSpecies;
|
||||
if (name === "Bruxish") name = "Brux";
|
||||
return {
|
||||
name,
|
||||
species: forme,
|
||||
speciesId: species.id,
|
||||
gender: species.baseSpecies === 'Greninja' ? 'M' : (species.gender || (this.random(2) ? 'F' : 'M')),
|
||||
shiny: this.randomChance(1, 1024),
|
||||
level,
|
||||
moves: shuffledMoves,
|
||||
ability,
|
||||
evs,
|
||||
ivs,
|
||||
item,
|
||||
teraType,
|
||||
role,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the new species is compatible with the other mons currently on the team.
|
||||
*/
|
||||
override getPokemonCompatibility(
|
||||
species: Species,
|
||||
pokemon: RandomTeamsTypes.RandomSet[]
|
||||
): boolean {
|
||||
const webSetters = [
|
||||
'ariados', 'smeargle', 'masquerain', 'kricketune', 'leavanny', 'galvantula', 'vikavolt', 'ribombee', 'araquanid', 'spidops',
|
||||
];
|
||||
const screenSetters = ['meowstic', 'grimmsnarl', 'ninetalesalola', 'abomasnow'];
|
||||
|
||||
const sunSetters = ['ninetales', 'torkoal', 'groudon', 'koraidon'];
|
||||
|
||||
const incompatiblePokemon = [
|
||||
// These Pokemon with support roles are considered too similar to each other.
|
||||
['blissey', 'chansey'],
|
||||
['illumise', 'volbeat'],
|
||||
|
||||
// These combinations are prevented to avoid double webs or screens.
|
||||
[webSetters, webSetters],
|
||||
[screenSetters, screenSetters],
|
||||
|
||||
// These Pokemon are incompatible because the presence of one actively harms the other.
|
||||
// Prevent Dry Skin + sun setting ability
|
||||
['toxicroak', sunSetters],
|
||||
];
|
||||
|
||||
const incompatibilityList = incompatiblePokemon;
|
||||
for (const pair of incompatibilityList) {
|
||||
const monsArrayA = (Array.isArray(pair[0])) ? pair[0] : [pair[0]];
|
||||
const monsArrayB = (Array.isArray(pair[1])) ? pair[1] : [pair[1]];
|
||||
if (monsArrayB.includes(species.id)) {
|
||||
if (pokemon.some(m => monsArrayA.includes(m.speciesId!))) return false;
|
||||
}
|
||||
if (monsArrayA.includes(species.id)) {
|
||||
if (pokemon.some(m => monsArrayB.includes(m.speciesId!))) return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
randomAFDSets: { [species: string]: RandomTeamsTypes.RandomSpeciesData } = require('./sets.json');
|
||||
|
||||
override randomTeam() {
|
||||
this.enforceNoDirectCustomBanlistChanges();
|
||||
|
||||
const seed = this.prng.getSeed();
|
||||
const ruleTable = this.dex.formats.getRuleTable(this.format);
|
||||
const pokemon: RandomTeamsTypes.RandomSet[] = [];
|
||||
|
||||
// PotD stuff
|
||||
const usePotD = global.Config && Config.potd && ruleTable.has('potd');
|
||||
const potd = usePotD ? this.dex.species.get(Config.potd) : null;
|
||||
|
||||
const baseFormes: { [k: string]: number } = {};
|
||||
|
||||
const typeCount: { [k: string]: number } = {};
|
||||
const typeComboCount: { [k: string]: number } = {};
|
||||
const typeWeaknesses: { [k: string]: number } = {};
|
||||
const typeDoubleWeaknesses: { [k: string]: number } = {};
|
||||
const teamDetails: RandomTeamsTypes.TeamDetails = {};
|
||||
let numMaxLevelPokemon = 0;
|
||||
|
||||
const pokemonList = Object.keys(this.randomSets);
|
||||
const afdList = Object.keys(this.randomAFDSets);
|
||||
const zaMegaList = Object.keys(this.randomAFDSets).filter(x => (
|
||||
this.dex.species.get(x).isMega && this.dex.species.get(x).gen === 9
|
||||
));
|
||||
const [pokemonPool, baseSpeciesPool] = this.getPokemonPool('', pokemon, false, pokemonList);
|
||||
const [afdPool, baseAfdPool] = this.getPokemonPool('', pokemon, false, afdList);
|
||||
const [zaMegaPool, zaBaseMegaPool] = this.getPokemonPool('', pokemon, false, zaMegaList);
|
||||
|
||||
let leadsRemaining = this.format.gameType === 'doubles' ? 2 : 1;
|
||||
while (baseSpeciesPool.length && pokemon.length < this.maxTeamSize) {
|
||||
let baseSpecies, species;
|
||||
if (pokemon.length === 0) {
|
||||
baseSpecies = this.sampleNoReplace(zaBaseMegaPool);
|
||||
species = this.dex.species.get(this.sample(zaMegaPool[baseSpecies]));
|
||||
} else if (this.randomChance(1, 5)) {
|
||||
baseSpecies = this.sampleNoReplace(baseAfdPool);
|
||||
species = this.dex.species.get(this.sample(afdPool[baseSpecies]));
|
||||
} else {
|
||||
baseSpecies = this.sampleNoReplace(baseSpeciesPool);
|
||||
species = this.dex.species.get(this.sample(pokemonPool[baseSpecies]));
|
||||
}
|
||||
if (!species.exists) continue;
|
||||
|
||||
// Limit to one of each species (Species Clause)
|
||||
if (baseFormes[species.baseSpecies]) continue;
|
||||
|
||||
// Treat Ogerpon formes and Terapagos like the Tera Blast user role; reject if team has one already
|
||||
if (['ogerpon', 'ogerponhearthflame', 'terapagos'].includes(species.id) && teamDetails.teraBlast) continue;
|
||||
|
||||
// Illusion shouldn't be on the last slot
|
||||
if (species.baseSpecies === 'Zoroark' && pokemon.length >= (this.maxTeamSize - 1)) continue;
|
||||
|
||||
const types = species.types;
|
||||
const typeCombo = types.slice().sort().join();
|
||||
const weakToFreezeDry = (
|
||||
this.dex.getEffectiveness('Ice', species) > 0 ||
|
||||
(this.dex.getEffectiveness('Ice', species) > -2 && types.includes('Water'))
|
||||
);
|
||||
const weakToScald = (
|
||||
this.dex.getEffectiveness('Water', species) > 0 ||
|
||||
(this.dex.getEffectiveness('Water', species) > -2 && types.includes('Steel'))
|
||||
);
|
||||
// Dynamically scale limits for different team sizes. The default and minimum value is 1.
|
||||
const limitFactor = Math.round(this.maxTeamSize / 6) || 1;
|
||||
|
||||
let skip = false;
|
||||
|
||||
// Limit two of any type
|
||||
for (const typeName of types) {
|
||||
if (typeCount[typeName] >= 2 * limitFactor) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (skip) continue;
|
||||
|
||||
// Limit three weak to any type, and one double weak to any type
|
||||
for (const typeName of this.dex.types.names()) {
|
||||
// it's weak to the type
|
||||
if (this.dex.getEffectiveness(typeName, species) > 0) {
|
||||
if (!typeWeaknesses[typeName]) typeWeaknesses[typeName] = 0;
|
||||
if (typeWeaknesses[typeName] >= 3 * limitFactor) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (this.dex.getEffectiveness(typeName, species) > 1) {
|
||||
if (!typeDoubleWeaknesses[typeName]) typeDoubleWeaknesses[typeName] = 0;
|
||||
if (typeDoubleWeaknesses[typeName] >= limitFactor) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (skip) continue;
|
||||
|
||||
// Count Dry Skin/Fluffy as Fire weaknesses
|
||||
if (
|
||||
this.dex.getEffectiveness('Fire', species) === 0 &&
|
||||
Object.values(species.abilities).filter(a => ['Dry Skin', 'Fluffy'].includes(a)).length
|
||||
) {
|
||||
if (!typeWeaknesses['Fire']) typeWeaknesses['Fire'] = 0;
|
||||
if (typeWeaknesses['Fire'] >= 3 * limitFactor) continue;
|
||||
}
|
||||
|
||||
// Limit four weak to Freeze-Dry
|
||||
if (weakToFreezeDry) {
|
||||
if (!typeWeaknesses['Freeze-Dry']) typeWeaknesses['Freeze-Dry'] = 0;
|
||||
if (typeWeaknesses['Freeze-Dry'] >= 4 * limitFactor) continue;
|
||||
}
|
||||
if (weakToScald) {
|
||||
if (!typeWeaknesses['Scald']) typeWeaknesses['Scald'] = 0;
|
||||
if (typeWeaknesses['Scald'] >= 4 * limitFactor) continue;
|
||||
}
|
||||
|
||||
// Limit one level 100 Pokemon
|
||||
if (!this.adjustLevel && (this.getLevel(species) === 100) && numMaxLevelPokemon >= limitFactor) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check compatibility with team
|
||||
if (!this.getPokemonCompatibility(species, pokemon)) continue;
|
||||
|
||||
// The Pokemon of the Day
|
||||
if (potd?.exists && (pokemon.length === 1 || this.maxTeamSize === 1)) species = potd;
|
||||
|
||||
let set: RandomTeamsTypes.RandomSet;
|
||||
|
||||
if (leadsRemaining) {
|
||||
if (NO_LEAD_POKEMON.includes(species.baseSpecies)) {
|
||||
if (pokemon.length + leadsRemaining === this.maxTeamSize) continue;
|
||||
set = this.randomAFDSet(species, teamDetails, false);
|
||||
pokemon.push(set);
|
||||
} else {
|
||||
set = this.randomAFDSet(species, teamDetails, true);
|
||||
pokemon.unshift(set);
|
||||
leadsRemaining--;
|
||||
}
|
||||
} else {
|
||||
set = this.randomAFDSet(species, teamDetails, false);
|
||||
pokemon.push(set);
|
||||
}
|
||||
|
||||
// Don't bother tracking details for the last Pokemon
|
||||
if (pokemon.length === this.maxTeamSize) break;
|
||||
|
||||
// Now that our Pokemon has passed all checks, we can increment our counters
|
||||
baseFormes[species.baseSpecies] = 1;
|
||||
|
||||
// Increment type counters
|
||||
for (const typeName of types) {
|
||||
if (typeName in typeCount) {
|
||||
typeCount[typeName]++;
|
||||
} else {
|
||||
typeCount[typeName] = 1;
|
||||
}
|
||||
}
|
||||
if (typeCombo in typeComboCount) {
|
||||
typeComboCount[typeCombo]++;
|
||||
} else {
|
||||
typeComboCount[typeCombo] = 1;
|
||||
}
|
||||
|
||||
// Increment weakness counter
|
||||
for (const typeName of this.dex.types.names()) {
|
||||
// it's weak to the type
|
||||
if (this.dex.getEffectiveness(typeName, species) > 0) {
|
||||
typeWeaknesses[typeName]++;
|
||||
}
|
||||
if (this.dex.getEffectiveness(typeName, species) > 1) {
|
||||
typeDoubleWeaknesses[typeName]++;
|
||||
}
|
||||
}
|
||||
// Count Dry Skin/Fluffy as Fire weaknesses
|
||||
if (['Dry Skin', 'Fluffy'].includes(set.ability) && this.dex.getEffectiveness('Fire', species) === 0) {
|
||||
typeWeaknesses['Fire']++;
|
||||
}
|
||||
if (weakToFreezeDry) typeWeaknesses['Freeze-Dry']++;
|
||||
if (weakToScald) typeWeaknesses['Scald']++;
|
||||
|
||||
// Increment level 100 counter
|
||||
if (set.level === 100) numMaxLevelPokemon++;
|
||||
|
||||
// Track what the team has
|
||||
if (set.ability === 'Drizzle' || set.moves.includes('raindance')) teamDetails.rain = 1;
|
||||
if (set.ability === 'Drought' || set.ability === 'Orichalcum Pulse' || set.moves.includes('sunnyday')) {
|
||||
teamDetails.sun = 1;
|
||||
}
|
||||
if (set.ability === 'Sand Stream') teamDetails.sand = 1;
|
||||
if (set.ability === 'Snow Warning' || set.moves.includes('snowscape') || set.moves.includes('chillyreception')) {
|
||||
teamDetails.snow = 1;
|
||||
}
|
||||
if (set.moves.includes('healbell')) teamDetails.statusCure = 1;
|
||||
if (set.moves.includes('spikes') || set.moves.includes('ceaselessedge')) {
|
||||
teamDetails.spikes = (teamDetails.spikes || 0) + 1;
|
||||
}
|
||||
if (set.moves.includes('toxicspikes') || set.ability === 'Toxic Debris') teamDetails.toxicSpikes = 1;
|
||||
if (set.moves.includes('stealthrock') || set.moves.includes('stoneaxe')) teamDetails.stealthRock = 1;
|
||||
if (set.moves.includes('stickyweb')) teamDetails.stickyWeb = 1;
|
||||
if (set.moves.includes('defog')) teamDetails.defog = 1;
|
||||
if (set.moves.includes('rapidspin') || set.moves.includes('mortalspin')) teamDetails.rapidSpin = 1;
|
||||
if (set.moves.includes('auroraveil') || (set.moves.includes('reflect') && set.moves.includes('lightscreen'))) {
|
||||
teamDetails.screens = 1;
|
||||
}
|
||||
if (set.role === 'Tera Blast user' || ['ogerpon', 'ogerponhearthflame', 'terapagos'].includes(species.id)) {
|
||||
teamDetails.teraBlast = 1;
|
||||
}
|
||||
}
|
||||
if (pokemon.length < this.maxTeamSize && pokemon.length < 12) { // large teams sometimes cannot be built
|
||||
throw new Error(`Could not build a random team for ${this.format} (seed=${seed})`);
|
||||
}
|
||||
|
||||
return pokemon;
|
||||
}
|
||||
}
|
||||
|
||||
export default RandomAFDTeams;
|
||||
626
data/mods/afd/scripts.ts
Normal file
626
data/mods/afd/scripts.ts
Normal file
|
|
@ -0,0 +1,626 @@
|
|||
export const Scripts: ModdedBattleScriptsData = {
|
||||
gen: 9,
|
||||
init() {
|
||||
for (const id in this.data.Pokedex) {
|
||||
const species = this.data.Pokedex[id];
|
||||
if (species.isCosmeticForme) continue;
|
||||
if (species.types.includes('Ground')) {
|
||||
if (this.data.Learnsets[id]?.learnset) this.modData('Learnsets', id).learnset.thousandarrows = ['9L1'];
|
||||
}
|
||||
if (species.types.includes('Grass') && !species.types.includes('Fire')) {
|
||||
if (this.data.Learnsets[id]?.learnset) this.modData('Learnsets', id).learnset.solarflare = ['9L1'];
|
||||
}
|
||||
const abilities = this.modData('Pokedex', id, true).abilities;
|
||||
if (species.baseStats['atk'] >= 130) {
|
||||
const hasHP = Object.values(abilities).includes('Huge Power') ||
|
||||
Object.values(abilities).includes('Pure Power');
|
||||
if (!hasHP) {
|
||||
const slot = !abilities['1'] ? '1' : !abilities['H'] ? 'H' : 'S';
|
||||
abilities[slot] ||= 'Huge Power';
|
||||
}
|
||||
}
|
||||
const hasRegen = Object.values(abilities).includes('Regenerator');
|
||||
if (!hasRegen) {
|
||||
const slot = !abilities['1'] ? '1' : !abilities['H'] ? 'H' : 'S';
|
||||
abilities[slot] ||= 'Regenerator';
|
||||
}
|
||||
}
|
||||
this.modData('Learnsets', 'tyranitar').learnset.shoreup = ['9L1'];
|
||||
this.modData('Learnsets', 'bastiodon').learnset.blastiodon = ['9L1'];
|
||||
this.modData('Learnsets', 'seaking').learnset.boltbeak = ['9L1'];
|
||||
this.modData('Learnsets', 'seaking').learnset.fishiousrend = ['9L1'];
|
||||
this.modData('Learnsets', 'ampharos').learnset.tailglow = ['9L1'];
|
||||
this.modData('Learnsets', 'ampharos').learnset.dracometeor = ['9L1'];
|
||||
this.modData('Learnsets', 'serperior').learnset.dracometeor = ['9L1'];
|
||||
this.modData('Learnsets', 'serperior').learnset.overheat = ['9L1'];
|
||||
this.modData('Learnsets', 'serperior').learnset.makeitrain = ['9L1'];
|
||||
this.modData('Learnsets', 'rampardos').learnset.accelerock = ['9L1'];
|
||||
this.modData('Learnsets', 'bibarel').learnset.bellydrum = ['9L1'];
|
||||
this.modData('Learnsets', 'bibarel').learnset.storedpower = ['9L1'];
|
||||
this.modData('Learnsets', 'bibarel').learnset.powertrip = ['9L1'];
|
||||
this.modData('Learnsets', 'golisopod').learnset.bellydrum = ['9L1'];
|
||||
this.modData('Learnsets', 'skuntank').learnset.shitpulse = ['9L1'];
|
||||
this.modData('Learnsets', 'dusknoir').learnset = { explosion: ['9L1'] };
|
||||
for (const move of this.moves.all()) {
|
||||
if (move.flags['bite']) {
|
||||
this.modData('Learnsets', 'bruxish').learnset[move.id] = ['9L1'];
|
||||
}
|
||||
}
|
||||
for (const moveid in this.data.Learnsets['incineroar'].learnset) {
|
||||
if (this.moves.get(moveid).type === 'Dark') {
|
||||
delete this.modData('Learnsets', 'incineroar').learnset[moveid];
|
||||
}
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
runMegaEvo(pokemon: Pokemon) {
|
||||
const speciesid = pokemon.canMegaEvo || pokemon.canUltraBurst;
|
||||
if (!speciesid) return false;
|
||||
|
||||
pokemon.formeChange(speciesid, pokemon.getItem(), true);
|
||||
|
||||
// Limit one mega evolution
|
||||
pokemon.canMegaEvo = null;
|
||||
|
||||
this.battle.runEvent('AfterMega', pokemon);
|
||||
return true;
|
||||
},
|
||||
switchIn(pokemon, pos, sourceEffect = null, isDrag) {
|
||||
if (!pokemon || pokemon.isActive) {
|
||||
this.battle.hint("A switch failed because the Pokémon trying to switch in is already in.");
|
||||
return false;
|
||||
}
|
||||
|
||||
const side = pokemon.side;
|
||||
if (pos >= side.active.length) {
|
||||
throw new Error(`Invalid switch position ${pos} / ${side.active.length}`);
|
||||
}
|
||||
const oldActive = side.active[pos];
|
||||
const unfaintedActive = oldActive?.hp ? oldActive : null;
|
||||
if (unfaintedActive) {
|
||||
oldActive.beingCalledBack = true;
|
||||
let switchCopyFlag: 'copyvolatile' | 'shedtail' | boolean = false;
|
||||
if (sourceEffect && typeof (sourceEffect as Move).selfSwitch === 'string') {
|
||||
switchCopyFlag = (sourceEffect as Move).selfSwitch!;
|
||||
}
|
||||
if (!oldActive.skipBeforeSwitchOutEventFlag && !isDrag) {
|
||||
this.battle.runEvent('BeforeSwitchOut', oldActive);
|
||||
if (this.battle.gen >= 5) {
|
||||
this.battle.eachEvent('Update');
|
||||
}
|
||||
}
|
||||
oldActive.skipBeforeSwitchOutEventFlag = false;
|
||||
if (!this.battle.runEvent('SwitchOut', oldActive)) {
|
||||
// Warning: DO NOT interrupt a switch-out if you just want to trap a pokemon.
|
||||
// To trap a pokemon and prevent it from switching out, (e.g. Mean Look, Magnet Pull)
|
||||
// use the 'trapped' flag instead.
|
||||
|
||||
// Note: Nothing in the real games can interrupt a switch-out (except Pursuit KOing,
|
||||
// which is handled elsewhere); this is just for custom formats.
|
||||
return false;
|
||||
}
|
||||
if (!oldActive.hp) {
|
||||
// a pokemon fainted from Pursuit before it could switch
|
||||
return 'pursuitfaint';
|
||||
}
|
||||
|
||||
// will definitely switch out at this point
|
||||
|
||||
this.battle.singleEvent('End', oldActive.getAbility(), oldActive.abilityState, oldActive);
|
||||
this.battle.singleEvent('End', oldActive.getItem(), oldActive.itemState, oldActive);
|
||||
|
||||
// if a pokemon is forced out by Whirlwind/etc or Eject Button/Pack, it can't use its chosen move
|
||||
this.battle.queue.cancelAction(oldActive);
|
||||
|
||||
let newMove = null;
|
||||
if (this.battle.gen === 4 && sourceEffect) {
|
||||
newMove = oldActive.lastMove;
|
||||
}
|
||||
if (switchCopyFlag) {
|
||||
pokemon.copyVolatileFrom(oldActive, switchCopyFlag);
|
||||
}
|
||||
if (newMove) pokemon.lastMove = newMove;
|
||||
oldActive.clearVolatile();
|
||||
}
|
||||
if (oldActive) {
|
||||
oldActive.isActive = false;
|
||||
oldActive.isStarted = false;
|
||||
oldActive.usedItemThisTurn = false;
|
||||
oldActive.statsRaisedThisTurn = false;
|
||||
oldActive.statsLoweredThisTurn = false;
|
||||
oldActive.position = pokemon.position;
|
||||
if (oldActive.fainted) oldActive.status = '';
|
||||
if (this.battle.gen <= 4) {
|
||||
pokemon.lastItem = oldActive.lastItem;
|
||||
oldActive.lastItem = '';
|
||||
}
|
||||
pokemon.position = pos;
|
||||
side.pokemon[pokemon.position] = pokemon;
|
||||
side.pokemon[oldActive.position] = oldActive;
|
||||
}
|
||||
pokemon.isActive = true;
|
||||
side.active[pos] = pokemon;
|
||||
pokemon.activeTurns = 0;
|
||||
pokemon.activeMoveActions = 0;
|
||||
for (const moveSlot of pokemon.moveSlots) {
|
||||
moveSlot.used = false;
|
||||
}
|
||||
pokemon.abilityState = this.battle.initEffectState({ id: pokemon.ability, target: pokemon });
|
||||
pokemon.itemState = this.battle.initEffectState({ id: pokemon.item, target: pokemon });
|
||||
this.battle.runEvent('BeforeSwitchIn', pokemon);
|
||||
if (sourceEffect) {
|
||||
this.battle.add(isDrag ? 'drag' : 'switch', pokemon, pokemon.getFullDetails, `[from] ${sourceEffect}`);
|
||||
} else {
|
||||
this.battle.add(isDrag ? 'drag' : 'switch', pokemon, pokemon.getFullDetails);
|
||||
}
|
||||
if (isDrag && this.battle.gen === 2) pokemon.draggedIn = this.battle.turn;
|
||||
pokemon.previouslySwitchedIn++;
|
||||
|
||||
if (isDrag && this.battle.gen >= 5) {
|
||||
// runSwitch happens immediately so that Mold Breaker can make hazards bypass Clear Body and Levitate
|
||||
this.runSwitch(pokemon);
|
||||
} else {
|
||||
this.battle.queue.insertChoice({ choice: 'runSwitch', pokemon });
|
||||
}
|
||||
|
||||
if (pokemon.hasType('Flying')) {
|
||||
this.battle.field.addPseudoWeather('Tailwind', pokemon);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
useMoveInner(moveOrMoveName, pokemon, options) {
|
||||
let target = options?.target;
|
||||
let sourceEffect = options?.sourceEffect;
|
||||
const zMove = options?.zMove;
|
||||
const maxMove = options?.maxMove;
|
||||
if (!sourceEffect && this.battle.effect.id) sourceEffect = this.battle.effect;
|
||||
if (sourceEffect && ['instruct', 'custapberry'].includes(sourceEffect.id)) sourceEffect = null;
|
||||
|
||||
let move = this.dex.getActiveMove(moveOrMoveName);
|
||||
pokemon.lastMoveUsed = move;
|
||||
if (move.id === 'weatherball' && zMove) {
|
||||
// Z-Weather Ball only changes types if it's used directly,
|
||||
// not if it's called by Z-Sleep Talk or something.
|
||||
this.battle.singleEvent('ModifyType', move, null, pokemon, target, move, move);
|
||||
if (move.type !== 'Normal') sourceEffect = move;
|
||||
}
|
||||
if (zMove || (move.category !== 'Status' && sourceEffect && (sourceEffect as ActiveMove).isZ)) {
|
||||
move = this.getActiveZMove(move, pokemon);
|
||||
}
|
||||
if (maxMove && move.category !== 'Status') {
|
||||
// Max move outcome is dependent on the move type after type modifications from ability and the move itself
|
||||
this.battle.singleEvent('ModifyType', move, null, pokemon, target, move, move);
|
||||
this.battle.runEvent('ModifyType', pokemon, target, move, move);
|
||||
}
|
||||
if (maxMove || (move.category !== 'Status' && sourceEffect && (sourceEffect as ActiveMove).isMax)) {
|
||||
move = this.getActiveMaxMove(move, pokemon);
|
||||
}
|
||||
|
||||
if (this.battle.activeMove) {
|
||||
move.priority = this.battle.activeMove.priority;
|
||||
if (!move.hasBounced) move.pranksterBoosted = this.battle.activeMove.pranksterBoosted;
|
||||
}
|
||||
const baseTarget = move.target;
|
||||
let targetRelayVar = { target };
|
||||
targetRelayVar = this.battle.runEvent('ModifyTarget', pokemon, target, move, targetRelayVar, true);
|
||||
if (targetRelayVar.target !== undefined) target = targetRelayVar.target;
|
||||
if (target === undefined) target = this.battle.getRandomTarget(pokemon, move);
|
||||
if (move.target === 'self' || move.target === 'allies') {
|
||||
target = pokemon;
|
||||
}
|
||||
if (sourceEffect) {
|
||||
move.sourceEffect = sourceEffect.id;
|
||||
move.ignoreAbility = (sourceEffect as ActiveMove).ignoreAbility;
|
||||
}
|
||||
let moveResult = false;
|
||||
|
||||
this.battle.setActiveMove(move, pokemon, target);
|
||||
|
||||
this.battle.singleEvent('ModifyType', move, null, pokemon, target, move, move);
|
||||
this.battle.singleEvent('ModifyMove', move, null, pokemon, target, move, move);
|
||||
if (baseTarget !== move.target) {
|
||||
// Target changed in ModifyMove, so we must adjust it here
|
||||
// Adjust before the next event so the correct target is passed to the
|
||||
// event
|
||||
target = this.battle.getRandomTarget(pokemon, move);
|
||||
}
|
||||
move = this.battle.runEvent('ModifyType', pokemon, target, move, move);
|
||||
move = this.battle.runEvent('ModifyMove', pokemon, target, move, move);
|
||||
if (baseTarget !== move.target) {
|
||||
// Adjust again
|
||||
target = this.battle.getRandomTarget(pokemon, move);
|
||||
}
|
||||
if (!move || pokemon.fainted) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let attrs = '';
|
||||
|
||||
let movename = move.name;
|
||||
if (move.id === 'hiddenpower') movename = 'Hidden Power';
|
||||
if (sourceEffect) attrs += `|[from] ${sourceEffect.fullname}`;
|
||||
if (zMove && move.isZ === true) {
|
||||
attrs = `|[anim]${movename}${attrs}`;
|
||||
movename = `Z-${movename}`;
|
||||
}
|
||||
this.battle.addMove('move', pokemon, movename, `${target}${attrs}`);
|
||||
|
||||
if (zMove) this.runZPower(move, pokemon);
|
||||
|
||||
if (!target) {
|
||||
this.battle.attrLastMove('[notarget]');
|
||||
this.battle.add(this.battle.gen >= 5 ? '-fail' : '-notarget', pokemon);
|
||||
return false;
|
||||
}
|
||||
|
||||
const { targets, pressureTargets } = pokemon.getMoveTargets(move, target);
|
||||
if (targets.length) {
|
||||
target = targets[targets.length - 1]; // in case of redirection
|
||||
}
|
||||
|
||||
const callerMoveForPressure = sourceEffect && (sourceEffect as ActiveMove).pp ? sourceEffect as ActiveMove : null;
|
||||
if (!sourceEffect || callerMoveForPressure || sourceEffect.id === 'pursuit') {
|
||||
let extraPP = 0;
|
||||
for (const source of pressureTargets) {
|
||||
const ppDrop = this.battle.runEvent('DeductPP', source, pokemon, move);
|
||||
if (ppDrop !== true) {
|
||||
extraPP += ppDrop || 0;
|
||||
}
|
||||
}
|
||||
if (extraPP > 0) {
|
||||
pokemon.deductPP(callerMoveForPressure || moveOrMoveName, extraPP);
|
||||
}
|
||||
}
|
||||
|
||||
let tryMoveResult = this.battle.singleEvent('TryMove', move, null, pokemon, target, move);
|
||||
if (tryMoveResult) {
|
||||
tryMoveResult = this.battle.runEvent('TryMove', pokemon, target, move);
|
||||
}
|
||||
if (!tryMoveResult) {
|
||||
move.mindBlownRecoil = false;
|
||||
return tryMoveResult;
|
||||
}
|
||||
|
||||
this.battle.singleEvent('UseMoveMessage', move, null, pokemon, target, move);
|
||||
|
||||
if (move.ignoreImmunity === undefined) {
|
||||
move.ignoreImmunity = (move.category === 'Status');
|
||||
}
|
||||
|
||||
if (this.battle.gen !== 4 && move.selfdestruct === 'always') {
|
||||
this.battle.faint(pokemon, pokemon, move);
|
||||
}
|
||||
|
||||
let damage: number | false | undefined | '' = false;
|
||||
if (move.target === 'all' || move.target === 'foeSide' || move.target === 'allySide' || move.target === 'allyTeam') {
|
||||
damage = this.tryMoveHit(targets, pokemon, move);
|
||||
if (damage === this.battle.NOT_FAIL) pokemon.moveThisTurnResult = null;
|
||||
if (damage || damage === 0 || damage === undefined) moveResult = true;
|
||||
} else {
|
||||
if (!targets.length) {
|
||||
this.battle.attrLastMove('[notarget]');
|
||||
this.battle.add(this.battle.gen >= 5 ? '-fail' : '-notarget', pokemon);
|
||||
return false;
|
||||
}
|
||||
if (this.battle.gen === 4 && move.selfdestruct === 'always') {
|
||||
this.battle.faint(pokemon, pokemon, move);
|
||||
}
|
||||
moveResult = this.trySpreadMoveHit(targets, pokemon, move);
|
||||
}
|
||||
if (move.selfBoost && moveResult) this.moveHit(pokemon, pokemon, move, move.selfBoost, false, true);
|
||||
if (!pokemon.hp) {
|
||||
this.battle.faint(pokemon, pokemon, move);
|
||||
}
|
||||
|
||||
if (!moveResult) {
|
||||
this.battle.singleEvent('MoveFail', move, null, target, pokemon, move);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(move.hasSheerForce && pokemon.hasAbility('sheerforce')) && !move.flags['futuremove']) {
|
||||
const originalHp = pokemon.hp;
|
||||
this.battle.singleEvent('AfterMoveSecondarySelf', move, null, pokemon, target, move);
|
||||
this.battle.runEvent('AfterMoveSecondarySelf', pokemon, target, move);
|
||||
if (pokemon && pokemon !== target && move.category !== 'Status') {
|
||||
if (pokemon.hp <= pokemon.maxhp / 2 && originalHp > pokemon.maxhp / 2) {
|
||||
this.battle.runEvent('EmergencyExit', pokemon, pokemon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
canTerastallize(pokemon: Pokemon) {
|
||||
if (this.dex.gen !== 9) {
|
||||
return null;
|
||||
}
|
||||
return pokemon.teraType;
|
||||
},
|
||||
canMegaEvo(pokemon) {
|
||||
const species = pokemon.baseSpecies;
|
||||
const altForme = species.otherFormes && this.dex.species.get(species.otherFormes[0]);
|
||||
const item = pokemon.getItem();
|
||||
// Mega Rayquaza
|
||||
if ((this.battle.gen <= 7 || this.battle.ruleTable.has('+pokemontag:past') ||
|
||||
this.battle.ruleTable.has('+pokemontag:future')) &&
|
||||
altForme?.isMega && altForme?.requiredMove &&
|
||||
pokemon.baseMoves.includes(this.battle.toID(altForme.requiredMove)) && !item.zMove) {
|
||||
return altForme.name;
|
||||
}
|
||||
if (species.baseSpecies === 'Magearna' && !species.isMega) {
|
||||
return species.name.includes('Original') ? 'Magearna-Original-Mega' : 'Magearna-Mega';
|
||||
}
|
||||
if (!item.megaStone) return null;
|
||||
return item.megaStone[species.name];
|
||||
},
|
||||
modifyDamage(baseDamage, pokemon, target, move, suppressMessages = false) {
|
||||
const tr = this.battle.trunc;
|
||||
if (!move.type) move.type = '???';
|
||||
const type = move.type;
|
||||
|
||||
baseDamage += 2;
|
||||
|
||||
if (move.spreadHit) {
|
||||
// multi-target modifier (doubles only)
|
||||
const spreadModifier = this.battle.gameType === 'freeforall' ? 0.5 : 0.75;
|
||||
this.battle.debug(`Spread modifier: ${spreadModifier}`);
|
||||
baseDamage = this.battle.modify(baseDamage, spreadModifier);
|
||||
} else if (move.multihitType === 'parentalbond' && move.hit > 1) {
|
||||
// Parental Bond modifier
|
||||
const bondModifier = this.battle.gen > 6 ? 0.25 : 0.5;
|
||||
this.battle.debug(`Parental Bond modifier: ${bondModifier}`);
|
||||
baseDamage = this.battle.modify(baseDamage, bondModifier);
|
||||
}
|
||||
|
||||
// weather modifier
|
||||
baseDamage = this.battle.runEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
|
||||
|
||||
// crit - not a modifier
|
||||
const isCrit = target.getMoveHitData(move).crit;
|
||||
if (isCrit) {
|
||||
baseDamage = tr(baseDamage * (move.critModifier || (this.battle.gen >= 6 ? 1.5 : 2)));
|
||||
}
|
||||
|
||||
// random factor - also not a modifier
|
||||
baseDamage = this.battle.randomizer(baseDamage);
|
||||
|
||||
// STAB
|
||||
// The "???" type never gets STAB
|
||||
// Not even if you Roost in Gen 4 and somehow manage to use
|
||||
// Struggle in the same turn.
|
||||
// (On second thought, it might be easier to get a MissingNo.)
|
||||
if (type !== '???') {
|
||||
let stab: number | [number, number] = 1;
|
||||
|
||||
const pokeTypes = pokemon.getTypes(false, true);
|
||||
const isPrimarySTAB = move.forceSTAB || (pokemon.hasType(type) && pokeTypes[0] === type);
|
||||
const isSecondarySTAB = move.forceSTAB || (pokemon.hasType(type) && pokeTypes.length > 1 && pokeTypes[1] === type);
|
||||
const isSTAB = move.forceSTAB || pokemon.hasType(type) || pokemon.getTypes(false, true).includes(type);
|
||||
if (isPrimarySTAB) {
|
||||
stab = 1.7;
|
||||
}
|
||||
if (isSecondarySTAB) {
|
||||
stab = 1.2;
|
||||
}
|
||||
|
||||
// The Stellar tera type makes this incredibly confusing
|
||||
// If the move's type does not match one of the user's base types,
|
||||
// the Stellar tera type applies a one-time 1.2x damage boost for that type.
|
||||
//
|
||||
// If the move's type does match one of the user's base types,
|
||||
// then the Stellar tera type applies a one-time 2x STAB boost for that type,
|
||||
// and then goes back to using the regular 1.5x STAB boost for those types.
|
||||
if (pokemon.terastallized === 'Stellar') {
|
||||
if (!pokemon.stellarBoostedTypes.includes(type) || move.stellarBoosted) {
|
||||
stab = isSTAB ? 2.3 : [4915, 4096];
|
||||
move.stellarBoosted = true;
|
||||
if (pokemon.species.name !== 'Terapagos-Stellar') {
|
||||
pokemon.stellarBoostedTypes.push(type);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (pokemon.terastallized === type && pokeTypes.includes(type)) {
|
||||
stab = 2.3;
|
||||
}
|
||||
stab = this.battle.runEvent('ModifySTAB', pokemon, target, move, stab);
|
||||
}
|
||||
|
||||
baseDamage = this.battle.modify(baseDamage, stab);
|
||||
}
|
||||
|
||||
// types
|
||||
let typeMod = target.runEffectiveness(move);
|
||||
typeMod = this.battle.clampIntRange(typeMod, -6, 6);
|
||||
target.getMoveHitData(move).typeMod = typeMod;
|
||||
if (typeMod > 0) {
|
||||
if (!suppressMessages) this.battle.add('-supereffective', target);
|
||||
|
||||
for (let i = 0; i < typeMod; i++) {
|
||||
baseDamage *= 2;
|
||||
}
|
||||
}
|
||||
if (typeMod < 0) {
|
||||
if (!suppressMessages) this.battle.add('-resisted', target);
|
||||
|
||||
for (let i = 0; i > typeMod; i--) {
|
||||
baseDamage = tr(baseDamage / 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (isCrit && !suppressMessages) this.battle.add('-crit', target);
|
||||
|
||||
if (pokemon.status === 'brn' && move.category === 'Physical' && !pokemon.hasAbility('guts')) {
|
||||
if (this.battle.gen < 6 || move.id !== 'facade') {
|
||||
baseDamage = this.battle.modify(baseDamage, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
if (pokemon.status === 'psn' && move.category === 'Special') {
|
||||
if (this.battle.gen < 6 || move.id !== 'facade') {
|
||||
baseDamage = this.battle.modify(baseDamage, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
// Generation 5, but nothing later, sets damage to 1 before the final damage modifiers
|
||||
if (this.battle.gen === 5 && !baseDamage) baseDamage = 1;
|
||||
|
||||
// Final modifier. Modifiers that modify damage after min damage check, such as Life Orb.
|
||||
baseDamage = this.battle.runEvent('ModifyDamage', pokemon, target, move, baseDamage);
|
||||
|
||||
const bypassProtect = target.getMoveHitData(move).bypassProtect;
|
||||
if (bypassProtect) {
|
||||
baseDamage = this.battle.modify(baseDamage, 0.25);
|
||||
if (bypassProtect !== true && bypassProtect.effectType === 'Ability') {
|
||||
this.battle.add('-ability', pokemon, bypassProtect.name);
|
||||
}
|
||||
this.battle.add('-zbroken', target);
|
||||
}
|
||||
|
||||
// Generation 6-7 moves the check for minimum 1 damage after the final modifier...
|
||||
if (this.battle.gen !== 5 && !baseDamage) return 1;
|
||||
|
||||
// ...but 16-bit truncation happens even later, and can truncate to 0
|
||||
return tr(baseDamage, 16);
|
||||
},
|
||||
getDamage(source, target, move, suppressMessages = false) {
|
||||
if (typeof move === 'string') move = this.dex.getActiveMove(move);
|
||||
|
||||
if (typeof move === 'number') {
|
||||
const basePower = move;
|
||||
move = new Dex.Move({
|
||||
basePower,
|
||||
type: '???',
|
||||
category: 'Physical',
|
||||
willCrit: false,
|
||||
}) as ActiveMove;
|
||||
move.hit = 0;
|
||||
}
|
||||
|
||||
if (!target.runImmunity(move, !suppressMessages)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (move.ohko) return this.battle.gen === 3 ? target.hp : target.maxhp;
|
||||
if (move.damageCallback) return move.damageCallback.call(this.battle, source, target);
|
||||
if (move.damage === 'level') {
|
||||
return source.level;
|
||||
} else if (move.damage) {
|
||||
return move.damage;
|
||||
}
|
||||
|
||||
let category = this.battle.getCategory(move);
|
||||
|
||||
let basePower: number | false | null = move.basePower;
|
||||
if (move.basePowerCallback) {
|
||||
basePower = move.basePowerCallback.call(this.battle, source, target, move);
|
||||
}
|
||||
if (!basePower) return basePower === 0 ? undefined : basePower;
|
||||
basePower = this.battle.clampIntRange(basePower, 1);
|
||||
if (move.type === 'Electric' && move.category === 'Physical') {
|
||||
basePower += 15;
|
||||
category = 'Special';
|
||||
}
|
||||
|
||||
let critMult;
|
||||
let critRatio = this.battle.runEvent('ModifyCritRatio', source, target, move, move.critRatio || 0);
|
||||
if (this.battle.gen <= 5) {
|
||||
critRatio = this.battle.clampIntRange(critRatio, 0, 5);
|
||||
critMult = [0, 16, 8, 4, 3, 2];
|
||||
} else {
|
||||
critRatio = this.battle.clampIntRange(critRatio, 0, 4);
|
||||
if (this.battle.gen === 6) {
|
||||
critMult = [0, 16, 8, 2, 1];
|
||||
} else {
|
||||
critMult = [0, 24, 8, 2, 1];
|
||||
}
|
||||
}
|
||||
|
||||
const moveHit = target.getMoveHitData(move);
|
||||
moveHit.crit = move.willCrit || false;
|
||||
if (move.willCrit === undefined) {
|
||||
if (critRatio) {
|
||||
moveHit.crit = this.battle.randomChance(1, critMult[critRatio]);
|
||||
}
|
||||
}
|
||||
|
||||
if (moveHit.crit) {
|
||||
moveHit.crit = this.battle.runEvent('CriticalHit', target, null, move);
|
||||
}
|
||||
|
||||
// happens after crit calculation
|
||||
basePower = this.battle.runEvent('BasePower', source, target, move, basePower, true);
|
||||
|
||||
if (!basePower) return 0;
|
||||
basePower = this.battle.clampIntRange(basePower, 1);
|
||||
// Hacked Max Moves have 0 base power, even if you Dynamax
|
||||
if ((!source.volatiles['dynamax'] && move.isMax) || (move.isMax && this.dex.moves.get(move.baseMove).isMax)) {
|
||||
basePower = 0;
|
||||
}
|
||||
|
||||
const dexMove = this.dex.moves.get(move.id);
|
||||
if (source.terastallized && (source.terastallized === 'Stellar' ?
|
||||
!source.stellarBoostedTypes.includes(move.type) : source.hasType(move.type)) &&
|
||||
basePower < 60 && dexMove.priority <= 0 && !dexMove.multihit &&
|
||||
// Hard move.basePower check for moves like Dragon Energy that have variable BP
|
||||
!((move.basePower === 0 || move.basePower === 150) && move.basePowerCallback)
|
||||
) {
|
||||
basePower = 60;
|
||||
}
|
||||
|
||||
const level = source.level;
|
||||
|
||||
const attacker = move.overrideOffensivePokemon === 'target' ? target : source;
|
||||
const defender = move.overrideDefensivePokemon === 'source' ? source : target;
|
||||
|
||||
const isPhysical = move.category === 'Physical';
|
||||
let attackStat: StatIDExceptHP = move.overrideOffensiveStat || (isPhysical ? 'atk' : 'spa');
|
||||
const defenseStat: StatIDExceptHP = move.overrideDefensiveStat || (isPhysical ? 'def' : 'spd');
|
||||
|
||||
const statTable = { atk: 'Atk', def: 'Def', spa: 'SpA', spd: 'SpD', spe: 'Spe' };
|
||||
|
||||
let atkBoosts = attacker.boosts[attackStat];
|
||||
let defBoosts = defender.boosts[defenseStat];
|
||||
|
||||
let ignoreNegativeOffensive = !!move.ignoreNegativeOffensive;
|
||||
let ignorePositiveDefensive = !!move.ignorePositiveDefensive;
|
||||
|
||||
if (moveHit.crit) {
|
||||
ignoreNegativeOffensive = true;
|
||||
ignorePositiveDefensive = true;
|
||||
}
|
||||
const ignoreOffensive = !!(move.ignoreOffensive || (ignoreNegativeOffensive && atkBoosts < 0));
|
||||
const ignoreDefensive = !!(move.ignoreDefensive || (ignorePositiveDefensive && defBoosts > 0));
|
||||
|
||||
if (ignoreOffensive) {
|
||||
this.battle.debug('Negating (sp)atk boost/penalty.');
|
||||
atkBoosts = 0;
|
||||
}
|
||||
if (ignoreDefensive) {
|
||||
this.battle.debug('Negating (sp)def boost/penalty.');
|
||||
defBoosts = 0;
|
||||
}
|
||||
|
||||
let attack = attacker.calculateStat(attackStat, atkBoosts, 1, source);
|
||||
let defense = defender.calculateStat(defenseStat, defBoosts, 1, target);
|
||||
|
||||
attackStat = (category === 'Physical' ? 'atk' : 'spa');
|
||||
|
||||
// Apply Stat Modifiers
|
||||
attack = this.battle.runEvent('Modify' + statTable[attackStat], source, target, move, attack);
|
||||
defense = this.battle.runEvent('Modify' + statTable[defenseStat], target, source, move, defense);
|
||||
|
||||
if (this.battle.gen <= 4 && ['explosion', 'selfdestruct'].includes(move.id) && defenseStat === 'def') {
|
||||
defense = this.battle.clampIntRange(Math.floor(defense / 2), 1);
|
||||
}
|
||||
|
||||
const tr = this.battle.trunc;
|
||||
|
||||
// int(int(int(2 * L / 5 + 2) * A * P / D) / 50);
|
||||
const baseDamage = tr(tr(tr(tr(2 * level / 5 + 2) * basePower * attack) / defense) / 50);
|
||||
|
||||
// Calculate damage modifiers separately (order differs between generations)
|
||||
return this.modifyDamage(baseDamage, source, target, move, suppressMessages);
|
||||
},
|
||||
},
|
||||
};
|
||||
1052
data/mods/afd/sets.json
Normal file
1052
data/mods/afd/sets.json
Normal file
File diff suppressed because it is too large
Load Diff
49
data/mods/afd/typechart.ts
Normal file
49
data/mods/afd/typechart.ts
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
export const TypeChart: import('../../../sim/dex-data').ModdedTypeDataTable = {
|
||||
fairy: {
|
||||
damageTaken: {
|
||||
Bug: 2,
|
||||
Dark: 2,
|
||||
Dragon: 3,
|
||||
Electric: 0,
|
||||
Fairy: 0,
|
||||
Fighting: 2,
|
||||
Fire: 0,
|
||||
Flying: 0,
|
||||
Ghost: 0,
|
||||
Grass: 0,
|
||||
Ground: 0,
|
||||
Ice: 0,
|
||||
Normal: 1,
|
||||
Poison: 1,
|
||||
Psychic: 0,
|
||||
Rock: 0,
|
||||
Steel: 1,
|
||||
Stellar: 0,
|
||||
Water: 0,
|
||||
},
|
||||
},
|
||||
ghost: {
|
||||
inherit: true,
|
||||
damageTaken: {
|
||||
Bug: 3,
|
||||
Dark: 1,
|
||||
Dragon: 1,
|
||||
Electric: 1,
|
||||
Fairy: 3,
|
||||
Fighting: 3,
|
||||
Fire: 1,
|
||||
Flying: 3,
|
||||
Ghost: 3,
|
||||
Grass: 1,
|
||||
Ground: 3,
|
||||
Ice: 1,
|
||||
Normal: 3,
|
||||
Poison: 3,
|
||||
Psychic: 1,
|
||||
Rock: 3,
|
||||
Steel: 3,
|
||||
Stellar: 0,
|
||||
Water: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
209
data/mods/biomechmons/abilities.ts
Normal file
209
data/mods/biomechmons/abilities.ts
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTable = {
|
||||
magician: {
|
||||
inherit: true,
|
||||
onAfterMoveSecondarySelf(source, target, move) {
|
||||
if (!move || source.switchFlag === true || !move.hitTargets || source.item || source.volatiles['gem'] ||
|
||||
move.id === 'fling' || move.category === 'Status') return;
|
||||
const hitTargets = move.hitTargets;
|
||||
this.speedSort(hitTargets);
|
||||
for (const pokemon of hitTargets) {
|
||||
if (pokemon !== source) {
|
||||
const yourItem = pokemon.takeItem(source);
|
||||
if (!yourItem) continue;
|
||||
if (!source.setItem(yourItem)) {
|
||||
if (!this.dex.items.get(yourItem.id).exists) {
|
||||
pokemon.setItem(yourItem.id);
|
||||
continue;
|
||||
}
|
||||
pokemon.item = yourItem.id; // bypass setItem so we don't break choicelock or anything
|
||||
continue;
|
||||
}
|
||||
this.add('-item', source, yourItem, '[from] ability: Magician', `[of] ${pokemon}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
neutralizinggas: {
|
||||
inherit: true,
|
||||
onSwitchIn(pokemon) {
|
||||
this.add('-ability', pokemon, 'Neutralizing Gas');
|
||||
pokemon.abilityState.ending = false;
|
||||
const strongWeathers = ['desolateland', 'primordialsea', 'deltastream'];
|
||||
for (const target of this.getAllActive()) {
|
||||
if (target.hasItem('Ability Shield')) {
|
||||
this.add('-block', target, 'item: Ability Shield');
|
||||
continue;
|
||||
}
|
||||
// Can't suppress a Tatsugiri inside of Dondozo already
|
||||
if (target.volatiles['commanding']) {
|
||||
continue;
|
||||
}
|
||||
if (target.illusion) {
|
||||
this.singleEvent('End', this.dex.abilities.get('Illusion'), target.abilityState, target, pokemon, 'neutralizinggas');
|
||||
}
|
||||
if (target.volatiles['slowstart']) {
|
||||
delete target.volatiles['slowstart'];
|
||||
this.add('-end', target, 'Slow Start', '[silent]');
|
||||
}
|
||||
if (strongWeathers.includes(target.getAbility().id)) {
|
||||
this.singleEvent('End', this.dex.abilities.get(target.getAbility().id), target.abilityState, target, pokemon, 'neutralizinggas');
|
||||
}
|
||||
if (!this.dex.abilities.get(target.ability).exists) {
|
||||
const isItem = (target.m.scrambled.items as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
|
||||
if (isItem >= 0) {
|
||||
target.removeVolatile('item:' + this.toID(target.m.scrambled.items[isItem].thing));
|
||||
} else if ((target.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability') >= 0) {
|
||||
const isMove = (target.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
|
||||
const indexOfMove = target.moveSlots.findIndex(m => this.toID(target.m.scrambled.moves[isMove].thing) === m.id);
|
||||
if (indexOfMove >= 0) target.moveSlots.splice(indexOfMove, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onEnd(source) {
|
||||
if (source.transformed) return;
|
||||
for (const pokemon of this.getAllActive()) {
|
||||
if (pokemon !== source && pokemon.hasAbility('Neutralizing Gas')) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.add('-end', source, 'ability: Neutralizing Gas');
|
||||
|
||||
// FIXME this happens before the pokemon switches out, should be the opposite order.
|
||||
// Not an easy fix since we cant use a supported event. Would need some kind of special event that
|
||||
// gathers events to run after the switch and then runs them when the ability is no longer accessible.
|
||||
// (If you're tackling this, do note extreme weathers have the same issue)
|
||||
|
||||
// Mark this pokemon's ability as ending so Pokemon#ignoringAbility skips it
|
||||
if (source.abilityState.ending) return;
|
||||
source.abilityState.ending = true;
|
||||
const sortedActive = this.getAllActive();
|
||||
this.speedSort(sortedActive);
|
||||
for (const pokemon of sortedActive) {
|
||||
if (pokemon !== source) {
|
||||
if (pokemon.getAbility().flags['cantsuppress']) continue; // does not interact with e.g Ice Face, Zen Mode
|
||||
if (pokemon.hasItem('abilityshield')) continue; // don't restart abilities that weren't suppressed
|
||||
|
||||
// Will be suppressed by Pokemon#ignoringAbility if needed
|
||||
this.singleEvent('Start', pokemon.getAbility(), pokemon.abilityState, pokemon);
|
||||
if (pokemon.ability === "gluttony") {
|
||||
pokemon.abilityState.gluttony = false;
|
||||
}
|
||||
}
|
||||
if (!this.dex.abilities.get(pokemon.ability).exists) {
|
||||
const isItem = (pokemon.m.scrambled.items as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
|
||||
if (isItem >= 0) {
|
||||
pokemon.addVolatile('item:' + this.toID(pokemon.m.scrambled.items[isItem].thing));
|
||||
} else if ((pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability') >= 0) {
|
||||
const findMove = (pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
|
||||
const findSlot = pokemon.baseMoveSlots.find(e => e.id === this.toID(pokemon.m.scrambled.moves[findMove].thing));
|
||||
pokemon.moveSlots.push(this.dex.deepClone(findSlot));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
pickpocket: {
|
||||
inherit: true,
|
||||
onAfterMoveSecondary(target, source, move) {
|
||||
if (source && source !== target && move?.flags['contact']) {
|
||||
if (target.item || target.switchFlag || target.forceSwitchFlag || source.switchFlag === true) {
|
||||
return;
|
||||
}
|
||||
const yourItem = source.takeItem(target);
|
||||
if (!yourItem) {
|
||||
return;
|
||||
}
|
||||
if (!target.setItem(yourItem)) {
|
||||
if (!this.dex.items.get(yourItem.id).exists) {
|
||||
target.setItem(yourItem.id);
|
||||
return;
|
||||
}
|
||||
source.item = yourItem.id;
|
||||
return;
|
||||
}
|
||||
this.add('-enditem', source, yourItem, '[silent]', '[from] ability: Pickpocket', `[of] ${source}`);
|
||||
this.add('-item', target, yourItem, '[from] ability: Pickpocket', `[of] ${source}`);
|
||||
}
|
||||
},
|
||||
},
|
||||
trace: {
|
||||
inherit: true,
|
||||
onStart(pokemon) {
|
||||
this.effectState.seek = true;
|
||||
// n.b. only affects Hackmons
|
||||
// interaction with No Ability is complicated: https://www.smogon.com/forums/threads/pokemon-sun-moon-battle-mechanics-research.3586701/page-76#post-7790209
|
||||
if (pokemon.adjacentFoes().some(foeActive => foeActive.ability === 'noability')) {
|
||||
this.effectState.seek = false;
|
||||
}
|
||||
// interaction with Ability Shield is similar to No Ability
|
||||
if (pokemon.hasItem('Ability Shield') && this.toID(pokemon.ability) === 'trace') {
|
||||
this.add('-block', pokemon, 'item: Ability Shield');
|
||||
this.effectState.seek = false;
|
||||
}
|
||||
if (this.effectState.seek) {
|
||||
this.singleEvent('Update', this.effect, this.effectState, pokemon);
|
||||
}
|
||||
},
|
||||
onUpdate(pokemon) {
|
||||
if (!this.effectState.seek) return;
|
||||
|
||||
const possibleTargets = pokemon.adjacentFoes().filter(
|
||||
target => !target.getAbility().flags['notrace'] && target.ability !== 'noability'
|
||||
);
|
||||
if (!possibleTargets.length) return;
|
||||
|
||||
const target = this.sample(possibleTargets);
|
||||
const ability = target.getAbility();
|
||||
if (this.toID(pokemon.item) === 'trace') {
|
||||
this.add('-ability', pokemon, ability.name, 'Trace');
|
||||
pokemon.setItem(ability.name);
|
||||
return;
|
||||
} else if (pokemon.volatiles['ability:trace']?.inSlot === 'Move') {
|
||||
if (this.dex.abilities.get(ability.name).exists) {
|
||||
pokemon.removeVolatile('ability:trace');
|
||||
pokemon.m.scrambled.abilities.splice(
|
||||
(pokemon.m.scrambled.abilities as { thing: string, inSlot: string }[]).findIndex(e =>
|
||||
this.toID(e.thing) === 'trace' && e.inSlot === 'Move'), 1);
|
||||
this.add('-ability', pokemon, ability.name, 'Trace');
|
||||
pokemon.addVolatile(`ability:${ability.id}`);
|
||||
pokemon.m.scrambled.abilities.push({ thing: ability.name, inSlot: 'Move' });
|
||||
} else if (this.dex.items.get(ability.name).exists) {
|
||||
pokemon.removeVolatile('ability:trace');
|
||||
pokemon.m.scrambled.abilities.splice(
|
||||
(pokemon.m.scrambled.abilities as { thing: string, inSlot: string }[]).findIndex(e =>
|
||||
this.toID(e.thing) === 'trace' && e.inSlot === 'Move'), 1);
|
||||
this.add('-ability', pokemon, ability.name, 'Trace');
|
||||
pokemon.addVolatile(`item:${ability.id}`);
|
||||
pokemon.m.scrambled.items.push({ thing: this.dex.items.get(ability.name).name, inSlot: 'Move' });
|
||||
} else {
|
||||
const move = this.dex.moves.get(ability.name);
|
||||
if (move.exists) {
|
||||
pokemon.removeVolatile('ability:trace');
|
||||
pokemon.m.scrambled.abilities.splice(
|
||||
(pokemon.m.scrambled.abilities as { thing: string, inSlot: string }[]).findIndex(e =>
|
||||
this.toID(e.thing) === 'trace' && e.inSlot === 'Move'), 1);
|
||||
this.add('-ability', pokemon, move.name, 'Trace');
|
||||
const ppUps = move.noPPBoosts ? 0 : 3;
|
||||
const basePP = this.calculatePP(move, ppUps);
|
||||
const newMove = {
|
||||
move: move.name,
|
||||
id: move.id,
|
||||
pp: basePP,
|
||||
maxpp: basePP,
|
||||
target: move.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
pokemon.baseMoveSlots.push(newMove);
|
||||
pokemon.moveSlots.push(newMove);
|
||||
pokemon.ppUps.push(ppUps);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
pokemon.setAbility(ability, target);
|
||||
},
|
||||
},
|
||||
};
|
||||
44
data/mods/biomechmons/conditions.ts
Normal file
44
data/mods/biomechmons/conditions.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDataTable = {
|
||||
choicelock: {
|
||||
inherit: true,
|
||||
onBeforeMove(pokemon, target, move) {
|
||||
const choiceItem = pokemon.getItem().isChoice ||
|
||||
Object.keys(pokemon.volatiles).some(v => (
|
||||
v.startsWith('item:') && this.dex.items.get(v.split(':')[1]).isChoice
|
||||
));
|
||||
if (!choiceItem) {
|
||||
pokemon.removeVolatile('choicelock');
|
||||
return;
|
||||
}
|
||||
if (
|
||||
!pokemon.ignoringItem() && !pokemon.volatiles['dynamax'] &&
|
||||
move.id !== this.effectState.move && move.id !== 'struggle'
|
||||
) {
|
||||
// Fails unless the Choice item is being ignored, and no PP is lost
|
||||
this.addMove('move', pokemon, move.name);
|
||||
this.attrLastMove('[still]');
|
||||
this.debug("Disabled by Choice item lock");
|
||||
this.add('-fail', pokemon);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onDisableMove(pokemon) {
|
||||
const choiceItem = pokemon.getItem().isChoice ||
|
||||
Object.keys(pokemon.volatiles).some(v => (
|
||||
v.startsWith('item:') && this.dex.items.get(v.split(':')[1]).isChoice
|
||||
));
|
||||
if (!choiceItem || !pokemon.hasMove(this.effectState.move)) {
|
||||
pokemon.removeVolatile('choicelock');
|
||||
return;
|
||||
}
|
||||
if (pokemon.ignoringItem() || pokemon.volatiles['dynamax']) {
|
||||
return;
|
||||
}
|
||||
for (const moveSlot of pokemon.moveSlots) {
|
||||
if (moveSlot.id !== this.effectState.move) {
|
||||
pokemon.disableMove(moveSlot.id, false, this.effectState.sourceEffect);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
41
data/mods/biomechmons/items.ts
Normal file
41
data/mods/biomechmons/items.ts
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
||||
airballoon: {
|
||||
inherit: true,
|
||||
// airborneness implemented in sim/pokemon.js:Pokemon#isGrounded
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
this.add('-enditem', target, 'Air Balloon');
|
||||
if (target.item === 'airballoon') {
|
||||
target.item = '';
|
||||
this.clearEffectState(target.itemState);
|
||||
} else {
|
||||
const isBMM = target.volatiles['item:airballoon']?.inSlot;
|
||||
if (isBMM) {
|
||||
target.removeVolatile('item:airballoon');
|
||||
target.m.scrambled.items.splice((target.m.scrambled.items as { thing: string, inSlot: string }[]).findIndex(e =>
|
||||
this.toID(e.thing) === 'airballoon' && e.inSlot === isBMM), 1);
|
||||
if (isBMM === 'Ability') target.setAbility('No Ability');
|
||||
}
|
||||
}
|
||||
this.runEvent('AfterUseItem', target, null, null, this.dex.items.get('airballoon'));
|
||||
},
|
||||
onAfterSubDamage(damage, target, source, effect) {
|
||||
this.debug('effect: ' + effect.id);
|
||||
if (effect.effectType === 'Move') {
|
||||
this.add('-enditem', target, 'Air Balloon');
|
||||
if (target.item === 'airballoon') {
|
||||
target.item = '';
|
||||
this.clearEffectState(target.itemState);
|
||||
} else {
|
||||
const isBMM = target.volatiles['item:airballoon']?.inSlot;
|
||||
if (isBMM) {
|
||||
target.removeVolatile('item:airballoon');
|
||||
target.m.scrambled.items.splice((target.m.scrambled.items as { thing: string, inSlot: string }[]).findIndex(e =>
|
||||
this.toID(e.thing) === 'airballoon' && e.inSlot === isBMM), 1);
|
||||
if (isBMM === 'Ability') target.setAbility('No Ability');
|
||||
}
|
||||
}
|
||||
this.runEvent('AfterUseItem', target, null, null, this.dex.items.get('airballoon'));
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
425
data/mods/biomechmons/moves.ts
Normal file
425
data/mods/biomechmons/moves.ts
Normal file
|
|
@ -0,0 +1,425 @@
|
|||
export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
||||
// Remember, everything deals with SLOTS not with properties as they are!
|
||||
covet: {
|
||||
inherit: true,
|
||||
onAfterHit(target, source, move) {
|
||||
if (source.item || source.volatiles['gem']) {
|
||||
return;
|
||||
}
|
||||
const yourItem = target.takeItem(source);
|
||||
if (!yourItem) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
!this.singleEvent('TakeItem', yourItem, target.itemState, source, target, move, yourItem) ||
|
||||
!source.setItem(yourItem)
|
||||
) {
|
||||
if (!this.dex.items.get(yourItem.id).exists) {
|
||||
target.setItem(yourItem.id);
|
||||
return;
|
||||
}
|
||||
target.item = yourItem.id; // bypass setItem so we don't break choicelock or anything
|
||||
return;
|
||||
}
|
||||
this.add('-item', source, yourItem, '[from] move: Covet', `[of] ${target}`);
|
||||
},
|
||||
},
|
||||
embargo: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
duration: 5,
|
||||
onStart(pokemon) {
|
||||
this.add('-start', pokemon, 'Embargo');
|
||||
this.singleEvent('End', pokemon.getItem(), pokemon.itemState, pokemon);
|
||||
if (!this.dex.items.get(pokemon.item).exists) {
|
||||
const isAbil = (pokemon.m.scrambled.abilities as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
|
||||
if (isAbil >= 0) {
|
||||
pokemon.removeVolatile('ability:' + this.toID(pokemon.m.scrambled.abilities[isAbil].thing));
|
||||
} else if ((pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item') >= 0) {
|
||||
const isMove = (pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
|
||||
const slotNo = pokemon.moveSlots.findIndex(m => this.toID(pokemon.m.scrambled.moves[isMove].thing) === m.id);
|
||||
if (slotNo >= 0) pokemon.moveSlots.splice(slotNo, 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
// Item suppression implemented in Pokemon.ignoringItem() within sim/pokemon.js
|
||||
onResidualOrder: 21,
|
||||
onEnd(pokemon) {
|
||||
this.add('-end', pokemon, 'Embargo');
|
||||
if (!this.dex.items.get(pokemon.item).exists) {
|
||||
const isAbil = (pokemon.m.scrambled.abilities as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
|
||||
if (isAbil >= 0) {
|
||||
pokemon.addVolatile('ability:' + this.toID(pokemon.m.scrambled.abilities[isAbil].thing));
|
||||
} else if ((pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item') >= 0) {
|
||||
const findMove = (pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
|
||||
const findSlot = pokemon.baseMoveSlots.find(e => e.id === this.toID(pokemon.m.scrambled.moves[findMove].thing));
|
||||
pokemon.moveSlots.push(this.dex.deepClone(findSlot));
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
magicroom: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
duration: 5,
|
||||
durationCallback(source, effect) {
|
||||
if (source?.hasAbility('persistent')) {
|
||||
this.add('-activate', source, 'ability: Persistent', '[move] Magic Room');
|
||||
return 7;
|
||||
}
|
||||
return 5;
|
||||
},
|
||||
onFieldStart(target, source) {
|
||||
if (source?.hasAbility('persistent')) {
|
||||
this.add('-fieldstart', 'move: Magic Room', `[of] ${source}`, '[persistent]');
|
||||
} else {
|
||||
this.add('-fieldstart', 'move: Magic Room', `[of] ${source}`);
|
||||
}
|
||||
for (const mon of this.getAllActive()) {
|
||||
this.singleEvent('End', mon.getItem(), mon.itemState, mon);
|
||||
if (!this.dex.items.get(mon.item).exists) {
|
||||
const isAbil = (mon.m.scrambled.abilities as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
|
||||
if (isAbil >= 0) {
|
||||
mon.removeVolatile('ability:' + this.toID(mon.m.scrambled.abilities[isAbil].thing));
|
||||
} else if ((mon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item') >= 0) {
|
||||
const isMove = (mon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
|
||||
const slotNo = mon.moveSlots.findIndex(m => this.toID(mon.m.scrambled.moves[isMove].thing) === m.id);
|
||||
if (slotNo >= 0) mon.moveSlots.splice(slotNo, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onFieldRestart(target, source) {
|
||||
this.field.removePseudoWeather('magicroom');
|
||||
},
|
||||
// Item suppression implemented in Pokemon.ignoringItem() within sim/pokemon.js
|
||||
onFieldResidualOrder: 27,
|
||||
onFieldResidualSubOrder: 6,
|
||||
onFieldEnd() {
|
||||
this.add('-fieldend', 'move: Magic Room', '[of] ' + this.effectState.source);
|
||||
for (const pokemon of this.getAllActive()) {
|
||||
if (!this.dex.items.get(pokemon.item).exists) {
|
||||
const isAbil = (pokemon.m.scrambled.abilities as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
|
||||
if (isAbil >= 0) {
|
||||
pokemon.addVolatile('ability:' + this.toID(pokemon.m.scrambled.abilities[isAbil].thing));
|
||||
} else if ((pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item') >= 0) {
|
||||
const findMove = (pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
|
||||
const findSlot = pokemon.baseMoveSlots.find(e => e.id === this.toID(pokemon.m.scrambled.moves[findMove].thing));
|
||||
pokemon.moveSlots.push(this.dex.deepClone(findSlot));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
gastroacid: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
// Ability suppression implemented in Pokemon.ignoringAbility() within sim/pokemon.js
|
||||
onStart(pokemon) {
|
||||
this.add('-endability', pokemon);
|
||||
this.singleEvent('End', pokemon.getAbility(), pokemon.abilityState, pokemon, pokemon, 'gastroacid');
|
||||
if (!this.dex.abilities.get(pokemon.ability).exists) {
|
||||
const isItem = (pokemon.m.scrambled.items as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
|
||||
if (isItem >= 0) {
|
||||
pokemon.removeVolatile('item:' + this.toID(pokemon.m.scrambled.items[isItem].thing));
|
||||
} else if ((pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability') >= 0) {
|
||||
const isMove = (pokemon.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
|
||||
const slotNo = pokemon.moveSlots.findIndex(m => this.toID(pokemon.m.scrambled.moves[isMove].thing) === m.id);
|
||||
if (slotNo >= 0) pokemon.moveSlots.splice(slotNo, 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
trick: {
|
||||
inherit: true,
|
||||
onHit(target, source, move) {
|
||||
const yourItem = target.takeItem(source);
|
||||
const myItem = source.takeItem();
|
||||
if (target.item || source.item || (!yourItem && !myItem)) {
|
||||
if (yourItem) {
|
||||
if (!this.dex.items.get(yourItem.id).exists) {
|
||||
target.setItem(yourItem.id);
|
||||
} else {
|
||||
target.item = yourItem.id;
|
||||
}
|
||||
}
|
||||
if (myItem) {
|
||||
if (!this.dex.items.get(myItem.id).exists) {
|
||||
source.setItem(myItem.id);
|
||||
} else {
|
||||
source.item = myItem.id;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
(myItem && !this.singleEvent('TakeItem', myItem, source.itemState, target, source, move, myItem)) ||
|
||||
(yourItem && !this.singleEvent('TakeItem', yourItem, target.itemState, source, target, move, yourItem))
|
||||
) {
|
||||
if (yourItem) {
|
||||
if (!this.dex.items.get(yourItem.id).exists) {
|
||||
target.setItem(yourItem.id);
|
||||
} else {
|
||||
target.item = yourItem.id;
|
||||
}
|
||||
}
|
||||
if (myItem) {
|
||||
if (!this.dex.items.get(myItem.id).exists) {
|
||||
source.setItem(myItem.id);
|
||||
} else {
|
||||
source.item = myItem.id;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
this.add('-activate', source, 'move: Trick', `[of] ${target}`);
|
||||
if (myItem) {
|
||||
target.setItem(myItem);
|
||||
this.add('-item', target, myItem, '[from] move: Trick');
|
||||
} else {
|
||||
this.add('-enditem', target, yourItem, '[silent]', '[from] move: Trick');
|
||||
}
|
||||
if (yourItem) {
|
||||
source.setItem(yourItem);
|
||||
this.add('-item', source, yourItem, '[from] move: Trick');
|
||||
} else {
|
||||
this.add('-enditem', source, myItem, '[silent]', '[from] move: Trick');
|
||||
}
|
||||
},
|
||||
},
|
||||
sketch: {
|
||||
inherit: true,
|
||||
onHit(target, source) {
|
||||
const move = target.lastMove;
|
||||
if (source.transformed || !move || source.moves.includes(move.id)) return false;
|
||||
if (move.flags['nosketch'] || move.isZ || move.isMax) return false;
|
||||
const sketchIndex = source.moves.indexOf('sketch');
|
||||
if (sketchIndex < 0) return false;
|
||||
if (this.toID(source.item) === 'sketch') {
|
||||
source.setItem(move.name);
|
||||
this.add('-activate', source, 'move: Sketch', move.name);
|
||||
return;
|
||||
} else if (this.toID(source.ability) === 'sketch') {
|
||||
source.setAbility(move.name);
|
||||
this.add('-activate', source, 'move: Sketch', move.name);
|
||||
return;
|
||||
}
|
||||
const sketchedMove = {
|
||||
move: move.name,
|
||||
id: move.id,
|
||||
pp: move.pp,
|
||||
maxpp: move.pp,
|
||||
target: move.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
source.moveSlots[sketchIndex] = sketchedMove;
|
||||
source.baseMoveSlots[sketchIndex] = sketchedMove;
|
||||
this.add('-activate', source, 'move: Sketch', move.name);
|
||||
},
|
||||
},
|
||||
skillswap: {
|
||||
inherit: true,
|
||||
onTryHit(target, source) {
|
||||
const targetAbility = target.getAbility();
|
||||
const sourceAbility = source.getAbility();
|
||||
if (sourceAbility.flags['failskillswap'] || targetAbility.flags['failskillswap'] || target.volatiles['dynamax']) {
|
||||
return false;
|
||||
}
|
||||
let sourceCanBeSet = this.runEvent('SetAbility', source, source, this.effect, targetAbility);
|
||||
if (!this.dex.abilities.get(sourceAbility).exists && this.dex.items.get(sourceAbility.id).exists) {
|
||||
sourceCanBeSet = this.runEvent('TakeItem', source, source, this.effect, this.dex.items.get(sourceAbility.id));
|
||||
}
|
||||
|
||||
if (!sourceCanBeSet) return sourceCanBeSet;
|
||||
let targetCanBeSet = this.runEvent('SetAbility', target, source, this.effect, sourceAbility);
|
||||
if (!this.dex.abilities.get(targetAbility).exists && this.dex.items.get(targetAbility.id).exists) {
|
||||
targetCanBeSet = this.runEvent('TakeItem', target, source, this.effect, this.dex.items.get(targetAbility.id));
|
||||
}
|
||||
if (!targetCanBeSet) return targetCanBeSet;
|
||||
},
|
||||
onHit(target, source, move) {
|
||||
const targetAbility = target.getAbility();
|
||||
const sourceAbility = source.getAbility();
|
||||
const sourceIsBMM = !this.dex.abilities.get(sourceAbility).exists;
|
||||
const targetIsBMM = !this.dex.abilities.get(targetAbility).exists;
|
||||
if (target.isAlly(source)) {
|
||||
this.add('-activate', source, 'move: Skill Swap', '', '', `[of] ${target}`);
|
||||
} else {
|
||||
this.add('-activate', source, 'move: Skill Swap', targetAbility, sourceAbility, `[of] ${target}`);
|
||||
}
|
||||
this.singleEvent('End', sourceAbility, source.abilityState, source);
|
||||
if (sourceIsBMM) {
|
||||
const isItem = (source.m.scrambled.items as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
|
||||
if (isItem >= 0) {
|
||||
source.removeVolatile('item:' + this.toID(source.m.scrambled.items[isItem].thing));
|
||||
source.m.scrambled.items.splice(isItem, 1);
|
||||
} else if ((source.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability') >= 0) {
|
||||
const isMove = (source.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
|
||||
source.baseMoveSlots.splice(
|
||||
source.baseMoveSlots.findIndex(m => this.toID(source.m.scrambled.moves[isMove].thing) === m.id), 1);
|
||||
source.moveSlots.splice(source.moveSlots.findIndex(m => this.toID(source.m.scrambled.moves[isMove].thing) === m.id), 1);
|
||||
source.m.scrambled.moves.splice(isMove, 1);
|
||||
}
|
||||
}
|
||||
this.singleEvent('End', targetAbility, target.abilityState, target);
|
||||
if (targetIsBMM) {
|
||||
const isItem = (target.m.scrambled.items as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
|
||||
if (isItem >= 0) {
|
||||
target.removeVolatile('item:' + this.toID(target.m.scrambled.items[isItem].thing));
|
||||
target.m.scrambled.items.splice(isItem, 1);
|
||||
} else if ((target.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability') >= 0) {
|
||||
const isMove = (target.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
|
||||
target.baseMoveSlots.splice(
|
||||
target.baseMoveSlots.findIndex(m => this.toID(target.m.scrambled.moves[isMove].thing) === m.id), 1);
|
||||
target.moveSlots.splice(target.moveSlots.findIndex(m => this.toID(target.m.scrambled.moves[isMove].thing) === m.id), 1);
|
||||
target.m.scrambled.moves.splice(isMove, 1);
|
||||
}
|
||||
}
|
||||
|
||||
source.ability = source.baseAbility = targetAbility.id;
|
||||
target.ability = target.baseAbility = sourceAbility.id;
|
||||
source.abilityState = this.initEffectState({ id: this.toID(source.ability), target: source });
|
||||
target.abilityState = this.initEffectState({ id: this.toID(target.ability), target });
|
||||
|
||||
source.volatileStaleness = undefined;
|
||||
if (!target.isAlly(source)) target.volatileStaleness = 'external';
|
||||
|
||||
this.singleEvent('Start', targetAbility, source.abilityState, source);
|
||||
if (targetIsBMM) {
|
||||
if (this.dex.items.get(targetAbility.id).exists) {
|
||||
source.m.scrambled.items.push({ thing: targetAbility.id, inSlot: 'Ability' });
|
||||
const effect = 'item:' + this.toID(targetAbility.id);
|
||||
source.addVolatile(effect);
|
||||
source.volatiles[effect].inSlot = 'Ability';
|
||||
} else {
|
||||
source.m.scrambled.moves.push({ thing: targetAbility.id, inSlot: 'Ability' });
|
||||
const bmmMove = Dex.moves.get(targetAbility.id);
|
||||
const ppUps = move.noPPBoosts ? 0 : 3;
|
||||
const basePP = this.calculatePP(move, ppUps);
|
||||
const newMove = {
|
||||
move: bmmMove.name,
|
||||
id: bmmMove.id,
|
||||
pp: basePP,
|
||||
maxpp: basePP,
|
||||
target: bmmMove.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
source.baseMoveSlots.push(newMove);
|
||||
source.moveSlots.push(newMove);
|
||||
source.ppUps.push(ppUps);
|
||||
}
|
||||
}
|
||||
this.singleEvent('Start', sourceAbility, target.abilityState, target);
|
||||
if (sourceIsBMM) {
|
||||
if (this.dex.items.get(sourceAbility.id).exists) {
|
||||
target.m.scrambled.items.push({ thing: sourceAbility.id, inSlot: 'Ability' });
|
||||
const effect = 'item:' + this.toID(sourceAbility.id);
|
||||
target.addVolatile(effect);
|
||||
target.volatiles[effect].inSlot = 'Ability';
|
||||
} else {
|
||||
target.m.scrambled.moves.push({ thing: sourceAbility.id, inSlot: 'Ability' });
|
||||
const bmmMove = Dex.moves.get(sourceAbility.id);
|
||||
const ppUps = move.noPPBoosts ? 0 : 3;
|
||||
const basePP = this.calculatePP(move, ppUps);
|
||||
const newMove = {
|
||||
move: bmmMove.name,
|
||||
id: bmmMove.id,
|
||||
pp: basePP,
|
||||
maxpp: basePP,
|
||||
target: bmmMove.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
target.baseMoveSlots.push(newMove);
|
||||
target.moveSlots.push(newMove);
|
||||
target.ppUps.push(ppUps);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
switcheroo: {
|
||||
inherit: true,
|
||||
onHit(target, source, move) {
|
||||
const yourItem = target.takeItem(source);
|
||||
const myItem = source.takeItem();
|
||||
if (target.item || source.item || (!yourItem && !myItem)) {
|
||||
if (yourItem) {
|
||||
if (!this.dex.items.get(yourItem.id).exists) {
|
||||
target.setItem(yourItem.id);
|
||||
} else {
|
||||
target.item = yourItem.id;
|
||||
}
|
||||
}
|
||||
if (myItem) {
|
||||
if (!this.dex.items.get(myItem.id).exists) {
|
||||
source.setItem(myItem.id);
|
||||
} else {
|
||||
source.item = myItem.id;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
(myItem && !this.singleEvent('TakeItem', myItem, source.itemState, target, source, move, myItem)) ||
|
||||
(yourItem && !this.singleEvent('TakeItem', yourItem, target.itemState, source, target, move, yourItem))
|
||||
) {
|
||||
if (yourItem) {
|
||||
if (!this.dex.items.get(yourItem.id).exists) {
|
||||
target.setItem(yourItem.id);
|
||||
} else {
|
||||
target.item = yourItem.id;
|
||||
}
|
||||
}
|
||||
if (myItem) {
|
||||
if (!this.dex.items.get(myItem.id).exists) {
|
||||
source.setItem(myItem.id);
|
||||
} else {
|
||||
source.item = myItem.id;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
this.add('-activate', source, 'move: Trick', `[of] ${target}`);
|
||||
if (myItem) {
|
||||
target.setItem(myItem);
|
||||
this.add('-item', target, myItem, '[from] move: Switcheroo');
|
||||
} else {
|
||||
this.add('-enditem', target, yourItem, '[silent]', '[from] move: Switcheroo');
|
||||
}
|
||||
if (yourItem) {
|
||||
source.setItem(yourItem);
|
||||
this.add('-item', source, yourItem, '[from] move: Switcheroo');
|
||||
} else {
|
||||
this.add('-enditem', source, myItem, '[silent]', '[from] move: Switcheroo');
|
||||
}
|
||||
},
|
||||
},
|
||||
thief: {
|
||||
inherit: true,
|
||||
onAfterHit(target, source, move) {
|
||||
if (source.item || source.volatiles['gem']) {
|
||||
return;
|
||||
}
|
||||
const yourItem = target.takeItem(source);
|
||||
if (!yourItem) {
|
||||
return;
|
||||
}
|
||||
if (!this.singleEvent('TakeItem', yourItem, target.itemState, source, target, move, yourItem) ||
|
||||
!source.setItem(yourItem)) {
|
||||
if (!this.dex.items.get(yourItem.id).exists) {
|
||||
target.setItem(yourItem.id);
|
||||
return;
|
||||
}
|
||||
target.item = yourItem.id; // bypass setItem so we don't break choicelock or anything
|
||||
return;
|
||||
}
|
||||
this.add('-enditem', target, yourItem, '[silent]', '[from] move: Thief', `[of] ${source}`);
|
||||
this.add('-item', source, yourItem, '[from] move: Thief', `[of] ${target}`);
|
||||
},
|
||||
},
|
||||
};
|
||||
591
data/mods/biomechmons/scripts.ts
Normal file
591
data/mods/biomechmons/scripts.ts
Normal file
|
|
@ -0,0 +1,591 @@
|
|||
import { RESTORATIVE_BERRIES } from "../../../sim/pokemon";
|
||||
|
||||
export const Scripts: ModdedBattleScriptsData = {
|
||||
pokemon: {
|
||||
isGrounded(negateImmunity) {
|
||||
if ('gravity' in this.battle.field.pseudoWeather) return true;
|
||||
if ('ingrain' in this.volatiles && this.battle.gen >= 4) return true;
|
||||
if ('smackdown' in this.volatiles) return true;
|
||||
const item = (this.ignoringItem() ? '' : this.item);
|
||||
if (item === 'ironball' || (this.volatiles['item:ironball'] && !this.ignoringItem())) return true;
|
||||
// If a Fire/Flying type uses Burn Up and Roost, it becomes ???/Flying-type, but it's still grounded.
|
||||
if (!negateImmunity && this.hasType('Flying') && !(this.hasType('???') && 'roost' in this.volatiles)) return false;
|
||||
if (this.hasAbility('levitate') && !this.battle.suppressingAbility(this)) return null;
|
||||
if ('magnetrise' in this.volatiles) return false;
|
||||
if ('telekinesis' in this.volatiles) return false;
|
||||
if (item === 'airballoon' || (this.volatiles['item:airballoon'] && !this.ignoringItem())) return false;
|
||||
return true;
|
||||
},
|
||||
getAbility() {
|
||||
const ability = this.battle.dex.abilities.getByID(this.ability);
|
||||
if (ability.exists) return ability;
|
||||
let abil = this.battle.dex.items.getByID(this.ability) as Item | Move;
|
||||
if (!abil.exists) abil = this.battle.dex.moves.getByID(this.ability);
|
||||
return {
|
||||
id: this.ability,
|
||||
name: abil.name || this.ability,
|
||||
flags: {},
|
||||
effectType: "Ability",
|
||||
toString() {
|
||||
return abil.name || this.id;
|
||||
},
|
||||
} as Ability;
|
||||
},
|
||||
hasAbility(ability) {
|
||||
if (this.ignoringAbility()) return false;
|
||||
if (Array.isArray(ability)) return ability.some(abil => this.hasAbility(abil));
|
||||
const abilityid = this.battle.toID(ability);
|
||||
return this.ability === abilityid || !!this.volatiles['ability:' + abilityid];
|
||||
},
|
||||
ignoringAbility() {
|
||||
// Check if any active pokemon have the ability Neutralizing Gas
|
||||
let neutralizinggas = false;
|
||||
for (const pokemon of this.battle.getAllActive()) {
|
||||
// can't use hasAbility because it would lead to infinite recursion
|
||||
if (
|
||||
(pokemon.ability === ('neutralizinggas' as ID) ||
|
||||
(pokemon.m.scrambled.abilities as { thing: string }[]).some(
|
||||
abils => this.battle.toID(abils.thing) === 'neutralizinggas')) &&
|
||||
!pokemon.volatiles['gastroacid'] && !pokemon.abilityState.ending
|
||||
) {
|
||||
neutralizinggas = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return !!(
|
||||
(this.battle.gen >= 5 && !this.isActive) ||
|
||||
((this.volatiles['gastroacid'] ||
|
||||
(neutralizinggas && (this.ability !== ('neutralizinggas' as ID) ||
|
||||
(this.m.scrambled.abilities as { thing: string }[]).some(abils => this.battle.toID(abils.thing) === 'neutralizinggas'))
|
||||
)) && !this.getAbility().flags['cantsuppress']
|
||||
)
|
||||
);
|
||||
},
|
||||
setAbility(ability, source, sourceEffect, isFromFormeChange = false, isTransform = false) {
|
||||
const allThings = new Set([
|
||||
...(this.m.scrambled.abilities as { thing: string }[]).map(e => e.thing),
|
||||
...(this.m.scrambled.items as { thing: string }[]).map(e => e.thing),
|
||||
...(this.m.scrambled.moves as { thing: string }[]).map(e => e.thing),
|
||||
this.ability, ...this.moveSlots.map(e => e.move), this.item,
|
||||
].map(this.battle.toID));
|
||||
|
||||
let isBMMAbil = false;
|
||||
let isOldBMMAbil = false;
|
||||
if (!this.hp) return false;
|
||||
if (typeof ability === 'string') {
|
||||
if (this.battle.dex.abilities.get(ability).exists) {
|
||||
ability = this.battle.dex.abilities.get(ability);
|
||||
} else {
|
||||
const abilString = ability;
|
||||
let abil = this.battle.dex.items.get(abilString) as Item | Move;
|
||||
if (!abil.exists) abil = this.battle.dex.moves.get(abilString);
|
||||
ability = {
|
||||
id: abil.id || abilString,
|
||||
name: abil.name || abilString,
|
||||
flags: {},
|
||||
effectType: "Ability",
|
||||
toString() {
|
||||
return abil.name || abilString;
|
||||
},
|
||||
} as Ability;
|
||||
}
|
||||
}
|
||||
if (ability.name.length && !this.battle.dex.abilities.get(ability).exists) isBMMAbil = true;
|
||||
if (!sourceEffect && this.battle.effect) sourceEffect = this.battle.effect;
|
||||
let oldAbility;
|
||||
if (this.battle.dex.abilities.get(this.ability).exists) {
|
||||
oldAbility = this.battle.dex.abilities.get(this.ability);
|
||||
} else {
|
||||
let abil = this.battle.dex.items.getByID(this.ability) as Item | Move;
|
||||
if (!abil.exists) {
|
||||
abil = this.battle.dex.moves.getByID(this.ability);
|
||||
} else {
|
||||
if (!this.battle.runEvent('TakeItem', this, source, null, abil as Item)) return false;
|
||||
}
|
||||
oldAbility = {
|
||||
id: this.ability,
|
||||
name: abil.name || this.ability,
|
||||
flags: {},
|
||||
effectType: "Ability",
|
||||
toString() {
|
||||
return abil.name || this.id;
|
||||
},
|
||||
} as Ability;
|
||||
isOldBMMAbil = true;
|
||||
}
|
||||
|
||||
if (allThings.has(ability.id)) return false;
|
||||
|
||||
if (!isFromFormeChange) {
|
||||
if (ability.flags['cantsuppress'] || this.getAbility().flags['cantsuppress']) return false;
|
||||
}
|
||||
if (!isFromFormeChange && !isTransform) {
|
||||
const setAbilityEvent: boolean | null = this.battle.runEvent('SetAbility', this, source, sourceEffect, ability);
|
||||
if (!setAbilityEvent) return setAbilityEvent;
|
||||
}
|
||||
this.battle.singleEvent('End', oldAbility, this.abilityState, this, source);
|
||||
if (isOldBMMAbil) {
|
||||
const isItem = (this.m.scrambled.items as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
|
||||
if (isItem >= 0) {
|
||||
this.removeVolatile('item:' + this.battle.toID(this.m.scrambled.items[isItem].thing));
|
||||
this.m.scrambled.items.splice(isItem, 1);
|
||||
} else if ((this.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability') >= 0) {
|
||||
const isMove = (this.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Ability');
|
||||
if (!isTransform) {
|
||||
let indexOfMove = this.baseMoveSlots.findIndex(m => this.battle.toID(this.m.scrambled.moves[isMove].thing) === m.id);
|
||||
if (indexOfMove >= 0) this.baseMoveSlots.splice(indexOfMove, 1);
|
||||
if (oldAbility.id !== 'mimic') {
|
||||
indexOfMove = this.moveSlots.findIndex(m => this.battle.toID(this.m.scrambled.moves[isMove].thing) === m.id);
|
||||
}
|
||||
if (indexOfMove >= 0) this.moveSlots.splice(indexOfMove, 1);
|
||||
}
|
||||
this.m.scrambled.moves.splice(isMove, 1);
|
||||
}
|
||||
}
|
||||
this.ability = ability.id;
|
||||
// ability changes are permanent in BioMechMons
|
||||
if (!isTransform && !this.transformed) this.baseAbility = ability.id;
|
||||
this.abilityState = this.battle.initEffectState({ id: ability.id, target: this });
|
||||
if (sourceEffect && !isFromFormeChange && !isTransform) {
|
||||
if (source) {
|
||||
this.battle.add('-ability', this, ability.name, oldAbility.name, `[from] ${sourceEffect.fullname}`, `[of] ${source}`);
|
||||
} else {
|
||||
this.battle.add('-ability', this, ability.name, oldAbility.name, `[from] ${sourceEffect.fullname}`);
|
||||
}
|
||||
}
|
||||
if (ability.id && this.battle.gen > 3 &&
|
||||
(!isTransform || oldAbility.id !== ability.id || this.battle.gen <= 4)) {
|
||||
this.battle.singleEvent('Start', ability, this.abilityState, this, source);
|
||||
}
|
||||
if (isBMMAbil) {
|
||||
if (this.battle.dex.items.get(ability.id).exists) {
|
||||
this.m.scrambled.items.push({ thing: ability.id, inSlot: 'Ability' });
|
||||
const effect = 'item:' + this.battle.toID(ability.id);
|
||||
this.addVolatile(effect);
|
||||
this.volatiles[effect].inSlot = 'Ability';
|
||||
} else {
|
||||
this.m.scrambled.moves.push({ thing: ability.id, inSlot: 'Ability' });
|
||||
const move = Dex.moves.get(ability.id);
|
||||
const ppUps = move.noPPBoosts ? 0 : 3;
|
||||
const basePP = this.battle.calculatePP(move, ppUps);
|
||||
const newMove = {
|
||||
move: move.name,
|
||||
id: move.id,
|
||||
pp: basePP,
|
||||
maxpp: basePP,
|
||||
target: move.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
if (!isTransform) {
|
||||
this.baseMoveSlots.push(newMove);
|
||||
this.moveSlots.push(newMove);
|
||||
this.ppUps.push(ppUps);
|
||||
}
|
||||
}
|
||||
}
|
||||
return oldAbility.id;
|
||||
},
|
||||
getItem() {
|
||||
const item = this.battle.dex.items.getByID(this.item);
|
||||
if (item.exists) return item;
|
||||
let bmmItem = this.battle.dex.abilities.getByID(this.item) as Ability | Move;
|
||||
if (!bmmItem.exists) bmmItem = this.battle.dex.moves.getByID(this.item);
|
||||
return {
|
||||
id: this.item,
|
||||
name: bmmItem.name || this.name,
|
||||
effectType: "Item",
|
||||
toString() {
|
||||
return bmmItem.name || this.id;
|
||||
},
|
||||
} as Item;
|
||||
},
|
||||
hasItem(item) {
|
||||
if (this.ignoringItem()) return false;
|
||||
if (Array.isArray(item)) return item.some(i => this.hasItem(i));
|
||||
const itemId = this.battle.toID(item);
|
||||
return this.item === itemId || !!this.volatiles['item:' + itemId];
|
||||
},
|
||||
takeItem(source) {
|
||||
if (!this.item) return false;
|
||||
if (!source) source = this;
|
||||
if (this.battle.gen <= 4) {
|
||||
if (source.itemKnockedOff) return false;
|
||||
if (this.battle.toID(this.ability) === 'multitype' || (this.m.scrambled.abilities as { thing: string }[])
|
||||
.findIndex(e => this.battle.toID(e.thing) === 'multitype') >= 0) {
|
||||
return false;
|
||||
}
|
||||
if (this.battle.toID(source.ability) === 'multitype' || (source.m.scrambled.abilities as { thing: string }[])
|
||||
.findIndex(e => this.battle.toID(e.thing) === 'multitype') >= 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const item = this.getItem();
|
||||
if (this.battle.runEvent('TakeItem', this, source, null, item)) {
|
||||
this.item = '';
|
||||
let wrongSlot = (this.m.scrambled.abilities as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
|
||||
if (wrongSlot >= 0) {
|
||||
const dexAbil = this.battle.dex.abilities.get(this.m.scrambled.abilities[wrongSlot].thing);
|
||||
if (dexAbil.flags['failskillswap']) return false;
|
||||
this.removeVolatile('ability:' + this.battle.toID(this.m.scrambled.abilities[wrongSlot].thing));
|
||||
this.m.scrambled.abilities.splice(wrongSlot, 1);
|
||||
} else if ((this.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item') >= 0) {
|
||||
wrongSlot = (this.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
|
||||
let indexOfMove = this.baseMoveSlots.findIndex(m => this.battle.toID(this.m.scrambled.moves[wrongSlot].thing) === m.id);
|
||||
if (indexOfMove >= 0) this.baseMoveSlots.splice(indexOfMove, 1);
|
||||
if (item.id !== 'mimic') {
|
||||
indexOfMove = this.moveSlots.findIndex(m => this.battle.toID(this.m.scrambled.moves[wrongSlot].thing) === m.id);
|
||||
}
|
||||
if (indexOfMove >= 0) this.moveSlots.splice(indexOfMove, 1);
|
||||
this.m.scrambled.moves.splice(wrongSlot, 1);
|
||||
}
|
||||
const oldItemState = this.itemState;
|
||||
this.battle.clearEffectState(this.itemState);
|
||||
this.pendingStaleness = undefined;
|
||||
this.battle.singleEvent('End', item, oldItemState, this);
|
||||
this.battle.runEvent('AfterTakeItem', this, null, null, item);
|
||||
return item;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
setItem(item, source, effect) {
|
||||
const allThings = new Set([
|
||||
...(this.m.scrambled.abilities as { thing: string }[]).map(e => e.thing),
|
||||
...(this.m.scrambled.items as { thing: string }[]).map(e => e.thing),
|
||||
...(this.m.scrambled.moves as { thing: string }[]).map(e => e.thing),
|
||||
this.ability, ...this.moveSlots.map(e => e.move), this.item,
|
||||
].map(this.battle.toID));
|
||||
|
||||
let isBMMItem = false;
|
||||
let isOldBMMItem = false;
|
||||
if (!this.hp || !this.isActive) return false;
|
||||
if (typeof item === 'string') {
|
||||
if (!item.length || this.battle.dex.items.get(item).exists) {
|
||||
item = this.battle.dex.items.get(item);
|
||||
} else {
|
||||
const itemString = item;
|
||||
let newData = this.battle.dex.abilities.get(itemString) as Ability | Move;
|
||||
if (!newData.exists) {
|
||||
newData = this.battle.dex.moves.get(itemString);
|
||||
} else {
|
||||
if ((newData as Ability).flags['failskillswap']) return false;
|
||||
}
|
||||
item = {
|
||||
id: newData.id || itemString,
|
||||
name: newData.name || itemString,
|
||||
effectType: "Item",
|
||||
toString() {
|
||||
return newData.name || itemString;
|
||||
},
|
||||
} as Item;
|
||||
}
|
||||
}
|
||||
if (item.name.length && !this.battle.dex.items.get(item).exists) isBMMItem = true;
|
||||
if (allThings.has(item.id)) return false;
|
||||
const effectid = this.battle.effect ? this.battle.effect.id : '';
|
||||
if (RESTORATIVE_BERRIES.has('leppaberry' as ID)) {
|
||||
const inflicted = ['trick', 'switcheroo'].includes(effectid);
|
||||
const external = inflicted && source && !source.isAlly(this);
|
||||
this.pendingStaleness = external ? 'external' : 'internal';
|
||||
} else {
|
||||
this.pendingStaleness = undefined;
|
||||
}
|
||||
const oldItem = this.getItem();
|
||||
if (!this.battle.dex.items.get(oldItem).exists) isOldBMMItem = true;
|
||||
const oldItemState = this.itemState;
|
||||
this.item = item.id;
|
||||
this.itemState = this.battle.initEffectState({ id: item.id, target: this });
|
||||
if (oldItem.exists) this.battle.singleEvent('End', oldItem, oldItemState, this);
|
||||
if (isOldBMMItem) {
|
||||
const isAbil = (this.m.scrambled.abilities as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
|
||||
if (isAbil >= 0) {
|
||||
this.removeVolatile('ability:' + this.battle.toID(this.m.scrambled.items[isAbil].thing));
|
||||
this.m.scrambled.abilities.splice(isAbil, 1);
|
||||
} else if ((this.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item') >= 0) {
|
||||
const isMove = (this.m.scrambled.moves as { inSlot: string }[]).findIndex(e => e.inSlot === 'Item');
|
||||
let indexOfMove = this.baseMoveSlots.findIndex(m => this.battle.toID(this.m.scrambled.moves[isMove].thing) === m.id);
|
||||
if (indexOfMove >= 0) this.baseMoveSlots.splice(indexOfMove, 1);
|
||||
if (oldItem.id !== 'mimic') {
|
||||
indexOfMove = this.moveSlots.findIndex(m => this.battle.toID(this.m.scrambled.moves[isMove].thing) === m.id);
|
||||
}
|
||||
if (indexOfMove >= 0) this.moveSlots.splice(indexOfMove, 1);
|
||||
this.m.scrambled.moves.splice(isMove, 1);
|
||||
}
|
||||
}
|
||||
if (item.id) {
|
||||
this.battle.singleEvent('Start', item, this.itemState, this, source, effect);
|
||||
}
|
||||
if (isBMMItem) {
|
||||
if (this.battle.dex.abilities.get(item.id).exists) {
|
||||
this.m.scrambled.abilities.push({ thing: item.id, inSlot: 'Item' });
|
||||
const abileffect = 'ability:' + this.battle.toID(item.id);
|
||||
this.addVolatile(abileffect);
|
||||
this.volatiles[abileffect].inSlot = 'Item';
|
||||
} else {
|
||||
this.m.scrambled.moves.push({ thing: item.id, inSlot: 'Item' });
|
||||
const move = Dex.moves.get(item.id);
|
||||
const ppUps = move.noPPBoosts ? 0 : 3;
|
||||
const basePP = this.battle.calculatePP(move, ppUps);
|
||||
const newMove = {
|
||||
move: move.name,
|
||||
id: move.id,
|
||||
pp: basePP,
|
||||
maxpp: basePP,
|
||||
target: move.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
this.baseMoveSlots.push(newMove);
|
||||
this.moveSlots.push(newMove);
|
||||
this.ppUps.push(ppUps);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
eatItem(force, source, sourceEffect) {
|
||||
const item = sourceEffect?.effectType === 'Item' ? sourceEffect :
|
||||
this.battle.effect.effectType === 'Item' ? this.battle.effect : this.getItem();
|
||||
if (!item) return false;
|
||||
if ((!this.hp && this.battle.toID(item.name) !== 'jabocaberry' && this.battle.toID(item.name) !== 'rowapberry') ||
|
||||
!this.isActive) return false;
|
||||
|
||||
if (!sourceEffect && this.battle.effect) sourceEffect = this.battle.effect;
|
||||
if (!source && this.battle.event?.target) source = this.battle.event.target;
|
||||
// if (sourceEffect?.effectType === 'Item' && this.item !== sourceEffect.id && source === this) {
|
||||
// // if an item is telling us to eat it but we aren't holding it, we probably shouldn't eat what we are holding
|
||||
// return false;
|
||||
// }
|
||||
if (
|
||||
this.battle.runEvent('UseItem', this, null, null, Dex.items.get(item.name)) &&
|
||||
(force || this.battle.runEvent('TryEatItem', this, null, null, Dex.items.get(item.name)))
|
||||
) {
|
||||
this.battle.add('-enditem', this, Dex.items.get(item.name), '[eat]');
|
||||
|
||||
this.battle.singleEvent('Eat', Dex.items.get(item.name), this.itemState, this, source, sourceEffect);
|
||||
this.battle.runEvent('EatItem', this, source, sourceEffect, Dex.items.get(item.name));
|
||||
|
||||
if (RESTORATIVE_BERRIES.has(item.id)) {
|
||||
switch (this.pendingStaleness) {
|
||||
case 'internal':
|
||||
if (this.staleness !== 'external') this.staleness = 'internal';
|
||||
break;
|
||||
case 'external':
|
||||
this.staleness = 'external';
|
||||
break;
|
||||
}
|
||||
this.pendingStaleness = undefined;
|
||||
}
|
||||
|
||||
const isBMM = this.volatiles[item.id]?.inSlot;
|
||||
if (isBMM) {
|
||||
const dexItem = this.battle.dex.items.get(item.name);
|
||||
this.removeVolatile(item.id);
|
||||
const itemIndex = (this.m.scrambled.items as { thing: string, inSlot: string }[]).findIndex(e =>
|
||||
this.battle.toID(e.thing) === dexItem.id && e.inSlot === isBMM);
|
||||
if (itemIndex >= 0) this.m.scrambled.items.splice(itemIndex, 1);
|
||||
if (isBMM === 'Ability') this.setAbility('No Ability');
|
||||
} else {
|
||||
this.lastItem = this.item;
|
||||
this.item = '';
|
||||
}
|
||||
this.battle.clearEffectState(this.itemState);
|
||||
this.usedItemThisTurn = true;
|
||||
this.ateBerry = true;
|
||||
this.battle.runEvent('AfterUseItem', this, null, null, Dex.items.get(item.name));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
useItem(source, sourceEffect) {
|
||||
const item = sourceEffect?.effectType === 'Item' ? sourceEffect :
|
||||
this.battle.effect.effectType === 'Item' ? this.battle.effect : this.getItem();
|
||||
if ((!this.hp && !item.isGem) || !this.isActive) return false;
|
||||
if (!item) return false;
|
||||
|
||||
if (!sourceEffect && this.battle.effect) sourceEffect = this.battle.effect;
|
||||
if (!source && this.battle.event?.target) source = this.battle.event.target;
|
||||
// const item = this.getItem();
|
||||
// if (sourceEffect?.effectType === 'Item' && this.item !== sourceEffect.id && source === this) {
|
||||
// // if an item is telling us to eat it but we aren't holding it, we probably shouldn't eat what we are holding
|
||||
// return false;
|
||||
// }
|
||||
if (this.battle.runEvent('UseItem', this, null, null, Dex.items.get(item.name))) {
|
||||
switch (item.id) {
|
||||
case 'redcard':
|
||||
this.battle.add('-enditem', this, Dex.items.get(item.name), `[of] ${source}`);
|
||||
break;
|
||||
default:
|
||||
if (item.isGem) {
|
||||
this.battle.add('-enditem', this, Dex.items.get(item.name), '[from] gem');
|
||||
} else {
|
||||
this.battle.add('-enditem', this, Dex.items.get(item.name));
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (item.boosts) {
|
||||
this.battle.boost(item.boosts, this, source, Dex.items.get(item.name));
|
||||
}
|
||||
|
||||
this.battle.singleEvent('Use', Dex.items.get(item.name), this.itemState, this, source, sourceEffect);
|
||||
|
||||
const isBMM = this.volatiles[item.id]?.inSlot;
|
||||
if (isBMM) {
|
||||
const dexItem = this.battle.dex.items.get(item.name);
|
||||
this.removeVolatile(item.id);
|
||||
const itemIndex = (this.m.scrambled.items as { thing: string, inSlot: string }[]).findIndex(e =>
|
||||
this.battle.toID(e.thing) === dexItem.id && e.inSlot === isBMM);
|
||||
if (itemIndex >= 0) this.m.scrambled.items.splice(itemIndex, 1);
|
||||
if (isBMM === 'Ability') this.setAbility('No Ability');
|
||||
} else {
|
||||
this.lastItem = this.item;
|
||||
this.item = '';
|
||||
}
|
||||
this.battle.clearEffectState(this.itemState);
|
||||
this.usedItemThisTurn = true;
|
||||
this.battle.runEvent('AfterUseItem', this, null, null, item);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
transformInto(pokemon, effect) {
|
||||
const species = pokemon.species;
|
||||
if (
|
||||
pokemon.fainted || this.illusion || pokemon.illusion || (pokemon.volatiles['substitute'] && this.battle.gen >= 5) ||
|
||||
(pokemon.transformed && this.battle.gen >= 2) || (this.transformed && this.battle.gen >= 5) ||
|
||||
species.name === 'Eternatus-Eternamax' ||
|
||||
(['Ogerpon', 'Terapagos'].includes(species.baseSpecies) && (this.terastallized || pokemon.terastallized)) ||
|
||||
this.terastallized === 'Stellar'
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.battle.dex.currentMod === 'gen1stadium' && (
|
||||
species.name === 'Ditto' ||
|
||||
(this.species.name === 'Ditto' && pokemon.moves.includes('transform'))
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.setSpecies(species, effect, true)) return false;
|
||||
|
||||
this.transformed = true;
|
||||
this.weighthg = pokemon.weighthg;
|
||||
|
||||
const types = pokemon.getTypes(true, true);
|
||||
this.setType(pokemon.volatiles['roost'] ? pokemon.volatiles['roost'].typeWas : types, true);
|
||||
this.addedType = pokemon.addedType;
|
||||
this.knownType = this.isAlly(pokemon) && pokemon.knownType;
|
||||
this.apparentType = pokemon.apparentType;
|
||||
|
||||
let statName: StatIDExceptHP;
|
||||
for (statName in this.storedStats) {
|
||||
this.storedStats[statName] = pokemon.storedStats[statName];
|
||||
if (this.modifiedStats) this.modifiedStats[statName] = pokemon.modifiedStats![statName]; // Gen 1: Copy modified stats.
|
||||
}
|
||||
this.moveSlots = [];
|
||||
this.hpType = (this.battle.gen >= 5 ? this.hpType : pokemon.hpType);
|
||||
this.hpPower = (this.battle.gen >= 5 ? this.hpPower : pokemon.hpPower);
|
||||
this.timesAttacked = pokemon.timesAttacked;
|
||||
for (const [i, moveSlot] of pokemon.moveSlots.entries()) {
|
||||
let moveName = moveSlot.move;
|
||||
if (moveSlot.id === 'hiddenpower') {
|
||||
moveName = 'Hidden Power ' + this.hpType;
|
||||
}
|
||||
const move = this.battle.dex.moves.get(moveSlot.id);
|
||||
this.moveSlots.push({
|
||||
move: moveName,
|
||||
id: moveSlot.id,
|
||||
pp: Math.min(5, move.pp),
|
||||
maxpp: this.battle.gen >= 5 ? Math.min(5, move.pp) : moveSlot.maxpp,
|
||||
target: moveSlot.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
virtual: true,
|
||||
});
|
||||
}
|
||||
let boostName: BoostID;
|
||||
for (boostName in pokemon.boosts) {
|
||||
this.boosts[boostName] = pokemon.boosts[boostName];
|
||||
}
|
||||
if (this.battle.gen >= 6) {
|
||||
// we need to remove all of the overlapping crit volatiles before adding any of them
|
||||
const volatilesToCopy = ['dragoncheer', 'focusenergy', 'gmaxchistrike', 'laserfocus'];
|
||||
for (const volatile of volatilesToCopy) this.removeVolatile(volatile);
|
||||
for (const volatile of volatilesToCopy) {
|
||||
if (pokemon.volatiles[volatile]) {
|
||||
this.addVolatile(volatile);
|
||||
if (volatile === 'gmaxchistrike') this.volatiles[volatile].layers = pokemon.volatiles[volatile].layers;
|
||||
if (volatile === 'dragoncheer') this.volatiles[volatile].hasDragonType = pokemon.volatiles[volatile].hasDragonType;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (effect) {
|
||||
this.battle.add('-transform', this, pokemon, '[from] ' + effect.fullname);
|
||||
} else {
|
||||
this.battle.add('-transform', this, pokemon);
|
||||
}
|
||||
if (this.terastallized) {
|
||||
this.knownType = true;
|
||||
this.apparentType = this.terastallized;
|
||||
}
|
||||
if (this.battle.gen > 2) this.setAbility(pokemon.ability, this, null, true, true);
|
||||
|
||||
// Change formes based on held items (for Transform)
|
||||
// Only ever relevant in Generation 4 since Generation 3 didn't have item-based forme changes
|
||||
if (this.battle.gen === 4) {
|
||||
if (this.species.num === 487) {
|
||||
// Giratina formes
|
||||
if (this.species.name === 'Giratina' && this.item === 'griseousorb') {
|
||||
this.formeChange('Giratina-Origin');
|
||||
} else if (this.species.name === 'Giratina-Origin' && this.item !== 'griseousorb') {
|
||||
this.formeChange('Giratina');
|
||||
}
|
||||
}
|
||||
if (this.species.num === 493) {
|
||||
// Arceus formes
|
||||
const item = this.getItem();
|
||||
const targetForme = (item?.onPlate ? 'Arceus-' + item.onPlate : 'Arceus');
|
||||
if (this.species.name !== targetForme) {
|
||||
this.formeChange(targetForme);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pokemon transformed into Ogerpon cannot Terastallize
|
||||
// restoring their ability to tera after they untransform is handled ELSEWHERE
|
||||
if (['Ogerpon', 'Terapagos'].includes(this.species.baseSpecies) && this.canTerastallize) this.canTerastallize = false;
|
||||
|
||||
for (const volatile in this.volatiles) {
|
||||
if (this.volatiles[volatile].inSlot && this.volatiles[volatile].inSlot === 'Move') {
|
||||
this.removeVolatile(volatile);
|
||||
}
|
||||
}
|
||||
|
||||
for (const volatile in pokemon.volatiles) {
|
||||
if (pokemon.volatiles[volatile].inSlot && pokemon.volatiles[volatile].inSlot === 'Move') {
|
||||
this.addVolatile(volatile);
|
||||
this.volatiles[volatile].inSlot = 'Move';
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
},
|
||||
field: {
|
||||
suppressingWeather() {
|
||||
for (const pokemon of this.battle.getAllActive()) {
|
||||
const innates = Object.keys(pokemon.volatiles).filter(x => x.startsWith('ability:'));
|
||||
if (pokemon && !pokemon.ignoringAbility() &&
|
||||
(pokemon.getAbility().suppressWeather || innates.some(x => (
|
||||
this.battle.dex.abilities.get(x.replace('ability:', '')).suppressWeather
|
||||
)))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
},
|
||||
};
|
||||
1388
data/mods/ccapm2025/abilities.ts
Normal file
1388
data/mods/ccapm2025/abilities.ts
Normal file
File diff suppressed because it is too large
Load Diff
178
data/mods/ccapm2025/conditions.ts
Normal file
178
data/mods/ccapm2025/conditions.ts
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDataTable = {
|
||||
snowscape: {
|
||||
inherit: true,
|
||||
onFieldEnd() {
|
||||
this.add('-weather', 'none');
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
for (const pokemon of this.getAllActive()) {
|
||||
if (pokemon.species.id === 'wyrdeer') {
|
||||
pokemon.formeChange('Wyrdeer-Snowblind', this.effect, true);
|
||||
this.add('-activate', pokemon, 'ability: Heart of Cold');
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
ber: {
|
||||
name: 'ber',
|
||||
effectType: 'Status',
|
||||
onStart(target, source, sourceEffect) {
|
||||
this.add('-start', target, 'Berserk');
|
||||
this.effectState.counter = 0;
|
||||
if (sourceEffect && sourceEffect.effectType === 'Ability') {
|
||||
this.add('-activate', target, 'ber', '[from] ability: ' + sourceEffect.name, `[of] ${source}`);
|
||||
} else {
|
||||
this.add('-activate', target, 'ber');
|
||||
}
|
||||
if (target.species.name === 'Drifblim') {
|
||||
target.formeChange('Drifblim-Inflamed', this.effect, false);
|
||||
}
|
||||
for (const opponent of target.side.foe.active) {
|
||||
const active = opponent.side.foe.active.filter(mon => mon.status === 'ber').length > 0;
|
||||
if (opponent.species.name === 'Mesprit' && active) {
|
||||
opponent.formeChange('Mesprit-Rampaging', this.effect, false);
|
||||
}
|
||||
if (opponent.species.name === 'Mesprit-Rampaging' && !active) {
|
||||
opponent.formeChange('Mesprit', this.effect, false);
|
||||
}
|
||||
}
|
||||
},
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (!target) return damage;
|
||||
const hp = target.maxhp / 16;
|
||||
this.effectState.counter += hp;
|
||||
return damage + hp;
|
||||
},
|
||||
onFoeDamage(damage, target, source, effect) {
|
||||
if (source?.getStatus().name === 'ber') {
|
||||
const hp = target.maxhp / 16;
|
||||
this.effectState.counter += hp;
|
||||
return damage + hp;
|
||||
}
|
||||
},
|
||||
onEnd(pokemon) {
|
||||
for (const opponent of pokemon.side.foe.active) {
|
||||
const active = opponent.side.foe.active.filter(mon => mon.status === 'ber').length > 0;
|
||||
if (opponent.species.name === 'Mesprit' && active) {
|
||||
opponent.formeChange('Mesprit-Rampaging', this.effect, false);
|
||||
}
|
||||
if (opponent.species.name === 'Mesprit-Rampaging' && !active) {
|
||||
opponent.formeChange('Mesprit', this.effect, false);
|
||||
}
|
||||
}
|
||||
if (pokemon.species.name === 'Drifblim-Inflamed') {
|
||||
pokemon.formeChange('Drifblim', this.effect, false);
|
||||
}
|
||||
this.add('-end', pokemon, 'Berserk');
|
||||
},
|
||||
onBeforeFaint(pokemon) {
|
||||
for (const opponent of pokemon.side.foe.active) {
|
||||
const active = opponent.side.foe.active.filter(mon => mon.status === 'ber').length - 1 > 0;
|
||||
if (opponent.species.name === 'Mesprit' && active) {
|
||||
opponent.formeChange('Mesprit-Rampaging', this.effect, false);
|
||||
}
|
||||
if (opponent.species.name === 'Mesprit-Rampaging' && !active) {
|
||||
opponent.formeChange('Mesprit', this.effect, false);
|
||||
}
|
||||
}
|
||||
},
|
||||
onSwitchOut(pokemon) {
|
||||
for (const opponent of pokemon.side.foe.active) {
|
||||
const active = opponent.side.foe.active.filter(mon => mon.status === 'ber').length - 1 > 0;
|
||||
if (opponent.species.name === 'Mesprit' && active) {
|
||||
opponent.formeChange('Mesprit-Rampaging', this.effect, false);
|
||||
}
|
||||
if (opponent.species.name === 'Mesprit-Rampaging' && !active) {
|
||||
opponent.formeChange('Mesprit', this.effect, false);
|
||||
}
|
||||
}
|
||||
},
|
||||
onSwitchIn(pokemon) {
|
||||
this.add('-start', pokemon, 'Berserk');
|
||||
if (this.effectState.counter >= 10000 * pokemon.maxhp) pokemon.cureStatus();
|
||||
for (const opponent of pokemon.side.foe.active) {
|
||||
const active = opponent.side.foe.active.filter(mon => mon.status === 'ber').length > 0;
|
||||
if (opponent.species.name === 'Mesprit' && active) {
|
||||
opponent.formeChange('Mesprit-Rampaging', this.effect, false);
|
||||
}
|
||||
if (opponent.species.name === 'Mesprit-Rampaging' && !active) {
|
||||
opponent.formeChange('Mesprit', this.effect, false);
|
||||
}
|
||||
}
|
||||
if (pokemon.species.name === 'Drifblim') {
|
||||
pokemon.formeChange('Drifblim-Inflamed', this.effect, false);
|
||||
}
|
||||
},
|
||||
},
|
||||
restoring: {
|
||||
name: 'Restoring',
|
||||
duration: 1,
|
||||
onStart(target, source, sourceEffect) {
|
||||
this.add('-start', target, 'restoring');
|
||||
},
|
||||
onEnd(target) {
|
||||
if (target.species.id === 'aurorus') {
|
||||
target.formeChange('Aurorus-Glorious', this.effect, true);
|
||||
target.setAbility('megalauncher', target);
|
||||
this.add('-activate', target, 'ability: Mega Launcher');
|
||||
if (this.field.isWeather(['hail', 'snowscape'])) {
|
||||
target.heal(target.baseMaxhp / 2);
|
||||
}
|
||||
}
|
||||
this.add('-end', target, 'restoring');
|
||||
},
|
||||
},
|
||||
backbeat: {
|
||||
onStart(pokemon) {
|
||||
this.add('-start', pokemon, 'Backbeat');
|
||||
},
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
return this.chainModify(1.5);
|
||||
},
|
||||
onEnd(pokemon) {
|
||||
this.add('-end', pokemon, 'Backbeat');
|
||||
},
|
||||
},
|
||||
// advent
|
||||
gingerstorm: {
|
||||
name: 'Gingerstorm',
|
||||
effectType: 'Weather',
|
||||
duration: 5,
|
||||
// This should be applied directly to the stat before any of the other modifiers are chained
|
||||
// So we give it increased priority.
|
||||
onModifyDefPriority: 10,
|
||||
onModifyDef(def, pokemon) {
|
||||
if (pokemon.hasType('Fire') && this.field.isWeather('gingerstorm')) {
|
||||
return this.modify(def, 1.5);
|
||||
}
|
||||
},
|
||||
onFieldStart(field, source, effect) {
|
||||
if (effect?.effectType === 'Ability') {
|
||||
if (this.gen <= 5) this.effectState.duration = 0;
|
||||
this.add('-weather', 'Gingerstorm', '[from] ability: ' + effect.name, `[of] ${source}`);
|
||||
} else {
|
||||
this.add('-weather', 'Gingerstorm');
|
||||
}
|
||||
this.add('-message', `${source} whipped up a gingerstorm!`);
|
||||
},
|
||||
onFieldResidualOrder: 1,
|
||||
onFieldResidual() {
|
||||
this.add('-weather', 'Gingerstorm', '[upkeep]');
|
||||
this.add('-message', `The gingerstorm continues!`);
|
||||
if (this.field.isWeather('gingerstorm')) this.eachEvent('Weather');
|
||||
},
|
||||
onWeather(target) {
|
||||
if (target.hasType('Fire')) return;
|
||||
if (target.status === 'brn') {
|
||||
this.damage(target.baseMaxhp / 8);
|
||||
this.add('-message', `${target.name} was buffeted by the gingerstorm!`);
|
||||
} else {
|
||||
this.damage(target.baseMaxhp / 16);
|
||||
this.add('-message', `${target.name} was buffeted by the gingerstorm!`);
|
||||
}
|
||||
},
|
||||
onFieldEnd() {
|
||||
this.add('-weather', 'none');
|
||||
this.add('-message', `The gingerstorm subsided...`);
|
||||
},
|
||||
},
|
||||
};
|
||||
599
data/mods/ccapm2025/formats-data.ts
Normal file
599
data/mods/ccapm2025/formats-data.ts
Normal file
|
|
@ -0,0 +1,599 @@
|
|||
export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormatsDataTable = {
|
||||
syclar: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
syclant: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
revenankh: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
embirch: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
flarelm: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP NFE",
|
||||
},
|
||||
pyroak: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
breezi: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
fidgit: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
rebble: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
tactite: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP NFE",
|
||||
},
|
||||
stratagem: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
privatyke: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
arghonaut: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
nohface: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
kitsunoh: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
monohm: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
duohm: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP NFE",
|
||||
},
|
||||
cyclohm: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
dorsoil: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
colossoil: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
protowatt: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
krilowatt: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
voodoll: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
voodoom: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
scratchet: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
tomohawk: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
necturine: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
necturna: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
mollux: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
cupra: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
argalis: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP NFE",
|
||||
},
|
||||
aurumoth: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
brattler: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
malaconda: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
cawdet: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
cawmodore: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
volkritter: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
volkraken: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
snugglow: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
plasmanta: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
floatoy: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
caimanoe: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP NFE",
|
||||
},
|
||||
naviathan: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
crucibelle: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
crucibellemega: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
pluffle: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
kerfluffle: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
pajantom: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
mumbao: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
jumbao: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
fawnifer: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
electrelk: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP NFE",
|
||||
},
|
||||
caribolt: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
smogecko: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
smoguana: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP NFE",
|
||||
},
|
||||
smokomodo: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
swirlpool: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
coribalis: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP NFE",
|
||||
},
|
||||
snaelstrom: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
justyke: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
equilibra: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
solotl: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
astrolotl: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
miasmite: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
miasmaw: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
chromera: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
venomicon: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
venomiconepilogue: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
saharascal: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
saharaja: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
ababo: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
scattervein: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP NFE",
|
||||
},
|
||||
hemogoblin: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
cresceidon: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
chuggon: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP LC",
|
||||
},
|
||||
draggalong: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP NFE",
|
||||
},
|
||||
chuggalong: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
shox: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
ramnarok: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "CAP",
|
||||
},
|
||||
ramnarokradiant: {
|
||||
isNonstandard: "Custom",
|
||||
tier: "Illegal",
|
||||
},
|
||||
|
||||
// mostly for advent mons
|
||||
ogerponpixiedust: {
|
||||
tier: "OU",
|
||||
doublesTier: "DOU",
|
||||
},
|
||||
shakite: {
|
||||
tier: "OU",
|
||||
doublesTier: "DOU",
|
||||
},
|
||||
strobite: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
xurkitreesinnoh: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
sandta: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
eiscuesnowcone: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
cardemelli: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
gingertar: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
gingertarmega: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
nuzcracker: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
smorgasbag: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
sableyefestive: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
mariahcarey: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
draydol: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
gamesi: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
vipux: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
popsicelf: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
bellbeque: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
chorislam: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
gholdengofestive: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
indeedeecook: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
dulceirene: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
dulceirenemega: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
wreith: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
eternalflowerwreith: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
clamperlalola: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
goodybyss: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
naughtail: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
gospiel: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
rusalvia: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
seraphexe: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
mirrelette: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
klefkimccallister: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
sacchamorte: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
treench: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
grincheartcaged: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
grincheartgrown: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
lelitoccia: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
deckherd: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
caneine: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
picktreebel: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
picktreebelmega: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
twinklingshade: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
irontwilight: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
faerwork: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
antaron: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
snowglob: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
dinjingle: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
guywithsweater: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
gristletoe: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
aegibashpolar: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
gingermason: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
swadloonfestive: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
leavannyfestive: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
mausholddysfunctional: {
|
||||
isNonstandard: "CAP",
|
||||
tier: "CAP",
|
||||
doublesTier: "CAP",
|
||||
},
|
||||
|
||||
};
|
||||
631
data/mods/ccapm2025/items.ts
Normal file
631
data/mods/ccapm2025/items.ts
Normal file
|
|
@ -0,0 +1,631 @@
|
|||
export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
||||
// Changed Items
|
||||
berserkgene: {
|
||||
name: "Berserk Gene",
|
||||
spritenum: 388,
|
||||
onStart(pokemon) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (pokemon.useItem()) {
|
||||
pokemon.trySetStatus('ber');
|
||||
}
|
||||
},
|
||||
boosts: {},
|
||||
num: 0,
|
||||
gen: 2,
|
||||
isNonstandard: null,
|
||||
shortDesc: "Makes the holder go berserk on switch-in. Single use.",
|
||||
},
|
||||
// Custom Items
|
||||
darminitanite: {
|
||||
name: "Darminitanite",
|
||||
spritenum: 576,
|
||||
megaStone: { "Darmanitan": "Darmanitan-Mega" },
|
||||
itemUser: ["Darmanitan"],
|
||||
onTakeItem(item, source) {
|
||||
return !item.megaStone?.[source.baseSpecies.baseSpecies];
|
||||
},
|
||||
gen: 9,
|
||||
shortDesc: "If held by a Darmanitan, this item allows it to Mega Evolve in battle.",
|
||||
num: -1,
|
||||
},
|
||||
emolgite: {
|
||||
name: "Emolgite",
|
||||
spritenum: 576,
|
||||
megaStone: { "Emolga": "Emolga-Mega" },
|
||||
itemUser: ["Emolga"],
|
||||
onTakeItem(item, source) {
|
||||
return !item.megaStone?.[source.baseSpecies.baseSpecies];
|
||||
},
|
||||
gen: 9,
|
||||
shortDesc: "If held by an Emolga, this item allows it to Mega Evolve in battle.",
|
||||
num: -2,
|
||||
},
|
||||
flygonite: {
|
||||
name: "Flygonite",
|
||||
spritenum: 576,
|
||||
megaStone: { "Flygon": "Flygon-Mega" },
|
||||
itemUser: ["Flygon"],
|
||||
onTakeItem(item, source) {
|
||||
return !item.megaStone?.[source.baseSpecies.baseSpecies];
|
||||
},
|
||||
gen: 9,
|
||||
shortDesc: "If held by a Flygon, this item allows it to Mega Evolve in battle.",
|
||||
num: -3,
|
||||
},
|
||||
mysterioustusk: {
|
||||
name: "Mysterious Tusk",
|
||||
spritenum: 382,
|
||||
onTakeItem(item, pokemon, source) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (source?.baseSpecies.name === 'Mamoswine') {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onAfterMoveSecondarySelf(pokemon, target, move) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (pokemon.species.name === 'Mamoswine' && move.totalDamage === target.maxhp) {
|
||||
pokemon.formeChange('Mamoswine-Overflow', this.effect, true);
|
||||
}
|
||||
},
|
||||
gen: 9,
|
||||
},
|
||||
pixiedustmask: {
|
||||
name: "Pixiedust Mask",
|
||||
spritenum: 759,
|
||||
fling: {
|
||||
basePower: 60,
|
||||
},
|
||||
onBasePowerPriority: 15,
|
||||
onBasePower(basePower, user, target, move) {
|
||||
if (user.baseSpecies.name.startsWith('Ogerpon-Pixiedust')) {
|
||||
return this.chainModify([4915, 4096]);
|
||||
}
|
||||
},
|
||||
onTakeItem(item, source) {
|
||||
if (source.baseSpecies.baseSpecies === 'Ogerpon') return false;
|
||||
return true;
|
||||
},
|
||||
forcedForme: "Ogerpon-Pixiedust",
|
||||
itemUser: ["Ogerpon-Pixiedust"],
|
||||
shortDesc: "Ogerpon-Pixiedust: 1.2x power attacks; Terastallize to gain Embody Aspect.",
|
||||
num: -4,
|
||||
gen: 9,
|
||||
},
|
||||
ultrasimiseariumz: {
|
||||
name: "Ultrasimisearium Z",
|
||||
spritenum: 687,
|
||||
onTakeItem: false,
|
||||
zMove: "Yin-Yang Blast",
|
||||
zMoveFrom: "Fire Blast",
|
||||
itemUser: ["Simisear-Ultra"],
|
||||
shortDesc: "Simisear: Ultra Burst, then Z-Move w/ Fire Blast.",
|
||||
num: -4,
|
||||
gen: 9,
|
||||
},
|
||||
drearymushroom: {
|
||||
name: "Dreary Mushroom",
|
||||
spritenum: 609,
|
||||
fling: {
|
||||
basePower: 30,
|
||||
},
|
||||
onDamagePriority: 1,
|
||||
onSourceModifyDamage(damage, source, target, move) {
|
||||
if (move && target.getMoveHitData(move).typeMod > 0 && !target.transformed) {
|
||||
target.formeChange('Parasect-Wicked', this.effect, true);
|
||||
this.damage(target.baseMaxhp / 8);
|
||||
target.trySetStatus('ber');
|
||||
target.useItem();
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
shortDesc: "Parasect: Block 1 SE move, lose 1/8 HP, change form, and become Berserk. Single use.",
|
||||
num: -5,
|
||||
gen: 9,
|
||||
},
|
||||
restorationcapsule: {
|
||||
name: "Restoration Capsule",
|
||||
spritenum: 6,
|
||||
fling: {
|
||||
basePower: 10,
|
||||
},
|
||||
onStart(target) {
|
||||
this.add('-item', target, 'Restoration Capsule');
|
||||
target.addVolatile('restoring');
|
||||
},
|
||||
// hazard immunity implemented in moves.ts
|
||||
shortDesc: "Aurorus: Hazard immunity, changes its form after 1 turn.",
|
||||
num: -6,
|
||||
gen: 9,
|
||||
},
|
||||
venomstake: {
|
||||
name: "Venom Stake",
|
||||
spritenum: 515,
|
||||
fling: {
|
||||
basePower: 40,
|
||||
status: 'tox',
|
||||
},
|
||||
onResidualOrder: 28,
|
||||
onResidualSubOrder: 3,
|
||||
onResidual(pokemon) {
|
||||
pokemon.trySetStatus('tox', pokemon);
|
||||
this.damage(pokemon.baseMaxhp / 8);
|
||||
},
|
||||
onHit(target, source, move) {
|
||||
if (source && source !== target && !source.item && move && this.checkMoveMakesContact(move, source, target)) {
|
||||
const stake = target.takeItem();
|
||||
if (!stake) return; // Gen 4 Multitype
|
||||
source.setItem(stake);
|
||||
// no message for Sticky Barb changing hands
|
||||
}
|
||||
},
|
||||
num: -7,
|
||||
shortDesc: "Effects of Toxic Orb and Sticky Barb.",
|
||||
},
|
||||
buggem: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
onTakeItem(item, pokemon, source) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (source.name === "Diancie" || source?.ability === "geminfusion" || pokemon.ability === "geminfusion") {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onUseItem(item, pokemon) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if ((pokemon.name === "Diancie" || pokemon?.ability === "geminfusion") && item?.isGem) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onSourceTryPrimaryHit(target, source, move) {
|
||||
if (target === source || move.category === 'Status' || move.flags['pledgecombo']) return;
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (move.type === 'Bug' && source.ability === "geminfusion") {
|
||||
source.addVolatile('gem');
|
||||
} else if (move.type === 'Bug' && source.useItem()) {
|
||||
source.addVolatile('gem');
|
||||
}
|
||||
},
|
||||
},
|
||||
darkgem: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
onTakeItem(item, pokemon, source) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (source.name === "Diancie" || source?.ability === "geminfusion" || pokemon.ability === "geminfusion") {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onUseItem(item, pokemon) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if ((pokemon.name === "Diancie" || pokemon?.ability === "geminfusion") && item?.isGem) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onSourceTryPrimaryHit(target, source, move) {
|
||||
if (target === source || move.category === 'Status' || move.flags['pledgecombo']) return;
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (move.type === 'Dark' && source.ability === "geminfusion") {
|
||||
source.addVolatile('gem');
|
||||
} else if (move.type === 'Dark' && source.useItem()) {
|
||||
source.addVolatile('gem');
|
||||
}
|
||||
},
|
||||
},
|
||||
dragongem: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
onTakeItem(item, pokemon, source) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (source.name === "Diancie" || source?.ability === "geminfusion" || pokemon.ability === "geminfusion") {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onUseItem(item, pokemon) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if ((pokemon.name === "Diancie" || pokemon?.ability === "geminfusion") && item?.isGem) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onSourceTryPrimaryHit(target, source, move) {
|
||||
if (target === source || move.category === 'Status' || move.flags['pledgecombo']) return;
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (move.type === 'Dragon' && source.ability === "geminfusion") {
|
||||
source.addVolatile('gem');
|
||||
} else if (move.type === 'Dragon' && source.useItem()) {
|
||||
source.addVolatile('gem');
|
||||
}
|
||||
},
|
||||
},
|
||||
electricgem: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
onTakeItem(item, pokemon, source) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (source.name === "Diancie" || source?.ability === "geminfusion" || pokemon.ability === "geminfusion") {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onUseItem(item, pokemon) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if ((pokemon.name === "Diancie" || pokemon?.ability === "geminfusion") && item?.isGem) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onSourceTryPrimaryHit(target, source, move) {
|
||||
if (target === source || move.category === 'Status' || move.flags['pledgecombo']) return;
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (move.type === 'Electric' && source.ability === "geminfusion") {
|
||||
source.addVolatile('gem');
|
||||
} else if (move.type === 'Electric' && source.useItem()) {
|
||||
source.addVolatile('gem');
|
||||
}
|
||||
},
|
||||
},
|
||||
fairygem: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
onTakeItem(item, pokemon, source) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (source.name === "Diancie" || source?.ability === "geminfusion" || pokemon.ability === "geminfusion") {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onUseItem(item, pokemon) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if ((pokemon.name === "Diancie" || pokemon?.ability === "geminfusion") && item?.isGem) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onSourceTryPrimaryHit(target, source, move) {
|
||||
if (target === source || move.category === 'Status' || move.flags['pledgecombo']) return;
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (move.type === 'Fairy' && source.ability === "geminfusion") {
|
||||
source.addVolatile('gem');
|
||||
} else if (move.type === 'Fairy' && source.useItem()) {
|
||||
source.addVolatile('gem');
|
||||
}
|
||||
},
|
||||
},
|
||||
fightinggem: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
onTakeItem(item, pokemon, source) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (source.name === "Diancie" || source?.ability === "geminfusion" || pokemon.ability === "geminfusion") {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onUseItem(item, pokemon) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if ((pokemon.name === "Diancie" || pokemon?.ability === "geminfusion") && item?.isGem) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onSourceTryPrimaryHit(target, source, move) {
|
||||
if (target === source || move.category === 'Status' || move.flags['pledgecombo']) return;
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (move.type === 'Fighting' && source.ability === "geminfusion") {
|
||||
source.addVolatile('gem');
|
||||
} else if (move.type === 'Fighting' && source.useItem()) {
|
||||
source.addVolatile('gem');
|
||||
}
|
||||
},
|
||||
},
|
||||
firegem: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
onTakeItem(item, pokemon, source) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (source.name === "Diancie" || source?.ability === "geminfusion" || pokemon.ability === "geminfusion") {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onUseItem(item, pokemon) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if ((pokemon.name === "Diancie" || pokemon?.ability === "geminfusion") && item?.isGem) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onSourceTryPrimaryHit(target, source, move) {
|
||||
if (target === source || move.category === 'Status' || move.flags['pledgecombo']) return;
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (move.type === 'Fire' && source.ability === "geminfusion") {
|
||||
source.addVolatile('gem');
|
||||
} else if (move.type === 'Fire' && source.useItem()) {
|
||||
source.addVolatile('gem');
|
||||
}
|
||||
},
|
||||
},
|
||||
flyinggem: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
onTakeItem(item, pokemon, source) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (source.name === "Diancie" || source?.ability === "geminfusion" || pokemon.ability === "geminfusion") {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onUseItem(item, pokemon) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if ((pokemon.name === "Diancie" || pokemon?.ability === "geminfusion") && item?.isGem) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onSourceTryPrimaryHit(target, source, move) {
|
||||
if (target === source || move.category === 'Status' || move.flags['pledgecombo']) return;
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (move.type === 'Flying' && source.ability === "geminfusion") {
|
||||
source.addVolatile('gem');
|
||||
} else if (move.type === 'Flying' && source.useItem()) {
|
||||
source.addVolatile('gem');
|
||||
}
|
||||
},
|
||||
},
|
||||
ghostgem: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
onTakeItem(item, pokemon, source) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (source.name === "Diancie" || source?.ability === "geminfusion" || pokemon.ability === "geminfusion") {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onUseItem(item, pokemon) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if ((pokemon.name === "Diancie" || pokemon?.ability === "geminfusion") && item?.isGem) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onSourceTryPrimaryHit(target, source, move) {
|
||||
if (target === source || move.category === 'Status' || move.flags['pledgecombo']) return;
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (move.type === 'Ghost' && source.ability === "geminfusion") {
|
||||
source.addVolatile('gem');
|
||||
} else if (move.type === 'Ghost' && source.useItem()) {
|
||||
source.addVolatile('gem');
|
||||
}
|
||||
},
|
||||
},
|
||||
grassgem: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
onTakeItem(item, pokemon, source) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (source.name === "Diancie" || source?.ability === "geminfusion" || pokemon.ability === "geminfusion") {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onUseItem(item, pokemon) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if ((pokemon.name === "Diancie" || pokemon?.ability === "geminfusion") && item?.isGem) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onSourceTryPrimaryHit(target, source, move) {
|
||||
if (target === source || move.category === 'Status' || move.flags['pledgecombo']) return;
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (move.type === 'Grass' && source.ability === "geminfusion") {
|
||||
source.addVolatile('gem');
|
||||
} else if (move.type === 'Grass' && source.useItem()) {
|
||||
source.addVolatile('gem');
|
||||
}
|
||||
},
|
||||
},
|
||||
groundgem: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
onTakeItem(item, pokemon, source) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (source.name === "Diancie" || source?.ability === "geminfusion" || pokemon.ability === "geminfusion") {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onUseItem(item, pokemon) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if ((pokemon.name === "Diancie" || pokemon?.ability === "geminfusion") && item?.isGem) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onSourceTryPrimaryHit(target, source, move) {
|
||||
if (target === source || move.category === 'Status' || move.flags['pledgecombo']) return;
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (move.type === 'Ground' && source.ability === "geminfusion") {
|
||||
source.addVolatile('gem');
|
||||
} else if (move.type === 'Ground' && source.useItem()) {
|
||||
source.addVolatile('gem');
|
||||
}
|
||||
},
|
||||
},
|
||||
icegem: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
onTakeItem(item, pokemon, source) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (source.name === "Diancie" || source?.ability === "geminfusion" || pokemon.ability === "geminfusion") {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onUseItem(item, pokemon) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if ((pokemon.name === "Diancie" || pokemon?.ability === "geminfusion") && item?.isGem) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onSourceTryPrimaryHit(target, source, move) {
|
||||
if (target === source || move.category === 'Status' || move.flags['pledgecombo']) return;
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (move.type === 'Ice' && source.ability === "geminfusion") {
|
||||
source.addVolatile('gem');
|
||||
} else if (move.type === 'Ice' && source.useItem()) {
|
||||
source.addVolatile('gem');
|
||||
}
|
||||
},
|
||||
},
|
||||
normalgem: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
onTakeItem(item, pokemon, source) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (source.name === "Diancie" || source?.ability === "geminfusion" || pokemon.ability === "geminfusion") {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onUseItem(item, pokemon) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if ((pokemon.name === "Diancie" || pokemon?.ability === "geminfusion") && item?.isGem) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onSourceTryPrimaryHit(target, source, move) {
|
||||
if (target === source || move.category === 'Status' || move.flags['pledgecombo']) return;
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (move.type === 'Normal' && source.ability === "geminfusion") {
|
||||
source.addVolatile('gem');
|
||||
} else if (move.type === 'Normal' && source.useItem()) {
|
||||
source.addVolatile('gem');
|
||||
}
|
||||
},
|
||||
},
|
||||
poisongem: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
onTakeItem(item, pokemon, source) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (source.name === "Diancie" || source?.ability === "geminfusion" || pokemon.ability === "geminfusion") {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onUseItem(item, pokemon) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if ((pokemon.name === "Diancie" || pokemon?.ability === "geminfusion") && item?.isGem) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onSourceTryPrimaryHit(target, source, move) {
|
||||
if (target === source || move.category === 'Status' || move.flags['pledgecombo']) return;
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (move.type === 'Poison' && source.ability === "geminfusion") {
|
||||
source.addVolatile('gem');
|
||||
} else if (move.type === 'Poison' && source.useItem()) {
|
||||
source.addVolatile('gem');
|
||||
}
|
||||
},
|
||||
},
|
||||
rockgem: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
onTakeItem(item, pokemon, source) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (source.name === "Diancie" || source?.ability === "geminfusion" || pokemon.ability === "geminfusion") {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onUseItem(item, pokemon) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if ((pokemon.name === "Diancie" || pokemon?.ability === "geminfusion") && item?.isGem) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onSourceTryPrimaryHit(target, source, move) {
|
||||
if (target === source || move.category === 'Status' || move.flags['pledgecombo']) return;
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (move.type === 'Rock' && source.ability === "geminfusion") {
|
||||
source.addVolatile('gem');
|
||||
} else if (move.type === 'Rock' && source.useItem()) {
|
||||
source.addVolatile('gem');
|
||||
}
|
||||
},
|
||||
},
|
||||
steelgem: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
onTakeItem(item, pokemon, source) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (source.name === "Diancie" || source?.ability === "geminfusion" || pokemon.ability === "geminfusion") {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onUseItem(item, pokemon) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if ((pokemon.name === "Diancie" || pokemon?.ability === "geminfusion") && item?.isGem) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onSourceTryPrimaryHit(target, source, move) {
|
||||
if (target === source || move.category === 'Status' || move.flags['pledgecombo']) return;
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (move.type === 'Steel' && source.ability === "geminfusion") {
|
||||
source.addVolatile('gem');
|
||||
} else if (move.type === 'Steel' && source.useItem()) {
|
||||
source.addVolatile('gem');
|
||||
}
|
||||
},
|
||||
},
|
||||
watergem: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
onTakeItem(item, pokemon, source) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (source.name === "Diancie" || source?.ability === "geminfusion" || pokemon.ability === "geminfusion") {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onUseItem(item, pokemon) {
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if ((pokemon.name === "Diancie" || pokemon?.ability === "geminfusion") && item?.isGem) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onSourceTryPrimaryHit(target, source, move) {
|
||||
if (target === source || move.category === 'Status' || move.flags['pledgecombo']) return;
|
||||
if (this.ruleTable.tagRules.includes("+pokemontag:cap")) return;
|
||||
if (move.type === 'Water' && source.ability === "geminfusion") {
|
||||
source.addVolatile('gem');
|
||||
} else if (move.type === 'Water' && source.useItem()) {
|
||||
source.addVolatile('gem');
|
||||
}
|
||||
},
|
||||
},
|
||||
// advent
|
||||
gingerite: {
|
||||
name: "Gingerite",
|
||||
spritenum: 576,
|
||||
megaStone: { "Gingertar": "Gingertar-Mega" },
|
||||
itemUser: ["Gingertar"],
|
||||
onTakeItem(item, source) {
|
||||
return !item.megaStone?.[source.baseSpecies.baseSpecies];
|
||||
},
|
||||
gen: 9,
|
||||
shortDesc: "If held by a Gingertar, this item allows it to Mega Evolve in battle.",
|
||||
num: -1000,
|
||||
},
|
||||
dulceirenite: {
|
||||
name: "Dulceirenite",
|
||||
spritenum: 576,
|
||||
megaStone: { "Dulceirene": "Dulceirene-Mega" },
|
||||
itemUser: ["Dulceirene"],
|
||||
onTakeItem(item, source) {
|
||||
return !item.megaStone?.[source.baseSpecies.baseSpecies];
|
||||
},
|
||||
gen: 9,
|
||||
shortDesc: "If held by a Dulceirene, this item allows it to Mega Evolve in battle.",
|
||||
num: -1001,
|
||||
},
|
||||
picktreelite: {
|
||||
name: "Picktreelite",
|
||||
spritenum: 576,
|
||||
megaStone: { "Picktreebel": "Picktreebel-Mega" },
|
||||
itemUser: ["Picktreebel"],
|
||||
onTakeItem(item, source) {
|
||||
return !item.megaStone?.[source.baseSpecies.baseSpecies];
|
||||
},
|
||||
gen: 9,
|
||||
shortDesc: "If held by a Picktreebel, this item allows it to Mega Evolve in battle.",
|
||||
num: -1002,
|
||||
},
|
||||
sablenite: {
|
||||
inherit: true,
|
||||
megaStone: { "Sableye-Festive": "Sableye-Festive-Mega" },
|
||||
itemUser: ["Sableye-Festive"],
|
||||
},
|
||||
};
|
||||
3041
data/mods/ccapm2025/learnsets.ts
Normal file
3041
data/mods/ccapm2025/learnsets.ts
Normal file
File diff suppressed because it is too large
Load Diff
2775
data/mods/ccapm2025/moves.ts
Normal file
2775
data/mods/ccapm2025/moves.ts
Normal file
File diff suppressed because it is too large
Load Diff
2218
data/mods/ccapm2025/pokedex.ts
Normal file
2218
data/mods/ccapm2025/pokedex.ts
Normal file
File diff suppressed because it is too large
Load Diff
286
data/mods/ccapm2025/rulesets.ts
Normal file
286
data/mods/ccapm2025/rulesets.ts
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
terastalclause: {
|
||||
effectType: 'Rule',
|
||||
name: 'Terastal Clause',
|
||||
desc: "Prevents Pokémon from Terastallizing",
|
||||
onBegin() {
|
||||
for (const pokemon of this.getAllPokemon()) {
|
||||
if (pokemon.species.baseSpecies !== 'Ogerpon') {
|
||||
pokemon.canTerastallize = null;
|
||||
}
|
||||
}
|
||||
this.add('rule', 'Terastal Clause: You cannot Terastallize');
|
||||
},
|
||||
},
|
||||
ccapmformchanges: {
|
||||
effectType: 'Rule',
|
||||
name: 'CCAPM Form Changes',
|
||||
desc: "Makes a bunch of form changes function",
|
||||
onBegin() {
|
||||
this.add('rule', 'CCAPM Form Changes: Makes many form changes work');
|
||||
},
|
||||
onSwitchIn(pokemon) {
|
||||
if (!this.ruleTable.tagRules.includes("+pokemontag:cap")) {
|
||||
if (pokemon.species.name === "Samurott" && pokemon.side.totalFainted >= 3) {
|
||||
pokemon.formeChange('Samurott-Overlord', null, true);
|
||||
}
|
||||
if (pokemon.species.name === "Jirachi" && (pokemon.side as any).holdHandsUsers?.length >= 2) {
|
||||
pokemon.formeChange('Jirachi-Harmonic', null, true);
|
||||
|
||||
const holdHandsIndex = pokemon.set.moves
|
||||
.map(move => move.toLowerCase().replace(/[^a-z0-9]/g, '')).indexOf('holdhands' as ID);
|
||||
if (holdHandsIndex < 0) return;
|
||||
|
||||
const move = this.dex.moves.get('lightofruin');
|
||||
const sketchedMove = {
|
||||
move: move.name,
|
||||
id: move.id,
|
||||
pp: move.pp,
|
||||
maxpp: move.pp,
|
||||
target: move.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
pokemon.moveSlots[holdHandsIndex] = sketchedMove;
|
||||
pokemon.baseMoveSlots[holdHandsIndex] = sketchedMove;
|
||||
}
|
||||
if (pokemon.species.name === "Luvdisc" && pokemon.side.totalFainted >= 5) {
|
||||
pokemon.formeChange('Luvdisc-Heartbreak', null, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
onWeatherChange(target, source, effect) {
|
||||
if (!this.ruleTable.tagRules.includes("+pokemontag:cap")) {
|
||||
const weather = target.effectiveWeather();
|
||||
if (weather === 'sunnyday' || weather === 'desolateland') {
|
||||
if (target.species.name === "Beartic") {
|
||||
target.formeChange('Beartic-Freshwater', null, true);
|
||||
const glacierFangIndex = target.set.moves
|
||||
.map(move => move.toLowerCase().replace(/[^a-z0-9]/g, '')).indexOf('glacierfang' as ID);
|
||||
if (glacierFangIndex < 0) return;
|
||||
|
||||
const move = this.dex.moves.get('meltingmaul');
|
||||
const sketchedMove = {
|
||||
move: move.name,
|
||||
id: move.id,
|
||||
pp: move.pp,
|
||||
maxpp: move.pp,
|
||||
target: move.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
target.moveSlots[glacierFangIndex] = sketchedMove;
|
||||
target.baseMoveSlots[glacierFangIndex] = sketchedMove;
|
||||
}
|
||||
} else if (weather === 'hail' || weather === 'snowscape') {
|
||||
if (target.species.name === "Beartic-Freshwater") {
|
||||
target.formeChange('Beartic', null, true);
|
||||
const meltingMaulIndex = target.set.moves
|
||||
.map(move => move.toLowerCase().replace(/[^a-z0-9]/g, '')).indexOf('meltingmaul' as ID);
|
||||
if (meltingMaulIndex < 0) return;
|
||||
|
||||
const move = this.dex.moves.get('glacierfang');
|
||||
const sketchedMove = {
|
||||
move: move.name,
|
||||
id: move.id,
|
||||
pp: move.pp,
|
||||
maxpp: move.pp,
|
||||
target: move.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
target.moveSlots[meltingMaulIndex] = sketchedMove;
|
||||
target.baseMoveSlots[meltingMaulIndex] = sketchedMove;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (!this.ruleTable.tagRules.includes("+pokemontag:cap")) {
|
||||
if (move.type === 'Fire' && target.species.name === "Beartic") {
|
||||
target.formeChange('Beartic-Freshwater', null, true);
|
||||
target.setAbility('drizzle', target);
|
||||
|
||||
const glacierFangIndex = target.set.moves
|
||||
.map(setMove => setMove.toLowerCase().replace(/[^a-z0-9]/g, '')).indexOf('glacierfang' as ID);
|
||||
if (glacierFangIndex < 0) return;
|
||||
|
||||
const meltingmaul = this.dex.moves.get('meltingmaul');
|
||||
const sketchedMove = {
|
||||
move: meltingmaul.name,
|
||||
id: meltingmaul.id,
|
||||
pp: meltingmaul.pp,
|
||||
maxpp: meltingmaul.pp,
|
||||
target: meltingmaul.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
|
||||
target.moveSlots[glacierFangIndex] = sketchedMove;
|
||||
target.baseMoveSlots[glacierFangIndex] = sketchedMove;
|
||||
} else if (move.type === 'Ice' && target.species.name === "Beartic-Freshwater") {
|
||||
target.formeChange('Beartic', null, true);
|
||||
target.setAbility('slushrush', target);
|
||||
|
||||
const meltingMaulIndex = target.set.moves
|
||||
.map(setMove => setMove.toLowerCase().replace(/[^a-z0-9]/g, '')).indexOf('meltingmaul' as ID);
|
||||
if (meltingMaulIndex < 0) return;
|
||||
|
||||
const glacierfang = this.dex.moves.get('glacierfang');
|
||||
const sketchedMove = {
|
||||
move: glacierfang.name,
|
||||
id: glacierfang.id,
|
||||
pp: glacierfang.pp,
|
||||
maxpp: glacierfang.pp,
|
||||
target: glacierfang.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
target.moveSlots[meltingMaulIndex] = sketchedMove;
|
||||
target.baseMoveSlots[meltingMaulIndex] = sketchedMove;
|
||||
} else if (move.type === 'Rock' && target.species.name === "Kommo-o") {
|
||||
target.formeChange('Kommo-o-Hard-Rock', null, true);
|
||||
} else if (move.type === 'Electric' && target.species.name === "Luxray") {
|
||||
target.formeChange('Luxray-Conductive', null, true);
|
||||
} else if (!move.damage && !move.damageCallback &&
|
||||
target.getMoveHitData(move).typeMod > 0 &&
|
||||
target.species.name === "Rhyperior") {
|
||||
target.formeChange('Rhyperior-Adversity', null, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (!this.ruleTable.tagRules.includes("+pokemontag:cap")) {
|
||||
if (effect && effect.id === 'stealthrock' && target.species.name === "Kommo-o") {
|
||||
target.formeChange('Kommo-o-Hard-Rock', null, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
onAfterBoost(boost, target, source, effect) {
|
||||
if (!this.ruleTable.tagRules.includes("+pokemontag:cap")) {
|
||||
/* let speedUp = false;
|
||||
let i: BoostID;
|
||||
for (i in boost) {
|
||||
if (boost[i]! > 0) {
|
||||
speedUp = true;
|
||||
}
|
||||
}
|
||||
if (speedUp && target.species.name === "Blaziken") {
|
||||
target.formeChange('Blaziken-Wildfire', null, true);
|
||||
target.setAbility('burnout', target);
|
||||
} */
|
||||
if (boost.spe && boost.spe > 0 &&
|
||||
target.species.name === "Blaziken") {
|
||||
target.formeChange('Blaziken-Wildfire', null, true);
|
||||
}
|
||||
}
|
||||
if (effect?.name === 'Fiery Dance' && boost.spa &&
|
||||
source.species.name === "Volcarona") {
|
||||
source.formeChange('Volcarona-Radiant', null, true);
|
||||
this.add('-activate', source, 'ability: Desolate Land');
|
||||
}
|
||||
},
|
||||
onModifyMovePriority: 1,
|
||||
onModifyMove(move, attacker, defender) {
|
||||
const shayLand = [
|
||||
'seedflare', 'gigadrain', 'flowertrick', 'sappyseed',
|
||||
];
|
||||
const shaySky = [
|
||||
'aromatherapy', 'worryseed', 'synthesis', 'flowershield', 'floralhealing', 'strengthsap',
|
||||
];
|
||||
if (attacker.species.name === "Shaymin" && shaySky.includes(move.id)) {
|
||||
attacker.formeChange('Shaymin-Sky', null, true);
|
||||
} else if (attacker.species.name === "Shaymin-Sky" && shayLand.includes(move.id)) {
|
||||
attacker.formeChange('Shaymin', null, true);
|
||||
}
|
||||
},
|
||||
onAfterMoveSecondarySelf(source, target, move) {
|
||||
if (!this.ruleTable.tagRules.includes("+pokemontag:cap")) {
|
||||
if (source.species.name === "Clawitzer" && move.flags['pulse']) {
|
||||
source.formeChange('Clawitzer-Curled', null, true);
|
||||
} else if (source.species.name === "Lilligant" && move.flags['dance']) {
|
||||
source.formeChange('Lilligant-Hisui', null, true);
|
||||
} else if (source.species.name === "Luxray-Conductive" &&
|
||||
move.type !== 'Electric') {
|
||||
source.formeChange('Luxray', null, true);
|
||||
} else if (source.species.name === "Luxray" && move.type === 'Electric') {
|
||||
source.formeChange('Luxray-Conductive', null, true);
|
||||
} else if (source.species.name === "Talonflame" && move.type === 'Flying') {
|
||||
source.formeChange('Talonflame-Tempest', null, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
onResidualOrder: 28,
|
||||
onResidualSubOrder: 2,
|
||||
onResidual(pokemon) {
|
||||
if (!this.ruleTable.tagRules.includes("+pokemontag:cap")) {
|
||||
if (pokemon.activeTurns && pokemon.species.name === "Fearow") {
|
||||
pokemon.formeChange('Fearow-Ferocious', null, true);
|
||||
this.add('-ability', pokemon, 'Wonder Guard');
|
||||
} else if (pokemon.activeTurns && pokemon.species.name === "Fearow-Ferocious") {
|
||||
pokemon.formeChange('Fearow', null, true);
|
||||
this.add('-ability', pokemon, 'Sniper');
|
||||
} else if (pokemon.hp <= pokemon.maxhp / 2 &&
|
||||
pokemon.species.name === "Sunflora") {
|
||||
pokemon.formeChange('Sunflora-Wilted', null, true);
|
||||
} else if (pokemon.hp <= pokemon.maxhp / 2 &&
|
||||
pokemon.species.name === "Torterra") {
|
||||
pokemon.sethp(Math.min(pokemon.maxhp, pokemon.hp + pokemon.baseMaxhp / 4));
|
||||
this.add('-heal', pokemon, pokemon.getHealth);
|
||||
pokemon.formeChange('Torterra-Old!', null, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
onAfterFaint(length, target, source, effect) {
|
||||
if (!this.ruleTable.tagRules.includes("+pokemontag:cap")) {
|
||||
if (source?.species.id === 'lucario') {
|
||||
if (this.effectState.auraTriggered) return;
|
||||
if (effect?.effectType !== 'Move') {
|
||||
return;
|
||||
}
|
||||
if (source.hp && !source.transformed && source.side.foePokemonLeft()) {
|
||||
this.add('-activate', source, 'ability: Aura Bond');
|
||||
// the ability isn't real
|
||||
source.formeChange('Lucario-Aura Bond', this.effect, true);
|
||||
source.formeRegression = true;
|
||||
this.effectState.auraTriggered = true;
|
||||
}
|
||||
} else if (source?.species.name === "Octillery") {
|
||||
if (effect && effect.effectType === 'Move' && target.getMoveHitData(effect).crit) {
|
||||
source.formeChange('Octillery-Sharpshooter', null, true);
|
||||
}
|
||||
} else if (source?.species.name === "Dudunsparce" || source?.species.name === "Du-Dudunsparce") {
|
||||
if (effect && effect.effectType === 'Move') {
|
||||
source.formeChange('Dudunsparce-tongueemoji', null, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onUpdate(pokemon) {
|
||||
if (!this.ruleTable.tagRules.includes("+pokemontag:cap")) {
|
||||
if (pokemon.species.baseSpecies === "Beartic") {
|
||||
this.singleEvent('WeatherChange', this.effect, this.effectState, pokemon);
|
||||
}
|
||||
for (const target of pokemon.adjacentFoes()) {
|
||||
if ((target.status === 'psn' || target.status === 'tox') &&
|
||||
pokemon.species.name === "Pecharunt") {
|
||||
pokemon.formeChange('Pecharunt-Puppetmaster', null, true);
|
||||
} else if (target.status !== 'psn' && target.status !== 'tox' &&
|
||||
pokemon.species.name === "Pecharunt-Puppetmaster") {
|
||||
pokemon.formeChange('Pecharunt', null, true);
|
||||
}
|
||||
}
|
||||
if (pokemon.species.name === "Victini" && pokemon.hp <= pokemon.maxhp / 4 &&
|
||||
pokemon.hp > 0 && pokemon.side.pokemonLeft > 1) {
|
||||
let stat: BoostID;
|
||||
for (stat in pokemon.boosts) {
|
||||
if (pokemon.boosts[stat] < 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
pokemon.formeChange('Victini-Victorious', null, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
799
data/mods/ccapm2025/scripts.ts
Normal file
799
data/mods/ccapm2025/scripts.ts
Normal file
|
|
@ -0,0 +1,799 @@
|
|||
import { toID } from '../../../sim/dex-data';
|
||||
import { RESTORATIVE_BERRIES } from "../../../sim/pokemon";
|
||||
export const Scripts: ModdedBattleScriptsData = {
|
||||
gen: 9,
|
||||
init() {
|
||||
for (const mon of this.species.all()) {
|
||||
if (mon.name === mon.baseSpecies && this.modData("Learnsets", mon.id)?.learnset) {
|
||||
this.modData("Learnsets", mon.id).learnset.holdhands = ["9L1"];
|
||||
}
|
||||
}
|
||||
this.modData("Learnsets", "alcremie").learnset.acidarmor = ["9L1"];
|
||||
this.modData("Learnsets", "drifblim").learnset.hurricane = ["9L1"];
|
||||
this.modData("Learnsets", "drifblim").learnset.infernalparade = ["9L1"];
|
||||
this.modData("Learnsets", "electrode").learnset.healingwish = ["9L1"];
|
||||
this.modData("Learnsets", "electrode").learnset.lunardance = ["9L1"];
|
||||
this.modData("Learnsets", "electrode").learnset.memento = ["9L1"];
|
||||
this.modData("Learnsets", "electrode").learnset.mistyexplosion = ["9L1"];
|
||||
this.modData("Learnsets", "flygon").learnset.healbell = ["9L1"];
|
||||
this.modData("Learnsets", "flygon").learnset.snarl = ["9L1"];
|
||||
this.modData("Learnsets", "flygon").learnset.quiverdance = ["9L1"];
|
||||
this.modData("Learnsets", "flygon").learnset.vacuumwave = ["9L1"];
|
||||
this.modData("Learnsets", "genesect").learnset.agility = ["9L1"];
|
||||
this.modData("Learnsets", "genesect").learnset.bubblebeam = ["9L1"];
|
||||
this.modData("Learnsets", "genesect").learnset.earthquake = ["9L1"];
|
||||
this.modData("Learnsets", "genesect").learnset.firepunch = ["9L1"];
|
||||
this.modData("Learnsets", "genesect").learnset.icepunch = ["9L1"];
|
||||
this.modData("Learnsets", "genesect").learnset.megapunch = ["9L1"];
|
||||
this.modData("Learnsets", "genesect").learnset.terablast = ["9L1"];
|
||||
this.modData("Learnsets", "genesect").learnset.terrainpulse = ["9L1"];
|
||||
this.modData("Learnsets", "genesect").learnset.thunderpunch = ["9L1"];
|
||||
this.modData("Learnsets", "genesect").learnset.waterpulse = ["9L1"];
|
||||
this.modData("Learnsets", "ironvaliant").learnset.playrough = ["9L1"];
|
||||
this.modData("Learnsets", "ironvaliant").learnset.willowisp = ["9L1"];
|
||||
this.modData("Learnsets", "ironvaliant").learnset.wish = ["9L1"];
|
||||
this.modData("Learnsets", "jirachi").learnset.holdhands = ["9L1"];
|
||||
this.modData("Learnsets", "kommoo").learnset.powergem = ["9L1"];
|
||||
this.modData("Learnsets", "kommoo").learnset.stoneedge = ["9L1"];
|
||||
this.modData("Learnsets", "mesprit").learnset.recover = ["9L1"];
|
||||
this.modData("Learnsets", "mesprit").learnset.gaslight = ["9L1"];
|
||||
this.modData("Learnsets", "octillery").learnset.recover = ["9L1"];
|
||||
this.modData("Learnsets", "shaymin").learnset.floralhealing = ["9L1"];
|
||||
this.modData("Learnsets", "shaymin").learnset.flowershield = ["9L1"];
|
||||
this.modData("Learnsets", "shaymin").learnset.flowertrick = ["9L1"];
|
||||
this.modData("Learnsets", "shaymin").learnset.sappyseed = ["9L1"];
|
||||
this.modData("Learnsets", "shaymin").learnset.strengthsap = ["9L1"];
|
||||
this.modData("Learnsets", "simisear").learnset.burningjealousy = ["9L1"];
|
||||
this.modData("Learnsets", "simisear").learnset.earthpower = ["9L1"];
|
||||
this.modData("Learnsets", "simisear").learnset.eruption = ["9L1"];
|
||||
this.modData("Learnsets", "simisear").learnset.fakeout = ["9L1"];
|
||||
this.modData("Learnsets", "simisear").learnset.mudshot = ["9L1"];
|
||||
this.modData("Learnsets", "simisear").learnset.temperflare = ["9L1"];
|
||||
this.modData("Learnsets", "simisear").learnset.terablast = ["9L1"];
|
||||
this.modData("Learnsets", "simisear").learnset.stoneedge = ["9L1"];
|
||||
this.modData("Learnsets", "simisear").learnset.swordsdance = ["9L1"];
|
||||
this.modData("Learnsets", "slowking").learnset.darkpulse = ["9L1"];
|
||||
this.modData("Learnsets", "slowking").learnset.sludgebomb = ["9L1"];
|
||||
this.modData("Learnsets", "slowking").learnset.sludgewave = ["9L1"];
|
||||
this.modData("Learnsets", "stakataka").learnset.taunt = ["9L1"];
|
||||
this.modData("Learnsets", "volcarona").learnset.weatherball = ["9L1"];
|
||||
this.modData("Learnsets", "volcarona").learnset.quiverdance = ["9L1"];
|
||||
this.modData("Learnsets", "weavile").learnset.amnesia = ["9L1"];
|
||||
this.modData("Learnsets", "weavile").learnset.auroraveil = ["9L1"];
|
||||
this.modData("Learnsets", "weavile").learnset.berrier = ["9L1"];
|
||||
this.modData("Learnsets", "weavile").learnset.dive = ["9L1"];
|
||||
this.modData("Learnsets", "weavile").learnset.haze = ["9L1"];
|
||||
this.modData("Learnsets", "weavile").learnset.hypnosis = ["9L1"];
|
||||
this.modData("Learnsets", "weavile").learnset.moonlight = ["9L1"];
|
||||
this.modData("Learnsets", "weavile").learnset.obstruct = ["9L1"];
|
||||
this.modData("Learnsets", "weavile").learnset.switcheroo = ["9L1"];
|
||||
this.modData("Learnsets", "wyrdeer").learnset.auroraveil = ["9L1"];
|
||||
this.modData("Learnsets", "wyrdeer").learnset.blizzard = ["9L1"];
|
||||
this.modData("Learnsets", "wyrdeer").learnset.freezedry = ["9L1"];
|
||||
this.modData("Learnsets", "wyrdeer").learnset.icebeam = ["9L1"];
|
||||
this.modData("Learnsets", "wyrdeer").learnset.iciclespear = ["9L1"];
|
||||
this.modData("Learnsets", "wyrdeer").learnset.icywind = ["9L1"];
|
||||
this.modData("Learnsets", "wyrdeer").learnset.solarbeam = ["9L1"];
|
||||
this.modData("Learnsets", "wyrdeer").learnset.energyball = ["9L1"];
|
||||
this.modData("Learnsets", "zarude").learnset.rest = ["9L1"];
|
||||
this.modData("Learnsets", "zeraora").learnset.doubleshock = ["9L1"];
|
||||
this.modData("Learnsets", "zeraora").learnset.highjumpkick = ["9L1"];
|
||||
this.modData("Learnsets", "zeraora").learnset.quickattack = ["9L1"];
|
||||
this.modData("Learnsets", "zeraora").learnset.charge = ["9L1"];
|
||||
this.modData("Learnsets", "aurorus").learnset.primalpulse = ["9L1"];
|
||||
this.modData("Learnsets", "cofagrigus").learnset.dragonscurse = ["9L1"];
|
||||
this.modData("Learnsets", "dudunsparce").learnset.sixtongueemojis = ["9L1"];
|
||||
this.modData("Learnsets", "kecleon").learnset.kaleidostorm = ["9L1"];
|
||||
this.modData("Learnsets", "beartic").learnset.glacierfang = ["9L1"];
|
||||
this.modData("Learnsets", "stakataka").learnset.stackshield = ["9L1"];
|
||||
this.modData("Learnsets", "aegislash").learnset.soulboundslash = ["9L1"];
|
||||
this.modData("Learnsets", "landorus").learnset.generationaldeevolution = ["9L1"];
|
||||
// this.modData("Learnsets", "landorus").learnset.generationalevolution = ["9L1"];
|
||||
this.modData("Learnsets", "sylveon").learnset.ribbonshift = ["9L1"];
|
||||
this.modData("Learnsets", "slowking").learnset.frostbittenreception = ["9L1"];
|
||||
},
|
||||
actions: {
|
||||
inherit: true,
|
||||
modifyDamage(
|
||||
baseDamage: number, pokemon: Pokemon, target: Pokemon, move: ActiveMove, suppressMessages = false
|
||||
) {
|
||||
const tr = this.battle.trunc;
|
||||
if (!move.type) move.type = '???';
|
||||
let type = move.type;
|
||||
|
||||
baseDamage += 2;
|
||||
|
||||
if (move.spreadHit) {
|
||||
// multi-target modifier (doubles only)
|
||||
const spreadModifier = this.battle.gameType === 'freeforall' ? 0.5 : 0.75;
|
||||
this.battle.debug(`Spread modifier: ${spreadModifier}`);
|
||||
baseDamage = this.battle.modify(baseDamage, spreadModifier);
|
||||
} else if (move.multihitType === 'parentalbond' && move.hit > 1) {
|
||||
// Parental Bond modifier
|
||||
const bondModifier = this.battle.gen > 6 ? 0.25 : 0.5;
|
||||
this.battle.debug(`Parental Bond modifier: ${bondModifier}`);
|
||||
baseDamage = this.battle.modify(baseDamage, bondModifier);
|
||||
if (pokemon.ability === 'aurapartner') {
|
||||
type = 'Ghost';
|
||||
move.type = 'Ghost';
|
||||
}
|
||||
}
|
||||
|
||||
// weather modifier
|
||||
baseDamage = this.battle.runEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
|
||||
|
||||
// crit - not a modifier
|
||||
const isCrit = target.getMoveHitData(move).crit;
|
||||
if (isCrit) {
|
||||
baseDamage = tr(baseDamage * (move.critModifier || (this.battle.gen >= 6 ? 1.5 : 2)));
|
||||
}
|
||||
|
||||
// random factor - also not a modifier
|
||||
baseDamage = this.battle.randomizer(baseDamage);
|
||||
|
||||
// STAB
|
||||
// The "???" type never gets STAB
|
||||
// Not even if you Roost in Gen 4 and somehow manage to use
|
||||
// Struggle in the same turn.
|
||||
// (On second thought, it might be easier to get a MissingNo.)
|
||||
if (type !== '???') {
|
||||
let stab: number | [number, number] = 1;
|
||||
|
||||
const isSTAB = move.forceSTAB || pokemon.hasType(type) || pokemon.getTypes(false, true).includes(type);
|
||||
if (isSTAB) {
|
||||
stab = 1.5;
|
||||
}
|
||||
|
||||
// The Stellar tera type makes this incredibly confusing
|
||||
// If the move's type does not match one of the user's base types,
|
||||
// the Stellar tera type applies a one-time 1.2x damage boost for that type.
|
||||
//
|
||||
// If the move's type does match one of the user's base types,
|
||||
// then the Stellar tera type applies a one-time 2x STAB boost for that type,
|
||||
// and then goes back to using the regular 1.5x STAB boost for those types.
|
||||
if (pokemon.terastallized === 'Stellar') {
|
||||
if (!pokemon.stellarBoostedTypes.includes(type) || move.stellarBoosted) {
|
||||
stab = isSTAB ? 2 : [4915, 4096];
|
||||
move.stellarBoosted = true;
|
||||
if (pokemon.species.name !== 'Terapagos-Stellar') {
|
||||
pokemon.stellarBoostedTypes.push(type);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (pokemon.terastallized === type && pokemon.getTypes(false, true).includes(type)) {
|
||||
stab = 2;
|
||||
}
|
||||
stab = this.battle.runEvent('ModifySTAB', pokemon, target, move, stab);
|
||||
}
|
||||
|
||||
baseDamage = this.battle.modify(baseDamage, stab);
|
||||
}
|
||||
|
||||
// types
|
||||
let typeMod = target.runEffectiveness(move);
|
||||
typeMod = this.battle.clampIntRange(typeMod, -6, 6);
|
||||
target.getMoveHitData(move).typeMod = typeMod;
|
||||
if (typeMod > 0) {
|
||||
if (!suppressMessages) this.battle.add('-supereffective', target);
|
||||
|
||||
for (let i = 0; i < typeMod; i++) {
|
||||
baseDamage *= 2;
|
||||
}
|
||||
}
|
||||
if (typeMod < 0) {
|
||||
if (!suppressMessages) this.battle.add('-resisted', target);
|
||||
|
||||
for (let i = 0; i > typeMod; i--) {
|
||||
baseDamage = tr(baseDamage / 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (isCrit && !suppressMessages) this.battle.add('-crit', target);
|
||||
|
||||
if (pokemon.status === 'brn' && move.category === 'Physical' && !pokemon.hasAbility('guts')) {
|
||||
if (this.battle.gen < 6 || move.id !== 'facade') {
|
||||
baseDamage = this.battle.modify(baseDamage, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
// Generation 5, but nothing later, sets damage to 1 before the final damage modifiers
|
||||
if (this.battle.gen === 5 && !baseDamage) baseDamage = 1;
|
||||
|
||||
// Final modifier. Modifiers that modify damage after min damage check, such as Life Orb.
|
||||
baseDamage = this.battle.runEvent('ModifyDamage', pokemon, target, move, baseDamage);
|
||||
|
||||
const bypassProtect = target.getMoveHitData(move).bypassProtect;
|
||||
if (bypassProtect) {
|
||||
baseDamage = this.battle.modify(baseDamage, 0.25);
|
||||
if (bypassProtect !== true && bypassProtect.effectType === 'Ability') {
|
||||
this.battle.add('-ability', pokemon, bypassProtect.name);
|
||||
}
|
||||
this.battle.add('-zbroken', target);
|
||||
}
|
||||
|
||||
// Generation 6-7 moves the check for minimum 1 damage after the final modifier...
|
||||
if (this.battle.gen !== 5 && !baseDamage) return 1;
|
||||
|
||||
// ...but 16-bit truncation happens even later, and can truncate to 0
|
||||
return tr(baseDamage, 16);
|
||||
},
|
||||
canUltraBurst(pokemon: Pokemon) {
|
||||
if (['Necrozma-Dawn-Wings', 'Necrozma-Dusk-Mane'].includes(pokemon.baseSpecies.name) &&
|
||||
pokemon.getItem().id === 'ultranecroziumz') {
|
||||
return "Necrozma-Ultra";
|
||||
} else if (pokemon.baseSpecies.name === 'Simisear' &&
|
||||
pokemon.getItem().id === 'ultrasimiseariumz') {
|
||||
return "Simisear-Ultra";
|
||||
}
|
||||
return null;
|
||||
},
|
||||
runSwitch(pokemon: Pokemon) {
|
||||
const switchersIn = [pokemon];
|
||||
while (this.battle.queue.peek()?.choice === 'runSwitch') {
|
||||
const nextSwitch = this.battle.queue.shift();
|
||||
switchersIn.push(nextSwitch!.pokemon!);
|
||||
}
|
||||
const allActive = this.battle.getAllActive(true);
|
||||
this.battle.speedSort(allActive);
|
||||
this.battle.speedOrder = allActive.map(a => a.side.n * a.battle.sides.length + a.position);
|
||||
this.battle.fieldEvent('SwitchIn', switchersIn);
|
||||
|
||||
for (const poke of switchersIn) {
|
||||
if (!poke.hp) continue;
|
||||
poke.isStarted = true;
|
||||
poke.draggedIn = null;
|
||||
if (poke.species.name === 'Iron Valiant' && !pokemon.battle.ruleTable.tagRules.includes("+pokemontag:cap"))
|
||||
pokemon.m.usedMoves = [];
|
||||
if (poke.species.name === 'Sudowoodo' && !pokemon.battle.ruleTable.tagRules.includes("+pokemontag:cap"))
|
||||
poke.m.grassMoves = 0;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
useMove(
|
||||
move: Move, pokemon: Pokemon, options?: {
|
||||
target?: Pokemon | null, sourceEffect?: Effect | null,
|
||||
zMove?: string, maxMove?: string,
|
||||
}
|
||||
) {
|
||||
pokemon.moveThisTurnResult = undefined;
|
||||
const oldMoveResult: boolean | null | undefined = pokemon.moveThisTurnResult;
|
||||
const success = this.useMoveInner(move, pokemon, options);
|
||||
if (oldMoveResult === pokemon.moveThisTurnResult) pokemon.moveThisTurnResult = success;
|
||||
|
||||
if (success && pokemon.species.name === 'Iron Valiant' &&
|
||||
!pokemon.battle.ruleTable.tagRules.includes("+pokemontag:cap")) {
|
||||
if (!pokemon.m.usedMoves) pokemon.m.usedMoves = [];
|
||||
if (!pokemon.m.usedMoves.includes(move.id)) pokemon.m.usedMoves.push(move.id);
|
||||
if (pokemon.moves.filter(name => pokemon.m.usedMoves.includes(name)).toString() === pokemon.moves.toString())
|
||||
pokemon.formeChange('Iron Valiant-High-Judge', null, true);
|
||||
}
|
||||
if (success && pokemon.species.name === 'Mewtwo' &&
|
||||
!pokemon.battle.ruleTable.tagRules.includes("+pokemontag:cap")) {
|
||||
if (!pokemon.m.darkMoves) pokemon.m.darkMoves = 0;
|
||||
if (move.type === 'Dark') pokemon.m.darkMoves++;
|
||||
if (pokemon.m.darkMoves >= 3)
|
||||
pokemon.formeChange('Mewtwo-Evil-Scary', null, true);
|
||||
}
|
||||
if (success && pokemon.species.name === 'Volcanion' &&
|
||||
!pokemon.battle.ruleTable.tagRules.includes("+pokemontag:cap")) {
|
||||
if (!pokemon.m.steamMoves) pokemon.m.steamMoves = 0;
|
||||
if ((move.type === 'Water' || move.type === 'Fire')) pokemon.m.steamMoves++;
|
||||
if (pokemon.m.steamMoves >= 3)
|
||||
pokemon.formeChange('Volcanion-Surge', null, true);
|
||||
}
|
||||
if (success && move.type === 'Grass' &&
|
||||
!pokemon.battle.ruleTable.tagRules.includes("+pokemontag:cap")) {
|
||||
for (const mon of pokemon.foes()) {
|
||||
if (mon.species.name !== 'Sudowoodo') continue;
|
||||
if (!mon.m.grassMoves) mon.m.grassMoves = 0;
|
||||
mon.m.grassMoves++;
|
||||
if (mon.m.grassMoves >= 2) {
|
||||
mon.formeChange('Sudowoodo-Nopseudo', null, true);
|
||||
}
|
||||
}
|
||||
for (const mon of pokemon.alliesAndSelf()) {
|
||||
if (mon.species.name !== 'Sudowoodo') continue;
|
||||
if (!mon.m.grassMoves) mon.m.grassMoves = 0;
|
||||
mon.m.grassMoves++;
|
||||
if (mon.m.grassMoves >= 2) {
|
||||
mon.formeChange('Sudowoodo-Nopseudo', null, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return success;
|
||||
},
|
||||
terastallize(pokemon: Pokemon) {
|
||||
if (pokemon.species.baseSpecies === 'Ogerpon' && !['Fire', 'Grass', 'Rock', 'Water', 'Fairy']
|
||||
.includes(pokemon.teraType) && (!pokemon.illusion || pokemon.illusion.species.baseSpecies === 'Ogerpon')) {
|
||||
this.battle.hint("If Ogerpon Terastallizes into a type other than Fire, Grass, Rock, or Water, the game crashes.", false, pokemon.side);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pokemon.illusion && ['Ogerpon', 'Terapagos'].includes(pokemon.illusion.species.baseSpecies)) {
|
||||
this.battle.singleEvent('End', this.dex.abilities.get('Illusion'), pokemon.abilityState, pokemon);
|
||||
}
|
||||
|
||||
const type = pokemon.teraType;
|
||||
this.battle.add('-terastallize', pokemon, type);
|
||||
pokemon.terastallized = type;
|
||||
for (const ally of pokemon.side.pokemon) {
|
||||
ally.canTerastallize = null;
|
||||
}
|
||||
pokemon.addedType = '';
|
||||
pokemon.knownType = true;
|
||||
pokemon.apparentType = type;
|
||||
if (pokemon.species.baseSpecies === 'Ogerpon') {
|
||||
let ogerponSpecies = toID(pokemon.species.battleOnly || pokemon.species.id);
|
||||
ogerponSpecies += ogerponSpecies === 'ogerpon' ? 'tealtera' : 'tera';
|
||||
pokemon.formeChange(ogerponSpecies, null, true);
|
||||
}
|
||||
if (pokemon.species.name === 'Terapagos-Terastal') {
|
||||
pokemon.formeChange('Terapagos-Stellar', null, true);
|
||||
}
|
||||
if (pokemon.species.baseSpecies === 'Morpeko' && !pokemon.transformed &&
|
||||
pokemon.baseSpecies.id !== pokemon.species.id
|
||||
) {
|
||||
pokemon.formeRegression = true;
|
||||
pokemon.baseSpecies = pokemon.species;
|
||||
pokemon.details = pokemon.getUpdatedDetails();
|
||||
}
|
||||
this.battle.runEvent('AfterTerastallization', pokemon);
|
||||
},
|
||||
},
|
||||
faintMessages(lastFirst = false, forceCheck = false, checkWin = true) {
|
||||
if (this.ended) return;
|
||||
const length = this.faintQueue.length;
|
||||
if (!length) {
|
||||
if (forceCheck && this.checkWin()) return true;
|
||||
return false;
|
||||
}
|
||||
if (lastFirst) {
|
||||
this.faintQueue.unshift(this.faintQueue[this.faintQueue.length - 1]);
|
||||
this.faintQueue.pop();
|
||||
}
|
||||
let faintQueueLeft, faintData;
|
||||
|
||||
while (this.faintQueue.length) {
|
||||
faintQueueLeft = this.faintQueue.length;
|
||||
faintData = this.faintQueue.shift()!;
|
||||
const pokemon: Pokemon = faintData.target;
|
||||
if (!pokemon.fainted && this.runEvent('BeforeFaint', pokemon, faintData.source, faintData.effect)) {
|
||||
if (pokemon.species.name === 'Kecleon' && !this.ruleTable.tagRules.includes("+pokemontag:cap")) {
|
||||
let forme = 'None';
|
||||
switch (pokemon.types[0]) {
|
||||
case 'Fire':
|
||||
case 'Rock':
|
||||
case 'Ground':
|
||||
forme = 'Kecleon-Volcanic';
|
||||
break;
|
||||
case 'Grass':
|
||||
case 'Bug':
|
||||
case 'Poison':
|
||||
forme = 'Kecleon-Wild';
|
||||
break;
|
||||
case 'Electric':
|
||||
case 'Fairy':
|
||||
case 'Psychic':
|
||||
forme = 'Kecleon-Luminous';
|
||||
break;
|
||||
case 'Ghost':
|
||||
case 'Dragon':
|
||||
case 'Steel':
|
||||
forme = 'Kecleon-Storybook';
|
||||
break;
|
||||
case 'Ice':
|
||||
case 'Water':
|
||||
case 'Flying':
|
||||
forme = 'Kecleon-Phasic';
|
||||
break;
|
||||
case 'Normal':
|
||||
case 'Fighting':
|
||||
case 'Dark':
|
||||
forme = 'Kecleon-Ruffian';
|
||||
break;
|
||||
default:
|
||||
forme = 'None';
|
||||
}
|
||||
|
||||
if (forme !== 'None') {
|
||||
pokemon.formeChange(forme, null, true);
|
||||
this.add('-message', `Kecleon was resurrected into ${pokemon.species}.`);
|
||||
|
||||
pokemon.faintQueued = false;
|
||||
pokemon.subFainted = false;
|
||||
pokemon.status = '';
|
||||
pokemon.hp = 1; // Needed so hp functions works
|
||||
pokemon.sethp(pokemon.maxhp);
|
||||
pokemon.ability = pokemon.baseAbility;
|
||||
|
||||
this.add('-heal', pokemon, pokemon.getHealth, '[from] move: Revival Blessing');
|
||||
continue;
|
||||
}
|
||||
}
|
||||
this.add('faint', pokemon);
|
||||
if (pokemon.side.pokemonLeft) pokemon.side.pokemonLeft--;
|
||||
if (pokemon.side.totalFainted < 100) pokemon.side.totalFainted++;
|
||||
this.runEvent('Faint', pokemon, faintData.source, faintData.effect);
|
||||
this.singleEvent('End', pokemon.getAbility(), pokemon.abilityState, pokemon);
|
||||
this.singleEvent('End', pokemon.getItem(), pokemon.itemState, pokemon);
|
||||
if (pokemon.formeRegression && !pokemon.transformed) {
|
||||
// before clearing volatiles
|
||||
pokemon.baseSpecies = this.dex.species.get(pokemon.set.species || pokemon.set.name);
|
||||
pokemon.baseAbility = toID(pokemon.set.ability);
|
||||
}
|
||||
pokemon.clearVolatile(false);
|
||||
pokemon.fainted = true;
|
||||
pokemon.illusion = null;
|
||||
pokemon.isActive = false;
|
||||
pokemon.isStarted = false;
|
||||
delete pokemon.terastallized;
|
||||
if (pokemon.formeRegression) {
|
||||
// after clearing volatiles
|
||||
pokemon.details = pokemon.getUpdatedDetails();
|
||||
this.add('detailschange', pokemon, pokemon.details, '[silent]');
|
||||
pokemon.updateMaxHp();
|
||||
pokemon.formeRegression = false;
|
||||
}
|
||||
pokemon.side.faintedThisTurn = pokemon;
|
||||
if (this.faintQueue.length >= faintQueueLeft) checkWin = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.gen <= 1) {
|
||||
// in gen 1, fainting skips the rest of the turn
|
||||
// residuals don't exist in gen 1
|
||||
this.queue.clear();
|
||||
// Fainting clears accumulated Bide damage
|
||||
for (const pokemon of this.getAllActive()) {
|
||||
if (pokemon.volatiles['bide']?.damage) {
|
||||
pokemon.volatiles['bide'].damage = 0;
|
||||
this.hint("Desync Clause Mod activated!");
|
||||
this.hint("In Gen 1, Bide's accumulated damage is reset to 0 when a Pokemon faints.");
|
||||
}
|
||||
}
|
||||
} else if (this.gen <= 3 && this.gameType === 'singles') {
|
||||
// in gen 3 or earlier, fainting in singles skips to residuals
|
||||
for (const pokemon of this.getAllActive()) {
|
||||
if (this.gen <= 2) {
|
||||
// in gen 2, fainting skips moves only
|
||||
this.queue.cancelMove(pokemon);
|
||||
} else {
|
||||
// in gen 3, fainting skips all moves and switches
|
||||
this.queue.cancelAction(pokemon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (checkWin && this.checkWin(faintData)) return true;
|
||||
|
||||
if (faintData && length) {
|
||||
this.runEvent('AfterFaint', faintData.target, faintData.source, faintData.effect, length);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
field: {
|
||||
setWeather(status: string | Condition, source: Pokemon | 'debug' | null = null, sourceEffect: Effect | null = null) {
|
||||
status = this.battle.dex.conditions.get(status);
|
||||
if (!sourceEffect && this.battle.effect) sourceEffect = this.battle.effect;
|
||||
if (!source && this.battle.event?.target) source = this.battle.event.target;
|
||||
if (source === 'debug') source = this.battle.sides[0].active[0];
|
||||
|
||||
if (this.weather === status.id) {
|
||||
if (sourceEffect && sourceEffect.effectType === 'Ability') {
|
||||
if (this.battle.gen > 5 || this.weatherState.duration === 0) {
|
||||
return false;
|
||||
}
|
||||
} else if (this.battle.gen > 2 || status.id === 'sandstorm') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (source) {
|
||||
const result = this.battle.runEvent('SetWeather', source, source, status);
|
||||
if (!result) {
|
||||
if (result === false) {
|
||||
if ((sourceEffect as Move)?.weather) {
|
||||
this.battle.add('-fail', source, sourceEffect, '[from] ' + this.weather);
|
||||
} else if (sourceEffect && sourceEffect.effectType === 'Ability') {
|
||||
this.battle.add('-ability', source, sourceEffect, '[from] ' + this.weather, '[fail]');
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
const prevWeather = this.weather;
|
||||
const prevWeatherState = this.weatherState;
|
||||
this.weather = status.id;
|
||||
this.weatherState = this.battle.initEffectState({ id: status.id });
|
||||
if (source) {
|
||||
this.weatherState.source = source;
|
||||
this.weatherState.sourceSlot = source.getSlot();
|
||||
}
|
||||
if (status.duration) {
|
||||
this.weatherState.duration = status.duration;
|
||||
}
|
||||
if (status.durationCallback) {
|
||||
if (!source) throw new Error(`setting weather without a source`);
|
||||
this.weatherState.duration = status.durationCallback.call(this.battle, source, source, sourceEffect);
|
||||
}
|
||||
if (!this.battle.singleEvent('FieldStart', status, this.weatherState, this, source, sourceEffect)) {
|
||||
this.weather = prevWeather;
|
||||
this.weatherState = prevWeatherState;
|
||||
return false;
|
||||
} else if (prevWeather === 'snowscape' && !this.battle.ruleTable.tagRules.includes("+pokemontag:cap")) {
|
||||
for (const pokemon of this.battle.getAllActive()) {
|
||||
if (pokemon.species.id === 'wyrdeer') {
|
||||
pokemon.formeChange('Wyrdeer-Snowblind', this.battle.effect, true);
|
||||
this.battle.add('-activate', pokemon, 'ability: Heart of Cold');
|
||||
}
|
||||
}
|
||||
}
|
||||
this.battle.eachEvent('WeatherChange', sourceEffect);
|
||||
return true;
|
||||
},
|
||||
},
|
||||
pokemon: {
|
||||
inherit: true,
|
||||
isGrounded(negateImmunity = false) {
|
||||
if ('gravity' in this.battle.field.pseudoWeather) return true;
|
||||
if ('ingrain' in this.volatiles && this.battle.gen >= 4) return true;
|
||||
if ('smackdown' in this.volatiles) return true;
|
||||
const item = (this.ignoringItem() ? '' : this.item);
|
||||
if (item === 'ironball') return true;
|
||||
// If a Fire/Flying type uses Burn Up and Roost, it becomes ???/Flying-type, but it's still grounded.
|
||||
if (!negateImmunity && this.hasType('Flying') && !(this.hasType('???') && 'roost' in this.volatiles)) return false;
|
||||
if ((this.hasAbility('levitate')) &&
|
||||
!this.battle.suppressingAbility(this)) {
|
||||
return null;
|
||||
}
|
||||
if ('magnetrise' in this.volatiles) return false;
|
||||
if ('telekinesis' in this.volatiles) return false;
|
||||
return item !== 'airballoon';
|
||||
},
|
||||
cureStatus(this: Pokemon, silent?: boolean, source: Pokemon | null = null) {
|
||||
if (!this.hp || !this.status) return false;
|
||||
|
||||
if (source?.ability === 'herbalelixir') {
|
||||
switch (this.status) {
|
||||
case 'psn':
|
||||
case 'tox':
|
||||
this.setAbility('poisonheal');
|
||||
this.baseAbility = this.ability;
|
||||
return false;
|
||||
case 'brn':
|
||||
this.setAbility('guts');
|
||||
this.baseAbility = this.ability;
|
||||
return false;
|
||||
case 'par':
|
||||
this.setAbility('quickfeet');
|
||||
this.baseAbility = this.ability;
|
||||
return false;
|
||||
case 'ber':
|
||||
this.setAbility('marvelscale');
|
||||
this.baseAbility = this.ability;
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.setStatus('');
|
||||
this.battle.add('-curestatus', this, this.status, silent ? '[silent]' : '[msg]');
|
||||
if (this.status === 'slp' && this.removeVolatile('nightmare')) {
|
||||
this.battle.add('-end', this, 'Nightmare', '[silent]');
|
||||
}
|
||||
|
||||
if (source?.species.name === 'Zarude' && !source.battle.ruleTable.tagRules.includes("+pokemontag:cap")) {
|
||||
source.formeChange('Zarude-Alchemist', null, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
eatItem(this: Pokemon, force?: boolean, source?: Pokemon, sourceEffect?: Effect) {
|
||||
if (!this.item) return false;
|
||||
if ((!this.hp && this.item !== 'jabocaberry' && this.item !== 'rowapberry') || !this.isActive) return false;
|
||||
|
||||
if (!sourceEffect && this.battle.effect) sourceEffect = this.battle.effect;
|
||||
if (!source && this.battle.event?.target) source = this.battle.event.target;
|
||||
const item = this.getItem();
|
||||
if (sourceEffect?.effectType === 'Item' && this.item !== sourceEffect.id && source === this) {
|
||||
// if an item is telling us to eat it but we aren't holding it, we probably shouldn't eat what we are holding
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
this.battle.runEvent('UseItem', this, null, null, item) &&
|
||||
(force || this.battle.runEvent('TryEatItem', this, null, null, item))
|
||||
) {
|
||||
this.battle.add('-enditem', this, item, '[eat]');
|
||||
|
||||
this.battle.singleEvent('Eat', item, this.itemState, this, source, sourceEffect);
|
||||
this.battle.runEvent('EatItem', this, source, sourceEffect, item);
|
||||
|
||||
if (RESTORATIVE_BERRIES.has(item.id)) {
|
||||
switch (this.pendingStaleness) {
|
||||
case 'internal':
|
||||
if (this.staleness !== 'external') this.staleness = 'internal';
|
||||
break;
|
||||
case 'external':
|
||||
this.staleness = 'external';
|
||||
break;
|
||||
}
|
||||
this.pendingStaleness = undefined;
|
||||
}
|
||||
|
||||
this.lastItem = this.item;
|
||||
this.item = '';
|
||||
this.battle.clearEffectState(this.itemState);
|
||||
this.usedItemThisTurn = true;
|
||||
this.ateBerry = true;
|
||||
if (this.species.baseSpecies === 'Alcremie' && !this.battle.ruleTable.tagRules.includes("+pokemontag:cap")) {
|
||||
switch (this.species.id) {
|
||||
case "alcremierubycream":
|
||||
this.formeChange('Alcremie-Sweetened-Ruby-Cream', null, true);
|
||||
break;
|
||||
case "alcremiematchacream":
|
||||
this.formeChange('Alcremie-Sweetened-Matcha-Cream', null, true);
|
||||
break;
|
||||
case "alcremiemintcream":
|
||||
this.formeChange('Alcremie-Sweetened-Mint-Cream', null, true);
|
||||
break;
|
||||
case "alcremielemoncream":
|
||||
this.formeChange('Alcremie-Sweetened-Lemon-Cream', null, true);
|
||||
break;
|
||||
case "alcremiesaltedcream":
|
||||
this.formeChange('Alcremie-Sweetened-Salted-Cream', null, true);
|
||||
break;
|
||||
case "alcremierubyswirl":
|
||||
this.formeChange('Alcremie-Sweetened-Ruby-Swirl', null, true);
|
||||
break;
|
||||
case "alcremiecaramelswirl":
|
||||
this.formeChange('Alcremie-Sweetened-Caramel-Swirl', null, true);
|
||||
break;
|
||||
case "alcremierainbowswirl":
|
||||
this.formeChange('Alcremie-Sweetened-Rainbow-Swirl', null, true);
|
||||
break;
|
||||
default:
|
||||
this.formeChange('Alcremie-Sweetened', null, true);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (this.lastItem) {
|
||||
case "aguavberry":
|
||||
this.battle.boost({ spd: 1 }, this);
|
||||
break;
|
||||
case "enigmaberry":
|
||||
const type = this.battle.dex.types.names()[this.battle.random(18)];
|
||||
if (this.hasType(type)) return false;
|
||||
if (!this.addType(type)) return false;
|
||||
this.battle.add('-start', this, 'typeadd', type);
|
||||
break;
|
||||
case "figyberry":
|
||||
this.battle.boost({ atk: 1 }, this);
|
||||
break;
|
||||
case "iapapaberry":
|
||||
this.battle.boost({ def: 1 }, this);
|
||||
break;
|
||||
case "magoberry":
|
||||
this.battle.boost({ spe: 1 }, this);
|
||||
break;
|
||||
case "oranberry":
|
||||
this.heal(this.maxhp);
|
||||
break;
|
||||
case "sitrusberry":
|
||||
const side = this.side.foe;
|
||||
if (!side.sideConditions['stickyweb']) {
|
||||
side.addSideCondition('stickyweb', this.foes()[0]);
|
||||
}
|
||||
break;
|
||||
case "wikiberry":
|
||||
this.battle.boost({ spa: 1 }, this);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.battle.runEvent('AfterUseItem', this, null, null, item);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
calculateStat(statName: StatIDExceptHP, boost: number, modifier?: number, statUser?: Pokemon) {
|
||||
statName = toID(statName) as StatIDExceptHP;
|
||||
// @ts-expect-error type checking prevents 'hp' from being passed, but we're paranoid
|
||||
if (statName === 'hp') throw new Error("Please read `maxhp` directly");
|
||||
|
||||
// base stat
|
||||
let stat = this.storedStats[statName];
|
||||
|
||||
// Implement Trying My Best!
|
||||
if (!this.battle.ruleTable.tagRules.includes("+pokemontag:cap")) {
|
||||
const mon = this as any;
|
||||
// Make sure it has changed abilities since
|
||||
if (mon.timesSwitchedIn && mon.ability !== 'tryingmybest') {
|
||||
stat *= (10 + mon.timesSwitchedIn) / 10;
|
||||
}
|
||||
}
|
||||
|
||||
// Wonder Room swaps defenses before calculating anything else
|
||||
if ('wonderroom' in this.battle.field.pseudoWeather) {
|
||||
if (statName === 'def') {
|
||||
stat = this.storedStats['spd'];
|
||||
} else if (statName === 'spd') {
|
||||
stat = this.storedStats['def'];
|
||||
}
|
||||
}
|
||||
|
||||
// stat boosts
|
||||
let boosts: SparseBoostsTable = {};
|
||||
const boostName = statName as BoostID;
|
||||
boosts[boostName] = boost;
|
||||
boosts = this.battle.runEvent('ModifyBoost', statUser || this, null, null, boosts);
|
||||
boost = boosts[boostName]!;
|
||||
const boostTable = [1, 1.5, 2, 2.5, 3, 3.5, 4];
|
||||
if (boost > 6) boost = 6;
|
||||
if (boost < -6) boost = -6;
|
||||
if (boost >= 0) {
|
||||
stat = Math.floor(stat * boostTable[boost]);
|
||||
} else {
|
||||
stat = Math.floor(stat / boostTable[-boost]);
|
||||
}
|
||||
|
||||
// stat modifier
|
||||
return this.battle.modify(stat, (modifier || 1));
|
||||
},
|
||||
|
||||
getStat(statName: StatIDExceptHP, unboosted?: boolean, unmodified?: boolean) {
|
||||
statName = toID(statName) as StatIDExceptHP;
|
||||
// @ts-expect-error type checking prevents 'hp' from being passed, but we're paranoid
|
||||
if (statName === 'hp') throw new Error("Please read `maxhp` directly");
|
||||
|
||||
// base stat
|
||||
let stat = this.storedStats[statName];
|
||||
|
||||
// Implement Trying My Best!
|
||||
if (!this.battle.ruleTable.tagRules.includes("+pokemontag:cap")) {
|
||||
const mon = this as any;
|
||||
// Make sure it has changed abilities since
|
||||
if (mon.timesSwitchedIn && mon.ability !== 'tryingmybest') {
|
||||
stat *= (10 + mon.timesSwitchedIn) / 10;
|
||||
}
|
||||
}
|
||||
|
||||
// Download ignores Wonder Room's effect, but this results in
|
||||
// stat stages being calculated on the opposite defensive stat
|
||||
if (unmodified && 'wonderroom' in this.battle.field.pseudoWeather) {
|
||||
if (statName === 'def') {
|
||||
statName = 'spd';
|
||||
} else if (statName === 'spd') {
|
||||
statName = 'def';
|
||||
}
|
||||
}
|
||||
|
||||
// stat boosts
|
||||
if (!unboosted) {
|
||||
let boosts = this.boosts;
|
||||
if (!unmodified) {
|
||||
boosts = this.battle.runEvent('ModifyBoost', this, null, null, { ...boosts });
|
||||
}
|
||||
let boost = boosts[statName];
|
||||
const boostTable = [1, 1.5, 2, 2.5, 3, 3.5, 4];
|
||||
if (boost > 6) boost = 6;
|
||||
if (boost < -6) boost = -6;
|
||||
if (boost >= 0) {
|
||||
stat = Math.floor(stat * boostTable[boost]);
|
||||
} else {
|
||||
stat = Math.floor(stat / boostTable[-boost]);
|
||||
}
|
||||
}
|
||||
|
||||
// stat modifier effects
|
||||
if (!unmodified) {
|
||||
const statTable: { [s in StatIDExceptHP]: string } = { atk: 'Atk', def: 'Def', spa: 'SpA', spd: 'SpD', spe: 'Spe' };
|
||||
stat = this.battle.runEvent('Modify' + statTable[statName], this, null, null, stat);
|
||||
}
|
||||
|
||||
if (statName === 'spe' && stat > 10000 && !this.battle.format.battle?.trunc) stat = 10000;
|
||||
return stat;
|
||||
},
|
||||
},
|
||||
};
|
||||
98
data/mods/champions/abilities.ts
Normal file
98
data/mods/champions/abilities.ts
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTable = {
|
||||
angershell: {
|
||||
inherit: true,
|
||||
onDamage(damage, target, source, effect) {
|
||||
this.effectState.checkedAngerShell = !(effect.effectType === "Move" && !effect.multihit);
|
||||
},
|
||||
},
|
||||
berserk: {
|
||||
inherit: true,
|
||||
onDamage(damage, target, source, effect) {
|
||||
this.effectState.checkedBerserk = !(effect.effectType === "Move" && !effect.multihit);
|
||||
},
|
||||
},
|
||||
disguise: {
|
||||
inherit: true,
|
||||
onEffectiveness(typeMod, target, type, move) {
|
||||
if (!target || move.category === 'Status') return;
|
||||
|
||||
if (move.hit === 1) delete this.effectState.neutral;
|
||||
if (this.effectState.neutral) return 0;
|
||||
|
||||
if (!['mimikyu', 'mimikyutotem'].includes(target.species.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const hitSub = target.volatiles['substitute'] && !move.flags['bypasssub'] && !(move.infiltrates && this.gen >= 6);
|
||||
if (hitSub) return;
|
||||
|
||||
if (!target.runImmunity(move)) return;
|
||||
this.effectState.neutral = true;
|
||||
return 0;
|
||||
},
|
||||
},
|
||||
dragonize: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
},
|
||||
healer: {
|
||||
inherit: true,
|
||||
onResidual(pokemon) {
|
||||
for (const allyActive of pokemon.adjacentAllies()) {
|
||||
if (allyActive.status && this.randomChance(1, 2)) {
|
||||
this.add('-activate', pokemon, 'ability: Healer');
|
||||
allyActive.cureStatus();
|
||||
}
|
||||
}
|
||||
},
|
||||
desc: "50% chance this Pokemon's ally has its non-volatile status condition cured at the end of each turn.",
|
||||
shortDesc: "50% chance this Pokemon's ally has its status cured at the end of each turn.",
|
||||
},
|
||||
megasol: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
},
|
||||
naturalcure: {
|
||||
inherit: true,
|
||||
onCheckShow: undefined, // no inherit
|
||||
onSwitchOut(pokemon) {
|
||||
if (!pokemon.status || pokemon.status === 'fnt') return;
|
||||
|
||||
this.add('-curestatus', pokemon, pokemon.status, '[from] ability: Natural Cure', '[silent]');
|
||||
pokemon.clearStatus();
|
||||
},
|
||||
},
|
||||
piercingdrill: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
},
|
||||
regenerator: {
|
||||
inherit: true,
|
||||
onSwitchOut(pokemon) {
|
||||
if (pokemon.heal(pokemon.baseMaxhp / 3)) {
|
||||
this.add('-heal', pokemon, pokemon.getHealth, '[from] ability: Regenerator', '[silent]');
|
||||
}
|
||||
},
|
||||
},
|
||||
spicyspray: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
// this is only in the mod folder because it is weird like Dire Claw
|
||||
if (!source.trySetStatus('brn', target) && !target.status && target.hasType('Fire')) {
|
||||
this.add('-immune', target);
|
||||
}
|
||||
},
|
||||
},
|
||||
unseenfist: {
|
||||
onModifyMove: undefined, // no inherit
|
||||
onHitProtect(source, target, move) {
|
||||
if (move.flags['contact']) {
|
||||
target.getMoveHitData(move).bypassProtect = this.effect;
|
||||
return false;
|
||||
}
|
||||
},
|
||||
inherit: true,
|
||||
shortDesc: "This Pokemon's contact moves ignore a target's protection and deal 1/4 the usual damage.",
|
||||
},
|
||||
};
|
||||
143
data/mods/champions/conditions.ts
Normal file
143
data/mods/champions/conditions.ts
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDataTable = {
|
||||
par: {
|
||||
inherit: true,
|
||||
onBeforeMove(pokemon) {
|
||||
if (this.randomChance(1, 8)) {
|
||||
this.add('cant', pokemon, 'par');
|
||||
return false;
|
||||
}
|
||||
},
|
||||
},
|
||||
slp: {
|
||||
inherit: true,
|
||||
onStart(target, source, sourceEffect) {
|
||||
if (sourceEffect && sourceEffect.effectType === 'Ability') {
|
||||
this.add('-status', target, 'slp', '[from] ability: ' + sourceEffect.name, `[of] ${source}`);
|
||||
} else if (sourceEffect && sourceEffect.effectType === 'Move') {
|
||||
this.add('-status', target, 'slp', `[from] move: ${sourceEffect.name}`);
|
||||
} else {
|
||||
this.add('-status', target, 'slp');
|
||||
}
|
||||
|
||||
// 1/3 chance for a Pokemon to wake up on turn 2
|
||||
this.effectState.startTime = this.sample([2, 3, 3]);
|
||||
this.effectState.time = this.effectState.startTime;
|
||||
|
||||
if (target.removeVolatile('nightmare')) {
|
||||
this.add('-end', target, 'Nightmare', '[silent]');
|
||||
}
|
||||
},
|
||||
},
|
||||
frz: {
|
||||
inherit: true,
|
||||
onStart(target, source, sourceEffect) {
|
||||
if (sourceEffect && sourceEffect.effectType === 'Ability') {
|
||||
this.add('-status', target, 'frz', '[from] ability: ' + sourceEffect.name, `[of] ${source}`);
|
||||
} else {
|
||||
this.add('-status', target, 'frz');
|
||||
}
|
||||
if (target.species.name === 'Shaymin-Sky' && target.baseSpecies.baseSpecies === 'Shaymin') {
|
||||
target.formeChange('Shaymin', this.effect, true);
|
||||
}
|
||||
|
||||
this.effectState.startTime = 3;
|
||||
this.effectState.time = this.effectState.startTime;
|
||||
},
|
||||
onBeforeMove(pokemon, target, move) {
|
||||
if (move.flags['defrost'] && !(move.id === 'burnup' && !pokemon.hasType('Fire'))) return;
|
||||
pokemon.statusState.time--;
|
||||
if (pokemon.statusState.time <= 0 || this.randomChance(1, 4)) {
|
||||
pokemon.cureStatus();
|
||||
return;
|
||||
}
|
||||
this.add('cant', pokemon, 'frz');
|
||||
return false;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* If Utility Umbrella continues to work as in previous gens and Mega Sol continues to bypass defensive
|
||||
* weather boosts, the best implementation is:
|
||||
* - run WeatherModifyDamage with `fastExit`
|
||||
* - give WeatherModifyDamagePriority to Mega Sol
|
||||
* - delete the weather conditions below
|
||||
*/
|
||||
raindance: {
|
||||
inherit: true,
|
||||
onWeatherModifyDamage(damage, attacker, defender, move) {
|
||||
if (attacker.effectiveWeather() !== 'raindance') return;
|
||||
if (move.type === 'Water') {
|
||||
this.debug('rain water boost');
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
if (move.type === 'Fire') {
|
||||
this.debug('rain fire suppress');
|
||||
return this.chainModify(0.5);
|
||||
}
|
||||
},
|
||||
},
|
||||
primordialsea: {
|
||||
inherit: true,
|
||||
onWeatherModifyDamage(damage, attacker, defender, move) {
|
||||
if (attacker.effectiveWeather() !== 'primordialsea') return;
|
||||
if (move.type === 'Water') {
|
||||
this.debug('Rain water boost');
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
},
|
||||
},
|
||||
sunnyday: {
|
||||
inherit: true,
|
||||
onWeatherModifyDamage(damage, attacker, defender, move) {
|
||||
if (attacker.effectiveWeather() !== 'sunnyday') return;
|
||||
if (move.id === 'hydrosteam') {
|
||||
this.debug('Sunny Day Hydro Steam boost');
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
if (move.type === 'Fire') {
|
||||
this.debug('Sunny Day fire boost');
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
if (move.type === 'Water') {
|
||||
this.debug('Sunny Day water suppress');
|
||||
return this.chainModify(0.5);
|
||||
}
|
||||
},
|
||||
},
|
||||
desolateland: {
|
||||
inherit: true,
|
||||
onWeatherModifyDamage(damage, attacker, defender, move) {
|
||||
if (attacker.effectiveWeather() !== 'desolateland') return;
|
||||
if (move.type === 'Fire') {
|
||||
this.debug('Desolate Land fire boost');
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
},
|
||||
},
|
||||
sandstorm: {
|
||||
inherit: true,
|
||||
onModifySpD(spd, target, source) {
|
||||
if (target.hasType('Rock') && source.effectiveWeather() === 'sandstorm') {
|
||||
return this.modify(spd, 1.5);
|
||||
}
|
||||
},
|
||||
},
|
||||
snowscape: {
|
||||
inherit: true,
|
||||
onModifyDef(def, target, source) {
|
||||
if (target.hasType('Ice') && source.effectiveWeather() === 'snowscape') {
|
||||
return this.modify(def, 1.5);
|
||||
}
|
||||
},
|
||||
},
|
||||
// TODO: check Mega Sol's interaction with Deltastream
|
||||
// deltastream: {
|
||||
// inherit: true,
|
||||
// onEffectiveness(typeMod, target, type, move) {
|
||||
// if (move && move.effectType === 'Move' && move.category !== 'Status' && type === 'Flying' && typeMod > 0) {
|
||||
// this.add('-fieldactivate', 'Delta Stream');
|
||||
// return 0;
|
||||
// }
|
||||
// },
|
||||
// },
|
||||
};
|
||||
5128
data/mods/champions/formats-data.ts
Normal file
5128
data/mods/champions/formats-data.ts
Normal file
File diff suppressed because it is too large
Load Diff
1054
data/mods/champions/items.ts
Normal file
1054
data/mods/champions/items.ts
Normal file
File diff suppressed because it is too large
Load Diff
13451
data/mods/champions/learnsets.ts
Normal file
13451
data/mods/champions/learnsets.ts
Normal file
File diff suppressed because it is too large
Load Diff
1179
data/mods/champions/moves.ts
Normal file
1179
data/mods/champions/moves.ts
Normal file
File diff suppressed because it is too large
Load Diff
55
data/mods/champions/rulesets.ts
Normal file
55
data/mods/champions/rulesets.ts
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
standardag: {
|
||||
inherit: true,
|
||||
ruleset: [
|
||||
'Obtainable', 'Team Preview', 'Cancel Mod', 'Endless Battle Clause',
|
||||
'Adjust Level = 50', 'Species Clause', 'Item Clause = 1', 'Min Team Size = 6',
|
||||
],
|
||||
},
|
||||
standard: {
|
||||
inherit: true,
|
||||
ruleset: [
|
||||
'Standard AG',
|
||||
'Sleep Moves Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'Evasion Items Clause',
|
||||
],
|
||||
},
|
||||
standarddraft: {
|
||||
inherit: true,
|
||||
ruleset: [
|
||||
'Standard AG',
|
||||
'Nickname Clause', 'Sleep Clause Mod', 'OHKO Clause', 'Evasion Clause',
|
||||
'!Item Clause',
|
||||
],
|
||||
onBegin() {
|
||||
this.reportPercentages = true;
|
||||
},
|
||||
// timer: {starting: 60 * 60, grace: 0, addPerTurn: 10, maxPerTurn: 100, timeoutAutoChoose: true},
|
||||
},
|
||||
flatrules: {
|
||||
inherit: true,
|
||||
desc: "The in-game Flat Rules: Adjust Level 50, Species Clause, Item Clause = 1, -Mythical, -Restricted Legendary, Bring 6 Pick 3-6 depending on game type.",
|
||||
ruleset: ['Obtainable', 'Team Preview', 'Species Clause', 'Nickname Clause', 'Item Clause = 1', 'Adjust Level = 50', 'Picked Team Size = Auto', 'Min Team Size = 6', 'Cancel Mod'],
|
||||
banlist: ['Mythical', 'Restricted Legendary'],
|
||||
},
|
||||
teampreview: {
|
||||
inherit: true,
|
||||
onTeamPreview() {
|
||||
this.add('clearpoke');
|
||||
for (const pokemon of this.getAllPokemon()) {
|
||||
const details = pokemon.details.replace(/(Xerneas|Zacian|Zamazenta)(-[a-zA-Z?-]+)?/g, '$1-*');
|
||||
this.add('poke', pokemon.side.id, details, '');
|
||||
}
|
||||
if (this.ruleTable.has(`teratypepreview`)) {
|
||||
for (const side of this.sides) {
|
||||
let buf = ``;
|
||||
for (const pokemon of side.pokemon) {
|
||||
buf += buf ? ` / ` : `raw|${side.name}'s Tera Types:<br />`;
|
||||
buf += `<psicon pokemon="${pokemon.species.id}" /><psicon type="${pokemon.teraType}" />`;
|
||||
}
|
||||
this.add(`${buf}`);
|
||||
}
|
||||
}
|
||||
this.makeRequest('teampreview');
|
||||
},
|
||||
},
|
||||
};
|
||||
556
data/mods/champions/scripts.ts
Normal file
556
data/mods/champions/scripts.ts
Normal file
|
|
@ -0,0 +1,556 @@
|
|||
export const Scripts: ModdedBattleScriptsData = {
|
||||
gen: 9,
|
||||
init() {
|
||||
for (const i in this.data.Moves) {
|
||||
if (this.data.Moves[i].pp > 20) {
|
||||
this.modData('Moves', i).pp = 20;
|
||||
}
|
||||
}
|
||||
},
|
||||
statModify(baseStats, set, statName) {
|
||||
const tr = this.trunc;
|
||||
let stat = baseStats[statName];
|
||||
const evs = set.evs[statName];
|
||||
if (statName === 'hp') {
|
||||
return stat + evs + 75;
|
||||
}
|
||||
stat = stat + evs + 20;
|
||||
const nature = this.dex.natures.get(set.nature);
|
||||
// Natures are calculated with 16-bit truncation.
|
||||
// This only affects Eternatus-Eternamax in Pure Hackmons.
|
||||
if (nature.plus === statName) {
|
||||
stat = this.ruleTable.has('overflowstatmod') ? Math.min(stat, 595) : stat;
|
||||
stat = tr(tr(stat * 110, 16) / 100);
|
||||
} else if (nature.minus === statName) {
|
||||
stat = this.ruleTable.has('overflowstatmod') ? Math.min(stat, 728) : stat;
|
||||
stat = tr(tr(stat * 90, 16) / 100);
|
||||
}
|
||||
return stat;
|
||||
},
|
||||
calculatePP(move, ppUps) {
|
||||
return move.noPPBoosts ? move.pp : (move.pp / 5 + 1) * 4;
|
||||
},
|
||||
pokemon: {
|
||||
// Remove Trick Room underflow
|
||||
getActionSpeed() {
|
||||
let speed = this.getStat('spe', false, false);
|
||||
const trickRoomCheck = this.battle.ruleTable.has('twisteddimensionmod') ?
|
||||
!this.battle.field.getPseudoWeather('trickroom') : this.battle.field.getPseudoWeather('trickroom');
|
||||
if (trickRoomCheck) {
|
||||
speed = -speed;
|
||||
}
|
||||
return speed;
|
||||
},
|
||||
// Don't revert Mega Evolutions after fainting
|
||||
// TODO: confirm interaction with Revival Blessing
|
||||
formeChange(speciesId, source, isPermanent, abilitySlot = '0', message) {
|
||||
const rawSpecies = this.battle.dex.species.get(speciesId);
|
||||
|
||||
const species = this.setSpecies(rawSpecies, source);
|
||||
if (!species) return false;
|
||||
|
||||
if (this.battle.gen <= 2) return true;
|
||||
|
||||
// The species the opponent sees
|
||||
const apparentSpecies =
|
||||
this.illusion ? this.illusion.species.name : species.baseSpecies;
|
||||
if (isPermanent) {
|
||||
this.baseSpecies = rawSpecies;
|
||||
this.details = this.getUpdatedDetails();
|
||||
let details = (this.illusion || this).details;
|
||||
if (this.terastallized) details += `, tera:${this.terastallized}`;
|
||||
this.battle.add('detailschange', this, details);
|
||||
this.updateMaxHp();
|
||||
if (!source) {
|
||||
// Tera forme
|
||||
// Ogerpon/Terapagos text goes here
|
||||
this.formeRegression = true;
|
||||
} else if (source.effectType === 'Item') {
|
||||
this.canTerastallize = null; // National Dex behavior
|
||||
if (source.zMove) {
|
||||
this.battle.add('-burst', this, apparentSpecies, species.requiredItem);
|
||||
this.moveThisTurnResult = true; // Ultra Burst counts as an action for Truant
|
||||
} else if (source.isPrimalOrb) {
|
||||
if (this.illusion) {
|
||||
this.ability = '';
|
||||
this.battle.add('-primal', this.illusion, species.requiredItem);
|
||||
} else {
|
||||
this.battle.add('-primal', this, species.requiredItem);
|
||||
}
|
||||
} else {
|
||||
this.battle.add('-mega', this, apparentSpecies, species.requiredItem);
|
||||
this.moveThisTurnResult = true; // Mega Evolution counts as an action for Truant
|
||||
}
|
||||
} else if (source.effectType === 'Status') {
|
||||
// Shaymin-Sky -> Shaymin
|
||||
this.battle.add('-formechange', this, species.name, message);
|
||||
}
|
||||
} else {
|
||||
if (source?.effectType === 'Ability') {
|
||||
this.battle.add('-formechange', this, species.name, message, `[from] ability: ${source.name}`);
|
||||
} else {
|
||||
this.battle.add('-formechange', this, this.illusion ? this.illusion.species.name : species.name, message);
|
||||
}
|
||||
}
|
||||
if (isPermanent && (!source || !['disguise', 'iceface'].includes(source.id))) {
|
||||
if (this.illusion && source) {
|
||||
// Tera forme by Ogerpon or Terapagos breaks the Illusion
|
||||
this.ability = ''; // Don't allow Illusion to wear off
|
||||
}
|
||||
const ability = species.abilities[abilitySlot] || species.abilities['0'];
|
||||
// Ogerpon's forme change doesn't override permanent abilities
|
||||
if (source || !this.getAbility().flags['cantsuppress']) this.setAbility(ability, null, null, true);
|
||||
// However, its ability does reset upon switching out
|
||||
this.baseAbility = this.battle.toID(ability);
|
||||
}
|
||||
if (this.terastallized) {
|
||||
this.knownType = true;
|
||||
this.apparentType = this.terastallized;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
canTerastallize(pokemon) {
|
||||
return null;
|
||||
},
|
||||
canMegaEvo(pokemon: Pokemon) {
|
||||
const species = pokemon.baseSpecies;
|
||||
const altForme = species.otherFormes && this.dex.species.get(species.otherFormes[0]);
|
||||
const item = pokemon.getItem();
|
||||
// Mega Rayquaza
|
||||
if ((this.battle.gen <= 7 || this.battle.ruleTable.has('+pokemontag:past') ||
|
||||
this.battle.ruleTable.has('+pokemontag:future')) &&
|
||||
altForme?.isMega && altForme?.requiredMove &&
|
||||
pokemon.baseMoves.includes(toID(altForme.requiredMove)) && !item.zMove) {
|
||||
return altForme.name;
|
||||
}
|
||||
return item.megaStone?.[species.name] || null;
|
||||
},
|
||||
// Announce 4x and 0.25x effectiveness
|
||||
modifyDamage(baseDamage, pokemon, target, move, suppressMessages) {
|
||||
const tr = this.battle.trunc;
|
||||
if (!move.type) move.type = '???';
|
||||
const type = move.type;
|
||||
|
||||
baseDamage += 2;
|
||||
|
||||
if (move.spreadHit) {
|
||||
// multi-target modifier (doubles only)
|
||||
const spreadModifier = this.battle.gameType === 'freeforall' ? 0.5 : 0.75;
|
||||
this.battle.debug(`Spread modifier: ${spreadModifier}`);
|
||||
baseDamage = this.battle.modify(baseDamage, spreadModifier);
|
||||
} else if (move.multihitType === 'parentalbond' && move.hit > 1) {
|
||||
// Parental Bond modifier
|
||||
const bondModifier = this.battle.gen > 6 ? 0.25 : 0.5;
|
||||
this.battle.debug(`Parental Bond modifier: ${bondModifier}`);
|
||||
baseDamage = this.battle.modify(baseDamage, bondModifier);
|
||||
}
|
||||
|
||||
// weather modifier
|
||||
baseDamage = this.battle.runEvent('WeatherModifyDamage', pokemon, target, move, baseDamage);
|
||||
|
||||
// crit - not a modifier
|
||||
const isCrit = target.getMoveHitData(move).crit;
|
||||
if (isCrit) {
|
||||
baseDamage = tr(baseDamage * (move.critModifier || (this.battle.gen >= 6 ? 1.5 : 2)));
|
||||
}
|
||||
|
||||
// random factor - also not a modifier
|
||||
baseDamage = this.battle.randomizer(baseDamage);
|
||||
|
||||
// STAB
|
||||
// The "???" type never gets STAB
|
||||
// Not even if you Roost in Gen 4 and somehow manage to use
|
||||
// Struggle in the same turn.
|
||||
// (On second thought, it might be easier to get a MissingNo.)
|
||||
if (type !== '???') {
|
||||
let stab: number | [number, number] = 1;
|
||||
|
||||
const isSTAB = move.forceSTAB || pokemon.hasType(type) || pokemon.getTypes(false, true).includes(type);
|
||||
if (isSTAB) {
|
||||
stab = 1.5;
|
||||
}
|
||||
|
||||
// The Stellar tera type makes this incredibly confusing
|
||||
// If the move's type does not match one of the user's base types,
|
||||
// the Stellar tera type applies a one-time 1.2x damage boost for that type.
|
||||
//
|
||||
// If the move's type does match one of the user's base types,
|
||||
// then the Stellar tera type applies a one-time 2x STAB boost for that type,
|
||||
// and then goes back to using the regular 1.5x STAB boost for those types.
|
||||
if (pokemon.terastallized === 'Stellar') {
|
||||
if (!pokemon.stellarBoostedTypes.includes(type) || move.stellarBoosted) {
|
||||
stab = isSTAB ? 2 : [4915, 4096];
|
||||
move.stellarBoosted = true;
|
||||
if (pokemon.species.name !== 'Terapagos-Stellar') {
|
||||
pokemon.stellarBoostedTypes.push(type);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (pokemon.terastallized === type && pokemon.getTypes(false, true).includes(type)) {
|
||||
stab = 2;
|
||||
}
|
||||
stab = this.battle.runEvent('ModifySTAB', pokemon, target, move, stab);
|
||||
}
|
||||
|
||||
baseDamage = this.battle.modify(baseDamage, stab);
|
||||
}
|
||||
|
||||
// types
|
||||
let typeMod = target.runEffectiveness(move);
|
||||
typeMod = this.battle.clampIntRange(typeMod, -6, 6);
|
||||
target.getMoveHitData(move).typeMod = typeMod;
|
||||
if (typeMod > 0) {
|
||||
if (!suppressMessages) this.battle.add('-supereffective', target, Math.min(typeMod, 2));
|
||||
|
||||
for (let i = 0; i < typeMod; i++) {
|
||||
baseDamage *= 2;
|
||||
}
|
||||
}
|
||||
if (typeMod < 0) {
|
||||
if (!suppressMessages) this.battle.add('-resisted', target, Math.min(-typeMod, 2));
|
||||
|
||||
for (let i = 0; i > typeMod; i--) {
|
||||
baseDamage = tr(baseDamage / 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (isCrit && !suppressMessages) this.battle.add('-crit', target);
|
||||
|
||||
if (pokemon.status === 'brn' && move.category === 'Physical' && !pokemon.hasAbility('guts')) {
|
||||
if (this.battle.gen < 6 || move.id !== 'facade') {
|
||||
baseDamage = this.battle.modify(baseDamage, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
// Generation 5, but nothing later, sets damage to 1 before the final damage modifiers
|
||||
if (this.battle.gen === 5 && !baseDamage) baseDamage = 1;
|
||||
|
||||
// Final modifier. Modifiers that modify damage after min damage check, such as Life Orb.
|
||||
baseDamage = this.battle.runEvent('ModifyDamage', pokemon, target, move, baseDamage);
|
||||
|
||||
const bypassProtect = target.getMoveHitData(move).bypassProtect;
|
||||
if (bypassProtect) {
|
||||
baseDamage = this.battle.modify(baseDamage, 0.25);
|
||||
if (bypassProtect !== true && bypassProtect.effectType === 'Ability') {
|
||||
this.battle.add('-ability', pokemon, bypassProtect.name);
|
||||
}
|
||||
this.battle.add('-zbroken', target);
|
||||
}
|
||||
|
||||
// Generation 6-7 moves the check for minimum 1 damage after the final modifier...
|
||||
if (this.battle.gen !== 5 && !baseDamage) return 1;
|
||||
|
||||
// ...but 16-bit truncation happens even later, and can truncate to 0
|
||||
return tr(baseDamage, 16);
|
||||
},
|
||||
// Run `AfterHit` events even if the source fainted
|
||||
spreadMoveHit(targets, pokemon, moveOrMoveName, hitEffect?, isSecondary?, isSelf?) {
|
||||
// Hardcoded for single-target purposes
|
||||
// (no spread moves have any kind of onTryHit handler)
|
||||
const target = targets[0];
|
||||
let damage: (number | boolean | undefined)[] = [];
|
||||
for (const i of targets.keys()) {
|
||||
damage[i] = true;
|
||||
}
|
||||
const move = this.dex.getActiveMove(moveOrMoveName);
|
||||
let hitResult: boolean | number | null = true;
|
||||
let moveData = hitEffect!;
|
||||
if (!moveData) moveData = move;
|
||||
if (!moveData.flags) moveData.flags = {};
|
||||
if (move.target === 'all' && !isSelf) {
|
||||
hitResult = this.battle.singleEvent('TryHitField', moveData, {}, target || null, pokemon, move);
|
||||
} else if ((move.target === 'foeSide' || move.target === 'allySide' || move.target === 'allyTeam') && !isSelf) {
|
||||
hitResult = this.battle.singleEvent('TryHitSide', moveData, {}, target || null, pokemon, move);
|
||||
} else if (target) {
|
||||
hitResult = this.battle.singleEvent('TryHit', moveData, {}, target, pokemon, move);
|
||||
}
|
||||
if (!hitResult) {
|
||||
if (hitResult === false) {
|
||||
this.battle.add('-fail', pokemon);
|
||||
this.battle.attrLastMove('[still]');
|
||||
}
|
||||
return [[false], targets]; // single-target only
|
||||
}
|
||||
|
||||
// 0. check for substitute
|
||||
if (!isSecondary && !isSelf) {
|
||||
if (move.target !== 'all' && move.target !== 'allyTeam' && move.target !== 'allySide' && move.target !== 'foeSide') {
|
||||
damage = this.tryPrimaryHitEvent(damage, targets, pokemon, move, moveData, isSecondary);
|
||||
}
|
||||
}
|
||||
|
||||
for (const i of targets.keys()) {
|
||||
if (damage[i] === this.battle.HIT_SUBSTITUTE) {
|
||||
damage[i] = true;
|
||||
targets[i] = null;
|
||||
}
|
||||
if (targets[i] && isSecondary && !moveData.self) {
|
||||
damage[i] = true;
|
||||
}
|
||||
if (!damage[i]) targets[i] = false;
|
||||
}
|
||||
// 1. call to this.battle.getDamage
|
||||
damage = this.getSpreadDamage(damage, targets, pokemon, move, moveData, isSecondary, isSelf);
|
||||
|
||||
for (const i of targets.keys()) {
|
||||
if (damage[i] === false) targets[i] = false;
|
||||
}
|
||||
|
||||
// 2. call to this.battle.spreadDamage
|
||||
damage = this.battle.spreadDamage(damage, targets, pokemon, move);
|
||||
|
||||
for (const i of targets.keys()) {
|
||||
if (damage[i] === false) targets[i] = false;
|
||||
}
|
||||
|
||||
// 3. onHit event happens here
|
||||
damage = this.runMoveEffects(damage, targets, pokemon, move, moveData, isSecondary, isSelf);
|
||||
|
||||
for (const i of targets.keys()) {
|
||||
if (!damage[i] && damage[i] !== 0) targets[i] = false;
|
||||
}
|
||||
|
||||
// steps 4 and 5 can mess with this.battle.activeTarget, which needs to be preserved for Dancer
|
||||
const activeTarget = this.battle.activeTarget;
|
||||
|
||||
// 4. self drops (start checking for targets[i] === false here)
|
||||
if (moveData.self && !move.selfDropped) this.selfDrops(targets, pokemon, move, moveData, isSecondary);
|
||||
|
||||
// 5. secondary effects
|
||||
if (moveData.secondaries) this.secondaries(targets, pokemon, move, moveData, isSelf);
|
||||
|
||||
this.battle.activeTarget = activeTarget;
|
||||
|
||||
// 6. force switch
|
||||
if (moveData.forceSwitch) damage = this.forceSwitch(damage, targets, pokemon, move);
|
||||
|
||||
for (const i of targets.keys()) {
|
||||
if (!damage[i] && damage[i] !== 0) targets[i] = false;
|
||||
}
|
||||
|
||||
const damagedTargets: Pokemon[] = [];
|
||||
const damagedDamage = [];
|
||||
for (const [i, t] of targets.entries()) {
|
||||
if (typeof damage[i] === 'number' && t) {
|
||||
damagedTargets.push(t);
|
||||
damagedDamage.push(damage[i]);
|
||||
}
|
||||
}
|
||||
const pokemonOriginalHP = pokemon.hp;
|
||||
if (damagedDamage.length && !isSecondary && !isSelf) {
|
||||
if (this.battle.gen >= 5) {
|
||||
this.battle.runEvent('DamagingHit', damagedTargets, pokemon, move, damagedDamage);
|
||||
}
|
||||
if (moveData.onAfterHit) {
|
||||
for (const t of damagedTargets) {
|
||||
this.battle.singleEvent('AfterHit', moveData, {}, t, pokemon, move);
|
||||
}
|
||||
}
|
||||
if (this.battle.gen < 5) {
|
||||
this.battle.runEvent('DamagingHit', damagedTargets, pokemon, move, damagedDamage);
|
||||
}
|
||||
if (pokemon.hp && pokemon.hp <= pokemon.maxhp / 2 && pokemonOriginalHP > pokemon.maxhp / 2) {
|
||||
this.battle.runEvent('EmergencyExit', pokemon);
|
||||
}
|
||||
}
|
||||
|
||||
return [damage, targets];
|
||||
},
|
||||
// Parental Bond shouldn't announce hit count if it only hits once
|
||||
hitStepMoveHitLoop(targets: Pokemon[], pokemon: Pokemon, move: ActiveMove) { // Temporary name
|
||||
let damage: (number | boolean | undefined)[] = [];
|
||||
for (const i of targets.keys()) {
|
||||
damage[i] = 0;
|
||||
}
|
||||
move.totalDamage = 0;
|
||||
pokemon.lastDamage = 0;
|
||||
let targetHits = move.multihit || 1;
|
||||
if (Array.isArray(targetHits)) {
|
||||
// yes, it's hardcoded... meh
|
||||
if (targetHits[0] === 2 && targetHits[1] === 5) {
|
||||
if (this.battle.gen >= 5) {
|
||||
// 35-35-15-15 out of 100 for 2-3-4-5 hits
|
||||
targetHits = this.battle.sample([2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5]);
|
||||
if (targetHits < 4 && pokemon.hasItem('loadeddice')) {
|
||||
targetHits = 5 - this.battle.random(2);
|
||||
}
|
||||
} else {
|
||||
targetHits = this.battle.sample([2, 2, 2, 3, 3, 3, 4, 5]);
|
||||
}
|
||||
} else {
|
||||
targetHits = this.battle.random(targetHits[0], targetHits[1] + 1);
|
||||
}
|
||||
}
|
||||
if (targetHits === 10 && pokemon.hasItem('loadeddice')) targetHits -= this.battle.random(7);
|
||||
targetHits = Math.floor(targetHits);
|
||||
let nullDamage = true;
|
||||
let moveDamage: (number | boolean | undefined)[] = [];
|
||||
// There is no need to recursively check the ´sleepUsable´ flag as Sleep Talk can only be used while asleep.
|
||||
const isSleepUsable = move.sleepUsable || this.dex.moves.get(move.sourceEffect).sleepUsable;
|
||||
|
||||
let targetsCopy: (Pokemon | false | null)[] = targets.slice(0);
|
||||
let hit: number;
|
||||
for (hit = 1; hit <= targetHits; hit++) {
|
||||
if (damage.includes(false)) break;
|
||||
if (hit > 1 && pokemon.status === 'slp' && (!isSleepUsable || this.battle.gen === 4)) break;
|
||||
if (targets.every(target => !target?.hp)) break;
|
||||
move.hit = hit;
|
||||
move.lastHit = move.hit === targetHits;
|
||||
if (move.smartTarget && targets.length > 1) {
|
||||
targetsCopy = [targets[hit - 1]];
|
||||
damage = [damage[hit - 1]];
|
||||
} else {
|
||||
targetsCopy = targets.slice(0);
|
||||
}
|
||||
const target = targetsCopy[0]; // some relevant-to-single-target-moves-only things are hardcoded
|
||||
if (target && typeof move.smartTarget === 'boolean') {
|
||||
if (hit > 1) {
|
||||
this.battle.addMove('-anim', pokemon, move.name, target);
|
||||
} else {
|
||||
this.battle.retargetLastMove(target);
|
||||
}
|
||||
}
|
||||
|
||||
// like this (Triple Kick)
|
||||
if (target && move.multiaccuracy && hit > 1) {
|
||||
let accuracy = move.accuracy;
|
||||
const boostTable = [1, 4 / 3, 5 / 3, 2, 7 / 3, 8 / 3, 3];
|
||||
if (accuracy !== true) {
|
||||
if (!move.ignoreAccuracy) {
|
||||
const boosts = this.battle.runEvent('ModifyBoost', pokemon, null, null, { ...pokemon.boosts });
|
||||
const boost = this.battle.clampIntRange(boosts['accuracy'], -6, 6);
|
||||
if (boost > 0) {
|
||||
accuracy *= boostTable[boost];
|
||||
} else {
|
||||
accuracy /= boostTable[-boost];
|
||||
}
|
||||
}
|
||||
if (!move.ignoreEvasion) {
|
||||
const boosts = this.battle.runEvent('ModifyBoost', target, null, null, { ...target.boosts });
|
||||
const boost = this.battle.clampIntRange(boosts['evasion'], -6, 6);
|
||||
if (boost > 0) {
|
||||
accuracy /= boostTable[boost];
|
||||
} else if (boost < 0) {
|
||||
accuracy *= boostTable[-boost];
|
||||
}
|
||||
}
|
||||
}
|
||||
accuracy = this.battle.runEvent('ModifyAccuracy', target, pokemon, move, accuracy);
|
||||
if (!move.alwaysHit) {
|
||||
accuracy = this.battle.runEvent('Accuracy', target, pokemon, move, accuracy);
|
||||
if (accuracy !== true && !this.battle.randomChance(accuracy, 100)) break;
|
||||
}
|
||||
}
|
||||
|
||||
const moveData = move;
|
||||
if (!moveData.flags) moveData.flags = {};
|
||||
|
||||
let moveDamageThisHit;
|
||||
// Modifies targetsCopy (which is why it's a copy)
|
||||
[moveDamageThisHit, targetsCopy] = this.spreadMoveHit(targetsCopy, pokemon, move, moveData);
|
||||
// When Dragon Darts targets two different pokemon, targetsCopy is a length 1 array each hit
|
||||
// so spreadMoveHit returns a length 1 damage array
|
||||
if (move.smartTarget) {
|
||||
moveDamage.push(...moveDamageThisHit);
|
||||
} else {
|
||||
moveDamage = moveDamageThisHit;
|
||||
}
|
||||
|
||||
if (!moveDamage.some(val => val !== false)) break;
|
||||
nullDamage = false;
|
||||
|
||||
for (const [i, md] of moveDamage.entries()) {
|
||||
if (move.smartTarget && i !== hit - 1) continue;
|
||||
// Damage from each hit is individually counted for the
|
||||
// purposes of Counter, Metal Burst, and Mirror Coat.
|
||||
damage[i] = md === true || !md ? 0 : md;
|
||||
// Total damage dealt is accumulated for the purposes of recoil (Parental Bond).
|
||||
move.totalDamage += damage[i];
|
||||
}
|
||||
if (move.mindBlownRecoil) {
|
||||
const hpBeforeRecoil = pokemon.hp;
|
||||
this.battle.damage(Math.round(pokemon.maxhp / 2), pokemon, pokemon, this.dex.conditions.get(move.id), true);
|
||||
move.mindBlownRecoil = false;
|
||||
if (pokemon.hp <= pokemon.maxhp / 2 && hpBeforeRecoil > pokemon.maxhp / 2) {
|
||||
this.battle.runEvent('EmergencyExit', pokemon, pokemon);
|
||||
}
|
||||
}
|
||||
this.battle.eachEvent('Update');
|
||||
if (!pokemon.hp && targets.length === 1) {
|
||||
hit++; // report the correct number of hits for multihit moves
|
||||
break;
|
||||
}
|
||||
}
|
||||
// hit is 1 higher than the actual hit count
|
||||
if (hit === 1) return damage.fill(false);
|
||||
if (nullDamage) damage.fill(false);
|
||||
this.battle.faintMessages(false, false, !pokemon.hp);
|
||||
if (move.multihit && typeof move.smartTarget !== 'boolean' &&
|
||||
!(move.hit === 1 && move.multihitType === 'parentalbond')) {
|
||||
this.battle.add('-hitcount', targets[0], hit - 1);
|
||||
}
|
||||
|
||||
if ((move.recoil || move.id === 'chloroblast') && move.totalDamage) {
|
||||
const hpBeforeRecoil = pokemon.hp;
|
||||
this.battle.damage(this.calcRecoilDamage(move.totalDamage, move, pokemon), pokemon, pokemon, 'recoil');
|
||||
if (pokemon.hp <= pokemon.maxhp / 2 && hpBeforeRecoil > pokemon.maxhp / 2) {
|
||||
this.battle.runEvent('EmergencyExit', pokemon, pokemon);
|
||||
}
|
||||
}
|
||||
|
||||
if (move.struggleRecoil) {
|
||||
const hpBeforeRecoil = pokemon.hp;
|
||||
let recoilDamage;
|
||||
if (this.dex.gen >= 5) {
|
||||
recoilDamage = this.battle.clampIntRange(Math.round(pokemon.baseMaxhp / 4), 1);
|
||||
} else {
|
||||
recoilDamage = this.battle.clampIntRange(this.battle.trunc(pokemon.maxhp / 4), 1);
|
||||
}
|
||||
this.battle.directDamage(recoilDamage, pokemon, pokemon, { id: 'strugglerecoil' } as Condition);
|
||||
if (pokemon.hp <= pokemon.maxhp / 2 && hpBeforeRecoil > pokemon.maxhp / 2) {
|
||||
this.battle.runEvent('EmergencyExit', pokemon, pokemon);
|
||||
}
|
||||
}
|
||||
|
||||
// smartTarget messes up targetsCopy, but smartTarget should in theory ensure that targets will never fail, anyway
|
||||
if (move.smartTarget) {
|
||||
targetsCopy = targets.slice(0);
|
||||
}
|
||||
|
||||
for (const [i, target] of targetsCopy.entries()) {
|
||||
if (target && pokemon !== target) {
|
||||
target.gotAttacked(move, moveDamage[i] as number | false | undefined, pokemon);
|
||||
if (typeof moveDamage[i] === 'number') {
|
||||
target.timesAttacked += move.smartTarget ? 1 : hit - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (move.ohko && !targets[0].hp) this.battle.add('-ohko');
|
||||
|
||||
if (!damage.some(val => !!val || val === 0)) return damage;
|
||||
|
||||
this.battle.eachEvent('Update');
|
||||
|
||||
this.afterMoveSecondaryEvent(targetsCopy.filter(val => !!val), pokemon, move);
|
||||
|
||||
if (!(move.hasSheerForce && pokemon.hasAbility('sheerforce'))) {
|
||||
for (const [i, d] of damage.entries()) {
|
||||
// There are no multihit spread moves, so it's safe to use move.totalDamage for multihit moves
|
||||
// The previous check was for `move.multihit`, but that fails for Dragon Darts
|
||||
const curDamage = targets.length === 1 ? move.totalDamage : d;
|
||||
if (typeof curDamage === 'number' && targets[i].hp) {
|
||||
const targetHPBeforeDamage = (targets[i].hurtThisTurn || 0) + curDamage;
|
||||
if (targets[i].hp <= targets[i].maxhp / 2 && targetHPBeforeDamage > targets[i].maxhp / 2) {
|
||||
this.battle.runEvent('EmergencyExit', targets[i], pokemon);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return damage;
|
||||
},
|
||||
},
|
||||
};
|
||||
993
data/mods/chatbats/abilities.ts
Normal file
993
data/mods/chatbats/abilities.ts
Normal file
|
|
@ -0,0 +1,993 @@
|
|||
export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTable = {
|
||||
thickfat: {
|
||||
// prevents burning
|
||||
inherit: true,
|
||||
onUpdate(pokemon) {
|
||||
if (pokemon.status === 'brn') {
|
||||
this.add('-activate', pokemon, 'ability: Thick Fat');
|
||||
pokemon.cureStatus();
|
||||
}
|
||||
},
|
||||
onSetStatus(status, target, source, effect) {
|
||||
if (status.id !== 'brn') return;
|
||||
if ((effect as Move)?.status) {
|
||||
this.add('-immune', target, '[from] ability: Thick Fat');
|
||||
}
|
||||
return false;
|
||||
},
|
||||
shortDesc: "-50% damage from Fire and Ice. Burn immune.",
|
||||
},
|
||||
callillumise: {
|
||||
onDamagePriority: -30,
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (damage >= target.hp) {
|
||||
this.add('-ability', target, 'Call Illumise');
|
||||
this.effectState.callillumise = true;
|
||||
return target.hp - 1;
|
||||
}
|
||||
},
|
||||
onUpdate(pokemon) {
|
||||
if (!this.effectState.callillumise) return;
|
||||
|
||||
this.add('-message', `Volbeat calls upon Illumise for aid!`);
|
||||
// Define new moves
|
||||
const newMoves = ['bugbuzz', 'icebeam', 'thunderbolt', 'quiverdance'];
|
||||
// Update move slots
|
||||
pokemon.moveSlots = newMoves.map(move => {
|
||||
const moveData = this.dex.moves.get(move);
|
||||
return {
|
||||
move: moveData.name,
|
||||
id: moveData.id,
|
||||
pp: moveData.pp,
|
||||
maxpp: moveData.pp,
|
||||
target: moveData.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
});
|
||||
// this forces the UI to update move slots visually
|
||||
(pokemon as any).baseMoveSlots = pokemon.moveSlots.slice();
|
||||
// removes status/boosts
|
||||
pokemon.cureStatus();
|
||||
pokemon.clearBoosts();
|
||||
// forces the UI to update part II
|
||||
this.add('-clearboost', pokemon, '[from] ability: Call Illumise', '[silent]');
|
||||
for (const volatile in pokemon.volatiles) {
|
||||
this.add('-end', pokemon, volatile);
|
||||
}
|
||||
pokemon.clearVolatile(true);
|
||||
// form change + heal
|
||||
pokemon.formeChange('Illumise', null, true);
|
||||
this.heal(pokemon.maxhp);
|
||||
// sets new ability
|
||||
pokemon.setAbility('Tinted Lens', null, null, true);
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
this.add('-ability', pokemon, 'Tinted Lens');
|
||||
},
|
||||
flags: {
|
||||
breakable: 1, failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, notransform: 1,
|
||||
},
|
||||
name: "Call Illumise",
|
||||
rating: 5,
|
||||
num: -100,
|
||||
shortDesc: "When Volbeat gets low on HP, it calls Illumise for aid.",
|
||||
},
|
||||
callvolbeat: {
|
||||
onDamagePriority: -30,
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (damage >= target.hp) {
|
||||
this.add('-ability', target, 'Call Volbeat');
|
||||
this.effectState.callvolbeat = true;
|
||||
return target.hp - 1;
|
||||
}
|
||||
},
|
||||
onUpdate(pokemon) {
|
||||
if (!this.effectState.callvolbeat) return;
|
||||
|
||||
this.add('-message', `Illumise calls upon Volbeat for aid!`);
|
||||
// Define new moves
|
||||
const newMoves = ['victorydance', 'lunge', 'mightycleave', 'earthquake'];
|
||||
// Update move slots
|
||||
pokemon.moveSlots = newMoves.map(move => {
|
||||
const moveData = this.dex.moves.get(move);
|
||||
return {
|
||||
move: moveData.name,
|
||||
id: moveData.id,
|
||||
pp: moveData.pp,
|
||||
maxpp: moveData.pp,
|
||||
target: moveData.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
});
|
||||
// this forces the UI to update move slots visually
|
||||
(pokemon as any).baseMoveSlots = pokemon.moveSlots.slice();
|
||||
// removes status/boosts
|
||||
pokemon.cureStatus();
|
||||
pokemon.clearBoosts();
|
||||
// forces the UI to update part II
|
||||
this.add('-clearboost', pokemon, '[from] ability: Call Volbeat', '[silent]');
|
||||
for (const volatile in pokemon.volatiles) {
|
||||
this.add('-end', pokemon, volatile);
|
||||
}
|
||||
pokemon.clearVolatile(true);
|
||||
// form change + heal
|
||||
pokemon.formeChange('Volbeat', null, true);
|
||||
this.heal(pokemon.maxhp);
|
||||
// sets new ability
|
||||
pokemon.setAbility('Dancer', null, null, true);
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
this.add('-ability', pokemon, 'Dancer');
|
||||
},
|
||||
flags: {
|
||||
breakable: 1, failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, notransform: 1,
|
||||
},
|
||||
name: "Call Volbeat",
|
||||
rating: 5,
|
||||
num: -101,
|
||||
shortDesc: "When Illumise gets low on HP, it calls Volbeat for aid.",
|
||||
},
|
||||
shortfuse: {
|
||||
onDamagePriority: -30,
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (damage >= target.hp) {
|
||||
this.add('-ability', target, 'Short Fuse');
|
||||
this.effectState.shortfuse = true;
|
||||
return target.hp - 1;
|
||||
}
|
||||
},
|
||||
onUpdate(pokemon) {
|
||||
if (this.effectState.shortfuse) {
|
||||
delete this.effectState.shortfuse;
|
||||
this.actions.useMove('explosion', pokemon);
|
||||
}
|
||||
this.checkFainted();
|
||||
},
|
||||
flags: {
|
||||
breakable: 1, failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1,
|
||||
},
|
||||
name: "Short Fuse",
|
||||
rating: 5,
|
||||
num: -102,
|
||||
shortDesc: "If KO'd, use Explosion instead.",
|
||||
},
|
||||
hydroelectricdam: {
|
||||
// Copied from the code for Sand Spit
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
this.field.setWeather('raindance');
|
||||
},
|
||||
flags: {},
|
||||
name: "Hydroelectric Dam",
|
||||
rating: 5,
|
||||
num: -103,
|
||||
shortDesc: "Starts Rain Dance when hit by an attack.",
|
||||
},
|
||||
frozenarmor: {
|
||||
onTryHit(target, source, move) {
|
||||
if (move.category !== 'Status') {
|
||||
this.add('-ability', target, 'Frozen Armor');
|
||||
// reduces base power of incoming moves by 20 (math.max prevents base power from reducing below 0)
|
||||
move.basePower = Math.max(move.basePower - 20, 0);
|
||||
}
|
||||
},
|
||||
onSwitchInPriority: -1,
|
||||
onUpdate(pokemon) {
|
||||
// checks if Glastrier is below 50% HP, if so transforms into Caly-Ice and sets ability to As One
|
||||
if (pokemon.species.id !== 'glastrier' || !pokemon.hp) return;
|
||||
if (pokemon.hp < pokemon.maxhp / 2) {
|
||||
if (pokemon.species.id !== 'calyrexice' && pokemon.ability === 'frozenarmor') {
|
||||
pokemon.formeChange('Calyrex-Ice', null, true);
|
||||
this.add('-message', `Glastrier's Frozen Armor has shattered!`);
|
||||
// pokemon.setAbility('As One (Glastrier)');
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
// this.add('-ability', pokemon, 'As One');
|
||||
}
|
||||
}
|
||||
},
|
||||
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1 },
|
||||
name: "Frozen Armor",
|
||||
rating: 5,
|
||||
num: -105,
|
||||
shortDesc: "-20 BP on attacks targeting Glastrier, at 50% HP become Calyrex-Ice.",
|
||||
},
|
||||
flipflop: {
|
||||
onDamagingHitOrder: 1,
|
||||
onTryHit(target, source, move) {
|
||||
if (move.flags['contact']) {
|
||||
let flipFlopBoosts = false;
|
||||
const invertedBoosts: SparseBoostsTable = {};
|
||||
for (const stat in source.boosts) {
|
||||
if (source.boosts[stat as BoostID] > 0) {
|
||||
// checks for boosts on source of move, inverts boosts and adds them to invertedBoosts table
|
||||
invertedBoosts[stat as BoostID] = -2 * source.boosts[stat as BoostID];
|
||||
if (!flipFlopBoosts) {
|
||||
this.add('-ability', target, 'Flip Flop');
|
||||
flipFlopBoosts = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// applies boosts
|
||||
this.boost(invertedBoosts, source, target);
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Flip Flop",
|
||||
rating: 5,
|
||||
num: -104,
|
||||
shortDesc: "When hit by contact move, invert attacker’s stat boosts.",
|
||||
},
|
||||
|
||||
grasspelt: {
|
||||
inherit: true,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
this.field.setTerrain('grassyterrain');
|
||||
},
|
||||
shortDesc: "Starts Grassy Terrain on hit. 1.5x Def in Grassy Terrain.",
|
||||
},
|
||||
aquaveil: {
|
||||
onSwitchInPriority: -1,
|
||||
// fakes the effect of aqua ring volatile lel
|
||||
onStart(pokemon) {
|
||||
this.add('-start', pokemon, 'Aqua Ring');
|
||||
},
|
||||
// provides effects of Water Bubble because Aqua Ring is modified to provide Water Bubble.
|
||||
onResidualOrder: 6,
|
||||
onResidual(pokemon) {
|
||||
this.heal(pokemon.baseMaxhp / 16);
|
||||
},
|
||||
onSourceModifyAtkPriority: 5,
|
||||
onSourceModifyAtk(atk, attacker, defender, move) {
|
||||
if (move.type === 'Fire') {
|
||||
return this.chainModify(0.5);
|
||||
}
|
||||
},
|
||||
onSourceModifySpAPriority: 5,
|
||||
onSourceModifySpA(atk, attacker, defender, move) {
|
||||
if (move.type === 'Fire') {
|
||||
return this.chainModify(0.5);
|
||||
}
|
||||
},
|
||||
onModifyAtk(atk, attacker, defender, move) {
|
||||
if (move.type === 'Water') {
|
||||
return this.chainModify(2);
|
||||
}
|
||||
},
|
||||
onModifySpA(atk, attacker, defender, move) {
|
||||
if (move.type === 'Water') {
|
||||
return this.chainModify(2);
|
||||
}
|
||||
},
|
||||
// this ability is supposed to just add Aqua Ring (the volatile) to the Pokemon on switch in
|
||||
flags: { cantsuppress: 1 },
|
||||
name: "Aqua Veil",
|
||||
rating: 5,
|
||||
num: -106,
|
||||
shortDesc: "Starts Aqua Ring on switch in.",
|
||||
},
|
||||
// unaware + water absorb
|
||||
stillwater: {
|
||||
onAnyModifyBoost(boosts, pokemon) {
|
||||
const unawareUser = this.effectState.target;
|
||||
if (unawareUser === pokemon) return;
|
||||
if (unawareUser === this.activePokemon && pokemon === this.activeTarget) {
|
||||
boosts['def'] = 0;
|
||||
boosts['spd'] = 0;
|
||||
boosts['evasion'] = 0;
|
||||
}
|
||||
if (pokemon === this.activePokemon && unawareUser === this.activeTarget) {
|
||||
boosts['atk'] = 0;
|
||||
boosts['def'] = 0;
|
||||
boosts['spa'] = 0;
|
||||
boosts['accuracy'] = 0;
|
||||
}
|
||||
},
|
||||
onTryHit(target, source, move) {
|
||||
if (target !== source && move.type === 'Water') {
|
||||
if (!this.heal(target.baseMaxhp / 4)) {
|
||||
this.add('-immune', target, '[from] ability: Still Water');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
},
|
||||
flags: { breakable: 1 },
|
||||
name: "Still Water",
|
||||
rating: 5,
|
||||
num: -107,
|
||||
shortDesc: "Unaware + Water Absorb",
|
||||
},
|
||||
kingofthehill: {
|
||||
// sharpness + mountaineer + prevents hazard immunity
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (effect && effect.id === 'stealthrock') {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onTryHit(target, source, move) {
|
||||
if (move.type === 'Rock' && !target.activeTurns) {
|
||||
this.add('-immune', target, '[from] ability: King of the Hill');
|
||||
return null;
|
||||
}
|
||||
},
|
||||
// sharpness
|
||||
onBasePowerPriority: 19,
|
||||
onBasePower(basePower, attacker, defender, move) {
|
||||
if (move.flags['slicing']) {
|
||||
this.debug('Sharpness boost');
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
},
|
||||
// starts side condition for foes, side condition interacts with hazard effects
|
||||
onStart(pokemon) {
|
||||
this.add('-ability', pokemon, 'King of the Hill');
|
||||
for (const side of pokemon.side.foeSidesWithConditions()) {
|
||||
side.addSideCondition('kingofthehill');
|
||||
}
|
||||
},
|
||||
onEnd(pokemon) {
|
||||
for (const side of pokemon.side.foeSidesWithConditions()) {
|
||||
if (side.getSideCondition('kingofthehill')) {
|
||||
side.removeSideCondition('kingofthehill');
|
||||
}
|
||||
}
|
||||
},
|
||||
condition: {},
|
||||
flags: { breakable: 1 },
|
||||
name: "King of the Hill",
|
||||
rating: 5,
|
||||
num: -108,
|
||||
shortDesc: "Mountaineer + Sharpness. Opponent cannot ignore hazard damage.",
|
||||
},
|
||||
// stockpile on hit
|
||||
omnivore: {
|
||||
onDamagingHitOrder: 1,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (!target.hp) return;
|
||||
this.add('-activate', target, 'ability: Omnivore');
|
||||
target.addVolatile('stockpile');
|
||||
},
|
||||
flags: {},
|
||||
name: "Omnivore",
|
||||
rating: 5,
|
||||
num: -109,
|
||||
shortDesc: "Gain Stockpile charge when hit by attack.",
|
||||
},
|
||||
// disguise clone
|
||||
pseudowoodo: {
|
||||
onDamagePriority: 1,
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (effect?.effectType === 'Move' && ['sudowoodo'].includes(target.species.id)) {
|
||||
this.add('-activate', target, 'ability: Pseudowoodo');
|
||||
this.effectState.rock = true;
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
onCriticalHit(target, source, move) {
|
||||
if (!target) return;
|
||||
if (!['sudowoodo'].includes(target.species.id)) {
|
||||
return;
|
||||
}
|
||||
const hitSub = target.volatiles['substitute'] && !move.flags['bypasssub'] && !(move.infiltrates && this.gen >= 6);
|
||||
if (hitSub) return;
|
||||
|
||||
if (!target.runImmunity(move.type)) return;
|
||||
return false;
|
||||
},
|
||||
onEffectiveness(typeMod, target, type, move) {
|
||||
if (!target || move.category === 'Status') return;
|
||||
if (!['sudowoodo'].includes(target.species.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const hitSub = target.volatiles['substitute'] && !move.flags['bypasssub'] && !(move.infiltrates && this.gen >= 6);
|
||||
if (hitSub) return;
|
||||
|
||||
if (!target.runImmunity(move.type)) return;
|
||||
return 0;
|
||||
},
|
||||
onUpdate(pokemon) {
|
||||
if (['sudowoodo'].includes(pokemon.species.id) && this.effectState.rock) {
|
||||
const speciesid = 'Sudowoodo-Rock';
|
||||
pokemon.formeChange(speciesid, this.effect, true);
|
||||
this.damage(pokemon.baseMaxhp / 8, pokemon, pokemon, this.dex.species.get(speciesid));
|
||||
}
|
||||
},
|
||||
flags: {
|
||||
failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1,
|
||||
breakable: 1, notransform: 1,
|
||||
},
|
||||
name: "Pseudowoodo",
|
||||
rating: 5,
|
||||
num: -110,
|
||||
shortDesc: "Disguise. Becomes Rock type when it breaks.",
|
||||
},
|
||||
magicguard: {
|
||||
onDamage(damage, target, source, effect) {
|
||||
// prevents magic guard from blocking hazard damage while King of the Hill is active
|
||||
if (target.side.getSideCondition('kingofthehill')) {
|
||||
const hazards = ['stealthrock', 'spikes', 'toxicspikes', 'stickyweb'];
|
||||
if (effect && hazards.includes(effect.id)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (effect.effectType !== 'Move') {
|
||||
if (effect.effectType === 'Ability') this.add('-activate', source, 'ability: ' + effect.name);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Magic Guard",
|
||||
rating: 4,
|
||||
num: 98,
|
||||
},
|
||||
disguise: {
|
||||
onDamagePriority: 1,
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (effect?.effectType === 'Move' && ['mimikyu', 'mimikyutotem'].includes(target.species.id)) {
|
||||
this.add('-activate', target, 'ability: Disguise');
|
||||
this.effectState.busted = true;
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
onCriticalHit(target, source, move) {
|
||||
if (!target) return;
|
||||
if (!['mimikyu', 'mimikyutotem'].includes(target.species.id)) {
|
||||
return;
|
||||
}
|
||||
const hitSub = target.volatiles['substitute'] && !move.flags['bypasssub'] && !(move.infiltrates && this.gen >= 6);
|
||||
if (hitSub) return;
|
||||
|
||||
if (!target.runImmunity(move.type)) return;
|
||||
return false;
|
||||
},
|
||||
onEffectiveness(typeMod, target, type, move) {
|
||||
if (!target || move.category === 'Status') return;
|
||||
if (!['mimikyu', 'mimikyutotem'].includes(target.species.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const hitSub = target.volatiles['substitute'] && !move.flags['bypasssub'] && !(move.infiltrates && this.gen >= 6);
|
||||
if (hitSub) return;
|
||||
|
||||
if (!target.runImmunity(move.type)) return;
|
||||
return 0;
|
||||
},
|
||||
onUpdate(pokemon) {
|
||||
if (['mimikyu', 'mimikyutotem'].includes(pokemon.species.id) && this.effectState.busted) {
|
||||
const speciesid = pokemon.species.id === 'mimikyutotem' ? 'Mimikyu-Busted-Totem' : 'Mimikyu-Busted';
|
||||
pokemon.formeChange(speciesid, this.effect, true);
|
||||
this.damage(pokemon.baseMaxhp / 8, pokemon, pokemon, this.dex.species.get(speciesid));
|
||||
}
|
||||
// sets ability to perish body
|
||||
if (pokemon.species.id === 'mimikyubusted' && pokemon.ability === 'disguise') {
|
||||
pokemon.setAbility("Perish Body");
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
}
|
||||
},
|
||||
// cantsuppress flag removed to allow for ability change
|
||||
flags: {
|
||||
failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1,
|
||||
breakable: 1, notransform: 1,
|
||||
},
|
||||
name: "Disguise",
|
||||
rating: 3.5,
|
||||
num: 209,
|
||||
},
|
||||
gulpmissile: {
|
||||
inherit: true,
|
||||
onTryHit(target, source, move) {
|
||||
// Storm Drain effect while cramorant-gulping
|
||||
if (target !== source && move.type === 'Water' && target.species.id === 'cramorantgulping') {
|
||||
if (!this.boost({ spa: 1 })) {
|
||||
this.add('-immune', target, '[from] ability: Gulp Missile');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// Lightning Rod effect while cramorant-gorging
|
||||
if (target !== source && move.type === 'Electric' && target.species.id === 'cramorantgorging') {
|
||||
if (!this.boost({ spa: 1 })) {
|
||||
this.add('-immune', target, '[from] ability: Gulp Missile');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return;
|
||||
},
|
||||
},
|
||||
asoneglastrier: {
|
||||
inherit: true,
|
||||
// removing these flags allows Frozen Armor to correctly set Caly-Ice ability as As One
|
||||
flags: {},
|
||||
},
|
||||
protean: {
|
||||
inherit: true,
|
||||
onPrepareHit(source, target, move) {
|
||||
if (move.hasBounced || move.flags['futuremove'] || move.sourceEffect === 'snatch' || move.callsMove) return;
|
||||
const type = move.type;
|
||||
if (type && type !== '???' && source.getTypes().join() !== type) {
|
||||
if (!source.setType(type)) return;
|
||||
this.add('-start', source, 'typechange', type, '[from] ability: Protean');
|
||||
}
|
||||
},
|
||||
rating: 4.5,
|
||||
shortDesc: "Gen 8 Protean.",
|
||||
},
|
||||
berserk: {
|
||||
onUpdate(pokemon) {
|
||||
if (pokemon.species.id !== 'infernape' || !pokemon.hp || pokemon.m.triggeredBerserk) return;
|
||||
if (pokemon.hp < pokemon.maxhp / 2) {
|
||||
this.boost({ spa: 1 }, pokemon, pokemon);
|
||||
pokemon.m.triggeredBerserk = true;
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Berserk",
|
||||
rating: 2,
|
||||
num: 201,
|
||||
},
|
||||
bloodsoakedcrescent: {
|
||||
// modifies atk
|
||||
onStart(pokemon) {
|
||||
this.add('-ability', pokemon, 'Blood-Soaked Crescent');
|
||||
},
|
||||
onModifyAtkPriority: 1,
|
||||
onModifyAtk(atk, pokemon) {
|
||||
if (pokemon.volatiles['dynamax']) return;
|
||||
this.debug('bsc Attack boost');
|
||||
return this.chainModify(1.5);
|
||||
},
|
||||
// ends move lock properly
|
||||
onAfterMove(pokemon) {
|
||||
if (pokemon.volatiles['bloodsoakedcrescent']?.duration === 1) {
|
||||
pokemon.removeVolatile('bloodsoakedcrescent');
|
||||
this.add('-end', pokemon, 'Blood-Soaked Rage');
|
||||
}
|
||||
},
|
||||
// applies move lock
|
||||
onAfterMoveSecondarySelf(pokemon, source, move) {
|
||||
if (move.id === 'dragondance') return;
|
||||
if (!pokemon.volatiles['bloodsoakedcrescent']) {
|
||||
this.add('-start', pokemon, 'Blood-Soaked Rage');
|
||||
}
|
||||
pokemon.addVolatile('bloodsoakedcrescent');
|
||||
},
|
||||
// condition is just lockedmove with some changes
|
||||
condition: {
|
||||
// Outrage, Thrash, Petal Dance...
|
||||
duration: 2,
|
||||
onResidual(target) {
|
||||
if (target.status === 'slp') {
|
||||
// don't lock, and bypass confusion for calming
|
||||
delete target.volatiles['bloodsoakedcrescent'];
|
||||
}
|
||||
this.effectState.trueDuration--;
|
||||
},
|
||||
onStart(target, source, effect) {
|
||||
this.effectState.trueDuration = this.random(2, 4);
|
||||
this.effectState.move = this.activeMove;
|
||||
},
|
||||
onRestart() {
|
||||
if (this.effectState.trueDuration >= 2) {
|
||||
this.effectState.duration = 2;
|
||||
}
|
||||
},
|
||||
onEnd(target) {
|
||||
if (this.effectState.trueDuration > 1) return;
|
||||
target.addVolatile('confusion');
|
||||
},
|
||||
onLockMove(pokemon) {
|
||||
if (pokemon.volatiles['dynamax']) return;
|
||||
return this.effectState.move;
|
||||
},
|
||||
},
|
||||
flags: {},
|
||||
name: "Blood-Soaked Crescent",
|
||||
rating: 5,
|
||||
num: -111,
|
||||
shortDesc: "1.5x Attack, but attacks have the Outrage effect.",
|
||||
},
|
||||
powerspot: {
|
||||
onChargeMove(pokemon, target, move) {
|
||||
this.debug('power spot - remove charge turn for ' + move.id);
|
||||
this.attrLastMove('[still]');
|
||||
this.addMove('-anim', pokemon, move.name, target);
|
||||
return false; // skip charge turn
|
||||
},
|
||||
onAfterMoveSecondarySelf(pokemon, target, move) {
|
||||
if (pokemon.getVolatile('mustrecharge')) {
|
||||
pokemon.removeVolatile('mustrecharge');
|
||||
this.add('-end', pokemon, 'mustrecharge');
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Power Spot",
|
||||
rating: 5,
|
||||
num: 249,
|
||||
shortDesc: "Moves ignore charge/recharge turns.",
|
||||
},
|
||||
biogenesis: {
|
||||
onSwitchInPriority: -1,
|
||||
onBeforeSwitchIn(pokemon) {
|
||||
if (pokemon.m.didRandomMoves) return;
|
||||
const moves = this.dex.moves.all();
|
||||
const newMoves = [];
|
||||
while (newMoves.length < 8) {
|
||||
const newMove = this.sample(moves);
|
||||
if (newMove.basePower === 1) continue;
|
||||
if (newMove.isMax === true) continue;
|
||||
if (newMove.isNonstandard === "Gigantamax") continue;
|
||||
if (newMoves.map(x => x.id).includes(newMove.id)) continue;
|
||||
newMoves.push(newMove);
|
||||
}
|
||||
// Update move slots
|
||||
pokemon.moveSlots = newMoves.map(move => {
|
||||
const moveData = this.dex.moves.get(move);
|
||||
return {
|
||||
move: moveData.name,
|
||||
id: moveData.id,
|
||||
pp: moveData.pp,
|
||||
maxpp: moveData.pp,
|
||||
target: moveData.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
};
|
||||
});
|
||||
// this forces the UI to update move slots visually
|
||||
(pokemon as any).baseMoveSlots = pokemon.moveSlots.slice();
|
||||
pokemon.m.didRandomMoves = true;
|
||||
},
|
||||
onSwitchIn(pokemon) {
|
||||
if (!pokemon) return; // Chat command
|
||||
if (!pokemon.m.hasTypeChanged) {
|
||||
this.add('-ability', pokemon, 'Biogenesis');
|
||||
this.add('-anim', pokemon, 'Growth', pokemon);
|
||||
this.add('-message', `Mew evolves into a new form with its Biogenesis!`);
|
||||
}
|
||||
const attackingMoves = pokemon.baseMoveSlots
|
||||
.map(slot => this.dex.moves.get(slot.id))
|
||||
.filter(move => move.category !== "Status");
|
||||
|
||||
// pick types of first 2 attacking moves (failsafe if there are none)
|
||||
const types = attackingMoves.length ?
|
||||
[...new Set(attackingMoves.slice(0, 2).map(move => move.type))] :
|
||||
pokemon.types;
|
||||
pokemon.setType(types);
|
||||
pokemon.baseTypes = pokemon.types;
|
||||
pokemon.m.hasTypeChanged = true;
|
||||
this.add('-start', pokemon, 'typechange', (pokemon.illusion || pokemon).getTypes(true).join('/'), '[silent]');
|
||||
},
|
||||
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1,
|
||||
breakable: 1, notransform: 1, cantsuppress: 1 },
|
||||
name: "Biogenesis",
|
||||
rating: 5,
|
||||
num: -112,
|
||||
shortDesc: "This Pokemon receives 8 completely random moves at the start of the game.",
|
||||
},
|
||||
orichalcumpulse: {
|
||||
onStart(pokemon) {
|
||||
pokemon.updateMaxHp();
|
||||
if (this.field.setWeather('sunnyday')) {
|
||||
this.add('-activate', pokemon, 'Orichalcum Pulse', '[source]');
|
||||
} else if (this.field.isWeather('sunnyday')) {
|
||||
this.add('-activate', pokemon, 'ability: Orichalcum Pulse');
|
||||
}
|
||||
},
|
||||
onModifyAtkPriority: 5,
|
||||
onModifyAtk(atk, pokemon) {
|
||||
if (['sunnyday', 'desolateland'].includes(pokemon.effectiveWeather())) {
|
||||
this.debug('Orichalcum boost');
|
||||
return this.chainModify([5461, 4096]);
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Orichalcum Pulse",
|
||||
rating: 4.5,
|
||||
num: 288,
|
||||
},
|
||||
hailmary: {
|
||||
onStart(pokemon) {
|
||||
this.add('-activate', pokemon, 'ability: Hail Mary');
|
||||
},
|
||||
onModifySpe(spe, pokemon) {
|
||||
if (this.field.isWeather(['hail', 'snowscape'])) {
|
||||
this.debug('hail mary spe boost');
|
||||
return this.chainModify(2);
|
||||
}
|
||||
},
|
||||
onModifyAtkPriority: 5,
|
||||
onModifyAtk(atk, pokemon) {
|
||||
if (this.field.isWeather(['hail', 'snowscape'])) {
|
||||
this.debug('hail mary atk boost');
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
},
|
||||
onSourceModifyAccuracyPriority: -1,
|
||||
onSourceModifyAccuracy(accuracy, target, source, move) {
|
||||
if (this.field.isWeather(['hail', 'snowscape'])) {
|
||||
if (move.category === 'Physical' && typeof accuracy === 'number') {
|
||||
return this.chainModify([3277, 4096]);
|
||||
}
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Hail Mary",
|
||||
rating: 5,
|
||||
num: -113,
|
||||
shortDesc: "In Snowscape: 2x Speed, 1.5x Attack, 0.8x accuracy.",
|
||||
},
|
||||
brainfreeze: {
|
||||
onModifyCritRatio(critRatio, source, target) {
|
||||
if (target && (target.status === 'frostbite' || this.field.isWeather('snowscape'))) return 5;
|
||||
},
|
||||
flags: {},
|
||||
name: "Brain Freeze",
|
||||
rating: 5,
|
||||
num: -114,
|
||||
shortDesc: "If Snowscape or target is Frostbitten, attacks auto Crit.",
|
||||
},
|
||||
neutralizinggas: {
|
||||
inherit: true,
|
||||
onStart(pokemon) {
|
||||
// this makes Neutralizing Gas properly show as activated in the client when Typhlosion Mega evolves
|
||||
this.add('-ability', pokemon, 'Neutralizing Gas');
|
||||
},
|
||||
},
|
||||
terawheel: {
|
||||
onStart(pokemon) {
|
||||
pokemon.canTerastallize = null;
|
||||
},
|
||||
// copied from SSB High Performance Computing
|
||||
onResidualOrder: 6,
|
||||
onResidual(source) {
|
||||
const type = this.sample(this.dex.types.names().filter(i => i !== source.getTypes()[0]));
|
||||
if (source.setType(type)) {
|
||||
this.add('-start', source, 'typechange', type, '[from] ability: Tera Wheel');
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Tera Wheel",
|
||||
rating: 5,
|
||||
num: -115,
|
||||
shortDesc: "End of turn: this Pokemon switches to a random type (including Stellar).",
|
||||
},
|
||||
download: {
|
||||
inherit: true,
|
||||
onUpdate(pokemon) {
|
||||
if (pokemon.species.name === 'Genesect-Burn' && pokemon.terastallized) {
|
||||
pokemon.setAbility('Drought', null, null, true);
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
this.add('-ability', pokemon, 'Drought');
|
||||
}
|
||||
if (pokemon.species.name === 'Genesect-Chill' && pokemon.terastallized) {
|
||||
pokemon.setAbility('Snow Warning', null, null, true);
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
this.add('-ability', pokemon, 'Snow Warning');
|
||||
}
|
||||
if (pokemon.species.name === 'Genesect-Douse' && pokemon.terastallized) {
|
||||
pokemon.setAbility('Drizzle', null, null, true);
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
this.add('-ability', pokemon, 'Drizzle');
|
||||
}
|
||||
if (pokemon.species.name === 'Genesect-Shock' && pokemon.terastallized) {
|
||||
pokemon.setAbility('Electric Surge', null, null, true);
|
||||
pokemon.baseAbility = pokemon.ability;
|
||||
this.add('-ability', pokemon, 'Electric Surge');
|
||||
}
|
||||
},
|
||||
shortDesc: "Download + Gets weather setting move when Tera.",
|
||||
},
|
||||
battlerage: {
|
||||
onDamagingHit(damage, target, source, effect) {
|
||||
this.boost({ atk: 1 });
|
||||
},
|
||||
flags: {},
|
||||
name: "Battle Rage",
|
||||
rating: 5,
|
||||
num: -116,
|
||||
shortDesc: "+1 Atk when hit by an attack.",
|
||||
},
|
||||
terrainshift: {
|
||||
onStart(source) {
|
||||
if (source.hp >= source.maxhp) {
|
||||
source.setType("Electric");
|
||||
this.field.setTerrain('electricterrain');
|
||||
this.add('-start', source, 'typechange', 'Electric', '[silent]');
|
||||
} else if (source.hp >= (2 * source.maxhp) / 3) {
|
||||
source.setType("Fairy");
|
||||
this.field.setTerrain('mistyterrain');
|
||||
this.add('-start', source, 'typechange', 'Fairy', '[silent]');
|
||||
} else if (source.hp >= source.maxhp / 3) {
|
||||
source.setType("Grass");
|
||||
this.field.setTerrain('grassyterrain');
|
||||
this.add('-start', source, 'typechange', 'Grass', '[silent]');
|
||||
} else {
|
||||
source.setType("Psychic");
|
||||
this.field.setTerrain('psychicterrain');
|
||||
this.add('-start', source, 'typechange', 'Psychic', '[silent]');
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Terrain Shift",
|
||||
rating: 5,
|
||||
num: -117,
|
||||
shortDesc: "Sets terrain depending on HP value.",
|
||||
},
|
||||
dragonsjaw: {
|
||||
onBasePower(basePower, attacker, defender, move) {
|
||||
if (defender.hasType('Dragon') && defender.hasType('Steel')) {
|
||||
return this.chainModify(1.5);
|
||||
} else if (defender.hasType('Dragon')) {
|
||||
return this.chainModify(2.25);
|
||||
} else if (defender.hasType('Steel')) {
|
||||
return;
|
||||
} else return this.chainModify(1.5);
|
||||
},
|
||||
onTryHit(target, source, move) {
|
||||
if (target.hasType('Fairy')) {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
onModifyMovePriority: -2,
|
||||
onModifyMove(move) {
|
||||
if (move.secondaries) {
|
||||
this.debug('doubling secondary chance');
|
||||
for (const secondary of move.secondaries) {
|
||||
if (secondary.chance) secondary.chance *= 2;
|
||||
}
|
||||
}
|
||||
if (move.self?.chance) move.self.chance *= 2;
|
||||
},
|
||||
flags: {},
|
||||
name: "Dragon's Jaw",
|
||||
rating: 5,
|
||||
num: -118,
|
||||
shortDesc: "Serene Grace + Bite attacks are Dragon type.",
|
||||
},
|
||||
corrosivesoul: {
|
||||
onStart(source) {
|
||||
this.field.setTerrain('corrosivesoul');
|
||||
},
|
||||
condition: {
|
||||
effectType: 'Terrain',
|
||||
duration: 5,
|
||||
durationCallback(source, effect) {
|
||||
if (source?.hasItem('terrainextender')) {
|
||||
return 8;
|
||||
}
|
||||
return 5;
|
||||
},
|
||||
onFieldStart(field, source, effect) {
|
||||
if (effect?.effectType === 'Ability') {
|
||||
this.add('-fieldstart', 'move: Corrosive Soul', '[from] ability: ' + effect.name, `[of] ${source}`);
|
||||
} else {
|
||||
this.add('-fieldstart', 'move: Corrosive Soul');
|
||||
}
|
||||
},
|
||||
onResidualOrder: 5,
|
||||
onResidualSubOrder: 2,
|
||||
onResidual(pokemon) {
|
||||
const move = this.dex.getActiveMove('smog');
|
||||
move.accuracy = 100;
|
||||
const target = pokemon.foes()[0];
|
||||
if (target && !target.fainted) {
|
||||
this.actions.useMove(move, pokemon, { target });
|
||||
}
|
||||
},
|
||||
onFieldResidualOrder: 27,
|
||||
onFieldResidualSubOrder: 7,
|
||||
onFieldEnd() {
|
||||
this.add('-fieldend', 'move: Corrosive Soul');
|
||||
},
|
||||
},
|
||||
flags: {},
|
||||
name: "Corrosive Soul",
|
||||
rating: 5,
|
||||
num: -119,
|
||||
shortDesc: "Sets Corrosive Terrian: active Pokemon hit each other with Smog.",
|
||||
},
|
||||
oceanicblessing: {
|
||||
onSwitchInPriority: -2,
|
||||
onStart(pokemon) {
|
||||
this.singleEvent('WeatherChange', this.effect, this.effectState, pokemon);
|
||||
},
|
||||
onWeatherChange(pokemon) {
|
||||
if (!pokemon.isActive || pokemon.baseSpecies.baseSpecies !== 'Kyogre' || pokemon.transformed) return;
|
||||
if (!pokemon.hp) return;
|
||||
if (['raindance', 'primordialsea'].includes(pokemon.effectiveWeather())) {
|
||||
if (pokemon.species.id !== 'kyogreprimal') {
|
||||
pokemon.formeChange('Kyogre-Primal', this.effect, false);
|
||||
}
|
||||
} else {
|
||||
if (pokemon.species.id === 'kyogreprimal') {
|
||||
pokemon.formeChange('kyogre', this.effect, false);
|
||||
}
|
||||
}
|
||||
},
|
||||
onAllyModifyAtkPriority: 3,
|
||||
onAllyModifyAtk(atk, pokemon) {
|
||||
if (this.effectState.target.baseSpecies.baseSpecies !== 'Kyogre') return;
|
||||
if (['raindance', 'primordialsea'].includes(pokemon.effectiveWeather())) {
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
},
|
||||
onAllyModifySpDPriority: 4,
|
||||
onAllyModifySpD(spd, pokemon) {
|
||||
if (this.effectState.target.baseSpecies.baseSpecies !== 'Kyogre') return;
|
||||
if (['raindance', 'primordialsea'].includes(pokemon.effectiveWeather())) {
|
||||
return this.chainModify(1.5);
|
||||
}
|
||||
},
|
||||
flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, breakable: 1 },
|
||||
name: "Oceanic Blessing",
|
||||
rating: 5,
|
||||
num: -120,
|
||||
shortDesc: "Flower Gift but Kyogre",
|
||||
},
|
||||
autospin: {
|
||||
onResidual(pokemon, s, effect) {
|
||||
const move = this.dex.getActiveMove('metronome');
|
||||
const target = pokemon.foes()[0];
|
||||
if (target && !target.fainted && (pokemon.hp >= pokemon.maxhp / 2)) {
|
||||
this.actions.useMove(move, pokemon, { target, sourceEffect: effect });
|
||||
} else if (target && !target.fainted && (pokemon.hp <= pokemon.maxhp / 10)) {
|
||||
this.actions.useMove(move, pokemon, { target, sourceEffect: effect });
|
||||
this.actions.useMove(move, pokemon, { target, sourceEffect: effect });
|
||||
this.actions.useMove(move, pokemon, { target, sourceEffect: effect });
|
||||
} else if (target && !target.fainted) {
|
||||
this.actions.useMove(move, pokemon, { target, sourceEffect: effect });
|
||||
this.actions.useMove(move, pokemon, { target, sourceEffect: effect });
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Auto Spin",
|
||||
rating: 5,
|
||||
num: -121,
|
||||
shortDesc: "Use Metronome at end of turn.",
|
||||
},
|
||||
corrosion: {
|
||||
inherit: true,
|
||||
onModifyMovePriority: -5,
|
||||
onModifyMove(move) {
|
||||
if (!move.ignoreImmunity) move.ignoreImmunity = {};
|
||||
if (move.ignoreImmunity !== true) {
|
||||
move.ignoreImmunity['Poison'] = true;
|
||||
}
|
||||
},
|
||||
shortDesc: "This Pokemon can poison a Pokemon regardless of its typing and hit them with Poison moves.",
|
||||
},
|
||||
jellobody: {
|
||||
onTryHit(pokemon, target, move) {
|
||||
if (move.selfSwitch) {
|
||||
this.add('-immune', pokemon, '[from] ability: Jello Body');
|
||||
this.heal(target.baseMaxhp / 2);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
onModifyMove(move, source, target) {
|
||||
move.drain = [1, 2];
|
||||
},
|
||||
flags: { breakable: 1 },
|
||||
name: "Jello Body",
|
||||
rating: 5,
|
||||
num: -122,
|
||||
shortDesc: "Immune to pivot moves, heals 50% HP when hit by one. All moves drain 50%.",
|
||||
},
|
||||
nibblenibble: {
|
||||
onPrepareHit(source, target, move) {
|
||||
if (move.category === 'Status' || move.multihit || move.flags['noparentalbond'] || move.flags['charge'] ||
|
||||
move.flags['futuremove'] || move.spreadHit || move.isZ || move.isMax || !move.flags['bite']) return;
|
||||
move.multihit = 2;
|
||||
move.multihitType = 'parentalbond';
|
||||
},
|
||||
// Damage modifier implemented in BattleActions#modifyDamage()
|
||||
onSourceModifySecondaries(secondaries, target, source, move) {
|
||||
if (move.multihitType === 'parentalbond' && move.id === 'secretpower' && move.hit < 2) {
|
||||
// hack to prevent accidentally suppressing King's Rock/Razor Fang
|
||||
return secondaries.filter(effect => effect.volatileStatus === 'flinch');
|
||||
}
|
||||
},
|
||||
flags: {},
|
||||
name: "Nibble Nibble",
|
||||
rating: 5,
|
||||
num: -123,
|
||||
shortDesc: "Parental Bond but for Bite moves.",
|
||||
},
|
||||
};
|
||||
20
data/mods/chatbats/conditions.ts
Normal file
20
data/mods/chatbats/conditions.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDataTable = {
|
||||
frostbite: {
|
||||
name: 'frostbite',
|
||||
effectType: 'Status',
|
||||
onStart(target) {
|
||||
this.add('-start', target, 'Frostbite', '[silent]');
|
||||
this.add('-message', `${target.species.name} is inflicted with frostbite!`);
|
||||
},
|
||||
onSwitchIn(pokemon) {
|
||||
this.add('-start', pokemon, 'Frostbite', '[silent]');
|
||||
},
|
||||
onResidualOrder: 10,
|
||||
onResidual(pokemon) {
|
||||
this.damage(pokemon.baseMaxhp / 16);
|
||||
},
|
||||
onBasePower(basePower, source, target) {
|
||||
return basePower / 2;
|
||||
},
|
||||
},
|
||||
};
|
||||
150
data/mods/chatbats/items.ts
Normal file
150
data/mods/chatbats/items.ts
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
||||
bigroot: {
|
||||
inherit: true,
|
||||
onTryHealPriority: 1,
|
||||
onTryHeal(damage, target, source, effect) {
|
||||
const heals = ['drain', 'leechseed', 'ingrain', 'aquaring', 'strengthsap'];
|
||||
if (heals.includes(effect.id)) {
|
||||
return this.chainModify([6144, 4096]);
|
||||
}
|
||||
},
|
||||
shortDesc: "Holder gains 1.5x HP from draining, Aqua Ring, Ingrain, Leech Seed, Strength Sap.",
|
||||
},
|
||||
masquerainite: {
|
||||
name: "Masquerainite",
|
||||
spritenum: 1,
|
||||
megaStone: { "Masquerain": "Masquerain-Mega" },
|
||||
itemUser: ["Masquerain"],
|
||||
onTakeItem(item, source) {
|
||||
return !item.megaStone?.[source.baseSpecies.baseSpecies];
|
||||
},
|
||||
num: -1,
|
||||
gen: 9,
|
||||
desc: "If held by a Masquerain, this item allows it to Mega Evolve in battle.",
|
||||
},
|
||||
starfberry: {
|
||||
name: "Starf Berry",
|
||||
spritenum: 472,
|
||||
isBerry: true,
|
||||
naturalGift: {
|
||||
basePower: 100,
|
||||
type: "Psychic",
|
||||
},
|
||||
onUpdate(pokemon) {
|
||||
if (pokemon.hp <= pokemon.maxhp / 2 ||
|
||||
((pokemon.hp <= pokemon.maxhp / 2 && pokemon.hasAbility('gluttony') && pokemon.abilityState.gluttony))) {
|
||||
pokemon.eatItem();
|
||||
}
|
||||
},
|
||||
onEat(pokemon) {
|
||||
const stats: BoostID[] = [];
|
||||
let stat: BoostID;
|
||||
for (stat in pokemon.boosts) {
|
||||
if (stat !== 'accuracy' && stat !== 'evasion' && pokemon.boosts[stat] < 6) {
|
||||
stats.push(stat);
|
||||
}
|
||||
}
|
||||
if (stats.length) {
|
||||
const randomStat = this.sample(stats);
|
||||
const boost: SparseBoostsTable = {};
|
||||
boost[randomStat] = 2;
|
||||
this.boost(boost);
|
||||
}
|
||||
},
|
||||
num: 207,
|
||||
gen: 3,
|
||||
},
|
||||
typhlosionite: {
|
||||
name: "Typhlosionite",
|
||||
spritenum: 1,
|
||||
megaStone: { "Typhlosion": "Typhlosion-Mega" },
|
||||
itemUser: ["Typhlosion"],
|
||||
onTakeItem(item, source) {
|
||||
return !item.megaStone?.[source.baseSpecies.baseSpecies];
|
||||
},
|
||||
num: -2,
|
||||
gen: 9,
|
||||
desc: "If held by a Typhlosion, this item allows it to Mega Evolve in battle.",
|
||||
},
|
||||
tartapple: {
|
||||
name: "Tart Apple",
|
||||
spritenum: 712,
|
||||
isBerry: true,
|
||||
fling: {
|
||||
basePower: 30,
|
||||
},
|
||||
onBasePowerPriority: 15,
|
||||
onBasePower(basePower, user, target, move) {
|
||||
if (
|
||||
move && (user.baseSpecies.num === 841) &&
|
||||
(move.type === 'Grass' || move.type === 'Ground')
|
||||
) {
|
||||
return this.chainModify([4915, 4096]);
|
||||
}
|
||||
},
|
||||
onUpdate(pokemon) {
|
||||
if (pokemon.hp <= pokemon.maxhp / 2) {
|
||||
pokemon.eatItem();
|
||||
}
|
||||
},
|
||||
onTryEatItem(item, pokemon) {
|
||||
if (!this.runEvent('TryHeal', pokemon, null, this.effect, pokemon.baseMaxhp / 4)) return false;
|
||||
},
|
||||
onEat(pokemon) {
|
||||
this.heal(pokemon.baseMaxhp / 4);
|
||||
},
|
||||
itemUser: ["Flapple"],
|
||||
num: 1117,
|
||||
gen: 8,
|
||||
desc: "Grass- and Ground-type moves have 1.2x power. Restores 1/4 max HP when at 1/2 max HP or less.",
|
||||
},
|
||||
thickclub: {
|
||||
name: "Thick Club",
|
||||
spritenum: 491,
|
||||
fling: {
|
||||
basePower: 130,
|
||||
},
|
||||
onModifyAtkPriority: 1,
|
||||
onModifyAtk(atk, pokemon) {
|
||||
if (pokemon.baseSpecies.baseSpecies === 'Mandibuzz' || pokemon.baseSpecies.baseSpecies === 'Mew') {
|
||||
return this.chainModify(2);
|
||||
}
|
||||
},
|
||||
itemUser: ["Marowak", "Marowak-Alola", "Marowak-Alola-Totem", "Cubone", "Mandibuzz", "Mew"],
|
||||
num: 258,
|
||||
gen: 2,
|
||||
desc: "Doubles Attack.",
|
||||
},
|
||||
focusband: {
|
||||
name: "Focus Band",
|
||||
spritenum: 150,
|
||||
fling: {
|
||||
basePower: 10,
|
||||
},
|
||||
onDamagePriority: -40,
|
||||
onDamage(damage, target, source, effect) {
|
||||
const chance = Math.max(Math.floor(100 - (target.maxhp - target.hp)), 10);
|
||||
if (this.randomChance(chance, 100) && damage >= target.hp && effect && effect.effectType === 'Move') {
|
||||
this.add("-activate", target, "item: Focus Band");
|
||||
return target.hp - 1;
|
||||
} else {
|
||||
return damage;
|
||||
}
|
||||
},
|
||||
num: 230,
|
||||
gen: 2,
|
||||
desc: "Chance to survive attack equal to percentage of remaining HP, minimum 10%.",
|
||||
},
|
||||
raticite: {
|
||||
name: "Raticite",
|
||||
spritenum: 1,
|
||||
megaStone: { "Raticate": "Raticate-Mega" },
|
||||
itemUser: ["Raticate"],
|
||||
onTakeItem(item, source) {
|
||||
return !item.megaStone?.[source.baseSpecies.baseSpecies];
|
||||
},
|
||||
num: -3,
|
||||
gen: 9,
|
||||
desc: "If held by a Raticate, this item allows it to Mega Evolve in battle.",
|
||||
},
|
||||
};
|
||||
1722
data/mods/chatbats/moves.ts
Normal file
1722
data/mods/chatbats/moves.ts
Normal file
File diff suppressed because it is too large
Load Diff
514
data/mods/chatbats/pokedex.ts
Normal file
514
data/mods/chatbats/pokedex.ts
Normal file
|
|
@ -0,0 +1,514 @@
|
|||
export const Pokedex: import('../../../sim/dex-species').ModdedSpeciesDataTable = {
|
||||
volcarona: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Fluffy" },
|
||||
},
|
||||
golemalola: {
|
||||
inherit: true,
|
||||
},
|
||||
lurantis: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 85, atk: 105, def: 90, spa: 95, spd: 90, spe: 75 },
|
||||
},
|
||||
ironcrown: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Queenly Majesty", H: "Battle Armor" },
|
||||
},
|
||||
mamoswine: {
|
||||
inherit: true,
|
||||
},
|
||||
ceruledge: {
|
||||
inherit: true,
|
||||
},
|
||||
carbink: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Magic Bounce" },
|
||||
},
|
||||
moltres: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Magic Guard" },
|
||||
},
|
||||
kommoo: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 75, atk: 100, def: 125, spa: 110, spd: 105, spe: 85 },
|
||||
abilities: { 0: "Punk Rock" },
|
||||
},
|
||||
illumise: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Call Volbeat" },
|
||||
},
|
||||
volbeat: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Call Illumise" },
|
||||
},
|
||||
abomasnow: {
|
||||
inherit: true,
|
||||
},
|
||||
abomasnowmega: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 90, atk: 132, def: 105, spa: 92, spd: 105, spe: 70 },
|
||||
abilities: { 0: "Slush Rush" },
|
||||
},
|
||||
dugtrio: {
|
||||
inherit: true,
|
||||
},
|
||||
altaria: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Fluffy" },
|
||||
},
|
||||
altariamega: {
|
||||
inherit: true,
|
||||
},
|
||||
tyranitar: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Sand Stream", H: "Sharpness" },
|
||||
},
|
||||
tyranitarmega: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 100, atk: 114, def: 150, spa: 155, spd: 110, spe: 71 },
|
||||
types: ["Rock", "Dragon"],
|
||||
},
|
||||
mimikyu: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 65, atk: 110, def: 80, spa: 50, spd: 105, spe: 96 },
|
||||
},
|
||||
mimikyubusted: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Perish Body" },
|
||||
baseStats: { hp: 65, atk: 90, def: 80, spa: 50, spd: 105, spe: 116 },
|
||||
},
|
||||
mesprit: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Liquid Voice" },
|
||||
types: ["Psychic", "Water"],
|
||||
},
|
||||
electrode: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Short Fuse" },
|
||||
types: ["Electric", "Normal"],
|
||||
},
|
||||
taurospaldeacombat: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Adaptability" },
|
||||
},
|
||||
chiyu: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Water Absorb" },
|
||||
baseStats: { hp: 55, atk: 135, def: 80, spa: 80, spd: 120, spe: 100 },
|
||||
},
|
||||
wochien: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Liquid Ooze" },
|
||||
types: ["Grass", "Water"],
|
||||
},
|
||||
staraptor: {
|
||||
inherit: true,
|
||||
types: ["Flying"],
|
||||
},
|
||||
archaludon: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Hydroelectric Dam", 1: "Stamina" },
|
||||
},
|
||||
malamar: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Flip Flop" },
|
||||
baseStats: { hp: 86, atk: 92, def: 88, spa: 88, spd: 75, spe: 73 },
|
||||
},
|
||||
empoleon: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Sharpness" },
|
||||
types: ["Water", "Steel", "Flying"],
|
||||
},
|
||||
glastrier: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Frozen Armor" },
|
||||
},
|
||||
calyrexice: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 100, atk: 165, def: 130, spa: 85, spd: 110, spe: 90 },
|
||||
},
|
||||
regieleki: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Galvanize" },
|
||||
},
|
||||
lycanrocmidnight: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Technician" },
|
||||
},
|
||||
lycanroc: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Drought" },
|
||||
},
|
||||
lycanrocdusk: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Strong Jaw" },
|
||||
},
|
||||
dodrio: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Speed Boost" },
|
||||
types: ["Flying", "Fighting"],
|
||||
},
|
||||
whiscash: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Regenerator" },
|
||||
baseStats: { hp: 110, atk: 78, def: 88, spa: 76, spd: 86, spe: 60 },
|
||||
},
|
||||
hippowdon: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Earth Eater" },
|
||||
},
|
||||
cramorant: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 90, atk: 85, def: 75, spa: 85, spd: 95, spe: 85 },
|
||||
},
|
||||
cramorantgulping: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 90, atk: 85, def: 75, spa: 85, spd: 95, spe: 85 },
|
||||
abilities: { 0: "Storm Drain" },
|
||||
},
|
||||
cramorantgorging: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 90, atk: 85, def: 75, spa: 85, spd: 95, spe: 85 },
|
||||
abilities: { 0: "Lightning Rod" },
|
||||
},
|
||||
grafaiai: {
|
||||
inherit: true,
|
||||
baseStats: { hp: 83, atk: 95, def: 65, spa: 80, spd: 72, spe: 110 },
|
||||
},
|
||||
tatsugiri: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Regenerator" },
|
||||
baseStats: { hp: 78, atk: 50, def: 70, spa: 120, spd: 95, spe: 82 },
|
||||
},
|
||||
kyurem: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Skill Link" },
|
||||
},
|
||||
roaringmoon: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Shadow Shield" },
|
||||
},
|
||||
milotic: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Aqua Veil" },
|
||||
types: ["Water", "Fairy"],
|
||||
},
|
||||
gogoat: {
|
||||
inherit: true,
|
||||
types: ["Grass", "Rock"],
|
||||
},
|
||||
clodsire: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Still Water" },
|
||||
},
|
||||
masquerain: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Intimidate" },
|
||||
},
|
||||
masquerainmega: {
|
||||
num: -999,
|
||||
name: "Masquerain-Mega",
|
||||
baseSpecies: "Masquerain",
|
||||
forme: "Mega",
|
||||
types: ["Bug", "Dark"],
|
||||
genderRatio: { M: 0.5, F: 0.5 },
|
||||
baseStats: { hp: 70, atk: 60, def: 82, spa: 140, spd: 82, spe: 120 },
|
||||
abilities: { 0: "Primordial Sea" },
|
||||
heightm: 0.8,
|
||||
weightkg: 3.6,
|
||||
color: "Blue",
|
||||
eggGroups: ["Water 1", "Bug"],
|
||||
requiredItem: "Masquerainite",
|
||||
},
|
||||
kyuremblack: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Teravolt" },
|
||||
types: ["Dragon", "Ice", "Electric"],
|
||||
},
|
||||
ironthorns: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Iron Barbs" },
|
||||
},
|
||||
dudunsparce: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Earth Eater" },
|
||||
types: ["Normal", "Ground"],
|
||||
},
|
||||
dudunsparcethreesegment: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Earth Eater" },
|
||||
types: ["Normal", "Ground"],
|
||||
},
|
||||
chienpao: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Tablets of Ruin" },
|
||||
},
|
||||
pelipper: {
|
||||
inherit: true,
|
||||
},
|
||||
kleavor: {
|
||||
inherit: true,
|
||||
abilities: { 0: "King of the Hill" },
|
||||
baseStats: { hp: 120, atk: 135, def: 95, spa: 45, spd: 75, spe: 85 },
|
||||
},
|
||||
araquanid: {
|
||||
inherit: true,
|
||||
},
|
||||
avalugghisui: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Multiscale" },
|
||||
baseStats: { hp: 95, atk: 127, def: 184, spa: 68, spd: 72, spe: 76 },
|
||||
},
|
||||
swalot: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Omnivore" },
|
||||
},
|
||||
zapdosgalar: {
|
||||
inherit: true,
|
||||
types: ["Electric", "Fighting"],
|
||||
},
|
||||
phione: {
|
||||
inherit: true,
|
||||
},
|
||||
sudowoodo: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Pseudowoodo" },
|
||||
types: ["Grass"],
|
||||
baseForme: "Grass",
|
||||
otherFormes: ["Sudowoodo-Rock"],
|
||||
formeOrder: ["Sudowoodo", "Sudowoodo-Rock"],
|
||||
},
|
||||
sudowoodorock: {
|
||||
num: 185,
|
||||
name: "Sudowoodo-Rock",
|
||||
baseSpecies: "Sudowoodo",
|
||||
forme: "Rock",
|
||||
types: ["Rock"],
|
||||
baseStats: { hp: 70, atk: 100, def: 110, spa: 30, spd: 65, spe: 30 },
|
||||
abilities: { 0: "Pseudowoodo" },
|
||||
heightm: 1.7,
|
||||
weightkg: 38,
|
||||
color: "Brown",
|
||||
eggGroups: ["Mineral"],
|
||||
requiredAbility: "Pseudowoodo",
|
||||
battleOnly: "Sudowoodo",
|
||||
},
|
||||
dondozo: {
|
||||
inherit: true,
|
||||
},
|
||||
golurk: {
|
||||
inherit: true,
|
||||
},
|
||||
meowscarada: {
|
||||
inherit: true,
|
||||
},
|
||||
infernape: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Berserk" },
|
||||
},
|
||||
salamence: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Aerilate" },
|
||||
},
|
||||
salamencemega: {
|
||||
num: 373,
|
||||
name: "Salamence-Mega",
|
||||
baseSpecies: "Salamence",
|
||||
forme: "Mega",
|
||||
types: ["Dragon", "Flying"],
|
||||
baseStats: { hp: 95, atk: 145, def: 130, spa: 120, spd: 90, spe: 120 },
|
||||
abilities: { 0: "Blood-Soaked Crescent" },
|
||||
heightm: 1.8,
|
||||
weightkg: 112.6,
|
||||
color: "Blue",
|
||||
eggGroups: ["Dragon"],
|
||||
requiredItem: "Salamencite",
|
||||
},
|
||||
urshifu: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Sniper" },
|
||||
},
|
||||
urshifurapidstrike: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Sniper" },
|
||||
},
|
||||
stonjourner: {
|
||||
inherit: true,
|
||||
},
|
||||
veluza: {
|
||||
inherit: true,
|
||||
types: ["Water", "Ghost"],
|
||||
},
|
||||
ogerponhearthflame: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Intimidate" },
|
||||
},
|
||||
dachsbun: {
|
||||
inherit: true,
|
||||
},
|
||||
koraidon: {
|
||||
inherit: true,
|
||||
},
|
||||
mew: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Biogenesis" },
|
||||
},
|
||||
magneton: {
|
||||
inherit: true,
|
||||
},
|
||||
delibird: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Hail Mary" },
|
||||
baseStats: { hp: 45, atk: 90, def: 45, spa: 65, spd: 45, spe: 136 },
|
||||
},
|
||||
articunogalar: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Brain Freeze" },
|
||||
},
|
||||
vaporeon: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Marvel Scale" },
|
||||
},
|
||||
jolteon: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Quick Feet" },
|
||||
},
|
||||
flareon: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Guts" },
|
||||
baseStats: { hp: 65, atk: 130, def: 65, spa: 60, spd: 110, spe: 95 },
|
||||
},
|
||||
garganacl: {
|
||||
inherit: true,
|
||||
},
|
||||
swanna: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Serene Grace" },
|
||||
baseStats: { hp: 75, atk: 117, def: 93, spa: 117, spd: 93, spe: 128 },
|
||||
},
|
||||
typhlosion: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Magic Guard" },
|
||||
},
|
||||
typhlosionmega: {
|
||||
num: -998,
|
||||
name: "Typhlosion-Mega",
|
||||
baseSpecies: "Typhlosion",
|
||||
forme: "Mega",
|
||||
types: ["Fire", "Water"],
|
||||
genderRatio: { M: 0.5, F: 0.5 },
|
||||
baseStats: { hp: 78, atk: 103, def: 98, spa: 140, spd: 115, spe: 100 },
|
||||
abilities: { 0: "Neutralizing Gas" },
|
||||
heightm: 1.7,
|
||||
weightkg: 84.5,
|
||||
color: "Blue",
|
||||
eggGroups: ["Field"],
|
||||
requiredItem: "Typhlosionite",
|
||||
},
|
||||
terapagos: {
|
||||
inherit: true,
|
||||
},
|
||||
terapagosterastal: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Tera Wheel" },
|
||||
},
|
||||
terapagosstellar: {
|
||||
inherit: true,
|
||||
types: ["Stellar"],
|
||||
},
|
||||
flapple: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Ripen" },
|
||||
types: ["Grass", "Ground"],
|
||||
},
|
||||
genesect: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Download" },
|
||||
},
|
||||
honchkrow: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Supreme Overlord" },
|
||||
baseStats: { hp: 100, atk: 125, def: 52, spa: 125, spd: 52, spe: 71 },
|
||||
},
|
||||
primeape: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Battle Rage" },
|
||||
},
|
||||
rillaboom: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Terrain Shift" },
|
||||
},
|
||||
mandibuzz: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Weak Armor" },
|
||||
types: ["Dark", "Ground"],
|
||||
},
|
||||
feraligatr: {
|
||||
inherit: true,
|
||||
},
|
||||
feraligatrmega: {
|
||||
num: -988,
|
||||
name: "Feraligatr-Mega",
|
||||
baseSpecies: "Feraligatr",
|
||||
forme: "Mega",
|
||||
types: ["Dragon"],
|
||||
genderRatio: { M: 0.875, F: 0.125 },
|
||||
baseStats: { hp: 85, atk: 145, def: 120, spa: 99, spd: 103, spe: 78 },
|
||||
abilities: { 0: "Dragon's Jaw" },
|
||||
heightm: 2.3,
|
||||
weightkg: 108.8,
|
||||
color: "Blue",
|
||||
eggGroups: ["Monster", "Water 1"],
|
||||
requiredItem: "Feraligite",
|
||||
gen: 9,
|
||||
},
|
||||
salazzle: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Corrosive Soul" },
|
||||
},
|
||||
kyogre: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Oceanic Blessing" },
|
||||
},
|
||||
azelf: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Auto Spin" },
|
||||
types: ["Psychic", "Normal"],
|
||||
},
|
||||
decidueye: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Overgrow", 1: "Sniper" },
|
||||
},
|
||||
ogerponcornerstone: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Solid Rock" },
|
||||
},
|
||||
glimmora: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Corrosion" },
|
||||
},
|
||||
wobbuffet: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Jello Body" },
|
||||
},
|
||||
raticate: {
|
||||
inherit: true,
|
||||
abilities: { 0: "Hustle" },
|
||||
baseStats: { hp: 90, atk: 81, def: 60, spa: 50, spd: 70, spe: 97 },
|
||||
},
|
||||
raticatemega: {
|
||||
num: -977,
|
||||
name: "Raticate-Mega",
|
||||
baseSpecies: "Raticate",
|
||||
forme: "Mega",
|
||||
types: ["Normal", "Ghost"],
|
||||
genderRatio: { M: 0.5, F: 0.5 },
|
||||
baseStats: { hp: 90, atk: 105, def: 60, spa: 50, spd: 70, spe: 173 },
|
||||
abilities: { 0: "Nibble Nibble" },
|
||||
heightm: 0.7,
|
||||
weightkg: 5,
|
||||
color: "Black",
|
||||
eggGroups: ["Field"],
|
||||
requiredItem: "Raticite",
|
||||
},
|
||||
};
|
||||
311
data/mods/chatbats/scripts.ts
Normal file
311
data/mods/chatbats/scripts.ts
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
export const Scripts: ModdedBattleScriptsData = {
|
||||
gen: 9,
|
||||
|
||||
init() {
|
||||
this.modData('Learnsets', 'lurantis').learnset.icehammer = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'ironcrown').learnset.kingsshield = ['9L1'];
|
||||
this.modData('Learnsets', 'ironcrown').learnset.bodypress = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'carbink').learnset.moonlight = ['9L1'];
|
||||
this.modData('Learnsets', 'carbink').learnset.voltswitch = ['9L1'];
|
||||
this.modData('Learnsets', 'carbink').learnset.spikes = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'moltres').learnset.woodhammer = ['9L1'];
|
||||
this.modData('Learnsets', 'moltres').learnset.wavecrash = ['9L1'];
|
||||
this.modData('Learnsets', 'moltres').learnset.defog = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'kommoo').learnset.aurasphere = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'illumise').learnset.quiverdance = ['9L1'];
|
||||
this.modData('Learnsets', 'illumise').learnset.thunderbolt = ['9L1'];
|
||||
this.modData('Learnsets', 'illumise').learnset.icebeam = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'volbeat').learnset.victorydance = ['9L1'];
|
||||
this.modData('Learnsets', 'volbeat').learnset.mightycleave = ['9L1'];
|
||||
this.modData('Learnsets', 'volbeat').learnset.earthquake = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'abomasnow').learnset.glaciallance = ['9L1'];
|
||||
this.modData('Learnsets', 'abomasnow').learnset.appleacid = ['9L1'];
|
||||
this.modData('Learnsets', 'abomasnow').learnset.partingshot = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'dugtrio').learnset.mightycleave = ['9L1'];
|
||||
this.modData('Learnsets', 'dugtrio').learnset.saltcure = ['9L1'];
|
||||
this.modData('Learnsets', 'dugtrio').learnset.acrobatics = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'altaria').learnset.beakblast = ['9L1'];
|
||||
this.modData('Learnsets', 'altaria').learnset.return = ['9L1'];
|
||||
this.modData('Learnsets', 'altaria').learnset.explosion = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'tyranitar').learnset.stoneaxe = ['9L1'];
|
||||
this.modData('Learnsets', 'tyranitar').learnset.ceaselessedge = ['9L1'];
|
||||
this.modData('Learnsets', 'tyranitar').learnset.kowtowcleave = ['9L1'];
|
||||
this.modData('Learnsets', 'tyranitar').learnset.pursuit = ['9L1'];
|
||||
this.modData('Learnsets', 'tyranitar').learnset.switcheroo = ['9L1'];
|
||||
this.modData('Learnsets', 'tyranitar').learnset.accelerock = ['9L1'];
|
||||
this.modData('Learnsets', 'tyranitar').learnset.dracometeor = ['9L1'];
|
||||
this.modData('Learnsets', 'tyranitar').learnset.mysticalpower = ['9L1'];
|
||||
this.modData('Learnsets', 'tyranitar').learnset.sandsearstorm = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'mimikyu').learnset.spiritshackle = ['9L1'];
|
||||
this.modData('Learnsets', 'mimikyu').learnset.uturn = ['9L1'];
|
||||
this.modData('Learnsets', 'mimikyu').learnset.obstruct = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'mesprit').learnset.agility = ['9L1'];
|
||||
this.modData('Learnsets', 'mesprit').learnset.storedpower = ['9L1'];
|
||||
this.modData('Learnsets', 'mesprit').learnset.torchsong = ['9L1'];
|
||||
this.modData('Learnsets', 'mesprit').learnset.cosmicpower = ['9L1'];
|
||||
this.modData('Learnsets', 'mesprit').learnset.aquaring = ['9L1'];
|
||||
this.modData('Learnsets', 'mesprit').learnset.freezedry = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'electrode').learnset.encore = ['9L1'];
|
||||
this.modData('Learnsets', 'electrode').learnset.rapidspin = ['9L1'];
|
||||
this.modData('Learnsets', 'electrode').learnset.explosion = ['9L1'];
|
||||
this.modData('Learnsets', 'electrode').learnset.finalgambit = ['9L1'];
|
||||
this.modData('Learnsets', 'electrode').learnset.healingwish = ['9L1'];
|
||||
this.modData('Learnsets', 'electrode').learnset.lunardance = ['9L1'];
|
||||
this.modData('Learnsets', 'electrode').learnset.memento = ['9L1'];
|
||||
this.modData('Learnsets', 'electrode').learnset.mistyexplosion = ['9L1'];
|
||||
this.modData('Learnsets', 'electrode').learnset.selfdestruct = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'taurospaldeacombat').learnset.extremespeed = ['9L1'];
|
||||
this.modData('Learnsets', 'taurospaldeacombat').learnset.uturn = ['9L1'];
|
||||
this.modData('Learnsets', 'taurospaldeacombat').learnset.knockoff = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'chiyu').learnset.splash = ['9L1'];
|
||||
this.modData('Learnsets', 'chiyu').learnset.tripledive = ['9L1'];
|
||||
this.modData('Learnsets', 'chiyu').learnset.pyroball = ['9L1'];
|
||||
this.modData('Learnsets', 'chiyu').learnset.knockoff = ['9L1'];
|
||||
this.modData('Learnsets', 'chiyu').learnset.suckerpunch = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'wochien').learnset.partingshot = ['9L1'];
|
||||
this.modData('Learnsets', 'wochien').learnset.strengthsap = ['9L1'];
|
||||
this.modData('Learnsets', 'wochien').learnset.bouncingbubble = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'staraptor').learnset.jumpkick = ['9L1'];
|
||||
this.modData('Learnsets', 'staraptor').learnset.flareblitz = ['9L1'];
|
||||
this.modData('Learnsets', 'staraptor').learnset.wavecrash = ['9L1'];
|
||||
this.modData('Learnsets', 'staraptor').learnset.headsmash = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'archaludon').learnset.scald = ['9L1'];
|
||||
this.modData('Learnsets', 'archaludon').learnset.hydropump = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'malamar').learnset.willowisp = ['9L1'];
|
||||
this.modData('Learnsets', 'malamar').learnset.recover = ['9L1'];
|
||||
this.modData('Learnsets', 'malamar').learnset.eeriespell = ['9L1'];
|
||||
this.modData('Learnsets', 'malamar').learnset.sweetkiss = ['9L1'];
|
||||
this.modData('Learnsets', 'malamar').learnset.spiritbreak = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'empoleon').learnset.nastyplot = ['9L1'];
|
||||
this.modData('Learnsets', 'empoleon').learnset.watershuriken = ['9L1'];
|
||||
this.modData('Learnsets', 'empoleon').learnset.tachyoncutter = ['9L1'];
|
||||
this.modData('Learnsets', 'empoleon').learnset.secretsword = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'regieleki').learnset.blazingtorque = ['9L1'];
|
||||
this.modData('Learnsets', 'regieleki').learnset.soak = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'lycanrocmidnight').learnset.accelerock = ['9L1'];
|
||||
this.modData('Learnsets', 'lycanrocmidnight').learnset.bonerush = ['9L1'];
|
||||
this.modData('Learnsets', 'lycanrocmidnight').learnset.stormthrow = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'lycanroc').learnset.firelash = ['9L1'];
|
||||
this.modData('Learnsets', 'lycanroc').learnset.uturn = ['9L1'];
|
||||
this.modData('Learnsets', 'lycanroc').learnset.spikes = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'lycanrocdusk').learnset.mountainmaw = ['9L1'];
|
||||
this.modData('Learnsets', 'lycanrocdusk').learnset.icefang = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'dodrio').learnset.triplearrows = ['9L1'];
|
||||
this.modData('Learnsets', 'dodrio').learnset.obstruct = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'whiscash').learnset.toxic = ['9L1'];
|
||||
this.modData('Learnsets', 'whiscash').learnset.flipturn = ['9L1'];
|
||||
this.modData('Learnsets', 'whiscash').learnset.scald = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'hippowdon').learnset.saltcure = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'cramorant').learnset.beakblast = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'grafaiai').learnset.bulkup = ['9L1'];
|
||||
this.modData('Learnsets', 'grafaiai').learnset.scavenge = ['9L1'];
|
||||
this.modData('Learnsets', 'grafaiai').learnset.drainpunch = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'kyurem').learnset.earthquake = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'roaringmoon').learnset.firelash = ['9L1'];
|
||||
this.modData('Learnsets', 'roaringmoon').learnset.glaiverush = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'milotic').learnset.bouncybubble = ['9L1'];
|
||||
this.modData('Learnsets', 'milotic').learnset.moonblast = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'gogoat').learnset.headsmash = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'clodsire').learnset.barbbarrage = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'masquerain').learnset.roost = ['9L1'];
|
||||
this.modData('Learnsets', 'masquerain').learnset.darkpulse = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'kyuremblack').learnset.icehammer = ['9L1'];
|
||||
this.modData('Learnsets', 'kyuremblack').learnset.dragonhammer = ['9L1'];
|
||||
this.modData('Learnsets', 'kyuremblack').learnset.roost = ['9L1'];
|
||||
this.modData('Learnsets', 'kyuremblack').learnset.earthquake = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'ironthorns').learnset.ironstrike = ['9L1'];
|
||||
this.modData('Learnsets', 'ironthorns').learnset.knockoff = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'chienpao').learnset.bulkup = ['9L1'];
|
||||
this.modData('Learnsets', 'chienpao').learnset.iciclestorm = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'pelipper').learnset.bleakwindstorm = ['9L1'];
|
||||
this.modData('Learnsets', 'pelipper').learnset.sandsearstorm = ['9L1'];
|
||||
this.modData('Learnsets', 'pelipper').learnset.wildboltstorm = ['9L1'];
|
||||
this.modData('Learnsets', 'pelipper').learnset.springtidestorm = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'araquanid').learnset.surgingstrikes = ['9L1'];
|
||||
this.modData('Learnsets', 'araquanid').learnset.flipturn = ['9L1'];
|
||||
this.modData('Learnsets', 'araquanid').learnset.silktrap = ['9L1'];
|
||||
this.modData('Learnsets', 'araquanid').learnset.firstimpression = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'avalugghisui').learnset.mountainmaw = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'swalot').learnset.earthpower = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'zapdosgalar').learnset.wildcharge = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'phione').learnset.workup = ['9L1'];
|
||||
this.modData('Learnsets', 'phione').learnset.tidalsurge = ['9L1'];
|
||||
this.modData('Learnsets', 'phione').learnset.geyser = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'sudowoodo').learnset.bonsaibounce = ['9L1'];
|
||||
this.modData('Learnsets', 'sudowoodo').learnset.synthesis = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'dondozo').learnset.hornleech = ['9L1'];
|
||||
this.modData('Learnsets', 'dondozo').learnset.fishiousrend = ['9L1'];
|
||||
this.modData('Learnsets', 'dondozo').learnset.recover = ['9L1'];
|
||||
this.modData('Learnsets', 'dondozo').learnset.flipturn = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'golurk').learnset.shatteredseal = ['9L1'];
|
||||
this.modData('Learnsets', 'golurk').learnset.trickroom = ['9L1'];
|
||||
this.modData('Learnsets', 'golurk').learnset.headlongrush = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'meowscarada').learnset.encore = ['9L1'];
|
||||
this.modData('Learnsets', 'meowscarada').learnset.spectralthief = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'infernape').learnset.alloutassault = ['9L1'];
|
||||
this.modData('Learnsets', 'infernape').learnset.mindblown = ['9L1'];
|
||||
this.modData('Learnsets', 'infernape').learnset.bitterblade = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'salamence').learnset.uturn = ['9L1'];
|
||||
this.modData('Learnsets', 'salamence').learnset.dragonascent = ['9L1'];
|
||||
this.modData('Learnsets', 'salamence').learnset.bloodmoon = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'urshifu').learnset.agility = ['9L1'];
|
||||
this.modData('Learnsets', 'urshifu').learnset.aquajet = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'urshifurapidstrike').learnset.agility = ['9L1'];
|
||||
this.modData('Learnsets', 'urshifurapidstrike').learnset.suckerpunch = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'stonjourner').learnset.rockwrecker = ['9L1'];
|
||||
this.modData('Learnsets', 'stonjourner').learnset.meteorassault = ['9L1'];
|
||||
this.modData('Learnsets', 'stonjourner').learnset.skyattack = ['9L1'];
|
||||
this.modData('Learnsets', 'stonjourner').learnset.solarblade = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'veluza').learnset.ragefist = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'ogerpon').learnset.leafblade = ['9L1'];
|
||||
this.modData('Learnsets', 'ogerpon').learnset.crabhammer = ['9L1'];
|
||||
this.modData('Learnsets', 'ogerpon').learnset.stoneedge = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'dachsbun').learnset.nuzzle = ['9L1'];
|
||||
this.modData('Learnsets', 'dachsbun').learnset.spiritbreak = ['9L1'];
|
||||
this.modData('Learnsets', 'dachsbun').learnset.morningsun = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'magneton').learnset.magnetbomb = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'delibird').learnset.iciclestorm = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'hitmontop').learnset.bulletseed = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'articunogalar').learnset.aeroblast = ['9L1'];
|
||||
this.modData('Learnsets', 'articunogalar').learnset.oblivionwing = ['9L1'];
|
||||
this.modData('Learnsets', 'articunogalar').learnset.aurasphere = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'vaporeon').learnset.voltswitch = ['9L1'];
|
||||
this.modData('Learnsets', 'vaporeon').learnset.burnout = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'garganacl').learnset.thunderwave = ['9L1'];
|
||||
this.modData('Learnsets', 'garganacl').learnset.saltcurse = ['9L1'];
|
||||
this.modData('Learnsets', 'garganacl').learnset.purify = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'swanna').learnset.bleakwindstorm = ['9L1'];
|
||||
this.modData('Learnsets', 'swanna').learnset.steameruption = ['9L1'];
|
||||
this.modData('Learnsets', 'swanna').learnset.flyby = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'typhlosion').learnset.heatsink = ['9L1'];
|
||||
this.modData('Learnsets', 'typhlosion').learnset.steameruption = ['9L1'];
|
||||
this.modData('Learnsets', 'typhlosion').learnset.matchagotcha = ['9L1'];
|
||||
this.modData('Learnsets', 'typhlosion').learnset.calmmind = ['9L1'];
|
||||
this.modData('Learnsets', 'typhlosion').learnset.morningsun = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'terapagos').learnset.nastyplot = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'tatsugiri').learnset.switcheroo = ['9L1'];
|
||||
this.modData('Learnsets', 'tatsugiri').learnset.sashimishuffle = ['9L1'];
|
||||
this.modData('Learnsets', 'tatsugiri').learnset.twister = ['9L1'];
|
||||
this.modData('Learnsets', 'tatsugiri').learnset.waterspout = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'flapple').learnset.earthquake = ['9L1'];
|
||||
this.modData('Learnsets', 'flapple').learnset.grabapple = ['9L1'];
|
||||
this.modData('Learnsets', 'flapple').learnset.flareblitz = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'genesect').learnset.earthquake = ['9L1'];
|
||||
this.modData('Learnsets', 'genesect').learnset.sunsteelstrike = ['9L1'];
|
||||
this.modData('Learnsets', 'genesect').learnset.behemothblade = ['9L1'];
|
||||
this.modData('Learnsets', 'genesect').learnset.makeitrain = ['9L1'];
|
||||
this.modData('Learnsets', 'genesect').learnset.tachyoncutter = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'honchkrow').learnset.crowverload = ['9L1'];
|
||||
this.modData('Learnsets', 'honchkrow').learnset.oblivionwing = ['9L1'];
|
||||
this.modData('Learnsets', 'honchkrow').learnset.closecombat = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'primeape').learnset.knockoff = ['9L1'];
|
||||
this.modData('Learnsets', 'primeape').learnset.ironhead = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'rillaboom').learnset.naturesfury = ['9L1'];
|
||||
this.modData('Learnsets', 'rillaboom').learnset.landswrath = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'mandibuzz').learnset.fling = ['9L1'];
|
||||
this.modData('Learnsets', 'mandibuzz').learnset.scavenge = ['9L1'];
|
||||
this.modData('Learnsets', 'mandibuzz').learnset.bonemerang = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'feraligatr').learnset.firefang = ['9L1'];
|
||||
this.modData('Learnsets', 'feraligatr').learnset.thunderfang = ['9L1'];
|
||||
this.modData('Learnsets', 'feraligatr').learnset.poisonfang = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'salazzle').learnset.magmastorm = ['9L1'];
|
||||
this.modData('Learnsets', 'salazzle').learnset.malignantchain = ['9L1'];
|
||||
this.modData('Learnsets', 'salazzle').learnset.psychicnoise = ['9L1'];
|
||||
this.modData('Learnsets', 'salazzle').learnset.banefulbunker = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'kyogre').learnset.hurricane = ['9L1'];
|
||||
this.modData('Learnsets', 'kyogre').learnset.tidalsurge = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'azelf').learnset.rapidspin = ['9L1'];
|
||||
this.modData('Learnsets', 'azelf').learnset.lootbox = ['9L1'];
|
||||
this.modData('Learnsets', 'azelf').learnset.acupressure = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'decidueye').learnset.sinisterarrows = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'ogerpon').learnset.sappyseed = ['9L1'];
|
||||
this.modData('Learnsets', 'ogerpon').learnset.thousandwaves = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'glimmora').learnset.icebeam = ['9L1'];
|
||||
this.modData('Learnsets', 'glimmora').learnset.malignantchain = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'wobbuffet').learnset.nightshade = ['9L1'];
|
||||
this.modData('Learnsets', 'wobbuffet').learnset.guillotine = ['9L1'];
|
||||
this.modData('Learnsets', 'wobbuffet').learnset.shedtail = ['9L1'];
|
||||
|
||||
this.modData('Learnsets', 'raticate').learnset.lastbreakfast = ['9L1'];
|
||||
},
|
||||
};
|
||||
|
|
@ -15,10 +15,8 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
move.hit = 0;
|
||||
}
|
||||
|
||||
if (!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) {
|
||||
if (!target.runImmunity(move.type, !suppressMessages)) {
|
||||
return false;
|
||||
}
|
||||
if (!target.runImmunity(move, !suppressMessages)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (move.ohko) return target.maxhp;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ There were only 151 Pokémon plus MissingNo, just a handful of moves, no abiliti
|
|||
EVd to the max and we had some kind of different IVs, which maxed at 15 and every point gave 2 to the stat, so in
|
||||
a similar fashion, Pokes used to have 30 IVs on each stat.
|
||||
|
||||
The following sources have been used and extremly useful when developing this mod:
|
||||
The following sources have been used and extremely useful when developing this mod:
|
||||
https://raw.github.com/po-devs/pokemon-online/master/bin/database/rby-stuff.txt
|
||||
https://www.smogon.com/rb/articles/differences
|
||||
https://www.smogon.com/forums/threads/past-gens-research-thread.3506992/#post-5878612
|
||||
|
|
|
|||
|
|
@ -80,6 +80,9 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
onAfterMoveSelf(pokemon) {
|
||||
if (pokemon.statusState.time <= 0) pokemon.cureStatus();
|
||||
},
|
||||
onDisableMove(target) {
|
||||
target.maybeLocked = false; // the player knows it is locked
|
||||
},
|
||||
},
|
||||
frz: {
|
||||
name: 'frz',
|
||||
|
|
@ -98,6 +101,9 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
target.cureStatus();
|
||||
}
|
||||
},
|
||||
onDisableMove(target) {
|
||||
target.maybeLocked = false; // the player knows it is locked
|
||||
},
|
||||
},
|
||||
psn: {
|
||||
name: 'psn',
|
||||
|
|
@ -185,30 +191,85 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
},
|
||||
partiallytrapped: {
|
||||
name: 'partiallytrapped',
|
||||
// this is the duration of Wrap if it doesn't continue.
|
||||
// (i.e. if the attacker switches out.)
|
||||
// the full duration is tracked in partialtrappinglock
|
||||
duration: 2,
|
||||
// defender still takes PSN damage, etc
|
||||
// TODO: research exact mechanics
|
||||
onBeforeMovePriority: 9,
|
||||
onBeforeMove(pokemon) {
|
||||
this.add('cant', pokemon, 'partiallytrapped');
|
||||
return false;
|
||||
},
|
||||
onRestart() {
|
||||
this.effectState.duration = 2;
|
||||
},
|
||||
onAccuracy(accuracy, target, source, move) {
|
||||
if (source === this.effectState.source) return true;
|
||||
},
|
||||
onDisableMovePriority: 1, // higher priority so it gets undone by frz, slp or Bide
|
||||
onDisableMove(target) {
|
||||
if (this.effectState.maybeLocked) {
|
||||
target.maybeLocked = true;
|
||||
}
|
||||
},
|
||||
},
|
||||
fakepartiallytrapped: {
|
||||
name: 'fakepartiallytrapped',
|
||||
// Wrap ended this turn, but you don't know that
|
||||
// until you try to use an attack
|
||||
duration: 2,
|
||||
onDisableMovePriority: 1, // higher priority so it gets undone by frz, slp or Bide
|
||||
onDisableMove(target) {
|
||||
target.maybeLocked = true;
|
||||
},
|
||||
},
|
||||
partialtrappinglock: {
|
||||
name: 'partialtrappinglock',
|
||||
durationCallback() {
|
||||
const duration = this.sample([2, 2, 2, 3, 3, 3, 4, 5]);
|
||||
return duration;
|
||||
return this.sample([2, 2, 2, 3, 3, 3, 4, 5]);
|
||||
},
|
||||
onStart(target, source, effect) {
|
||||
const foe = target.foes()[0];
|
||||
if (!foe) return false;
|
||||
|
||||
this.effectState.move = effect.id;
|
||||
this.effectState.totalDuration = this.effectState.duration!;
|
||||
this.effectState.damage = this.lastDamage;
|
||||
this.effectState.locked = foe;
|
||||
foe.addVolatile('partiallytrapped', target, effect);
|
||||
},
|
||||
onDisableMove(pokemon) {
|
||||
if (!pokemon.hasMove(this.effectState.move)) {
|
||||
onBeforeMove(pokemon, target, move) {
|
||||
if (target !== this.effectState.locked) {
|
||||
pokemon.removeVolatile('partialtrappinglock');
|
||||
}
|
||||
},
|
||||
onAfterMove(pokemon, target, move) {
|
||||
if (target && target.hp <= 0) {
|
||||
delete pokemon.volatiles['partialtrappinglock'];
|
||||
return;
|
||||
}
|
||||
for (const moveSlot of pokemon.moveSlots) {
|
||||
if (moveSlot.id !== this.effectState.move) {
|
||||
pokemon.disableMove(moveSlot.id);
|
||||
if (this.effectState.duration === 1) {
|
||||
if (this.effectState.totalDuration !== 5) {
|
||||
pokemon.addVolatile('fakepartiallytrapped');
|
||||
pokemon.volatiles['fakepartiallytrapped'].counterpart = target;
|
||||
target.addVolatile('fakepartiallytrapped');
|
||||
target.volatiles['fakepartiallytrapped'].counterpart = pokemon;
|
||||
}
|
||||
} else {
|
||||
target.addVolatile('partiallytrapped', pokemon, move);
|
||||
if (this.effectState.totalDuration - this.effectState.duration! > 0) {
|
||||
target.volatiles['partiallytrapped'].maybeLocked = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
onSemiLockMove() {
|
||||
return this.effectState.move;
|
||||
},
|
||||
onDisableMove(pokemon) {
|
||||
if (this.effectState.totalDuration - this.effectState.duration! > 1) {
|
||||
pokemon.maybeLocked = true;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
@ -216,7 +277,14 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
inherit: true,
|
||||
duration: 0,
|
||||
onBeforeMovePriority: 7,
|
||||
onStart() {},
|
||||
onStart: undefined, // no inherit
|
||||
onAfterMove(pokemon, target, move) {
|
||||
if (target && target.hp <= 0) {
|
||||
delete pokemon.volatiles['mustrecharge'];
|
||||
return;
|
||||
}
|
||||
this.add('-mustrecharge', pokemon);
|
||||
},
|
||||
},
|
||||
lockedmove: {
|
||||
// Thrash and Petal Dance.
|
||||
|
|
@ -236,6 +304,11 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
this.queue.changeAction(pokemon, { choice: 'move', moveid: move.id });
|
||||
}
|
||||
},
|
||||
onAfterMove(pokemon) {
|
||||
if (pokemon.volatiles['lockedmove'].time <= 0) {
|
||||
pokemon.removeVolatile('lockedmove');
|
||||
}
|
||||
},
|
||||
},
|
||||
twoturnmove: {
|
||||
// Skull Bash, Solar Beam, ...
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
wartortle: {
|
||||
tier: "ZU",
|
||||
tier: "NFE",
|
||||
},
|
||||
blastoise: {
|
||||
tier: "NU",
|
||||
|
|
@ -51,7 +51,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
pidgeot: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
rattata: {
|
||||
tier: "LC",
|
||||
|
|
@ -90,7 +90,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
nidoqueen: {
|
||||
tier: "PU",
|
||||
tier: "ZU",
|
||||
},
|
||||
nidoranm: {
|
||||
tier: "LC",
|
||||
|
|
@ -117,7 +117,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
wigglytuff: {
|
||||
tier: "PU",
|
||||
tier: "ZU",
|
||||
},
|
||||
zubat: {
|
||||
tier: "LC",
|
||||
|
|
@ -132,7 +132,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
vileplume: {
|
||||
tier: "PU",
|
||||
tier: "ZU",
|
||||
},
|
||||
paras: {
|
||||
tier: "LC",
|
||||
|
|
@ -168,7 +168,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
primeape: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
growlithe: {
|
||||
tier: "LC",
|
||||
|
|
@ -189,7 +189,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "PU",
|
||||
},
|
||||
kadabra: {
|
||||
tier: "UU",
|
||||
tier: "NU",
|
||||
},
|
||||
alakazam: {
|
||||
tier: "OU",
|
||||
|
|
@ -201,7 +201,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
machamp: {
|
||||
tier: "PU",
|
||||
tier: "ZU",
|
||||
},
|
||||
bellsprout: {
|
||||
tier: "LC",
|
||||
|
|
@ -210,13 +210,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
victreebel: {
|
||||
tier: "OU",
|
||||
tier: "NU",
|
||||
},
|
||||
tentacool: {
|
||||
tier: "ZU",
|
||||
},
|
||||
tentacruel: {
|
||||
tier: "UU",
|
||||
tier: "NU",
|
||||
},
|
||||
geodude: {
|
||||
tier: "LC",
|
||||
|
|
@ -225,19 +225,19 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "PU",
|
||||
},
|
||||
golem: {
|
||||
tier: "UU",
|
||||
tier: "NU",
|
||||
},
|
||||
ponyta: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
rapidash: {
|
||||
tier: "PU",
|
||||
tier: "UU",
|
||||
},
|
||||
slowpoke: {
|
||||
tier: "ZU",
|
||||
},
|
||||
slowbro: {
|
||||
tier: "OU",
|
||||
tier: "UU",
|
||||
},
|
||||
magnemite: {
|
||||
tier: "LC",
|
||||
|
|
@ -258,7 +258,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
dewgong: {
|
||||
tier: "UU",
|
||||
tier: "NU",
|
||||
},
|
||||
grimer: {
|
||||
tier: "LC",
|
||||
|
|
@ -288,19 +288,19 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "ZU",
|
||||
},
|
||||
hypno: {
|
||||
tier: "UUBL",
|
||||
tier: "UU",
|
||||
},
|
||||
krabby: {
|
||||
tier: "LC",
|
||||
},
|
||||
kingler: {
|
||||
tier: "PU",
|
||||
tier: "ZU",
|
||||
},
|
||||
voltorb: {
|
||||
tier: "LC",
|
||||
},
|
||||
electrode: {
|
||||
tier: "UU",
|
||||
tier: "NU",
|
||||
},
|
||||
exeggcute: {
|
||||
tier: "PU",
|
||||
|
|
@ -339,7 +339,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "OU",
|
||||
},
|
||||
tangela: {
|
||||
tier: "UU",
|
||||
tier: "NU",
|
||||
},
|
||||
kangaskhan: {
|
||||
tier: "UU",
|
||||
|
|
@ -366,7 +366,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NU",
|
||||
},
|
||||
scyther: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
jynx: {
|
||||
tier: "OU",
|
||||
|
|
@ -375,10 +375,10 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
magmar: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
pinsir: {
|
||||
tier: "PU",
|
||||
tier: "ZU",
|
||||
},
|
||||
tauros: {
|
||||
tier: "OU",
|
||||
|
|
@ -390,7 +390,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
lapras: {
|
||||
tier: "UUBL",
|
||||
tier: "UU",
|
||||
},
|
||||
ditto: {
|
||||
tier: "ZU",
|
||||
|
|
@ -399,7 +399,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
vaporeon: {
|
||||
tier: "UU",
|
||||
tier: "NU",
|
||||
},
|
||||
jolteon: {
|
||||
tier: "OU",
|
||||
|
|
@ -414,7 +414,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "ZU",
|
||||
},
|
||||
omastar: {
|
||||
tier: "UU",
|
||||
tier: "NU",
|
||||
},
|
||||
kabuto: {
|
||||
tier: "LC",
|
||||
|
|
@ -429,13 +429,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "OU",
|
||||
},
|
||||
articuno: {
|
||||
tier: "UUBL",
|
||||
tier: "UU",
|
||||
},
|
||||
zapdos: {
|
||||
tier: "OU",
|
||||
},
|
||||
moltres: {
|
||||
tier: "NU",
|
||||
tier: "UU",
|
||||
},
|
||||
dratini: {
|
||||
tier: "LC",
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
bide: {
|
||||
inherit: true,
|
||||
priority: 0,
|
||||
accuracy: true,
|
||||
condition: {
|
||||
onStart(pokemon) {
|
||||
|
|
@ -60,15 +59,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
this.add('-activate', pokemon, 'Bide');
|
||||
return false;
|
||||
},
|
||||
onDisableMove(pokemon) {
|
||||
if (!pokemon.hasMove('bide')) {
|
||||
return;
|
||||
}
|
||||
for (const moveSlot of pokemon.moveSlots) {
|
||||
if (moveSlot.id !== 'bide') {
|
||||
pokemon.disableMove(moveSlot.id);
|
||||
}
|
||||
}
|
||||
onSemiLockMove: 'bide',
|
||||
onDisableMove(target) {
|
||||
target.maybeLocked = false; // the player knows it is locked
|
||||
},
|
||||
},
|
||||
type: "???", // Will look as Normal but it's STAB-less
|
||||
|
|
@ -76,7 +69,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
bind: {
|
||||
inherit: true,
|
||||
ignoreImmunity: true,
|
||||
volatileStatus: 'partiallytrapped',
|
||||
self: {
|
||||
volatileStatus: 'partialtrappinglock',
|
||||
},
|
||||
|
|
@ -86,19 +78,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
this.hint("In Gen 1, partial trapping moves negate the recharge turn of Hyper Beam, even if they miss.", true);
|
||||
}
|
||||
},
|
||||
onHit(target, source) {
|
||||
/**
|
||||
* The duration of the partially trapped must be always renewed to 2
|
||||
* so target doesn't move on trapper switch out as happens in gen 1.
|
||||
* However, this won't happen if there's no switch and the trapper is
|
||||
* about to end its partial trapping.
|
||||
**/
|
||||
if (target.volatiles['partiallytrapped']) {
|
||||
if (source.volatiles['partialtrappinglock'] && source.volatiles['partialtrappinglock'].duration! > 1) {
|
||||
target.volatiles['partiallytrapped'].duration = 2;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
bite: {
|
||||
inherit: true,
|
||||
|
|
@ -137,7 +116,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
accuracy: 75,
|
||||
pp: 10,
|
||||
volatileStatus: 'partiallytrapped',
|
||||
self: {
|
||||
volatileStatus: 'partialtrappinglock',
|
||||
},
|
||||
|
|
@ -147,19 +125,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
this.hint("In Gen 1, partial trapping moves negate the recharge turn of Hyper Beam, even if they miss.", true);
|
||||
}
|
||||
},
|
||||
onHit(target, source) {
|
||||
/**
|
||||
* The duration of the partially trapped must be always renewed to 2
|
||||
* so target doesn't move on trapper switch out as happens in gen 1.
|
||||
* However, this won't happen if there's no switch and the trapper is
|
||||
* about to end its partial trapping.
|
||||
**/
|
||||
if (target.volatiles['partiallytrapped']) {
|
||||
if (source.volatiles['partialtrappinglock'] && source.volatiles['partialtrappinglock'].duration! > 1) {
|
||||
target.volatiles['partiallytrapped'].duration = 2;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
constrict: {
|
||||
inherit: true,
|
||||
|
|
@ -190,14 +155,14 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
// - if Counter is used by the opponent, it will succeed if the player's last selected move is Counterable
|
||||
// - (Counter will thus desync if the target's last used move is not as counterable as the target's last selected move)
|
||||
// - if Counter succeeds it will deal twice the last move damage dealt in battle (even if it's from a different pokemon because of a switch)
|
||||
const isCounterable = (move: Move | null) => move && move.basePower > 0 &&
|
||||
['Normal', 'Fighting'].includes(move.type) && move.id !== 'counter';
|
||||
|
||||
const lastMove = target.side.lastMove && this.dex.moves.get(target.side.lastMove.id);
|
||||
const lastMoveIsCounterable = lastMove && lastMove.basePower > 0 &&
|
||||
['Normal', 'Fighting'].includes(lastMove.type) && lastMove.id !== 'counter';
|
||||
const lastMoveIsCounterable = isCounterable(lastMove);
|
||||
|
||||
const lastSelectedMove = target.side.lastSelectedMove && this.dex.moves.get(target.side.lastSelectedMove);
|
||||
const lastSelectedMoveIsCounterable = lastSelectedMove && lastSelectedMove.basePower > 0 &&
|
||||
['Normal', 'Fighting'].includes(lastSelectedMove.type) && lastSelectedMove.id !== 'counter';
|
||||
const lastSelectedMoveIsCounterable = isCounterable(lastSelectedMove || null);
|
||||
|
||||
if (!lastMoveIsCounterable && !lastSelectedMoveIsCounterable) {
|
||||
this.debug("Gen 1 Counter: last move was not Counterable");
|
||||
|
|
@ -239,33 +204,23 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
},
|
||||
disable: {
|
||||
num: 50,
|
||||
accuracy: 55,
|
||||
basePower: 0,
|
||||
category: "Status",
|
||||
name: "Disable",
|
||||
pp: 20,
|
||||
priority: 0,
|
||||
flags: { protect: 1, mirror: 1, bypasssub: 1, metronome: 1 },
|
||||
volatileStatus: 'disable',
|
||||
inherit: true,
|
||||
onTryHit(target) {
|
||||
// This function should not return if the checks are met. Adding && undefined ensures this happens.
|
||||
return target.moveSlots.some(ms => ms.pp > 0) &&
|
||||
!('disable' in target.volatiles) &&
|
||||
undefined;
|
||||
return target.moveSlots.some(ms => ms.pp > 0);
|
||||
},
|
||||
condition: {
|
||||
inherit: true,
|
||||
durationCallback: undefined, // no inherit
|
||||
onStart(pokemon) {
|
||||
// disable can only select moves that have pp > 0, hence the onTryHit modification
|
||||
const moveSlot = this.sample(pokemon.moveSlots.filter(ms => ms.pp > 0));
|
||||
const [slotIndex, moveSlot] = this.sample(Array.from(pokemon.moveSlots.entries()).filter(([i, ms]) => ms.pp > 0));
|
||||
this.debug(`Disable: disabling move ${moveSlot.move} in slot ${slotIndex}`);
|
||||
this.add('-start', pokemon, 'Disable', moveSlot.move);
|
||||
this.effectState.move = moveSlot.id;
|
||||
this.effectState.slotIndex = slotIndex;
|
||||
// 1-8 turns (which will in effect translate to 0-7 missed turns for the target)
|
||||
this.effectState.time = this.random(1, 9);
|
||||
},
|
||||
onEnd(pokemon) {
|
||||
this.add('-end', pokemon, 'Disable');
|
||||
},
|
||||
onBeforeMovePriority: 6,
|
||||
onBeforeMove(pokemon, target, move) {
|
||||
pokemon.volatiles['disable'].time--;
|
||||
|
|
@ -281,20 +236,17 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
}
|
||||
},
|
||||
onDisableMove(pokemon) {
|
||||
for (const moveSlot of pokemon.moveSlots) {
|
||||
if (moveSlot.id === this.effectState.move) {
|
||||
pokemon.disableMove(moveSlot.id);
|
||||
}
|
||||
// disable the move slot
|
||||
if (pokemon.moveSlots.length > this.effectState.slotIndex) {
|
||||
pokemon.moveSlots[this.effectState.slotIndex].disabled = true;
|
||||
pokemon.moveSlots[this.effectState.slotIndex].disabledSource = this.effect.name;
|
||||
}
|
||||
},
|
||||
},
|
||||
secondary: null,
|
||||
target: "normal",
|
||||
type: "Normal",
|
||||
},
|
||||
dizzypunch: {
|
||||
inherit: true,
|
||||
secondary: null,
|
||||
secondary: undefined, // no inherit
|
||||
},
|
||||
doubleedge: {
|
||||
inherit: true,
|
||||
|
|
@ -320,7 +272,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
accuracy: 70,
|
||||
basePower: 15,
|
||||
volatileStatus: 'partiallytrapped',
|
||||
self: {
|
||||
volatileStatus: 'partialtrappinglock',
|
||||
},
|
||||
|
|
@ -330,19 +281,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
this.hint("In Gen 1, partial trapping moves negate the recharge turn of Hyper Beam, even if they miss.", true);
|
||||
}
|
||||
},
|
||||
onHit(target, source) {
|
||||
/**
|
||||
* The duration of the partially trapped must be always renewed to 2
|
||||
* so target doesn't move on trapper switch out as happens in gen 1.
|
||||
* However, this won't happen if there's no switch and the trapper is
|
||||
* about to end its partial trapping.
|
||||
**/
|
||||
if (target.volatiles['partiallytrapped']) {
|
||||
if (source.volatiles['partialtrappinglock'] && source.volatiles['partialtrappinglock'].duration! > 1) {
|
||||
target.volatiles['partiallytrapped'].duration = 2;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
fly: {
|
||||
inherit: true,
|
||||
|
|
@ -361,11 +299,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
focusenergy: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
onStart(pokemon) {
|
||||
this.add('-start', pokemon, 'move: Focus Energy');
|
||||
},
|
||||
inherit: true,
|
||||
// This does nothing as it's dealt with on critical hit calculation.
|
||||
onModifyMove() {},
|
||||
onModifyCritRatio: undefined, // no inherit
|
||||
},
|
||||
},
|
||||
glare: {
|
||||
|
|
@ -391,6 +327,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
for (const pokemon of this.getAllActive()) {
|
||||
pokemon.clearBoosts();
|
||||
if (pokemon !== source) {
|
||||
if (['frz', 'slp'].includes(pokemon.status)) {
|
||||
pokemon.side.lastSelectedMove = 'cannotmove' as ID;
|
||||
if (this.queue.willMove(pokemon)) {
|
||||
this.queue.changeAction(pokemon, { choice: 'move', pokemon, moveid: 'cannotmove' });
|
||||
}
|
||||
}
|
||||
pokemon.cureStatus(true);
|
||||
}
|
||||
if (pokemon.status === 'tox') {
|
||||
|
|
@ -448,11 +390,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
leechseed: {
|
||||
inherit: true,
|
||||
onHit() {},
|
||||
onHit: undefined, // no inherit
|
||||
condition: {
|
||||
onStart(target) {
|
||||
this.add('-start', target, 'move: Leech Seed');
|
||||
},
|
||||
inherit: true,
|
||||
onAfterMoveSelfPriority: 1,
|
||||
onAfterMoveSelf(pokemon) {
|
||||
const leecher = this.getAtSlot(pokemon.volatiles['leechseed'].sourceSlot);
|
||||
|
|
@ -478,15 +418,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
},
|
||||
lightscreen: {
|
||||
num: 113,
|
||||
accuracy: true,
|
||||
basePower: 0,
|
||||
category: "Status",
|
||||
name: "Light Screen",
|
||||
pp: 30,
|
||||
priority: 0,
|
||||
flags: { metronome: 1 },
|
||||
inherit: true,
|
||||
volatileStatus: 'lightscreen',
|
||||
sideCondition: undefined, // no inherit
|
||||
onTryHit(pokemon) {
|
||||
if (pokemon.volatiles['lightscreen']) {
|
||||
return false;
|
||||
|
|
@ -498,14 +432,28 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
},
|
||||
target: "self",
|
||||
type: "Psychic",
|
||||
},
|
||||
metronome: {
|
||||
inherit: true,
|
||||
onHit(pokemon) {
|
||||
const moves = this.dex.moves.all().filter(move => (
|
||||
(!move.isNonstandard || move.isNonstandard === 'Unobtainable') && move.flags['metronome']
|
||||
));
|
||||
let randomMove = '';
|
||||
if (moves.length) {
|
||||
moves.sort((a, b) => a.num - b.num);
|
||||
randomMove = this.sample(moves).id;
|
||||
}
|
||||
if (!randomMove) return false;
|
||||
pokemon.side.lastSelectedMove = this.toID(randomMove);
|
||||
this.actions.useMove(randomMove, pokemon);
|
||||
},
|
||||
},
|
||||
mimic: {
|
||||
inherit: true,
|
||||
flags: { protect: 1, bypasssub: 1, metronome: 1 },
|
||||
onHit(target, source) {
|
||||
const moveslot = source.moves.indexOf('mimic');
|
||||
if (moveslot < 0) return false;
|
||||
const moveslot = source.side.lastSelectedMoveSlot;
|
||||
const moves = target.moves;
|
||||
const moveid = this.sample(moves);
|
||||
if (!moveid) return false;
|
||||
|
|
@ -514,7 +462,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
move: move.name,
|
||||
id: move.id,
|
||||
pp: source.moveSlots[moveslot].pp,
|
||||
maxpp: move.pp * 8 / 5,
|
||||
maxpp: this.calculatePP(move, source.ppUps[moveslot] || 0),
|
||||
target: move.target,
|
||||
disabled: false,
|
||||
used: false,
|
||||
|
|
@ -523,6 +471,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
this.add('-start', source, 'Mimic', move.name);
|
||||
},
|
||||
},
|
||||
minimize: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
inherit: true,
|
||||
onSourceModifyDamage: undefined, // no inherit
|
||||
},
|
||||
},
|
||||
mirrormove: {
|
||||
inherit: true,
|
||||
onHit(pokemon) {
|
||||
|
|
@ -537,9 +492,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
mist: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
onStart(pokemon) {
|
||||
this.add('-start', pokemon, 'Mist');
|
||||
},
|
||||
inherit: true,
|
||||
onTryBoost(boost, target, source, effect) {
|
||||
if (effect.effectType === 'Move' && effect.category !== 'Status') return;
|
||||
if (source && target !== source) {
|
||||
|
|
@ -565,7 +518,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
petaldance: {
|
||||
inherit: true,
|
||||
onMoveFail() {},
|
||||
onMoveFail: undefined, // no inherit
|
||||
},
|
||||
poisonsting: {
|
||||
inherit: true,
|
||||
|
|
@ -588,9 +541,15 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
basePower: 1,
|
||||
damageCallback(pokemon) {
|
||||
if ([0, 1, 171].includes(pokemon.level)) {
|
||||
this.hint("Desync Clause Mod activated!");
|
||||
this.hint("In Gen 1, if a Pokémon at level 0, 1 or 171 uses Psywave, the game softlocks.");
|
||||
return false;
|
||||
}
|
||||
const psywaveDamage = (this.random(0, this.trunc(1.5 * pokemon.level)));
|
||||
if (psywaveDamage <= 0) {
|
||||
this.hint("Desync Clause Mod activated!");
|
||||
this.hint("In Gen 1, Psywave can roll 0 damage.");
|
||||
return false;
|
||||
}
|
||||
return psywaveDamage;
|
||||
|
|
@ -637,7 +596,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
recover: {
|
||||
inherit: true,
|
||||
heal: null,
|
||||
heal: undefined, // no inherit
|
||||
onHit(target) {
|
||||
if (target.hp === target.maxhp) return false;
|
||||
// Fail when health is 255 or 511 less than max, unless it is divisible by 256
|
||||
|
|
@ -655,15 +614,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
},
|
||||
reflect: {
|
||||
num: 115,
|
||||
accuracy: true,
|
||||
basePower: 0,
|
||||
category: "Status",
|
||||
name: "Reflect",
|
||||
pp: 20,
|
||||
priority: 0,
|
||||
flags: { metronome: 1 },
|
||||
inherit: true,
|
||||
volatileStatus: 'reflect',
|
||||
sideCondition: undefined, // no inherit
|
||||
onTryHit(pokemon) {
|
||||
if (pokemon.volatiles['reflect']) {
|
||||
return false;
|
||||
|
|
@ -674,13 +627,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
this.add('-start', pokemon, 'Reflect');
|
||||
},
|
||||
},
|
||||
secondary: null,
|
||||
target: "self",
|
||||
type: "Psychic",
|
||||
},
|
||||
rest: {
|
||||
inherit: true,
|
||||
onTry() {},
|
||||
onTry: undefined, // no inherit
|
||||
onHit(target, source, move) {
|
||||
if (target.hp === target.maxhp) return false;
|
||||
// Fail when health is 255 or 511 less than max, unless it is divisible by 256
|
||||
|
|
@ -703,12 +654,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
roar: {
|
||||
inherit: true,
|
||||
forceSwitch: false,
|
||||
onTryHit() {},
|
||||
onTryHit: undefined, // no inherit
|
||||
priority: 0,
|
||||
},
|
||||
rockslide: {
|
||||
inherit: true,
|
||||
secondary: null,
|
||||
secondary: undefined, // no inherit
|
||||
target: "normal",
|
||||
},
|
||||
rockthrow: {
|
||||
|
|
@ -784,7 +735,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
softboiled: {
|
||||
inherit: true,
|
||||
heal: null,
|
||||
heal: undefined, // no inherit
|
||||
onHit(target) {
|
||||
if (target.hp === target.maxhp) return false;
|
||||
// Fail when health is 255 or 511 less than max, unless it is divisible by 256
|
||||
|
|
@ -805,18 +756,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
pp: 10,
|
||||
recoil: [1, 2],
|
||||
onModifyMove() {},
|
||||
onModifyMove: undefined, // no inherit
|
||||
},
|
||||
substitute: {
|
||||
num: 164,
|
||||
accuracy: true,
|
||||
basePower: 0,
|
||||
category: "Status",
|
||||
name: "Substitute",
|
||||
pp: 10,
|
||||
priority: 0,
|
||||
flags: { metronome: 1 },
|
||||
volatileStatus: 'substitute',
|
||||
inherit: true,
|
||||
onTryHit(target) {
|
||||
if (target.volatiles['substitute']) {
|
||||
this.add('-fail', target, 'move: Substitute');
|
||||
|
|
@ -836,11 +779,16 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
}
|
||||
},
|
||||
condition: {
|
||||
inherit: true,
|
||||
onStart(target) {
|
||||
this.add('-start', target, 'Substitute');
|
||||
this.effectState.hp = Math.floor(target.maxhp / 4) + 1;
|
||||
delete target.volatiles['partiallytrapped'];
|
||||
if (target.volatiles['partiallytrapped']) {
|
||||
this.add('-end', target, target.volatiles['partiallytrapped'].sourceEffect, '[partiallytrapped]', '[silent]');
|
||||
delete target.volatiles['partiallytrapped'];
|
||||
}
|
||||
},
|
||||
onTryPrimaryHit: undefined, // no inherit
|
||||
onTryHitPriority: -1,
|
||||
onTryHit(target, source, move) {
|
||||
if (move.category === 'Status') {
|
||||
|
|
@ -862,8 +810,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
let uncappedDamage = move.hit > 1 ? this.lastDamage : this.actions.getDamage(source, target, move);
|
||||
if (move.id === 'bide') uncappedDamage = source.volatiles['bide'].damage * 2;
|
||||
if (!uncappedDamage && uncappedDamage !== 0) return null;
|
||||
uncappedDamage = this.runEvent('SubDamage', target, source, move, uncappedDamage);
|
||||
if (!uncappedDamage && uncappedDamage !== 0) return uncappedDamage;
|
||||
this.lastDamage = uncappedDamage;
|
||||
target.volatiles['substitute'].hp -= uncappedDamage > target.volatiles['substitute'].hp ?
|
||||
target.volatiles['substitute'].hp : uncappedDamage;
|
||||
|
|
@ -906,13 +852,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
}
|
||||
return 0;
|
||||
},
|
||||
onEnd(target) {
|
||||
this.add('-end', target, 'Substitute');
|
||||
},
|
||||
},
|
||||
secondary: null,
|
||||
target: "self",
|
||||
type: "Normal",
|
||||
},
|
||||
superfang: {
|
||||
inherit: true,
|
||||
|
|
@ -921,7 +861,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
thrash: {
|
||||
inherit: true,
|
||||
onMoveFail() {},
|
||||
onMoveFail: undefined, // no inherit
|
||||
},
|
||||
thunder: {
|
||||
inherit: true,
|
||||
|
|
@ -932,14 +872,14 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
triattack: {
|
||||
inherit: true,
|
||||
onHit() {},
|
||||
secondary: null,
|
||||
onHit: undefined, // no inherit
|
||||
secondary: undefined, // no inherit
|
||||
},
|
||||
whirlwind: {
|
||||
inherit: true,
|
||||
accuracy: 85,
|
||||
forceSwitch: false,
|
||||
onTryHit() {},
|
||||
onTryHit: undefined, // no inherit
|
||||
priority: 0,
|
||||
},
|
||||
wingattack: {
|
||||
|
|
@ -950,7 +890,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
accuracy: 85,
|
||||
ignoreImmunity: true,
|
||||
volatileStatus: 'partiallytrapped',
|
||||
self: {
|
||||
volatileStatus: 'partialtrappinglock',
|
||||
},
|
||||
|
|
@ -960,18 +899,5 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
this.hint("In Gen 1, partial trapping moves negate the recharge turn of Hyper Beam, even if they miss.", true);
|
||||
}
|
||||
},
|
||||
onHit(target, source) {
|
||||
/**
|
||||
* The duration of the partially trapped must be always renewed to 2
|
||||
* so target doesn't move on trapper switch out as happens in gen 1.
|
||||
* However, this won't happen if there's no switch and the trapper is
|
||||
* about to end its partial trapping.
|
||||
**/
|
||||
if (target.volatiles['partiallytrapped']) {
|
||||
if (source.volatiles['partialtrappinglock'] && source.volatiles['partialtrappinglock'].duration! > 1) {
|
||||
target.volatiles['partiallytrapped'].duration = 2;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,8 +1,17 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
standardag: {
|
||||
inherit: true,
|
||||
ruleset: [
|
||||
'Obtainable', 'Desync Clause Mod', 'HP Percentage Mod', 'Cancel Mod', 'Endless Battle Clause',
|
||||
],
|
||||
},
|
||||
standard: {
|
||||
effectType: 'ValidatorRule',
|
||||
name: 'Standard',
|
||||
ruleset: ['Obtainable', 'Desync Clause Mod', 'Sleep Clause Mod', 'Freeze Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod'],
|
||||
ruleset: [
|
||||
'Standard AG',
|
||||
'Sleep Clause Mod', 'Freeze Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause',
|
||||
],
|
||||
banlist: ['Dig', 'Fly'],
|
||||
},
|
||||
'350cupmod': {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,27 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
// BattlePokemon scripts.
|
||||
pokemon: {
|
||||
inherit: true,
|
||||
deductPP(move, amount) {
|
||||
// deduct PP based on side.lastSelectedMoveSlot
|
||||
const ppData = this.getMoveSlot(this.side.lastSelectedMoveSlot);
|
||||
if (!ppData) return 0;
|
||||
ppData.used = true;
|
||||
|
||||
if (!amount) amount = 1;
|
||||
ppData.pp -= amount;
|
||||
|
||||
if (ppData.pp < 0) {
|
||||
this.battle.hint("In Gen 1, if a Pokémon is forced to use a move with 0 PP, the move will underflow to have 63 PP.");
|
||||
}
|
||||
ppData.pp = ((ppData.pp % 64) + 64) % 64;
|
||||
|
||||
if (ppData.virtual && !this.transformed) {
|
||||
// sync PP from Mimic's slot, or Metronome/Mirror Move that called Mimic
|
||||
this.baseMoveSlots[this.side.lastSelectedMoveSlot].pp = ppData.pp;
|
||||
}
|
||||
|
||||
return amount;
|
||||
},
|
||||
getStat(statName, unmodified) {
|
||||
// @ts-expect-error type checking prevents 'hp' from being passed, but we're paranoid
|
||||
if (statName === 'hp') throw new Error("Please read `maxhp` directly");
|
||||
|
|
@ -129,16 +150,37 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
let sourceEffect = options?.sourceEffect;
|
||||
const target = this.battle.getTarget(pokemon, moveOrMoveName, targetLoc);
|
||||
let move = this.battle.dex.getActiveMove(moveOrMoveName);
|
||||
if (move.id !== 'struggle') {
|
||||
const changedMove = this.battle.runEvent('OverrideAction', pokemon, target, move);
|
||||
if (changedMove && changedMove !== true) {
|
||||
move = this.battle.dex.getActiveMove(changedMove);
|
||||
}
|
||||
}
|
||||
|
||||
// If a faster partial trapping move misses against a user of Hyper Beam during a recharge turn,
|
||||
// the user of Hyper Beam will automatically use Hyper Beam during that turn.
|
||||
const autoHyperBeam = (
|
||||
move.id === 'recharge' && !pokemon.volatiles['mustrecharge'] && !pokemon.volatiles['partiallytrapped']
|
||||
);
|
||||
if (autoHyperBeam) {
|
||||
move = this.battle.dex.getActiveMove('hyperbeam');
|
||||
this.battle.hint(`In Gen 1, If a faster partial trapping move misses against a user of Hyper Beam during a recharge turn, ` +
|
||||
`the user of Hyper Beam will automatically use Hyper Beam during that turn.`, true);
|
||||
const abortMove = () => {
|
||||
this.battle.clearActiveMove(true);
|
||||
this.battle.runEvent('AfterMoveSelf', pokemon, target, move);
|
||||
};
|
||||
|
||||
if (move.id === 'cannotmove') {
|
||||
if (pokemon.status === 'slp') {
|
||||
this.battle.hint(
|
||||
"In Gen 1, if a Pokémon spends a turn partially trapped and switches to a Pokémon that is asleep, " +
|
||||
"the sleep counter will not decrease until you select a move with a different Pokémon."
|
||||
);
|
||||
} else if (pokemon.getLockedMove()) {
|
||||
this.battle.hint(
|
||||
"In Gen 1, when Haze cures the sleep/freeze status of a Pokémon during a multi-turn move, " +
|
||||
"that Pokémon will become soft-locked."
|
||||
);
|
||||
} else if (pokemon.getSemiLockedMove()) {
|
||||
this.battle.hint(
|
||||
"In Gen 1, when Haze cures the sleep/freeze status of a Pokémon during Bide, " +
|
||||
"the move execution will never resolve."
|
||||
);
|
||||
}
|
||||
abortMove();
|
||||
return;
|
||||
}
|
||||
|
||||
if (target?.subFainted) target.subFainted = null;
|
||||
|
|
@ -146,47 +188,36 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
this.battle.setActiveMove(move, pokemon, target);
|
||||
|
||||
if (pokemon.moveThisTurn || !this.battle.runEvent('BeforeMove', pokemon, target, move)) {
|
||||
this.battle.clearActiveMove(true);
|
||||
// This is only run for sleep.
|
||||
this.battle.runEvent('AfterMoveSelf', pokemon, target, move);
|
||||
abortMove();
|
||||
return;
|
||||
}
|
||||
if (move.beforeMoveCallback) {
|
||||
if (move.beforeMoveCallback.call(this.battle, pokemon, target, move)) {
|
||||
this.battle.clearActiveMove(true);
|
||||
if (move.beforeMoveCallback?.call(this.battle, pokemon, target, move)) {
|
||||
abortMove();
|
||||
return;
|
||||
}
|
||||
|
||||
if (move.id !== 'struggle') {
|
||||
const lockedMove = pokemon.getLockedMove() || pokemon.getSemiLockedMove();
|
||||
if (lockedMove) sourceEffect = move;
|
||||
|
||||
// Locked moves don't deduct PP
|
||||
// Two-turn moves like Sky Attack deduct PP on their second turn.
|
||||
if ((!lockedMove && !TWO_TURN_MOVES.includes(move.id)) || pokemon.volatiles['twoturnmove']) {
|
||||
const moveSlot = pokemon.getMoveSlot(pokemon.side.lastSelectedMoveSlot);
|
||||
if (moveSlot) pokemon.deductPP(moveSlot.id, null, target);
|
||||
}
|
||||
|
||||
if (!lockedMove && move.id !== pokemon.getMoveSlot(pokemon.side.lastSelectedMoveSlot)?.id) {
|
||||
this.battle.hint("Desync Clause Mod activated!");
|
||||
this.battle.hint(
|
||||
"In Gen 1, a Pokémon might default to using a move that doesn't match the move of the slot it last selected.",
|
||||
);
|
||||
abortMove();
|
||||
return;
|
||||
}
|
||||
}
|
||||
let lockedMove = this.battle.runEvent('LockMove', pokemon);
|
||||
if (lockedMove === true) lockedMove = false;
|
||||
if (
|
||||
!lockedMove &&
|
||||
(!pokemon.volatiles['partialtrappinglock'] || pokemon.volatiles['partialtrappinglock'].locked !== target)
|
||||
) {
|
||||
pokemon.deductPP(move, null, target);
|
||||
} else {
|
||||
sourceEffect = move;
|
||||
if (pokemon.volatiles['twoturnmove']) {
|
||||
// Two-turn moves like Sky Attack deduct PP on their second turn.
|
||||
pokemon.deductPP(pokemon.volatiles['twoturnmove'].originalMove, null, target);
|
||||
}
|
||||
}
|
||||
if (
|
||||
(pokemon.volatiles['partialtrappinglock'] && target !== pokemon.volatiles['partialtrappinglock'].locked) ||
|
||||
autoHyperBeam
|
||||
) {
|
||||
const moveSlot = pokemon.moveSlots.find(ms => ms.id === move.id);
|
||||
if (moveSlot && moveSlot.pp < 0) {
|
||||
moveSlot.pp = 63;
|
||||
this.battle.hint("In Gen 1, if a player is forced to use a move with 0 PP, the move will underflow to have 63 PP.");
|
||||
}
|
||||
}
|
||||
|
||||
this.useMove(move, pokemon, { target, sourceEffect });
|
||||
// Restore PP if the move is the first turn of a charging move. Save the move from which PP should be deducted if the move succeeds.
|
||||
if (pokemon.volatiles['twoturnmove']) {
|
||||
pokemon.deductPP(move, -1, target);
|
||||
pokemon.volatiles['twoturnmove'].originalMove = move.id;
|
||||
}
|
||||
},
|
||||
// This function deals with AfterMoveSelf events.
|
||||
// This leads with partial trapping moves shenanigans after the move has been used.
|
||||
|
|
@ -202,6 +233,19 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
if (sourceEffect) move.sourceEffect = sourceEffect.id;
|
||||
|
||||
if (sourceEffect?.id === 'metronome' || sourceEffect?.id === 'mirrormove') {
|
||||
if (TWO_TURN_MOVES.includes(move.id)) {
|
||||
const moveSlot = pokemon.getMoveSlot(pokemon.side.lastSelectedMoveSlot);
|
||||
if (moveSlot) pokemon.deductPP(moveSlot.id, -1, target);
|
||||
}
|
||||
// FIXME: this should happen even if the slot was empty before Transform
|
||||
// https://bulbapedia.bulbagarden.net/wiki/List_of_Transform_glitches#Transform_.2B_Mirror_Move.2FMetronome_PP_error
|
||||
if (pokemon.transformed && pokemon.side.lastSelectedMoveSlot < pokemon.baseMoveSlots.length) {
|
||||
pokemon.baseMoveSlots[pokemon.side.lastSelectedMoveSlot].pp += 1;
|
||||
pokemon.baseMoveSlots[pokemon.side.lastSelectedMoveSlot].pp %= 64;
|
||||
}
|
||||
}
|
||||
|
||||
this.battle.singleEvent('ModifyMove', move, null, pokemon, target, move, move);
|
||||
if (baseMove.target !== move.target) {
|
||||
// Target changed in ModifyMove, so we must adjust it here
|
||||
|
|
@ -223,37 +267,9 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
// The move is our 'final' move (a failed Mirror Move, or any move that isn't Metronome or Mirror Move).
|
||||
pokemon.side.lastMove = move;
|
||||
|
||||
if (pokemon.volatiles['lockedmove']?.time <= 0) pokemon.removeVolatile('lockedmove');
|
||||
|
||||
// If target fainted
|
||||
if (target && target.hp <= 0) {
|
||||
// We remove recharge
|
||||
if (pokemon.volatiles['mustrecharge']) pokemon.removeVolatile('mustrecharge');
|
||||
delete pokemon.volatiles['partialtrappinglock'];
|
||||
} else {
|
||||
if (pokemon.volatiles['mustrecharge']) this.battle.add('-mustrecharge', pokemon);
|
||||
if (pokemon.hp) this.battle.runEvent('AfterMoveSelf', pokemon, target, move);
|
||||
}
|
||||
|
||||
// For partial trapping moves, we are saving the target
|
||||
if (move.volatileStatus === 'partiallytrapped' && target && target.hp > 0) {
|
||||
// Let's check if the lock exists
|
||||
if (pokemon.volatiles['partialtrappinglock'] && target.volatiles['partiallytrapped']) {
|
||||
// Here the partialtrappinglock volatile has been already applied
|
||||
const sourceVolatile = pokemon.volatiles['partialtrappinglock'];
|
||||
const targetVolatile = target.volatiles['partiallytrapped'];
|
||||
if (!sourceVolatile.locked) {
|
||||
// If it's the first hit, we save the target
|
||||
sourceVolatile.locked = target;
|
||||
} else if (target !== pokemon && target !== sourceVolatile.locked) {
|
||||
// Our target switched out! Re-roll the duration, damage, and accuracy.
|
||||
const duration = this.battle.sample([2, 2, 2, 3, 3, 3, 4, 5]);
|
||||
sourceVolatile.duration = duration;
|
||||
sourceVolatile.locked = target;
|
||||
// Duration reset thus partially trapped at 2 always.
|
||||
targetVolatile.duration = 2;
|
||||
}
|
||||
} // If we move to here, the move failed and there's no partial trapping lock.
|
||||
this.battle.runEvent('AfterMove', pokemon, target, move);
|
||||
if (!target || target.hp > 0) {
|
||||
this.battle.runEvent('AfterMoveSelf', pokemon, target, move);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -293,7 +309,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (sourceEffect) attrs += `|[from]${this.battle.dex.conditions.get(sourceEffect)}`;
|
||||
if (sourceEffect) attrs += `|[from] ${this.battle.dex.conditions.get(sourceEffect).name}`;
|
||||
this.battle.addMove('move', pokemon, move.name, `${target}${attrs}`);
|
||||
|
||||
if (!this.battle.singleEvent('Try', move, null, pokemon, target, move)) {
|
||||
|
|
@ -332,10 +348,8 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!move.negateSecondary) {
|
||||
this.battle.singleEvent('AfterMoveSecondarySelf', move, null, pokemon, target, move);
|
||||
this.battle.runEvent('AfterMoveSecondarySelf', pokemon, target, move);
|
||||
}
|
||||
this.battle.singleEvent('AfterMoveSecondarySelf', move, null, pokemon, target, move);
|
||||
this.battle.runEvent('AfterMoveSecondarySelf', pokemon, target, move);
|
||||
return true;
|
||||
},
|
||||
// This function attempts a move hit and returns the attempt result before the actual hit happens.
|
||||
|
|
@ -370,10 +384,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
|
||||
// Then, check if the Pokémon is immune to this move.
|
||||
if (
|
||||
(!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) &&
|
||||
!target.runImmunity(move.type, true)
|
||||
) {
|
||||
if (!target.runImmunity(move, true)) {
|
||||
if (move.selfdestruct) {
|
||||
this.battle.faint(pokemon, pokemon, move);
|
||||
}
|
||||
|
|
@ -388,11 +399,6 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
// Now, let's calculate the accuracy.
|
||||
let accuracy = move.accuracy;
|
||||
|
||||
// Partial trapping moves: true accuracy while it lasts
|
||||
if (move.volatileStatus === 'partiallytrapped' && target === pokemon.volatiles['partialtrappinglock']?.locked) {
|
||||
accuracy = true;
|
||||
}
|
||||
|
||||
// If a sleep inducing move is used while the user is recharging, the accuracy is true.
|
||||
if (move.status === 'slp' && target?.volatiles['mustrecharge']) {
|
||||
accuracy = true;
|
||||
|
|
@ -459,7 +465,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
let i: number;
|
||||
for (i = 0; i < hits && target.hp && pokemon.hp; i++) {
|
||||
move.hit = i + 1;
|
||||
if (move.hit === hits) move.lastHit = true;
|
||||
move.lastHit = move.hit === hits;
|
||||
moveDamage = this.moveHit(target, pokemon, move);
|
||||
if (moveDamage === false) break;
|
||||
damage = (moveDamage || 0);
|
||||
|
|
@ -499,10 +505,8 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
|
||||
if (move.ohko) this.battle.add('-ohko');
|
||||
|
||||
if (!move.negateSecondary) {
|
||||
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
|
||||
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
|
||||
}
|
||||
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
|
||||
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
|
||||
|
||||
return damage;
|
||||
},
|
||||
|
|
@ -527,14 +531,6 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
if (target) {
|
||||
hitResult = this.battle.singleEvent('TryHit', moveData, {}, target, pokemon, move);
|
||||
|
||||
// Handle here the applying of partial trapping moves to Pokémon with Substitute
|
||||
if (targetSub && moveData.volatileStatus && moveData.volatileStatus === 'partiallytrapped') {
|
||||
target.addVolatile(moveData.volatileStatus, pokemon, move);
|
||||
if (!pokemon.volatiles['partialtrappinglock'] || pokemon.volatiles['partialtrappinglock'].duration! > 1) {
|
||||
target.volatiles[moveData.volatileStatus].duration = 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hitResult) {
|
||||
if (hitResult === false) this.battle.add('-fail', target);
|
||||
return false;
|
||||
|
|
@ -609,7 +605,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
didSomething = true;
|
||||
// Check the status of the Pokémon whose turn is not.
|
||||
// When a move that affects stat levels is used, if the Pokémon whose turn it is not right now is paralyzed or
|
||||
// burned, the correspoding stat penalties will be applied again to that Pokémon.
|
||||
// burned, the corresponding stat penalties will be applied again to that Pokémon.
|
||||
if (pokemon.side.foe.active[0].status) {
|
||||
// If it's paralysed, quarter its speed.
|
||||
if (pokemon.side.foe.active[0].status === 'par') {
|
||||
|
|
@ -700,11 +696,6 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
this.moveHit(pokemon, pokemon, move, moveData.self, isSecondary, true);
|
||||
}
|
||||
|
||||
// Now we can save the partial trapping damage.
|
||||
if (pokemon.volatiles['partialtrappinglock']) {
|
||||
pokemon.volatiles['partialtrappinglock'].damage = this.battle.lastDamage;
|
||||
}
|
||||
|
||||
// Apply move secondaries.
|
||||
if (moveData.secondaries && target && target.hp > 0) {
|
||||
for (const secondary of moveData.secondaries) {
|
||||
|
|
@ -751,10 +742,8 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
|
||||
// Let's see if the target is immune to the move.
|
||||
if (!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) {
|
||||
if (!target.runImmunity(move.type, true)) {
|
||||
return false;
|
||||
}
|
||||
if (!target.runImmunity(move, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is it an OHKO move?
|
||||
|
|
@ -778,7 +767,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
|
||||
// If it's the first hit on a Normal-type partially trap move, it hits Ghosts anyways but damage is 0.
|
||||
if (move.volatileStatus === 'partiallytrapped' && move.type === 'Normal' && target.hasType('Ghost')) {
|
||||
if (move.self?.volatileStatus === 'partialtrappinglock' && move.type === 'Normal' && target.hasType('Ghost')) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,12 +13,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
substitute: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
onStart(target) {
|
||||
this.add('-start', target, 'Substitute');
|
||||
this.effectState.hp = Math.floor(target.maxhp / 4) + 1;
|
||||
delete target.volatiles['partiallytrapped'];
|
||||
},
|
||||
onTryHitPriority: -1,
|
||||
inherit: true,
|
||||
onTryHit(target, source, move) {
|
||||
if (move.drain) {
|
||||
this.add('-miss', source);
|
||||
|
|
@ -39,10 +34,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
// NOTE: In future generations the damage is capped to the remaining HP of the
|
||||
// Substitute, here we deliberately use the uncapped damage when tracking lastDamage etc.
|
||||
// Also, multi-hit moves must always deal the same damage as the first hit for any subsequent hits
|
||||
let uncappedDamage = move.hit > 1 ? this.lastDamage : this.actions.getDamage(source, target, move);
|
||||
const uncappedDamage = move.hit > 1 ? this.lastDamage : this.actions.getDamage(source, target, move);
|
||||
if (!uncappedDamage && uncappedDamage !== 0) return null;
|
||||
uncappedDamage = this.runEvent('SubDamage', target, source, move, uncappedDamage);
|
||||
if (!uncappedDamage && uncappedDamage !== 0) return uncappedDamage;
|
||||
this.lastDamage = uncappedDamage;
|
||||
target.volatiles['substitute'].hp -= uncappedDamage > target.volatiles['substitute'].hp ?
|
||||
target.volatiles['substitute'].hp : uncappedDamage;
|
||||
|
|
@ -78,9 +71,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
}
|
||||
return accuracy;
|
||||
},
|
||||
onEnd(target) {
|
||||
this.add('-end', target, 'Substitute');
|
||||
},
|
||||
},
|
||||
},
|
||||
swift: {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,10 @@ export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable
|
|||
standard: {
|
||||
effectType: 'ValidatorRule',
|
||||
name: 'Standard',
|
||||
ruleset: ['Obtainable', 'Desync Clause Mod', 'Sleep Clause Mod', 'Freeze Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod'],
|
||||
ruleset: [
|
||||
'Standard AG',
|
||||
'Sleep Clause Mod', 'Freeze Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause',
|
||||
],
|
||||
banlist: ['Dig', 'Fly'],
|
||||
},
|
||||
nc1997movelegality: {
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
},
|
||||
flinch: {
|
||||
inherit: true,
|
||||
onStart() {},
|
||||
onStart: undefined, // no inherit
|
||||
},
|
||||
partiallytrapped: {
|
||||
name: 'partiallytrapped',
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NFE",
|
||||
},
|
||||
golem: {
|
||||
tier: "OU",
|
||||
tier: "UU",
|
||||
},
|
||||
ponyta: {
|
||||
tier: "LC",
|
||||
|
|
@ -270,7 +270,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
cloyster: {
|
||||
tier: "OU",
|
||||
tier: "UU",
|
||||
},
|
||||
gastly: {
|
||||
tier: "LC",
|
||||
|
|
@ -279,7 +279,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
gengar: {
|
||||
tier: "OU",
|
||||
tier: "UU",
|
||||
},
|
||||
onix: {
|
||||
tier: "UU",
|
||||
|
|
@ -342,7 +342,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
kangaskhan: {
|
||||
tier: "OU",
|
||||
tier: "UU",
|
||||
},
|
||||
horsea: {
|
||||
tier: "LC",
|
||||
|
|
@ -369,7 +369,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
jynx: {
|
||||
tier: "OU",
|
||||
tier: "UU",
|
||||
},
|
||||
electabuzz: {
|
||||
tier: "UU",
|
||||
|
|
@ -402,7 +402,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
jolteon: {
|
||||
tier: "OU",
|
||||
tier: "UU",
|
||||
},
|
||||
flareon: {
|
||||
tier: "UU",
|
||||
|
|
|
|||
|
|
@ -160,11 +160,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
volatileStatus: 'rage',
|
||||
},
|
||||
condition: {
|
||||
inherit: true,
|
||||
// Rage lock
|
||||
onStart(target, source, effect) {
|
||||
this.effectState.move = 'rage';
|
||||
},
|
||||
onLockMove: 'rage',
|
||||
onHit(target, source, move) {
|
||||
if (target.boosts.atk < 6 && (move.category !== 'Status' || move.id === 'disable')) {
|
||||
this.boost({ atk: 1 });
|
||||
|
|
@ -174,7 +174,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
recover: {
|
||||
inherit: true,
|
||||
heal: null,
|
||||
onHit(target) {
|
||||
if (target.hp === target.maxhp) {
|
||||
return false;
|
||||
|
|
@ -197,7 +196,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
softboiled: {
|
||||
inherit: true,
|
||||
heal: null,
|
||||
onHit(target) {
|
||||
// Fail when health is 255 or 511 less than max
|
||||
if (target.hp === target.maxhp) {
|
||||
|
|
@ -220,12 +218,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
}
|
||||
},
|
||||
condition: {
|
||||
onStart(target) {
|
||||
this.add('-start', target, 'Substitute');
|
||||
this.effectState.hp = Math.floor(target.maxhp / 4);
|
||||
delete target.volatiles['partiallytrapped'];
|
||||
},
|
||||
onTryHitPriority: -1,
|
||||
inherit: true,
|
||||
onTryHit(target, source, move) {
|
||||
if (target === source) {
|
||||
this.debug('sub bypass: self hit');
|
||||
|
|
@ -249,8 +242,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
damage = target.volatiles['substitute'].hp;
|
||||
}
|
||||
if (!damage && damage !== 0) return null;
|
||||
damage = this.runEvent('SubDamage', target, source, move, damage);
|
||||
if (!damage && damage !== 0) return damage;
|
||||
target.volatiles['substitute'].hp -= damage;
|
||||
this.lastDamage = damage;
|
||||
if (target.volatiles['substitute'].hp <= 0) {
|
||||
|
|
@ -277,11 +268,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
}
|
||||
return 0;
|
||||
},
|
||||
onEnd(target) {
|
||||
this.add('-end', target, 'Substitute');
|
||||
},
|
||||
},
|
||||
secondary: null,
|
||||
target: "self",
|
||||
type: "Normal",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,7 +1,763 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
standardag: {
|
||||
inherit: true,
|
||||
ruleset: [
|
||||
'Obtainable', 'Exact HP Mod', 'Cancel Mod',
|
||||
],
|
||||
},
|
||||
standard: {
|
||||
effectType: 'ValidatorRule',
|
||||
name: 'Standard',
|
||||
ruleset: ['Obtainable', 'Stadium Sleep Clause', 'Freeze Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'Exact HP Mod', 'Cancel Mod'],
|
||||
ruleset: [
|
||||
'Standard AG',
|
||||
'Stadium Sleep Clause', 'Freeze Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause',
|
||||
],
|
||||
},
|
||||
stadiumpokecuprentals: {
|
||||
inherit: true,
|
||||
onChangeSet(set, format, setHas, teamHas) {
|
||||
set.level = 50;
|
||||
switch (this.dex.species.get(set.species).name) {
|
||||
case 'Bulbasaur':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Leech Seed', 'Toxic', 'Body Slam', 'Razor Leaf'];
|
||||
break;
|
||||
case 'Ivysaur':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Razor Leaf', 'Sleep Powder', 'Growth', 'Double-Edge'];
|
||||
break;
|
||||
case 'Venusaur':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Psychic', 'Seismic Toss', 'Reflect', 'Thunder Wave'];
|
||||
break;
|
||||
case 'Charmander':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Flamethrower', 'Slash', 'Dig', 'Fire Spin'];
|
||||
break;
|
||||
case 'Charmeleon':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Flamethrower', 'Counter', 'Seismic Toss', 'Strength'];
|
||||
break;
|
||||
case 'Charizard':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Fly', 'Swords Dance', 'Fire Spin', 'Fire Blast'];
|
||||
break;
|
||||
case 'Squirtle':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Surf', 'Blizzard', 'Body Slam', 'Dig'];
|
||||
break;
|
||||
case 'Wartortle':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Surf', 'Strength', 'Rest', 'Ice Beam'];
|
||||
break;
|
||||
case 'Blastoise':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Hydro Pump', 'Skull Bash', 'Withdraw', 'Seismic Toss'];
|
||||
break;
|
||||
case 'Caterpie':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['String Shot', 'Tackle'];
|
||||
break;
|
||||
case 'Metapod':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['String Shot', 'Tackle'];
|
||||
break;
|
||||
case 'Butterfree':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Psychic', 'Supersonic', 'Mega Drain', 'Stun Spore'];
|
||||
break;
|
||||
case 'Weedle':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['String Shot', 'Poison Sting'];
|
||||
break;
|
||||
case 'Kakuna':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['String Shot', 'Poison Sting'];
|
||||
break;
|
||||
case 'Beedrill':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Twineedle', 'Hyper Beam', 'Toxic', 'Focus Energy'];
|
||||
break;
|
||||
case 'Pidgey':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Fly', 'Toxic', 'Double-Edge', 'Double Team'];
|
||||
break;
|
||||
case 'Pidgeotto':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Fly', 'Quick Attack', 'Sand Attack', 'Take Down'];
|
||||
break;
|
||||
case 'Pidgeot':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Mirror Move', 'Fly', 'Quick Attack', 'Sand Attack'];
|
||||
break;
|
||||
case 'Rattata':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Super Fang', 'Blizzard', 'Quick Attack', 'Hyper Fang'];
|
||||
break;
|
||||
case 'Raticate':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Hyper Fang', 'Hyper Beam', 'Focus Energy', 'Thunder'];
|
||||
break;
|
||||
case 'Spearow':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Drill Peck', 'Mirror Move', 'Double Team', 'Double-Edge'];
|
||||
break;
|
||||
case 'Fearow':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Drill Peck', 'Mirror Move', 'Fury Attack', 'Swift'];
|
||||
break;
|
||||
case 'Ekans':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Earthquake', 'Acid', 'Screech', 'Body Slam'];
|
||||
break;
|
||||
case 'Arbok':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Glare', 'Wrap', 'Dig', 'Strength'];
|
||||
break;
|
||||
case 'Pikachu':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Thunderbolt', 'Slam', 'Thunder Wave', 'Seismic Toss'];
|
||||
break;
|
||||
case 'Raichu':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Thunder', 'Thunder Wave', 'Flash', 'Mega Kick'];
|
||||
break;
|
||||
case 'Sandshrew':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Earthquake', 'Slash', 'Seismic Toss', 'Sand Attack'];
|
||||
break;
|
||||
case 'Sandslash':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Dig', 'Swift', 'Seismic Toss', 'Sand Attack'];
|
||||
break;
|
||||
case 'Nidoran-F':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Toxic', 'Thunderbolt', 'Body Slam', 'Blizzard'];
|
||||
break;
|
||||
case 'Nidorina':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Toxic', 'Thunder', 'Double-Edge', 'Ice Beam'];
|
||||
break;
|
||||
case 'Nidoqueen':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Toxic', 'Double Kick', 'Bite', 'Earthquake'];
|
||||
break;
|
||||
case 'Nidoran-M':
|
||||
set.evs = { hp: 177, atk: 176, def: 176, spa: 176, spd: 176, spe: 176 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Blizzard', 'Body Slam', 'Thunderbolt', 'Focus Energy'];
|
||||
break;
|
||||
case 'Nidorino':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Double-Edge', 'Horn Drill', 'Focus Energy', 'Thunder'];
|
||||
break;
|
||||
case 'Nidoking':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Earthquake', 'Horn Drill', 'Rage', 'Substitute'];
|
||||
break;
|
||||
case 'Clefairy':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Thunderbolt', 'Psychic', 'Body Slam', 'Blizzard'];
|
||||
break;
|
||||
case 'Clefable':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Sing', 'Tri Attack', 'Minimize', 'Ice Beam'];
|
||||
break;
|
||||
case 'Vulpix':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Flamethrower', 'Dig', 'Confuse Ray', 'Double-Edge'];
|
||||
break;
|
||||
case 'Ninetales':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Fire Blast', 'Skull Bash', 'Confuse Ray', 'Tail Whip'];
|
||||
break;
|
||||
case 'Jigglypuff':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Sing', 'Body Slam', 'Seismic Toss', 'Psychic'];
|
||||
break;
|
||||
case 'Wigglytuff':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Sing', 'Double-Edge', 'Submission', 'Thunderbolt'];
|
||||
break;
|
||||
case 'Zubat':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Confuse Ray', 'Mega Drain', 'Toxic', 'Double-Edge'];
|
||||
break;
|
||||
case 'Golbat':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Confuse Ray', 'Mega Drain', 'Bite', 'Haze'];
|
||||
break;
|
||||
case 'Oddish':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Petal Dance', 'Toxic', 'Mega Drain', 'Double-Edge'];
|
||||
break;
|
||||
case 'Gloom':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Petal Dance', 'Take Down', 'Mega Drain', 'Stun Spore'];
|
||||
break;
|
||||
case 'Vileplume':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Petal Dance', 'Sleep Powder', 'Acid', 'Cut'];
|
||||
break;
|
||||
case 'Paras':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Spore', 'Slash', 'Dig', 'Mega Drain'];
|
||||
break;
|
||||
case 'Parasect':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Spore', 'Take Down', 'Dig', 'Solar Beam'];
|
||||
break;
|
||||
case 'Venonat':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Psychic', 'Mega Drain', 'Double-Edge', 'Stun Spore'];
|
||||
break;
|
||||
case 'Venomoth':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Psychic', 'Supersonic', 'Solar Beam', 'Swift'];
|
||||
break;
|
||||
case 'Diglett':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Earthquake', 'Slash', 'Sand Attack', 'Rock Slide'];
|
||||
break;
|
||||
case 'Dugtrio':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Dig', 'Sand Attack', 'Toxic', 'Hyper Beam'];
|
||||
break;
|
||||
case 'Meowth':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Slash', 'Thunderbolt', 'Swift', 'Double Team'];
|
||||
break;
|
||||
case 'Persian':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Slash', 'Bubble Beam', 'Mimic', 'Growl'];
|
||||
break;
|
||||
case 'Psyduck':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Surf', 'Confusion', 'Dig', 'Blizzard'];
|
||||
break;
|
||||
case 'Golduck':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Ice Beam', 'Surf', 'Toxic', 'Disable'];
|
||||
break;
|
||||
case 'Mankey':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Submission', 'Rock Slide', 'Seismic Toss', 'Screech'];
|
||||
break;
|
||||
case 'Primeape':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Fury Swipes', 'Rock Slide', 'Low Kick', 'Screech'];
|
||||
break;
|
||||
case 'Growlithe':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Flamethrower', 'Body Slam', 'Reflect', 'Dig'];
|
||||
break;
|
||||
case 'Arcanine':
|
||||
set.evs = { hp: 105, atk: 104, def: 104, spa: 104, spd: 104, spe: 104 };
|
||||
set.ivs = { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 };
|
||||
set.moves = ['Fire Blast', 'Take Down', 'Dragon Rage', 'Substitute'];
|
||||
break;
|
||||
case 'Poliwag':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Body Slam', 'Blizzard', 'Surf', 'Amnesia'];
|
||||
break;
|
||||
case 'Poliwhirl':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Hypnosis', 'Surf', 'Ice Beam', 'Earthquake'];
|
||||
break;
|
||||
case 'Poliwrath':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Hypnosis', 'Submission', 'Counter', 'Hydro Pump'];
|
||||
break;
|
||||
case 'Abra':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Psychic', 'Seismic Toss', 'Reflect', 'Thunder Wave'];
|
||||
break;
|
||||
case 'Kadabra':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Psychic', 'Counter', 'Recover', 'Dig'];
|
||||
break;
|
||||
case 'Alakazam':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Psybeam', 'Metronome', 'Disable', 'Tri Attack'];
|
||||
break;
|
||||
case 'Machop':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Submission', 'Rock Slide', 'Earthquake', 'Focus Energy'];
|
||||
break;
|
||||
case 'Machoke':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Submission', 'Strength', 'Rock Slide', 'Focus Energy'];
|
||||
break;
|
||||
case 'Machamp':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Low Kick', 'Strength', 'Counter', 'Focus Energy'];
|
||||
break;
|
||||
case 'Bellsprout':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Razor Leaf', 'Growth', 'Mega Drain', 'Stun Spore'];
|
||||
break;
|
||||
case 'Weepinbell':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Razor Leaf', 'Acid', 'Wrap', 'Toxic'];
|
||||
break;
|
||||
case 'Victreebel':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Solar Beam', 'Acid', 'Reflect', 'Slam'];
|
||||
break;
|
||||
case 'Tentacool':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Surf', 'Supersonic', 'Mega Drain', 'Blizzard'];
|
||||
break;
|
||||
case 'Tentacruel':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Acid', 'Supersonic', 'Hydro Pump', 'Cut'];
|
||||
break;
|
||||
case 'Geodude':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Earthquake', 'Seismic Toss', 'Rock Slide', 'Explosion'];
|
||||
break;
|
||||
case 'Graveler':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Earthquake', 'Seismic Toss', 'Strength', 'Self-Destruct'];
|
||||
break;
|
||||
case 'Golem':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Dig', 'Seismic Toss', 'Fire Blast', 'Metronome'];
|
||||
break;
|
||||
case 'Ponyta':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Fire Blast', 'Agility', 'Horn Drill', 'Body Slam'];
|
||||
break;
|
||||
case 'Rapidash':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Fire Blast', 'Stomp', 'Toxic', 'Fire Spin'];
|
||||
break;
|
||||
case 'Slowpoke':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Surf', 'Psychic', 'Thunder Wave', 'Amnesia'];
|
||||
break;
|
||||
case 'Slowbro':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Surf', 'Psychic', 'Disable', 'Withdraw'];
|
||||
break;
|
||||
case 'Magnemite':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Thunderbolt', 'Thunder Wave', 'Supersonic', 'Double-Edge'];
|
||||
break;
|
||||
case 'Magneton':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Thunderbolt', 'Screech', 'Supersonic', 'Swift'];
|
||||
break;
|
||||
case 'Farfetch\u2019d':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Slash', 'Sand Attack', 'Toxic', 'Fly'];
|
||||
break;
|
||||
case 'Doduo':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Drill Peck', 'Tri Attack', 'Double Team', 'Reflect'];
|
||||
break;
|
||||
case 'Dodrio':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Fly', 'Tri Attack', 'Agility', 'Reflect'];
|
||||
break;
|
||||
case 'Seel':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Ice Beam', 'Body Slam', 'Horn Drill', 'Surf'];
|
||||
break;
|
||||
case 'Dewgong':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Aurora Beam', 'Heabutt', 'Rest', 'Surf'];
|
||||
break;
|
||||
case 'Grimer':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Sludge', 'Body Slam', 'Explosion', 'Screech'];
|
||||
break;
|
||||
case 'Muk':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Sludge', 'Thunderbolt', 'Hyper Beam', 'Self-Destruct'];
|
||||
break;
|
||||
case 'Shellder':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Surf', 'Explosion', 'Blizzard', 'Tri Attack'];
|
||||
break;
|
||||
case 'Cloyster':
|
||||
set.evs = { hp: 105, atk: 104, def: 104, spa: 104, spd: 104, spe: 104 };
|
||||
set.ivs = { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 };
|
||||
set.moves = ['Clamp', 'Spike Cannon', 'Ice Beam', 'Supersonic'];
|
||||
break;
|
||||
case 'Gastly':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Hypnosis', 'Dream Eater', 'Psychic', 'Confuse Ray'];
|
||||
break;
|
||||
case 'Haunter':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Mega Drain', 'Psychic', 'Explosion', 'Confuse Ray'];
|
||||
break;
|
||||
case 'Gengar':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Thunderbolt', 'Night Shade', 'Hypnosis', 'Confuse Ray'];
|
||||
break;
|
||||
case 'Onix':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Earthquake', 'Rock Slide', 'Strength', 'Explosion'];
|
||||
break;
|
||||
case 'Drowzee':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Hypnois', 'Dream Eater', 'Psychic', 'Tri Attack'];
|
||||
break;
|
||||
case 'Hypno':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Hypnosis', 'Headbutt', 'Dream Eater', 'Meditate'];
|
||||
break;
|
||||
case 'Krabby':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Crabhammer', 'Guillotine', 'Double-Edge', 'Blizzard'];
|
||||
break;
|
||||
case 'Kingler':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Crabhammer', 'Guillotine', 'Stomp', 'Substitute'];
|
||||
break;
|
||||
case 'Voltorb':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Thunderbolt', 'Thunder Wave', 'Swift', 'Explosion'];
|
||||
break;
|
||||
case 'Electrode':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Thunder', 'Thunder Wave', 'Swift', 'Self-Destruct'];
|
||||
break;
|
||||
case 'Exeggcute':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Psychic', 'Explosion', 'Leech Seed', 'Toxic'];
|
||||
break;
|
||||
case 'Exeggutor':
|
||||
set.evs = { hp: 105, atk: 104, def: 104, spa: 104, spd: 104, spe: 104 };
|
||||
set.ivs = { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 };
|
||||
set.moves = ['Mega Drain', 'Stun Spore', 'Leech Seed', 'Egg Bomb'];
|
||||
break;
|
||||
case 'Cubone':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Earthquake', 'Submission', 'Blizzard', 'Strength'];
|
||||
break;
|
||||
case 'Marowak':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Bonemerang', 'Thrash', 'Fire Blast', 'Focus Energy'];
|
||||
break;
|
||||
case 'Hitmonlee':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['High Jump Kick', 'Mega Kick', 'Metronome', 'Seismic Toss'];
|
||||
break;
|
||||
case 'Hitmonchan':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Submission', 'Thunder Punch', 'Ice Punch', 'Strength'];
|
||||
break;
|
||||
case 'Lickitung':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Strength', 'Blizzard', 'Thunder', 'Fire Blast'];
|
||||
break;
|
||||
case 'Koffing':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Sludge', 'Toxic', 'Thunderbolt', 'Explosion'];
|
||||
break;
|
||||
case 'Weezing':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Sludge', 'Hyper Beam', 'Fire Blast', 'Self-Destruct'];
|
||||
break;
|
||||
case 'Rhyhorn':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Earthquake', 'Body Slam', 'Rock Slide', 'Fire Blast'];
|
||||
break;
|
||||
case 'Rhydon':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Dig', 'Strength', 'Thunder', 'Surf'];
|
||||
break;
|
||||
case 'Chansey':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Thunder', 'Fire Blast', 'Minimize', 'Rest'];
|
||||
break;
|
||||
case 'Tangela':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Mega Drain', 'Growth', 'Toxic', 'Double-Edge'];
|
||||
break;
|
||||
case 'Kangaskhan':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Dizzy Punch', 'Rock Slide', 'Surf', 'Thunderbolt'];
|
||||
break;
|
||||
case 'Horsea':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Hydro Pump', 'Toxic', 'Smokescreen', 'Ice Beam'];
|
||||
break;
|
||||
case 'Seadra':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Surf', 'Toxic', 'Smokescreen', 'Swift'];
|
||||
break;
|
||||
case 'Goldeen':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Surf', 'Supersonic', 'Horn Drill', 'Blizzard'];
|
||||
break;
|
||||
case 'Seaking':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Waterfall', 'Supersonic', 'Horn Attack', 'Ice Beam'];
|
||||
break;
|
||||
case 'Staryu':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Hydro Pump', 'Recover', 'Thunderbolt', 'Psychic'];
|
||||
break;
|
||||
case 'Starmie':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Surf', 'Thunder', 'Swift', 'Harden'];
|
||||
break;
|
||||
case 'Mr. Mime':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Barrier', 'Psychic', 'Metronome', 'Seismic Toss'];
|
||||
break;
|
||||
case 'Scyther':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Slash', 'Wing Attack', 'Leer', 'Double Team'];
|
||||
break;
|
||||
case 'Jynx':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Ice Punch', 'Mega Punch', 'Psychic', 'Lovely Kiss'];
|
||||
break;
|
||||
case 'Electabuzz':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Thunder Punch', 'Mega Punch', 'Psychic', 'Thunder Wave'];
|
||||
break;
|
||||
case 'Magmar':
|
||||
set.evs = { hp: 121, atk: 120, def: 120, spa: 120, spd: 120, spe: 120 };
|
||||
set.ivs = { hp: 6, atk: 8, def: 8, spa: 6, spd: 6, spe: 6 };
|
||||
set.moves = ['Fire Punch', 'Mega Punch', 'Psychic', 'Smokescreen'];
|
||||
break;
|
||||
case 'Pinsir':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Strength', 'Harden', 'Seismic Toss', 'Guillotine'];
|
||||
break;
|
||||
case 'Tauros':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Double-Edge', 'Fire Blast', 'Tail Whip', 'Bide'];
|
||||
break;
|
||||
case 'Magikarp':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Splash', 'Tackle'];
|
||||
break;
|
||||
case 'Gyarados':
|
||||
set.evs = { hp: 105, atk: 104, def: 104, spa: 104, spd: 104, spe: 104 };
|
||||
set.ivs = { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 };
|
||||
set.moves = ['Surf', 'Dragon Rage', 'Bite', 'Fire Blast'];
|
||||
break;
|
||||
case 'Lapras':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Ice Beam', 'Solar Beam', 'Body Slam', 'Sing'];
|
||||
break;
|
||||
case 'Ditto':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Transform'];
|
||||
break;
|
||||
case 'Eevee':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Body Slam', 'Swift', 'Sand Attack', 'Toxic'];
|
||||
break;
|
||||
case 'Vaporeon':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Surf', 'Quick Attack', 'Sand Attack', 'Acid Armor'];
|
||||
break;
|
||||
case 'Jolteon':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Thunderbolt', 'Pin Missile', 'Toxic', 'Sand Attack'];
|
||||
break;
|
||||
case 'Flareon':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Fire Blast', 'Take Down', 'Smog', 'Sand Attack'];
|
||||
break;
|
||||
case 'Omanyte':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Surf', 'Ice Beam', 'Double Edge', 'Double Team'];
|
||||
break;
|
||||
case 'Omastar':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Hydro Pump', 'Submission', 'Spike Cannon', 'Withdraw'];
|
||||
break;
|
||||
case 'Kabuto':
|
||||
set.evs = { hp: 145, atk: 144, def: 144, spa: 144, spd: 144, spe: 144 };
|
||||
set.ivs = { hp: 12, atk: 12, def: 10, spa: 12, spd: 12, spe: 10 };
|
||||
set.moves = ['Hydro Pump', 'Blizzard', 'Slash', 'Double Team'];
|
||||
break;
|
||||
case 'Kabutops':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Surf', 'Swords Dance', 'Mega Kick', 'Submission'];
|
||||
break;
|
||||
case 'Aerodactyl':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Fly', 'Hyper Beam', 'Supersonic', 'Dragon Rage'];
|
||||
break;
|
||||
case 'Snorlax':
|
||||
set.evs = { hp: 113, atk: 112, def: 112, spa: 112, spd: 112, spe: 112 };
|
||||
set.ivs = { hp: 4, atk: 4, def: 4, spa: 4, spd: 4, spe: 6 };
|
||||
set.moves = ['Mega Kick', 'Rock Slide', 'Metronome', 'Rest'];
|
||||
break;
|
||||
case 'Articuno':
|
||||
set.evs = { hp: 97, atk: 96, def: 96, spa: 96, spd: 96, spe: 96 };
|
||||
set.ivs = { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 };
|
||||
set.moves = ['Ice Beam', 'Sky Attack', 'Razor Wind', 'Substitute'];
|
||||
break;
|
||||
case 'Zapdos':
|
||||
set.evs = { hp: 97, atk: 96, def: 96, spa: 96, spd: 96, spe: 96 };
|
||||
set.ivs = { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 };
|
||||
set.moves = ['Thunderbolt', 'Sky Attack', 'Thunder Wave', 'Flash'];
|
||||
break;
|
||||
case 'Moltres':
|
||||
set.evs = { hp: 97, atk: 96, def: 96, spa: 96, spd: 96, spe: 96 };
|
||||
set.ivs = { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 };
|
||||
set.moves = ['Fire Blast', 'Fly', 'Swift', 'Substitute'];
|
||||
break;
|
||||
case 'Dratini':
|
||||
set.evs = { hp: 161, atk: 160, def: 160, spa: 160, spd: 160, spe: 160 };
|
||||
set.ivs = { hp: 14, atk: 12, def: 14, spa: 14, spd: 14, spe: 14 };
|
||||
set.moves = ['Hyper Beam', 'Body Slam', 'Thunderbolt', 'Thunder Wave'];
|
||||
break;
|
||||
case 'Dragonair':
|
||||
set.evs = { hp: 129, atk: 128, def: 128, spa: 128, spd: 128, spe: 128 };
|
||||
set.ivs = { hp: 10, atk: 8, def: 10, spa: 10, spd: 10, spe: 8 };
|
||||
set.moves = ['Hyper Beam', 'Swift', 'Ice Beam', 'Thunder Wave'];
|
||||
break;
|
||||
case 'Dragonite':
|
||||
set.evs = { hp: 97, atk: 96, def: 96, spa: 96, spd: 96, spe: 96 };
|
||||
set.ivs = { hp: 0, atk: 0, def: 0, spa: 0, spd: 0, spe: 0 };
|
||||
set.moves = ['Slam', 'Dragon Rage', 'Thunder', 'Agility'];
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -93,8 +93,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
return;
|
||||
}
|
||||
}
|
||||
let lockedMove = this.battle.runEvent('LockMove', pokemon);
|
||||
if (lockedMove === true) lockedMove = false;
|
||||
const lockedMove = pokemon.getLockedMove() || pokemon.getSemiLockedMove();
|
||||
if (
|
||||
!lockedMove &&
|
||||
(!pokemon.volatiles['partialtrappinglock'] || pokemon.volatiles['partialtrappinglock'].locked !== target)
|
||||
|
|
@ -199,7 +198,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (sourceEffect) attrs += `|[from]${this.battle.dex.conditions.get(sourceEffect)}`;
|
||||
if (sourceEffect) attrs += `|[from] ${this.battle.dex.conditions.get(sourceEffect).name}`;
|
||||
this.battle.addMove('move', pokemon, move.name, `${target}${attrs}`);
|
||||
|
||||
if (!this.battle.singleEvent('Try', move, null, pokemon, target, move)) {
|
||||
|
|
@ -231,10 +230,8 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!move.negateSecondary) {
|
||||
this.battle.singleEvent('AfterMoveSecondarySelf', move, null, pokemon, target, move);
|
||||
this.battle.runEvent('AfterMoveSecondarySelf', pokemon, target, move);
|
||||
}
|
||||
this.battle.singleEvent('AfterMoveSecondarySelf', move, null, pokemon, target, move);
|
||||
this.battle.runEvent('AfterMoveSecondarySelf', pokemon, target, move);
|
||||
return true;
|
||||
},
|
||||
tryMoveHit(target, pokemon, move) {
|
||||
|
|
@ -252,10 +249,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
|
||||
// Then, check if the Pokemon is immune to this move.
|
||||
if (
|
||||
(!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) &&
|
||||
!target.runImmunity(move.type, true)
|
||||
) {
|
||||
if (!target.runImmunity(move, true)) {
|
||||
if (move.selfdestruct) {
|
||||
this.battle.faint(pokemon, pokemon, move);
|
||||
}
|
||||
|
|
@ -305,10 +299,16 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
accuracy = this.battle.runEvent('Accuracy', target, pokemon, move, accuracy);
|
||||
|
||||
// Stadium fixes the 1/256 accuracy bug.
|
||||
if (accuracy !== true && !this.battle.randomChance(accuracy + 1, 256)) {
|
||||
// Stadium attempts to fix the 1/256 miss by rerolling if the first value
|
||||
// would trigger the 1/256 miss.
|
||||
let randomValue = this.battle.random(256);
|
||||
if (randomValue === 256) randomValue = this.battle.random(256);
|
||||
if (accuracy !== true && randomValue > accuracy) {
|
||||
this.battle.attrLastMove('[miss]');
|
||||
this.battle.add('-miss', pokemon);
|
||||
if (accuracy === 255) {
|
||||
this.battle.hint("In Pokemon Stadium, moves with 100% accuracy can still miss 1/65536 of the time.");
|
||||
}
|
||||
damage = false;
|
||||
this.battle.lastDamage = 0;
|
||||
}
|
||||
|
|
@ -331,7 +331,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
let i: number;
|
||||
for (i = 0; i < hits && target.hp && pokemon.hp; i++) {
|
||||
move.hit = i + 1;
|
||||
if (move.hit === hits) move.lastHit = true;
|
||||
move.lastHit = move.hit === hits;
|
||||
moveDamage = this.moveHit(target, pokemon, move);
|
||||
if (moveDamage === false) break;
|
||||
damage = (moveDamage || 0);
|
||||
|
|
@ -365,10 +365,8 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
|
||||
if (move.ohko) this.battle.add('-ohko');
|
||||
|
||||
if (!move.negateSecondary) {
|
||||
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
|
||||
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
|
||||
}
|
||||
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
|
||||
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
|
||||
|
||||
return damage;
|
||||
},
|
||||
|
|
@ -549,10 +547,8 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
|
||||
// Let's see if the target is immune to the move.
|
||||
if (!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) {
|
||||
if (!target.runImmunity(move.type, true)) {
|
||||
return false;
|
||||
}
|
||||
if (!target.runImmunity(move, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is it an OHKO move?
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
inherit: true,
|
||||
onBeforeMovePriority: 2,
|
||||
onBeforeMove(pokemon) {
|
||||
if (this.randomChance(1, 4)) {
|
||||
if (this.randomChance(63, 256)) {
|
||||
this.add('cant', pokemon, 'par');
|
||||
return false;
|
||||
}
|
||||
|
|
@ -62,8 +62,8 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
this.add('cant', pokemon, 'frz');
|
||||
return false;
|
||||
},
|
||||
onModifyMove() {},
|
||||
onDamagingHit() {},
|
||||
onModifyMove: undefined, // no inherit
|
||||
onDamagingHit: undefined, // no inherit
|
||||
onAfterMoveSecondary(target, source, move) {
|
||||
if ((move.secondary && move.secondary.status === 'brn') || move.statusRoll === 'brn') {
|
||||
target.cureStatus();
|
||||
|
|
@ -177,12 +177,17 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
onStart(target, source, effect) {
|
||||
this.effectState.move = effect.id;
|
||||
},
|
||||
onAfterMove(pokemon) {
|
||||
if (this.effectState.duration === 1) {
|
||||
pokemon.removeVolatile('lockedmove');
|
||||
}
|
||||
},
|
||||
onEnd(target) {
|
||||
// Confusion begins even if already confused
|
||||
delete target.volatiles['confusion'];
|
||||
if (!target.side.getSideCondition('safeguard')) target.addVolatile('confusion');
|
||||
},
|
||||
onLockMove(pokemon) {
|
||||
onLockMove() {
|
||||
return this.effectState.move;
|
||||
},
|
||||
onMoveAborted(pokemon) {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
charmeleon: {
|
||||
tier: "ZU",
|
||||
tier: "ZUBL",
|
||||
},
|
||||
charizard: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -21,7 +21,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
wartortle: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
blastoise: {
|
||||
tier: "UU",
|
||||
|
|
@ -57,7 +57,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
raticate: {
|
||||
tier: "NU",
|
||||
tier: "PU",
|
||||
},
|
||||
spearow: {
|
||||
tier: "LC",
|
||||
|
|
@ -69,7 +69,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
arbok: {
|
||||
tier: "NU",
|
||||
tier: "PU",
|
||||
},
|
||||
pichu: {
|
||||
tier: "LC",
|
||||
|
|
@ -162,7 +162,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "PU",
|
||||
},
|
||||
diglett: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
dugtrio: {
|
||||
tier: "NU",
|
||||
|
|
@ -192,10 +192,10 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
poliwag: {
|
||||
tier: "ZU",
|
||||
tier: "ZUBL",
|
||||
},
|
||||
poliwhirl: {
|
||||
tier: "ZUBL",
|
||||
tier: "PUBL",
|
||||
},
|
||||
poliwrath: {
|
||||
tier: "NUBL",
|
||||
|
|
@ -237,7 +237,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UUBL",
|
||||
},
|
||||
geodude: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
graveler: {
|
||||
tier: "NU",
|
||||
|
|
@ -246,13 +246,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "OU",
|
||||
},
|
||||
ponyta: {
|
||||
tier: "PU",
|
||||
tier: "ZU",
|
||||
},
|
||||
rapidash: {
|
||||
tier: "NU",
|
||||
},
|
||||
slowpoke: {
|
||||
tier: "ZU",
|
||||
tier: "LC",
|
||||
},
|
||||
slowbro: {
|
||||
tier: "UU",
|
||||
|
|
@ -267,7 +267,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
farfetchd: {
|
||||
tier: "NU",
|
||||
tier: "PU",
|
||||
},
|
||||
doduo: {
|
||||
tier: "ZU",
|
||||
|
|
@ -321,7 +321,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NU",
|
||||
},
|
||||
voltorb: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
electrode: {
|
||||
tier: "UU",
|
||||
|
|
@ -345,10 +345,10 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NU",
|
||||
},
|
||||
hitmonchan: {
|
||||
tier: "PUBL",
|
||||
tier: "PU",
|
||||
},
|
||||
hitmontop: {
|
||||
tier: "PU",
|
||||
tier: "NU",
|
||||
},
|
||||
lickitung: {
|
||||
tier: "NU",
|
||||
|
|
@ -465,7 +465,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "NU",
|
||||
},
|
||||
porygon2: {
|
||||
tier: "UUBL",
|
||||
tier: "(OU)",
|
||||
},
|
||||
omanyte: {
|
||||
tier: "ZU",
|
||||
|
|
@ -513,7 +513,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
bayleef: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
meganium: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -534,13 +534,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "ZU",
|
||||
},
|
||||
feraligatr: {
|
||||
tier: "NUBL",
|
||||
tier: "UU",
|
||||
},
|
||||
sentret: {
|
||||
tier: "LC",
|
||||
},
|
||||
furret: {
|
||||
tier: "PUBL",
|
||||
tier: "PU",
|
||||
},
|
||||
hoothoot: {
|
||||
tier: "LC",
|
||||
|
|
@ -558,7 +558,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
ariados: {
|
||||
tier: "PU",
|
||||
tier: "ZUBL",
|
||||
},
|
||||
chinchou: {
|
||||
tier: "NU",
|
||||
|
|
@ -591,7 +591,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
azumarill: {
|
||||
tier: "NU",
|
||||
tier: "PU",
|
||||
},
|
||||
sudowoodo: {
|
||||
tier: "NU",
|
||||
|
|
@ -645,7 +645,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "OU",
|
||||
},
|
||||
dunsparce: {
|
||||
tier: "NU",
|
||||
tier: "PU",
|
||||
},
|
||||
gligar: {
|
||||
tier: "UU",
|
||||
|
|
@ -699,13 +699,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "PU",
|
||||
},
|
||||
mantine: {
|
||||
tier: "ZU",
|
||||
tier: "ZUBL",
|
||||
},
|
||||
skarmory: {
|
||||
tier: "OU",
|
||||
},
|
||||
houndour: {
|
||||
tier: "NU",
|
||||
tier: "PU",
|
||||
},
|
||||
houndoom: {
|
||||
tier: "UUBL",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
blackbelt: {
|
||||
inherit: true,
|
||||
onModifyAtk() {},
|
||||
onModifyAtk: undefined, // no inherit
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Fighting') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -14,7 +14,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
blackglasses: {
|
||||
inherit: true,
|
||||
onModifySpA() {},
|
||||
onModifySpA: undefined, // no inherit
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Dark') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -31,7 +31,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
charcoal: {
|
||||
inherit: true,
|
||||
onModifySpA() {},
|
||||
onModifySpA: undefined, // no inherit
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Fire') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -40,7 +40,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
dragonfang: {
|
||||
inherit: true,
|
||||
onModifySpA() {},
|
||||
onModifySpA: undefined, // no inherit
|
||||
},
|
||||
dragonscale: {
|
||||
inherit: true,
|
||||
|
|
@ -65,7 +65,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
hardstone: {
|
||||
inherit: true,
|
||||
onModifyAtk() {},
|
||||
onModifyAtk: undefined, // no inherit
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Rock') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -106,7 +106,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
lightball: {
|
||||
inherit: true,
|
||||
// In Gen 2 this happens in stat calculation directly.
|
||||
onModifySpA() {},
|
||||
onModifySpA: undefined, // no inherit
|
||||
},
|
||||
loveball: {
|
||||
inherit: true,
|
||||
|
|
@ -127,7 +127,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
magnet: {
|
||||
inherit: true,
|
||||
onModifySpA() {},
|
||||
onModifySpA: undefined, // no inherit
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Electric') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -136,7 +136,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
metalcoat: {
|
||||
inherit: true,
|
||||
onModifyAtk() {},
|
||||
onModifyAtk: undefined, // no inherit
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Steel') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -146,12 +146,12 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
metalpowder: {
|
||||
inherit: true,
|
||||
// In Gen 2 this happens in stat calculation directly.
|
||||
onModifyDef() {},
|
||||
onModifySpD() {},
|
||||
onModifyDef: undefined, // no inherit
|
||||
onModifySpD: undefined, // no inherit
|
||||
},
|
||||
miracleseed: {
|
||||
inherit: true,
|
||||
onModifySpA() {},
|
||||
onModifySpA: undefined, // no inherit
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Grass') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -164,7 +164,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
mysticwater: {
|
||||
inherit: true,
|
||||
onModifySpA() {},
|
||||
onModifySpA: undefined, // no inherit
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Water') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -173,7 +173,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
nevermeltice: {
|
||||
inherit: true,
|
||||
onModifySpA() {},
|
||||
onModifySpA: undefined, // no inherit
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Ice') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -182,7 +182,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
poisonbarb: {
|
||||
inherit: true,
|
||||
onModifyAtk() {},
|
||||
onModifyAtk: undefined, // no inherit
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Poison') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -191,7 +191,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
sharpbeak: {
|
||||
inherit: true,
|
||||
onModifyAtk() {},
|
||||
onModifyAtk: undefined, // no inherit
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Flying') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -200,7 +200,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
silverpowder: {
|
||||
inherit: true,
|
||||
onModifyAtk() {},
|
||||
onModifyAtk: undefined, // no inherit
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Bug') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -209,7 +209,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
softsand: {
|
||||
inherit: true,
|
||||
onModifyAtk() {},
|
||||
onModifyAtk: undefined, // no inherit
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Ground') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -218,7 +218,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
spelltag: {
|
||||
inherit: true,
|
||||
onModifyAtk() {},
|
||||
onModifyAtk: undefined, // no inherit
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Ghost') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -241,22 +241,22 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
thickclub: {
|
||||
inherit: true,
|
||||
// In Gen 2 this happens in stat calculation directly.
|
||||
onModifyAtk() {},
|
||||
onModifyAtk: undefined, // no inherit
|
||||
},
|
||||
twistedspoon: {
|
||||
inherit: true,
|
||||
onModifySpA() {},
|
||||
onModifySpA: undefined, // no inherit
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Psychic') {
|
||||
return damage * 1.1;
|
||||
}
|
||||
},
|
||||
},
|
||||
berserkgene: {
|
||||
berry: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
},
|
||||
berry: {
|
||||
berserkgene: {
|
||||
inherit: true,
|
||||
isNonstandard: null,
|
||||
},
|
||||
|
|
@ -290,7 +290,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
pinkbow: {
|
||||
inherit: true,
|
||||
onBasePower() {},
|
||||
onBasePower: undefined, // no inherit
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Normal') {
|
||||
return damage * 1.1;
|
||||
|
|
@ -300,7 +300,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
polkadotbow: {
|
||||
inherit: true,
|
||||
onBasePower() {},
|
||||
onBasePower: undefined, // no inherit
|
||||
onModifyDamage(damage, source, target, move) {
|
||||
if (move?.type === 'Normal') {
|
||||
return damage * 1.1;
|
||||
|
|
|
|||
|
|
@ -51,64 +51,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
bide: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
duration: 3,
|
||||
inherit: true,
|
||||
durationCallback(target, source, effect) {
|
||||
return this.random(3, 5);
|
||||
},
|
||||
onLockMove: 'bide',
|
||||
onStart(pokemon) {
|
||||
this.effectState.totalDamage = 0;
|
||||
this.add('-start', pokemon, 'move: Bide');
|
||||
},
|
||||
onDamagePriority: -101,
|
||||
onDamage(damage, target, source, move) {
|
||||
if (!move || move.effectType !== 'Move' || !source) return;
|
||||
this.effectState.totalDamage += damage;
|
||||
this.effectState.lastDamageSource = source;
|
||||
},
|
||||
onBeforeMove(pokemon, target, move) {
|
||||
if (this.effectState.duration === 1) {
|
||||
this.add('-end', pokemon, 'move: Bide');
|
||||
if (!this.effectState.totalDamage) {
|
||||
this.add('-fail', pokemon);
|
||||
return false;
|
||||
}
|
||||
target = this.effectState.lastDamageSource;
|
||||
if (!target) {
|
||||
this.add('-fail', pokemon);
|
||||
return false;
|
||||
}
|
||||
if (!target.isActive) {
|
||||
const possibleTarget = this.getRandomTarget(pokemon, this.dex.moves.get('pound'));
|
||||
if (!possibleTarget) {
|
||||
this.add('-miss', pokemon);
|
||||
return false;
|
||||
}
|
||||
target = possibleTarget;
|
||||
}
|
||||
const moveData = {
|
||||
id: 'bide',
|
||||
name: "Bide",
|
||||
accuracy: 100,
|
||||
damage: this.effectState.totalDamage * 2,
|
||||
category: "Physical",
|
||||
priority: 0,
|
||||
flags: { contact: 1, protect: 1 },
|
||||
effectType: 'Move',
|
||||
type: 'Normal',
|
||||
} as unknown as ActiveMove;
|
||||
this.actions.tryMoveHit(target, pokemon, moveData);
|
||||
pokemon.removeVolatile('bide');
|
||||
return false;
|
||||
}
|
||||
this.add('-activate', pokemon, 'move: Bide');
|
||||
},
|
||||
onMoveAborted(pokemon) {
|
||||
pokemon.removeVolatile('bide');
|
||||
},
|
||||
onEnd(pokemon) {
|
||||
this.add('-end', pokemon, 'move: Bide', '[silent]');
|
||||
},
|
||||
onLockMove: undefined, // no inherit
|
||||
onSemiLockMove: 'bide',
|
||||
},
|
||||
},
|
||||
counter: {
|
||||
|
|
@ -123,8 +71,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
}
|
||||
return false;
|
||||
},
|
||||
beforeTurnCallback() {},
|
||||
onTry() {},
|
||||
beforeTurnCallback: undefined, // no inherit
|
||||
onTry: undefined, // no inherit
|
||||
condition: {},
|
||||
priority: -1,
|
||||
},
|
||||
|
|
@ -139,12 +87,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
curse: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
onStart(pokemon, source) {
|
||||
this.add('-start', pokemon, 'Curse', `[of] ${source}`);
|
||||
},
|
||||
inherit: true,
|
||||
onAfterMoveSelfPriority: 0, // explicit
|
||||
onAfterMoveSelf(pokemon) {
|
||||
this.damage(pokemon.baseMaxhp / 4);
|
||||
},
|
||||
onResidual: undefined, // no inherit
|
||||
},
|
||||
},
|
||||
detect: {
|
||||
|
|
@ -157,10 +105,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
return source.status !== 'slp';
|
||||
},
|
||||
condition: {
|
||||
duration: 2,
|
||||
onImmunity(type, pokemon) {
|
||||
if (type === 'sandstorm') return false;
|
||||
},
|
||||
inherit: true,
|
||||
onInvulnerability(target, source, move) {
|
||||
if (move.id === 'earthquake' || move.id === 'magnitude' || move.id === 'fissure') {
|
||||
return;
|
||||
|
|
@ -172,6 +117,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
if (source.volatiles['lockon'] && target === source.volatiles['lockon'].source) return;
|
||||
return false;
|
||||
},
|
||||
onSourceModifyDamage: undefined, // no inherit
|
||||
onSourceBasePower(basePower, target, source, move) {
|
||||
if (move.id === 'earthquake' || move.id === 'magnitude') {
|
||||
return this.chainModify(2);
|
||||
|
|
@ -186,43 +132,19 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
encore: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
durationCallback() {
|
||||
return this.random(3, 7);
|
||||
},
|
||||
inherit: true,
|
||||
onStart(target) {
|
||||
const lockedMove = target.lastMoveEncore?.id || '';
|
||||
const moveIndex = lockedMove ? target.moves.indexOf(lockedMove) : -1;
|
||||
if (moveIndex < 0 || target.lastMoveEncore?.flags['failencore'] || target.moveSlots[moveIndex].pp <= 0) {
|
||||
const moveSlot = lockedMove ? target.getMoveData(lockedMove) : null;
|
||||
if (!moveSlot || target.lastMoveEncore?.flags['failencore'] || moveSlot.pp <= 0) {
|
||||
// it failed
|
||||
return false;
|
||||
}
|
||||
this.effectState.move = lockedMove;
|
||||
this.add('-start', target, 'Encore');
|
||||
},
|
||||
onOverrideAction(pokemon) {
|
||||
return this.effectState.move;
|
||||
},
|
||||
onResidualOrder: 13,
|
||||
onResidual(target) {
|
||||
const lockedMoveIndex = target.moves.indexOf(this.effectState.move);
|
||||
if (lockedMoveIndex >= 0 && target.moveSlots[lockedMoveIndex].pp <= 0) {
|
||||
// early termination if you run out of PP
|
||||
target.removeVolatile('encore');
|
||||
}
|
||||
},
|
||||
onEnd(target) {
|
||||
this.add('-end', target, 'Encore');
|
||||
},
|
||||
onDisableMove(pokemon) {
|
||||
if (!this.effectState.move || !pokemon.hasMove(this.effectState.move)) {
|
||||
return;
|
||||
}
|
||||
for (const moveSlot of pokemon.moveSlots) {
|
||||
if (moveSlot.id !== this.effectState.move) {
|
||||
pokemon.disableMove(moveSlot.id);
|
||||
}
|
||||
}
|
||||
},
|
||||
onResidualSubOrder: undefined, // no inherit
|
||||
},
|
||||
},
|
||||
endure: {
|
||||
|
|
@ -244,7 +166,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
return source.status !== 'slp';
|
||||
},
|
||||
condition: {
|
||||
duration: 2,
|
||||
inherit: true,
|
||||
onInvulnerability(target, source, move) {
|
||||
if (move.id === 'gust' || move.id === 'twister' || move.id === 'thunder' || move.id === 'whirlwind') {
|
||||
return;
|
||||
|
|
@ -260,6 +182,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
if (source.volatiles['lockon'] && target === source.volatiles['lockon'].source) return;
|
||||
return false;
|
||||
},
|
||||
onSourceModifyDamage: undefined, // no inherit
|
||||
onSourceBasePower(basePower, target, source, move) {
|
||||
if (move.id === 'gust' || move.id === 'twister') {
|
||||
return this.chainModify(2);
|
||||
|
|
@ -270,9 +193,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
focusenergy: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
onStart(pokemon) {
|
||||
this.add('-start', pokemon, 'move: Focus Energy');
|
||||
},
|
||||
inherit: true,
|
||||
onModifyCritRatio(critRatio) {
|
||||
return critRatio + 1;
|
||||
},
|
||||
|
|
@ -284,17 +205,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
if (target.volatiles['foresight']) return false;
|
||||
},
|
||||
condition: {
|
||||
onStart(pokemon) {
|
||||
this.add('-start', pokemon, 'Foresight');
|
||||
},
|
||||
onNegateImmunity(pokemon, type) {
|
||||
if (pokemon.hasType('Ghost') && ['Normal', 'Fighting'].includes(type)) return false;
|
||||
},
|
||||
onModifyBoost(boosts) {
|
||||
if (boosts.evasion && boosts.evasion > 0) {
|
||||
boosts.evasion = 0;
|
||||
}
|
||||
},
|
||||
inherit: true,
|
||||
noCopy: false,
|
||||
},
|
||||
},
|
||||
frustration: {
|
||||
|
|
@ -338,11 +250,10 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
leechseed: {
|
||||
inherit: true,
|
||||
onHit() {},
|
||||
onHit: undefined, // no inherit
|
||||
condition: {
|
||||
onStart(target) {
|
||||
this.add('-start', target, 'move: Leech Seed');
|
||||
},
|
||||
inherit: true,
|
||||
onResidual: undefined, // no inherit
|
||||
onAfterMoveSelfPriority: 2,
|
||||
onAfterMoveSelf(pokemon) {
|
||||
if (!pokemon.hp) return;
|
||||
|
|
@ -378,19 +289,15 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
if (target.volatiles['foresight'] || target.volatiles['lockon']) return false;
|
||||
},
|
||||
condition: {
|
||||
duration: 2,
|
||||
onSourceAccuracy(accuracy, target, source, move) {
|
||||
if (move && source === this.effectState.target && target === this.effectState.source) return true;
|
||||
},
|
||||
inherit: true,
|
||||
onSourceInvulnerability: undefined, // no inherit
|
||||
},
|
||||
},
|
||||
lowkick: {
|
||||
inherit: true,
|
||||
accuracy: 90,
|
||||
basePower: 50,
|
||||
basePowerCallback() {
|
||||
return 50;
|
||||
},
|
||||
basePowerCallback: undefined, // no inherit
|
||||
secondary: {
|
||||
chance: 30,
|
||||
volatileStatus: 'flinch',
|
||||
|
|
@ -427,8 +334,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
}
|
||||
return false;
|
||||
},
|
||||
beforeTurnCallback() {},
|
||||
onTry() {},
|
||||
beforeTurnCallback: undefined, // no inherit
|
||||
onTry: undefined, // no inherit
|
||||
condition: {},
|
||||
priority: -1,
|
||||
},
|
||||
|
|
@ -449,15 +356,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
},
|
||||
mist: {
|
||||
num: 54,
|
||||
accuracy: true,
|
||||
basePower: 0,
|
||||
category: "Status",
|
||||
name: "Mist",
|
||||
pp: 30,
|
||||
priority: 0,
|
||||
flags: { metronome: 1 },
|
||||
inherit: true,
|
||||
volatileStatus: 'mist',
|
||||
sideCondition: undefined, // no inherit
|
||||
condition: {
|
||||
onStart(pokemon) {
|
||||
this.add('-start', pokemon, 'Mist');
|
||||
|
|
@ -478,9 +379,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
}
|
||||
},
|
||||
},
|
||||
secondary: null,
|
||||
target: "self",
|
||||
type: "Ice",
|
||||
},
|
||||
moonlight: {
|
||||
inherit: true,
|
||||
|
|
@ -509,13 +408,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
nightmare: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
noCopy: true,
|
||||
onStart(pokemon) {
|
||||
if (pokemon.status !== 'slp') {
|
||||
return false;
|
||||
}
|
||||
this.add('-start', pokemon, 'Nightmare');
|
||||
},
|
||||
inherit: true,
|
||||
onResidual: undefined, // no inherit
|
||||
onAfterMoveSelfPriority: 1,
|
||||
onAfterMoveSelf(pokemon) {
|
||||
if (pokemon.status === 'slp') this.damage(pokemon.baseMaxhp / 4);
|
||||
|
|
@ -527,11 +421,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
onMoveFail(target, source, move) {
|
||||
source.addVolatile('lockedmove');
|
||||
},
|
||||
onAfterMove(pokemon) {
|
||||
if (pokemon.volatiles['lockedmove'] && pokemon.volatiles['lockedmove'].duration === 1) {
|
||||
pokemon.removeVolatile('lockedmove');
|
||||
}
|
||||
},
|
||||
},
|
||||
painsplit: {
|
||||
inherit: true,
|
||||
|
|
@ -540,16 +429,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
perishsong: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
duration: 4,
|
||||
onEnd(target) {
|
||||
this.add('-start', target, 'perish0');
|
||||
target.faint();
|
||||
},
|
||||
inherit: true,
|
||||
onResidualOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
const duration = pokemon.volatiles['perishsong'].duration;
|
||||
this.add('-start', pokemon, `perish${duration}`);
|
||||
},
|
||||
},
|
||||
},
|
||||
petaldance: {
|
||||
|
|
@ -557,11 +438,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
onMoveFail(target, source, move) {
|
||||
source.addVolatile('lockedmove');
|
||||
},
|
||||
onAfterMove(pokemon) {
|
||||
if (pokemon.volatiles['lockedmove'] && pokemon.volatiles['lockedmove'].duration === 1) {
|
||||
pokemon.removeVolatile('lockedmove');
|
||||
}
|
||||
},
|
||||
},
|
||||
poisongas: {
|
||||
inherit: true,
|
||||
|
|
@ -583,9 +459,18 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
pursuit: {
|
||||
inherit: true,
|
||||
onModifyMove() {},
|
||||
beforeTurnCallback(pokemon, target) {
|
||||
if (pokemon.isAlly(target)) return;
|
||||
target.addVolatile('pursuit');
|
||||
const data = target.volatiles['pursuit'];
|
||||
if (!data.sources) {
|
||||
data.sources = [];
|
||||
}
|
||||
data.sources.push(pokemon);
|
||||
},
|
||||
onModifyMove: undefined, // no inherit
|
||||
condition: {
|
||||
duration: 1,
|
||||
inherit: true,
|
||||
onBeforeSwitchOut(pokemon) {
|
||||
this.debug('Pursuit start');
|
||||
let alreadyAdded = false;
|
||||
|
|
@ -659,7 +544,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
target.statusState.source = target;
|
||||
this.heal(target.maxhp);
|
||||
},
|
||||
secondary: null,
|
||||
},
|
||||
return: {
|
||||
inherit: true,
|
||||
|
|
@ -685,41 +569,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
safeguard: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
duration: 5,
|
||||
durationCallback(target, source, effect) {
|
||||
if (source?.hasAbility('persistent')) {
|
||||
this.add('-activate', source, 'ability: Persistent', effect);
|
||||
return 7;
|
||||
}
|
||||
return 5;
|
||||
},
|
||||
onSetStatus(status, target, source, effect) {
|
||||
if (!effect || !source) return;
|
||||
if (effect.id === 'yawn') return;
|
||||
if (effect.effectType === 'Move' && effect.infiltrates && !target.isAlly(source)) return;
|
||||
if (target !== source) {
|
||||
this.debug('interrupting setStatus');
|
||||
if (effect.id === 'synchronize' || (effect.effectType === 'Move' && !effect.secondaries)) {
|
||||
this.add('-activate', target, 'move: Safeguard');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
},
|
||||
onTryAddVolatile(status, target, source, effect) {
|
||||
if (!effect || !source) return;
|
||||
if (effect.effectType === 'Move' && effect.infiltrates && !target.isAlly(source)) return;
|
||||
if ((status.id === 'confusion' || status.id === 'yawn') && target !== source) {
|
||||
if (effect.effectType === 'Move' && !effect.secondaries) this.add('-activate', target, 'move: Safeguard');
|
||||
return null;
|
||||
}
|
||||
},
|
||||
onSideStart(side) {
|
||||
this.add('-sidestart', side, 'Safeguard');
|
||||
},
|
||||
inherit: true,
|
||||
onSideResidualOrder: 8,
|
||||
onSideEnd(side) {
|
||||
this.add('-sideend', side, 'Safeguard');
|
||||
},
|
||||
},
|
||||
},
|
||||
selfdestruct: {
|
||||
|
|
@ -746,7 +597,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
onPrepareHit(target, source) {
|
||||
return source.status !== 'slp';
|
||||
},
|
||||
secondary: null,
|
||||
secondary: undefined, // no inherit
|
||||
},
|
||||
slash: {
|
||||
inherit: true,
|
||||
|
|
@ -776,7 +627,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
return source.status !== 'slp';
|
||||
},
|
||||
// Rain weakening done directly in the damage formula
|
||||
onBasePower() {},
|
||||
onBasePower: undefined, // no inherit
|
||||
},
|
||||
spiderweb: {
|
||||
inherit: true,
|
||||
|
|
@ -785,31 +636,14 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
spikes: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
// this is a side condition
|
||||
onSideStart(side) {
|
||||
if (!this.effectState.layers || this.effectState.layers === 0) {
|
||||
this.add('-sidestart', side, 'Spikes');
|
||||
this.effectState.layers = 1;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onSwitchIn(pokemon) {
|
||||
if (!pokemon.runImmunity('Ground')) return;
|
||||
const damageAmounts = [0, 3];
|
||||
this.damage(damageAmounts[this.effectState.layers] * pokemon.maxhp / 24);
|
||||
},
|
||||
inherit: true,
|
||||
onSideRestart: undefined, // no inherit
|
||||
},
|
||||
},
|
||||
substitute: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
onStart(target) {
|
||||
this.add('-start', target, 'Substitute');
|
||||
this.effectState.hp = Math.floor(target.maxhp / 4);
|
||||
delete target.volatiles['partiallytrapped'];
|
||||
},
|
||||
onTryPrimaryHitPriority: -1,
|
||||
inherit: true,
|
||||
onTryPrimaryHit(target, source, move) {
|
||||
if (move.stallingMove) {
|
||||
this.add('-fail', source);
|
||||
|
|
@ -846,10 +680,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
if (!damage) {
|
||||
return null;
|
||||
}
|
||||
damage = this.runEvent('SubDamage', target, source, move, damage);
|
||||
if (!damage) {
|
||||
return damage;
|
||||
}
|
||||
if (damage > target.volatiles['substitute'].hp) {
|
||||
damage = target.volatiles['substitute'].hp as number;
|
||||
}
|
||||
|
|
@ -866,9 +696,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
this.runEvent('AfterSubDamage', target, source, move, damage);
|
||||
return this.HIT_SUBSTITUTE;
|
||||
},
|
||||
onEnd(target) {
|
||||
this.add('-end', target, 'Substitute');
|
||||
},
|
||||
},
|
||||
},
|
||||
swagger: {
|
||||
|
|
@ -894,7 +721,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
thief: {
|
||||
inherit: true,
|
||||
onAfterHit() {},
|
||||
onAfterHit: undefined, // no inherit
|
||||
secondary: {
|
||||
chance: 100,
|
||||
onHit(target, source) {
|
||||
|
|
@ -918,11 +745,6 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
onMoveFail(target, source, move) {
|
||||
source.addVolatile('lockedmove');
|
||||
},
|
||||
onAfterMove(pokemon) {
|
||||
if (pokemon.volatiles['lockedmove'] && pokemon.volatiles['lockedmove'].duration === 1) {
|
||||
pokemon.removeVolatile('lockedmove');
|
||||
}
|
||||
},
|
||||
},
|
||||
toxic: {
|
||||
inherit: true,
|
||||
|
|
@ -935,7 +757,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
triattack: {
|
||||
inherit: true,
|
||||
onHit(target, source, move) {
|
||||
move.statusRoll = ['par', 'frz', 'brn'][this.random(3)];
|
||||
move.statusRoll = this.sample(['par', 'frz', 'brn']);
|
||||
},
|
||||
secondary: {
|
||||
chance: 20,
|
||||
|
|
|
|||
|
|
@ -28,7 +28,10 @@ export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable
|
|||
standard: {
|
||||
effectType: 'ValidatorRule',
|
||||
name: 'Standard',
|
||||
ruleset: ['Obtainable', 'Sleep Clause Mod', 'Freeze Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Items Clause', 'Evasion Moves Clause', 'Endless battle Clause', 'HP Percentage Mod', 'Cancel Mod'],
|
||||
ruleset: [
|
||||
'Standard AG',
|
||||
'Sleep Clause Mod', 'Freeze Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Items Clause', 'Evasion Moves Clause',
|
||||
],
|
||||
banlist: [
|
||||
'Hypnosis + Mean Look',
|
||||
'Hypnosis + Spider Web',
|
||||
|
|
|
|||
|
|
@ -125,8 +125,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
}
|
||||
pokemon.lastDamage = 0;
|
||||
let lockedMove = this.battle.runEvent('LockMove', pokemon);
|
||||
if (lockedMove === true) lockedMove = false;
|
||||
const lockedMove = pokemon.getLockedMove() || pokemon.getSemiLockedMove();
|
||||
if (!lockedMove) {
|
||||
if (!pokemon.deductPP(move, null, target) && (move.id !== 'struggle')) {
|
||||
this.battle.add('cant', pokemon, 'nopp', move);
|
||||
|
|
@ -187,10 +186,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
move.ignoreImmunity = (move.category === 'Status');
|
||||
}
|
||||
|
||||
if (
|
||||
(!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) &&
|
||||
!target.runImmunity(move.type, true)
|
||||
) {
|
||||
if (!target.runImmunity(move, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -206,6 +202,11 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (move.ohko && pokemon.level < target.level) {
|
||||
this.battle.add('-immune', target, '[ohko]');
|
||||
return false;
|
||||
}
|
||||
|
||||
let accuracy = move.accuracy;
|
||||
if (move.alwaysHit) {
|
||||
accuracy = true;
|
||||
|
|
@ -216,13 +217,8 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
if (accuracy !== true) {
|
||||
accuracy = Math.floor(accuracy * 255 / 100);
|
||||
if (move.ohko) {
|
||||
if (pokemon.level >= target.level) {
|
||||
accuracy += (pokemon.level - target.level) * 2;
|
||||
accuracy = Math.min(accuracy, 255);
|
||||
} else {
|
||||
this.battle.add('-immune', target, '[ohko]');
|
||||
return false;
|
||||
}
|
||||
accuracy += (pokemon.level - target.level) * 2;
|
||||
accuracy = Math.min(accuracy, 255);
|
||||
}
|
||||
if (!move.ignoreAccuracy) {
|
||||
if (pokemon.boosts.accuracy > 0) {
|
||||
|
|
@ -276,7 +272,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
for (i = 0; i < hits && target.hp && pokemon.hp; i++) {
|
||||
if (pokemon.status === 'slp' && !isSleepUsable) break;
|
||||
move.hit = i + 1;
|
||||
if (move.hit === hits) move.lastHit = true;
|
||||
move.lastHit = move.hit === hits;
|
||||
moveDamage = this.moveHit(target, pokemon, move);
|
||||
if (moveDamage === false) break;
|
||||
if (nullDamage && (moveDamage || moveDamage === 0 || moveDamage === undefined)) nullDamage = false;
|
||||
|
|
@ -296,10 +292,8 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
if (move.ohko) this.battle.add('-ohko');
|
||||
|
||||
if (!move.negateSecondary) {
|
||||
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
|
||||
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
|
||||
}
|
||||
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
|
||||
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
|
||||
|
||||
if (move.recoil && move.totalDamage) {
|
||||
this.battle.damage(this.calcRecoilDamage(move.totalDamage, move, pokemon), pokemon, target, 'recoil');
|
||||
|
|
@ -497,10 +491,8 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
|
||||
// Let's test for immunities.
|
||||
if (!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) {
|
||||
if (!target.runImmunity(move.type, true)) {
|
||||
return false;
|
||||
}
|
||||
if (!target.runImmunity(move, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is it an OHKO move?
|
||||
|
|
|
|||
|
|
@ -1,49 +0,0 @@
|
|||
export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
||||
encore: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
durationCallback() {
|
||||
return this.random(3, 7);
|
||||
},
|
||||
onStart(target) {
|
||||
const lockedMove = target.lastMoveEncore?.id || '';
|
||||
const moveIndex = lockedMove ? target.moves.indexOf(lockedMove) : -1;
|
||||
if (moveIndex < 0 || target.lastMoveEncore?.flags['failencore'] || target.moveSlots[moveIndex].pp <= 0) {
|
||||
// it failed
|
||||
return false;
|
||||
}
|
||||
this.effectState.move = lockedMove;
|
||||
this.add('-start', target, 'Encore');
|
||||
},
|
||||
onOverrideAction(pokemon) {
|
||||
return this.effectState.move;
|
||||
},
|
||||
onModifyMove(move, pokemon) {
|
||||
if (['normal', 'any', 'adjacentFoe'].includes(move.target)) {
|
||||
move.target = 'randomNormal';
|
||||
}
|
||||
},
|
||||
onResidualOrder: 13,
|
||||
onResidual(target) {
|
||||
const lockedMoveIndex = target.moves.indexOf(this.effectState.move);
|
||||
if (lockedMoveIndex >= 0 && target.moveSlots[lockedMoveIndex].pp <= 0) {
|
||||
// early termination if you run out of PP
|
||||
target.removeVolatile('encore');
|
||||
}
|
||||
},
|
||||
onEnd(target) {
|
||||
this.add('-end', target, 'Encore');
|
||||
},
|
||||
onDisableMove(pokemon) {
|
||||
if (!this.effectState.move || !pokemon.hasMove(this.effectState.move)) {
|
||||
return;
|
||||
}
|
||||
for (const moveSlot of pokemon.moveSlots) {
|
||||
if (moveSlot.id !== this.effectState.move) {
|
||||
pokemon.disableMove(moveSlot.id);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
standarddoubles: {
|
||||
effectType: 'ValidatorRule',
|
||||
name: 'Standard Doubles',
|
||||
ruleset: ['Obtainable', 'Sleep Clause Mod', 'Freeze Clause Mod', 'Species Clause', 'OHKO Clause', 'Evasion Moves Clause', 'Endless battle Clause', 'HP Percentage Mod', 'Cancel Mod'],
|
||||
banlist: [
|
||||
'Hypnosis + Mean Look',
|
||||
'Hypnosis + Spider Web',
|
||||
'Lovely Kiss + Mean Look',
|
||||
'Lovely Kiss + Spider Web',
|
||||
'Sing + Mean Look',
|
||||
'Sing + Spider Web',
|
||||
'Sleep Powder + Mean Look',
|
||||
'Sleep Powder + Spider Web',
|
||||
'Spore + Mean Look',
|
||||
'Spore + Spider Web',
|
||||
],
|
||||
},
|
||||
};
|
||||
|
|
@ -1,319 +0,0 @@
|
|||
export const Scripts: ModdedBattleScriptsData = {
|
||||
inherit: 'gen2',
|
||||
gen: 2,
|
||||
pokemon: {
|
||||
inherit: true,
|
||||
getStat(statName, unboosted, unmodified, fastReturn) {
|
||||
// @ts-expect-error type checking prevents 'hp' from being passed, but we're paranoid
|
||||
if (statName === 'hp') throw new Error("Please read `maxhp` directly");
|
||||
|
||||
// base stat
|
||||
let stat = this.storedStats[statName];
|
||||
|
||||
// Stat boosts.
|
||||
if (!unboosted) {
|
||||
let boost = this.boosts[statName];
|
||||
if (boost > 6) boost = 6;
|
||||
if (boost < -6) boost = -6;
|
||||
if (boost >= 0) {
|
||||
const boostTable = [1, 1.5, 2, 2.5, 3, 3.5, 4];
|
||||
stat = Math.floor(stat * boostTable[boost]);
|
||||
} else {
|
||||
const numerators = [100, 66, 50, 40, 33, 28, 25];
|
||||
stat = Math.floor(stat * numerators[-boost] / 100);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.status === 'par' && statName === 'spe') {
|
||||
stat = Math.floor(stat / 4);
|
||||
}
|
||||
|
||||
if (!unmodified) {
|
||||
// Burn attack drop is checked when you get the attack stat upon switch in and used until switch out.
|
||||
if (this.status === 'brn' && statName === 'atk') {
|
||||
stat = Math.floor(stat / 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Gen 2 caps stats at 999 and min is 1.
|
||||
stat = this.battle.clampIntRange(stat, 1, 999);
|
||||
if (fastReturn) return stat;
|
||||
|
||||
// Screens
|
||||
if (!unboosted) {
|
||||
if (
|
||||
(statName === 'def' && this.side.sideConditions['reflect']) ||
|
||||
(statName === 'spd' && this.side.sideConditions['lightscreen'])
|
||||
) {
|
||||
if (this.side.active.length === 1) {
|
||||
stat *= 2;
|
||||
} else {
|
||||
stat *= 1.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle boosting items
|
||||
if (
|
||||
(['Cubone', 'Marowak'].includes(this.baseSpecies.name) && this.item === 'thickclub' && statName === 'atk') ||
|
||||
(this.baseSpecies.name === 'Pikachu' && this.item === 'lightball' && statName === 'spa')
|
||||
) {
|
||||
stat *= 2;
|
||||
} else if (this.baseSpecies.name === 'Ditto' && this.item === 'metalpowder' && ['def', 'spd'].includes(statName)) {
|
||||
stat = Math.floor(stat * 1.5);
|
||||
}
|
||||
|
||||
return stat;
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
inherit: true,
|
||||
getDamage(source, target, move, suppressMessages) {
|
||||
// First of all, we get the move.
|
||||
if (typeof move === 'string') {
|
||||
move = this.dex.getActiveMove(move);
|
||||
} else if (typeof move === 'number') {
|
||||
move = {
|
||||
basePower: move,
|
||||
type: '???',
|
||||
category: 'Physical',
|
||||
willCrit: false,
|
||||
flags: {},
|
||||
} as unknown as ActiveMove;
|
||||
}
|
||||
|
||||
// Let's test for immunities.
|
||||
if (!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) {
|
||||
if (!target.runImmunity(move.type, true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Is it an OHKO move?
|
||||
if (move.ohko) {
|
||||
return target.maxhp;
|
||||
}
|
||||
|
||||
// We edit the damage through move's damage callback
|
||||
if (move.damageCallback) {
|
||||
return move.damageCallback.call(this.battle, source, target);
|
||||
}
|
||||
|
||||
// We take damage from damage=level moves
|
||||
if (move.damage === 'level') {
|
||||
return source.level;
|
||||
}
|
||||
|
||||
// If there's a fix move damage, we run it
|
||||
if (move.damage) {
|
||||
return move.damage;
|
||||
}
|
||||
|
||||
// We check the category and typing to calculate later on the damage
|
||||
move.category = this.battle.getCategory(move);
|
||||
// '???' is typeless damage: used for Struggle and Confusion etc
|
||||
if (!move.type) move.type = '???';
|
||||
const type = move.type;
|
||||
|
||||
// We get the base power and apply basePowerCallback if necessary
|
||||
let basePower: number | false | null | undefined = move.basePower;
|
||||
if (move.basePowerCallback) {
|
||||
basePower = move.basePowerCallback.call(this.battle, source, target, move);
|
||||
}
|
||||
|
||||
// We check for Base Power
|
||||
if (!basePower) {
|
||||
if (basePower === 0) return; // Returning undefined means not dealing damage
|
||||
return basePower;
|
||||
}
|
||||
basePower = this.battle.clampIntRange(basePower, 1);
|
||||
|
||||
// Checking for the move's Critical Hit ratio
|
||||
let critRatio = this.battle.runEvent('ModifyCritRatio', source, target, move, move.critRatio || 0);
|
||||
critRatio = this.battle.clampIntRange(critRatio, 0, 5);
|
||||
const critMult = [0, 17, 32, 64, 85, 128];
|
||||
let isCrit = move.willCrit || false;
|
||||
if (typeof move.willCrit === 'undefined') {
|
||||
if (critRatio) {
|
||||
isCrit = this.battle.random(256) < critMult[critRatio];
|
||||
}
|
||||
}
|
||||
|
||||
if (isCrit && this.battle.runEvent('CriticalHit', target, null, move)) {
|
||||
target.getMoveHitData(move).crit = true;
|
||||
}
|
||||
|
||||
// Happens after crit calculation
|
||||
if (basePower) {
|
||||
// confusion damage
|
||||
if (move.isConfusionSelfHit) {
|
||||
move.type = move.baseMoveType!;
|
||||
basePower = this.battle.runEvent('BasePower', source, target, move, basePower, true);
|
||||
move.type = '???';
|
||||
} else {
|
||||
basePower = this.battle.runEvent('BasePower', source, target, move, basePower, true);
|
||||
}
|
||||
if (basePower && move.basePowerModifier) {
|
||||
basePower *= move.basePowerModifier;
|
||||
}
|
||||
}
|
||||
if (!basePower) return 0;
|
||||
basePower = this.battle.clampIntRange(basePower, 1);
|
||||
|
||||
// We now check for attacker and defender
|
||||
let level = source.level;
|
||||
|
||||
// Using Beat Up
|
||||
if (move.allies) {
|
||||
this.battle.add('-activate', source, 'move: Beat Up', '[of] ' + move.allies[0].name);
|
||||
level = move.allies[0].level;
|
||||
}
|
||||
|
||||
const attacker = move.overrideOffensivePokemon === 'target' ? target : source;
|
||||
const defender = move.overrideDefensivePokemon === 'source' ? source : target;
|
||||
|
||||
const isPhysical = move.category === 'Physical';
|
||||
const atkType: StatIDExceptHP = move.overrideOffensiveStat || (isPhysical ? 'atk' : 'spa');
|
||||
const defType: StatIDExceptHP = move.overrideDefensiveStat || (isPhysical ? 'def' : 'spd');
|
||||
|
||||
let unboosted = false;
|
||||
let noburndrop = false;
|
||||
|
||||
if (isCrit) {
|
||||
if (!suppressMessages) this.battle.add('-crit', target);
|
||||
// Stat level modifications are ignored if they are neutral to or favour the defender.
|
||||
// Reflect and Light Screen defensive boosts are only ignored if stat level modifications were also ignored as a result of that.
|
||||
if (attacker.boosts[atkType] <= defender.boosts[defType]) {
|
||||
unboosted = true;
|
||||
noburndrop = true;
|
||||
}
|
||||
}
|
||||
|
||||
let attack = attacker.getStat(atkType, unboosted, noburndrop);
|
||||
let defense = defender.getStat(defType, unboosted);
|
||||
|
||||
// Using Beat Up
|
||||
if (move.allies) {
|
||||
attack = move.allies[0].species.baseStats.atk;
|
||||
move.allies.shift();
|
||||
defense = defender.species.baseStats.def;
|
||||
}
|
||||
|
||||
// Moves that ignore offense and defense respectively.
|
||||
if (move.ignoreOffensive) {
|
||||
this.battle.debug('Negating (sp)atk boost/penalty.');
|
||||
// The attack drop from the burn is only applied when attacker's attack level is higher than defender's defense level.
|
||||
attack = attacker.getStat(atkType, true, true);
|
||||
}
|
||||
|
||||
if (move.ignoreDefensive) {
|
||||
this.battle.debug('Negating (sp)def boost/penalty.');
|
||||
defense = target.getStat(defType, true, true);
|
||||
}
|
||||
|
||||
if (move.id === 'present') {
|
||||
const typeIndexes: { [k: string]: number } = {
|
||||
Normal: 0, Fighting: 1, Flying: 2, Poison: 3, Ground: 4, Rock: 5, Bug: 7, Ghost: 8, Steel: 9,
|
||||
Fire: 20, Water: 21, Grass: 22, Electric: 23, Psychic: 24, Ice: 25, Dragon: 26, Dark: 27,
|
||||
};
|
||||
attack = 10;
|
||||
|
||||
const attackerLastType = attacker.getTypes().slice(-1)[0];
|
||||
const defenderLastType = defender.getTypes().slice(-1)[0];
|
||||
|
||||
defense = typeIndexes[attackerLastType] || 1;
|
||||
level = typeIndexes[defenderLastType] || 1;
|
||||
this.battle.hint("Gen 2 Present has a glitched damage calculation using the secondary types of the Pokemon for the Attacker's Level and Defender's Defense.", true);
|
||||
}
|
||||
|
||||
// When either attack or defense are higher than 256, they are both divided by 4 and modded by 256.
|
||||
// This is what causes the rollover bugs.
|
||||
if (attack >= 256 || defense >= 256) {
|
||||
if (attack >= 1024 || defense >= 1024) {
|
||||
this.battle.hint("In Gen 2, a stat will roll over to a small number if it is larger than 1024.");
|
||||
}
|
||||
attack = this.battle.clampIntRange(Math.floor(attack / 4) % 256, 1);
|
||||
defense = this.battle.clampIntRange(Math.floor(defense / 4) % 256, 1);
|
||||
}
|
||||
|
||||
// Self destruct moves halve defense at this point.
|
||||
if (move.selfdestruct && defType === 'def') {
|
||||
defense = this.battle.clampIntRange(Math.floor(defense / 2), 1);
|
||||
}
|
||||
|
||||
// Let's go with the calculation now that we have what we need.
|
||||
// We do it step by step just like the game does.
|
||||
let damage = level * 2;
|
||||
damage = Math.floor(damage / 5);
|
||||
damage += 2;
|
||||
damage *= basePower;
|
||||
damage *= attack;
|
||||
damage = Math.floor(damage / defense);
|
||||
damage = Math.floor(damage / 50);
|
||||
if (isCrit) damage *= 2;
|
||||
damage = Math.floor(this.battle.runEvent('ModifyDamage', attacker, defender, move, damage));
|
||||
damage = this.battle.clampIntRange(damage, 1, 997);
|
||||
damage += 2;
|
||||
|
||||
// Weather modifiers
|
||||
if (
|
||||
(type === 'Water' && this.battle.field.isWeather('raindance')) ||
|
||||
(type === 'Fire' && this.battle.field.isWeather('sunnyday'))
|
||||
) {
|
||||
damage = Math.floor(damage * 1.5);
|
||||
} else if (
|
||||
((type === 'Fire' || move.id === 'solarbeam') && this.battle.field.isWeather('raindance')) ||
|
||||
(type === 'Water' && this.battle.field.isWeather('sunnyday'))
|
||||
) {
|
||||
damage = Math.floor(damage / 2);
|
||||
}
|
||||
|
||||
// STAB damage bonus, the "???" type never gets STAB
|
||||
if (type !== '???' && source.hasType(type)) {
|
||||
damage += Math.floor(damage / 2);
|
||||
}
|
||||
|
||||
// Type effectiveness
|
||||
const totalTypeMod = target.runEffectiveness(move);
|
||||
// Super effective attack
|
||||
if (totalTypeMod > 0) {
|
||||
if (!suppressMessages) this.battle.add('-supereffective', target);
|
||||
damage *= 2;
|
||||
if (totalTypeMod >= 2) {
|
||||
damage *= 2;
|
||||
}
|
||||
}
|
||||
// Resisted attack
|
||||
if (totalTypeMod < 0) {
|
||||
if (!suppressMessages) this.battle.add('-resisted', target);
|
||||
damage = Math.floor(damage / 2);
|
||||
if (totalTypeMod <= -2) {
|
||||
damage = Math.floor(damage / 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Attempting to add correct spread damage nerf
|
||||
const { targets } = source.getMoveTargets(move, target);
|
||||
if (targets.length > 1) move.spreadHit = true;
|
||||
if (move.spreadHit && move.target === 'allAdjacentFoes') {
|
||||
const spreadModifier = move.spreadModifier || 0.5;
|
||||
this.battle.debug(`Spread modifier: ${spreadModifier}`);
|
||||
damage = this.battle.modify(damage, spreadModifier);
|
||||
}
|
||||
|
||||
// Apply random factor if damage is greater than 1, except for Flail and Reversal
|
||||
if (!move.noDamageVariance && damage > 1) {
|
||||
damage *= this.battle.random(217, 256);
|
||||
damage = Math.floor(damage / 255);
|
||||
}
|
||||
|
||||
// If damage is less than 1, we return 1
|
||||
if (basePower && !Math.floor(damage)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// We are done, this is the final damage
|
||||
return damage;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -10,6 +10,6 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
dragonscale: {
|
||||
inherit: true,
|
||||
onModifyDamage() {},
|
||||
onModifyDamage: undefined, // no inherit
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,8 +1,17 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
standardag: {
|
||||
inherit: true,
|
||||
ruleset: [
|
||||
'Obtainable', 'Team Preview', 'Exact HP Mod', 'Cancel Mod', 'Beat Up Nicknames Mod',
|
||||
],
|
||||
},
|
||||
standard: {
|
||||
effectType: 'ValidatorRule',
|
||||
name: 'Standard',
|
||||
ruleset: ['Obtainable', 'Team Preview', 'Stadium Sleep Clause', 'Freeze Clause Mod', 'Self-KO Clause', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'Exact HP Mod', 'Cancel Mod', 'Stadium Items Clause'],
|
||||
ruleset: [
|
||||
'Standard AG',
|
||||
'Stadium Sleep Clause', 'Freeze Clause Mod', 'Self-KO Clause', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Moves Clause', 'Stadium Items Clause',
|
||||
],
|
||||
},
|
||||
selfkoclause: {
|
||||
effectType: 'Rule',
|
||||
|
|
|
|||
|
|
@ -122,10 +122,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
move.ignoreImmunity = (move.category === 'Status');
|
||||
}
|
||||
|
||||
if (
|
||||
(!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) &&
|
||||
!target.runImmunity(move.type, true)
|
||||
) {
|
||||
if (!target.runImmunity(move, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -211,7 +208,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
for (i = 0; i < hits && target.hp && pokemon.hp; i++) {
|
||||
if (pokemon.status === 'slp' && !isSleepUsable) break;
|
||||
move.hit = i + 1;
|
||||
if (move.hit === hits) move.lastHit = true;
|
||||
move.lastHit = move.hit === hits;
|
||||
moveDamage = this.moveHit(target, pokemon, move);
|
||||
if (moveDamage === false) break;
|
||||
if (nullDamage && (moveDamage || moveDamage === 0 || moveDamage === undefined)) nullDamage = false;
|
||||
|
|
@ -231,10 +228,8 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
if (move.ohko) this.battle.add('-ohko');
|
||||
|
||||
if (!move.negateSecondary) {
|
||||
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
|
||||
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
|
||||
}
|
||||
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
|
||||
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
|
||||
// Implementing Recoil mechanics from Stadium 2.
|
||||
// If a pokemon caused the other to faint with a recoil move and only one pokemon remains on both sides,
|
||||
// recoil damage will not be taken.
|
||||
|
|
@ -258,10 +253,8 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
}
|
||||
|
||||
// Let's test for immunities.
|
||||
if (!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) {
|
||||
if (!target.runImmunity(move.type, true)) {
|
||||
return false;
|
||||
}
|
||||
if (!target.runImmunity(move, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is it an OHKO move?
|
||||
|
|
|
|||
|
|
@ -12,15 +12,9 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
effectspore: {
|
||||
inherit: true,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (damage && move.flags['contact'] && !source.status) {
|
||||
const r = this.random(300);
|
||||
if (r < 10) {
|
||||
source.setStatus('slp', target);
|
||||
} else if (r < 20) {
|
||||
source.setStatus('par', target);
|
||||
} else if (r < 30) {
|
||||
source.setStatus('psn', target);
|
||||
}
|
||||
if (damage && move.flags['contact'] && this.randomChance(1, 10)) {
|
||||
const status = this.sample(['slp', 'par', 'psn']);
|
||||
source.trySetStatus(status, target);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
@ -91,6 +85,8 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
},
|
||||
},
|
||||
lightningrod: {
|
||||
inherit: true,
|
||||
onAnyRedirectTarget: undefined, // no inherit
|
||||
onFoeRedirectTarget(target, source, source2, move) {
|
||||
// don't count Hidden Power as Electric-type
|
||||
if (this.dex.moves.get(move.id).type !== 'Electric') return;
|
||||
|
|
@ -98,10 +94,23 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
return this.effectState.target;
|
||||
}
|
||||
},
|
||||
flags: { breakable: 1 },
|
||||
name: "Lightning Rod",
|
||||
rating: 0,
|
||||
num: 32,
|
||||
},
|
||||
magnetpull: {
|
||||
inherit: true,
|
||||
onFoeTrapPokemon: undefined, // no inherit
|
||||
onFoeMaybeTrapPokemon: undefined, // no inherit
|
||||
onAnyTrapPokemon(pokemon) {
|
||||
if (pokemon.hasType('Steel') && pokemon.isAdjacent(this.effectState.target)) {
|
||||
pokemon.tryTrap(true);
|
||||
}
|
||||
},
|
||||
onAnyMaybeTrapPokemon(pokemon, source) {
|
||||
if (!source) source = this.effectState.target;
|
||||
if (!source || !pokemon.isAdjacent(source)) return;
|
||||
if (!pokemon.knownType || pokemon.hasType('Steel')) {
|
||||
pokemon.maybeTrapped = true;
|
||||
}
|
||||
},
|
||||
},
|
||||
minus: {
|
||||
inherit: true,
|
||||
|
|
@ -141,7 +150,7 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
},
|
||||
raindish: {
|
||||
inherit: true,
|
||||
onWeather() {},
|
||||
onWeather: undefined, // no inherit
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 3,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -176,20 +185,18 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
|
|||
},
|
||||
trace: {
|
||||
inherit: true,
|
||||
onUpdate() {},
|
||||
onUpdate: undefined, // no inherit
|
||||
onStart(pokemon) {
|
||||
const target = pokemon.side.randomFoe();
|
||||
if (!target || target.fainted) return;
|
||||
const ability = target.getAbility();
|
||||
if (pokemon.setAbility(ability)) {
|
||||
this.add('-ability', pokemon, ability, '[from] ability: Trace', `[of] ${target}`);
|
||||
}
|
||||
pokemon.setAbility(ability, target);
|
||||
},
|
||||
flags: {},
|
||||
},
|
||||
truant: {
|
||||
inherit: true,
|
||||
onStart() {},
|
||||
onStart: undefined, // no inherit
|
||||
onSwitchIn(pokemon) {
|
||||
pokemon.truantTurn = this.turn !== 0;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -51,6 +51,6 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa
|
|||
},
|
||||
sandstorm: {
|
||||
inherit: true,
|
||||
onModifySpD() {},
|
||||
onModifySpD: undefined, // no inherit
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
ivysaur: {
|
||||
tier: "PU",
|
||||
tier: "ZU",
|
||||
},
|
||||
venusaur: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -21,7 +21,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
wartortle: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
blastoise: {
|
||||
tier: "UU",
|
||||
|
|
@ -63,7 +63,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
fearow: {
|
||||
tier: "UU",
|
||||
tier: "RUBL",
|
||||
},
|
||||
ekans: {
|
||||
tier: "LC",
|
||||
|
|
@ -312,7 +312,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "ZU",
|
||||
},
|
||||
hypno: {
|
||||
tier: "UU",
|
||||
tier: "RU",
|
||||
},
|
||||
krabby: {
|
||||
tier: "LC",
|
||||
|
|
@ -465,7 +465,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "ZU",
|
||||
},
|
||||
porygon2: {
|
||||
tier: "UUBL",
|
||||
tier: "(OU)",
|
||||
},
|
||||
omanyte: {
|
||||
tier: "PU",
|
||||
|
|
@ -732,7 +732,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UUBL",
|
||||
},
|
||||
raikou: {
|
||||
tier: "UUBL",
|
||||
tier: "(OU)",
|
||||
},
|
||||
entei: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -762,7 +762,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
grovyle: {
|
||||
tier: "PU",
|
||||
tier: "ZU",
|
||||
},
|
||||
sceptile: {
|
||||
tier: "UUBL",
|
||||
|
|
@ -879,7 +879,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "RUBL",
|
||||
},
|
||||
shedinja: {
|
||||
tier: "ZUBL",
|
||||
tier: "PU",
|
||||
},
|
||||
whismur: {
|
||||
tier: "LC",
|
||||
|
|
@ -924,13 +924,13 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "ZU",
|
||||
},
|
||||
medicham: {
|
||||
tier: "UUBL",
|
||||
tier: "OU",
|
||||
},
|
||||
electrike: {
|
||||
tier: "LC",
|
||||
},
|
||||
manectric: {
|
||||
tier: "UU",
|
||||
tier: "RU",
|
||||
},
|
||||
plusle: {
|
||||
tier: "NU",
|
||||
|
|
@ -1056,13 +1056,10 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "ZU",
|
||||
},
|
||||
castformsunny: {
|
||||
tier: "ZU",
|
||||
},
|
||||
castformrainy: {
|
||||
tier: "ZU",
|
||||
},
|
||||
castformsnowy: {
|
||||
tier: "ZU",
|
||||
},
|
||||
kecleon: {
|
||||
tier: "NU",
|
||||
|
|
@ -1092,7 +1089,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "LC",
|
||||
},
|
||||
glalie: {
|
||||
tier: "NU",
|
||||
tier: "NUBL",
|
||||
},
|
||||
spheal: {
|
||||
tier: "LC",
|
||||
|
|
@ -1104,7 +1101,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UU",
|
||||
},
|
||||
clamperl: {
|
||||
tier: "ZU",
|
||||
tier: "PU",
|
||||
},
|
||||
huntail: {
|
||||
tier: "NU",
|
||||
|
|
@ -1140,7 +1137,7 @@ export const FormatsData: import('../../../sim/dex-species').ModdedSpeciesFormat
|
|||
tier: "UUBL",
|
||||
},
|
||||
regice: {
|
||||
tier: "UUBL",
|
||||
tier: "(OU)",
|
||||
},
|
||||
registeel: {
|
||||
tier: "UUBL",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
||||
aguavberry: {
|
||||
inherit: true,
|
||||
onUpdate() {},
|
||||
onUpdate: undefined, // no inherit
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -12,7 +12,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
apicotberry: {
|
||||
inherit: true,
|
||||
onUpdate() {},
|
||||
onUpdate: undefined, // no inherit
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -23,7 +23,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
berryjuice: {
|
||||
inherit: true,
|
||||
onUpdate() {},
|
||||
onUpdate: undefined, // no inherit
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -37,7 +37,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
blackbelt: {
|
||||
inherit: true,
|
||||
onBasePower() {},
|
||||
onBasePower: undefined, // no inherit
|
||||
onModifyAtkPriority: 1,
|
||||
onModifyAtk(atk, user, target, move) {
|
||||
if (move?.type === 'Fighting') {
|
||||
|
|
@ -47,7 +47,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
blackglasses: {
|
||||
inherit: true,
|
||||
onBasePower() {},
|
||||
onBasePower: undefined, // no inherit
|
||||
onModifySpAPriority: 1,
|
||||
onModifySpA(spa, user, target, move) {
|
||||
if (move?.type === 'Dark') {
|
||||
|
|
@ -57,7 +57,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
charcoal: {
|
||||
inherit: true,
|
||||
onBasePower() {},
|
||||
onBasePower: undefined, // no inherit
|
||||
onModifySpAPriority: 1,
|
||||
onModifySpA(spa, user, target, move) {
|
||||
if (move?.type === 'Fire') {
|
||||
|
|
@ -67,7 +67,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
dragonfang: {
|
||||
inherit: true,
|
||||
onBasePower() {},
|
||||
onBasePower: undefined, // no inherit
|
||||
onModifySpAPriority: 1,
|
||||
onModifySpA(spa, user, target, move) {
|
||||
if (move?.type === 'Dragon') {
|
||||
|
|
@ -82,6 +82,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
num: 208,
|
||||
gen: 3,
|
||||
isNonstandard: "Unobtainable",
|
||||
// No competitive use
|
||||
},
|
||||
fastball: {
|
||||
inherit: true,
|
||||
|
|
@ -89,7 +90,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
figyberry: {
|
||||
inherit: true,
|
||||
onUpdate() {},
|
||||
onUpdate: undefined, // no inherit
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -100,7 +101,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
ganlonberry: {
|
||||
inherit: true,
|
||||
onUpdate() {},
|
||||
onUpdate: undefined, // no inherit
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -111,7 +112,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
hardstone: {
|
||||
inherit: true,
|
||||
onBasePower() {},
|
||||
onBasePower: undefined, // no inherit
|
||||
onModifyAtkPriority: 1,
|
||||
onModifyAtk(atk, user, target, move) {
|
||||
if (move?.type === 'Rock') {
|
||||
|
|
@ -125,7 +126,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
iapapaberry: {
|
||||
inherit: true,
|
||||
onUpdate() {},
|
||||
onUpdate: undefined, // no inherit
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -138,8 +139,8 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
inherit: true,
|
||||
onModifyMove(move) {
|
||||
const affectedByKingsRock = [
|
||||
'aerialace', 'aeroblast', 'aircutter', 'armthrust', 'barrage', 'beatup', 'bide', 'bind', 'blastburn', 'bonerush', 'bonemerang', 'bounce', 'brickbreak', 'bulletseed', 'clamp', 'cometpunch', 'crabhammer', 'crosschop', 'cut', 'dig', 'dive', 'doublekick', 'doubleslap', 'doubleedge', 'dragonbreath', 'dragonclaw', 'dragonrage', 'drillpeck', 'earthquake', 'eggbomb', 'endeavor', 'eruption', 'explosion', 'extremespeed', 'falseswipe', 'feintattack', 'firespin', 'flail', 'fly', 'frenzyplant', 'frustration', 'furyattack', 'furycutter', 'furyswipes', 'gust', 'hiddenpower', 'highjumpkick', 'hornattack', 'hydrocannon', 'hydropump', 'hyperbeam', 'iceball', 'iciclespear', 'jumpkick', 'karatechop', 'leafblade', 'lowkick', 'machpunch', 'magicalleaf', 'magnitude', 'megakick', 'megapunch', 'megahorn', 'meteormash', 'mudshot', 'muddywater', 'nightshade', 'outrage', 'overheat', 'payday', 'peck', 'petaldance', 'pinmissile', 'poisontail', 'pound', 'psychoboost', 'psywave', 'quickattack', 'rage', 'rapidspin', 'razorleaf', 'razorwind', 'return', 'revenge', 'reversal', 'rockblast', 'rockthrow', 'rollingkick', 'rollout', 'sandtomb', 'scratch', 'seismictoss', 'selfdestruct', 'shadowpunch', 'shockwave', 'signalbeam', 'silverwind', 'skullbash', 'skyattack', 'skyuppercut', 'slam', 'slash', 'snore', 'solarbeam', 'sonicboom', 'spikecannon', 'spitup', 'steelwing', 'strength', 'struggle', 'submission', 'surf', 'swift', 'tackle', 'takedown', 'thrash', 'tickle', 'triplekick', 'twister', 'uproar', 'visegrip', 'vinewhip', 'vitalthrow', 'volttackle', 'watergun', 'waterpulse', 'waterfall', 'weatherball', 'whirlpool', 'wingattack', 'wrap',
|
||||
];
|
||||
'aerialace', 'aeroblast', 'aircutter', 'armthrust', 'barrage', 'beatup', 'bide', 'bind', 'blastburn', 'bonerush', 'bonemerang', 'bounce', 'brickbreak', 'bulletseed', 'clamp', 'cometpunch', 'crabhammer', 'crosschop', 'cut', 'dig', 'dive', 'doublekick', 'doubleslap', 'doubleedge', 'dragonbreath', 'dragonclaw', 'dragonrage', 'drillpeck', 'earthquake', 'eggbomb', 'endeavor', 'eruption', 'explosion', 'extremespeed', 'falseswipe', 'feintattack', 'firespin', 'flail', 'fly', 'frenzyplant', 'frustration', 'furyattack', 'furycutter', 'furyswipes', 'gust', 'hiddenpower', 'highjumpkick', 'hornattack', 'hydrocannon', 'hydropump', 'hyperbeam', 'iceball', 'iciclespear', 'jumpkick', 'karatechop', 'leafblade', 'lowkick', 'machpunch', 'magicalleaf', 'magnitude', 'megakick', 'megapunch', 'megahorn', 'meteormash', 'mudshot', 'muddywater', 'nightshade', 'outrage', 'overheat', 'payday', 'peck', 'petaldance', 'pinmissile', 'poisontail', 'pound', 'psychoboost', 'psywave', 'quickattack', 'rage', 'rapidspin', 'razorleaf', 'razorwind', 'return', 'revenge', 'reversal', 'rockblast', 'rockthrow', 'rollingkick', 'rollout', 'sandtomb', 'scratch', 'seismictoss', 'selfdestruct', 'shadowpunch', 'shockwave', 'signalbeam', 'silverwind', 'skullbash', 'skyattack', 'skyuppercut', 'slam', 'slash', 'snore', 'solarbeam', 'sonicboom', 'spikecannon', 'spitup', 'steelwing', 'strength', 'struggle', 'submission', 'surf', 'swift', 'tackle', 'takedown', 'thrash', 'triplekick', 'twister', 'uproar', 'visegrip', 'vinewhip', 'vitalthrow', 'volttackle', 'watergun', 'waterpulse', 'waterfall', 'weatherball', 'whirlpool', 'wingattack', 'wrap',
|
||||
]; // Tickle also has the move flag, but can never flinch because King's Rock requires damage to trigger
|
||||
if (affectedByKingsRock.includes(move.id)) {
|
||||
if (!move.secondaries) move.secondaries = [];
|
||||
move.secondaries.push({
|
||||
|
|
@ -151,7 +152,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
lansatberry: {
|
||||
inherit: true,
|
||||
onUpdate() {},
|
||||
onUpdate: undefined, // no inherit
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -174,7 +175,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
liechiberry: {
|
||||
inherit: true,
|
||||
onUpdate() {},
|
||||
onUpdate: undefined, // no inherit
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -190,7 +191,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
return this.chainModify(2);
|
||||
}
|
||||
},
|
||||
onBasePower() {},
|
||||
onBasePower: undefined, // no inherit
|
||||
},
|
||||
loveball: {
|
||||
inherit: true,
|
||||
|
|
@ -202,7 +203,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
magnet: {
|
||||
inherit: true,
|
||||
onBasePower() {},
|
||||
onBasePower: undefined, // no inherit
|
||||
onModifySpAPriority: 1,
|
||||
onModifySpA(spa, user, target, move) {
|
||||
if (move?.type === 'Electric') {
|
||||
|
|
@ -212,7 +213,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
magoberry: {
|
||||
inherit: true,
|
||||
onUpdate() {},
|
||||
onUpdate: undefined, // no inherit
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -223,7 +224,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
metalcoat: {
|
||||
inherit: true,
|
||||
onBasePower() {},
|
||||
onBasePower: undefined, // no inherit
|
||||
onModifyAtkPriority: 1,
|
||||
onModifyAtk(atk, user, target, move) {
|
||||
if (move?.type === 'Steel') {
|
||||
|
|
@ -233,7 +234,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
miracleseed: {
|
||||
inherit: true,
|
||||
onBasePower() {},
|
||||
onBasePower: undefined, // no inherit
|
||||
onModifySpAPriority: 1,
|
||||
onModifySpA(spa, user, target, move) {
|
||||
if (move?.type === 'Grass') {
|
||||
|
|
@ -247,7 +248,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
mysticwater: {
|
||||
inherit: true,
|
||||
onBasePower() {},
|
||||
onBasePower: undefined, // no inherit
|
||||
onModifySpAPriority: 1,
|
||||
onModifySpA(spa, user, target, move) {
|
||||
if (move?.type === 'Water') {
|
||||
|
|
@ -257,7 +258,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
nevermeltice: {
|
||||
inherit: true,
|
||||
onBasePower() {},
|
||||
onBasePower: undefined, // no inherit
|
||||
onModifySpAPriority: 1,
|
||||
onModifySpA(spa, user, target, move) {
|
||||
if (move?.type === 'Ice') {
|
||||
|
|
@ -267,7 +268,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
oranberry: {
|
||||
inherit: true,
|
||||
onUpdate() {},
|
||||
onUpdate: undefined, // no inherit
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -278,7 +279,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
petayaberry: {
|
||||
inherit: true,
|
||||
onUpdate() {},
|
||||
onUpdate: undefined, // no inherit
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -289,7 +290,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
poisonbarb: {
|
||||
inherit: true,
|
||||
onBasePower() {},
|
||||
onBasePower: undefined, // no inherit
|
||||
onModifyAtkPriority: 1,
|
||||
onModifyAtk(atk, user, target, move) {
|
||||
if (move?.type === 'Poison') {
|
||||
|
|
@ -299,12 +300,12 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
quickclaw: {
|
||||
inherit: true,
|
||||
onFractionalPriority() {},
|
||||
onFractionalPriority: undefined, // no inherit
|
||||
// implemented in Pokemon#getActionSpeed()
|
||||
},
|
||||
salacberry: {
|
||||
inherit: true,
|
||||
onUpdate() {},
|
||||
onUpdate: undefined, // no inherit
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -315,7 +316,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
seaincense: {
|
||||
inherit: true,
|
||||
onBasePower() {},
|
||||
onBasePower: undefined, // no inherit
|
||||
onModifySpAPriority: 1,
|
||||
onModifySpA(spa, user, target, move) {
|
||||
if (move?.type === 'Water') {
|
||||
|
|
@ -325,7 +326,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
sharpbeak: {
|
||||
inherit: true,
|
||||
onBasePower() {},
|
||||
onBasePower: undefined, // no inherit
|
||||
onModifyAtkPriority: 1,
|
||||
onModifyAtk(atk, user, target, move) {
|
||||
if (move?.type === 'Flying') {
|
||||
|
|
@ -335,7 +336,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
silkscarf: {
|
||||
inherit: true,
|
||||
onBasePower() {},
|
||||
onBasePower: undefined, // no inherit
|
||||
onModifyAtkPriority: 1,
|
||||
onModifyAtk(atk, user, target, move) {
|
||||
if (move?.type === 'Normal') {
|
||||
|
|
@ -345,7 +346,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
silverpowder: {
|
||||
inherit: true,
|
||||
onBasePower() {},
|
||||
onBasePower: undefined, // no inherit
|
||||
onModifyAtkPriority: 1,
|
||||
onModifyAtk(atk, user, target, move) {
|
||||
if (move?.type === 'Bug') {
|
||||
|
|
@ -355,7 +356,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
sitrusberry: {
|
||||
inherit: true,
|
||||
onUpdate() {},
|
||||
onUpdate: undefined, // no inherit
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -369,7 +370,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
softsand: {
|
||||
inherit: true,
|
||||
onBasePower() {},
|
||||
onBasePower: undefined, // no inherit
|
||||
onModifyAtkPriority: 1,
|
||||
onModifyAtk(atk, user, target, move) {
|
||||
if (move?.type === 'Ground') {
|
||||
|
|
@ -379,7 +380,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
spelltag: {
|
||||
inherit: true,
|
||||
onBasePower() {},
|
||||
onBasePower: undefined, // no inherit
|
||||
onModifyAtkPriority: 1,
|
||||
onModifyAtk(atk, user, target, move) {
|
||||
if (move?.type === 'Ghost') {
|
||||
|
|
@ -393,7 +394,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
starfberry: {
|
||||
inherit: true,
|
||||
onUpdate() {},
|
||||
onUpdate: undefined, // no inherit
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
@ -404,7 +405,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
twistedspoon: {
|
||||
inherit: true,
|
||||
onBasePower() {},
|
||||
onBasePower: undefined, // no inherit
|
||||
onModifySpAPriority: 1,
|
||||
onModifySpA(spa, user, target, move) {
|
||||
if (move?.type === 'Psychic') {
|
||||
|
|
@ -414,7 +415,7 @@ export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
|||
},
|
||||
wikiberry: {
|
||||
inherit: true,
|
||||
onUpdate() {},
|
||||
onUpdate: undefined, // no inherit
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 4,
|
||||
onResidual(pokemon) {
|
||||
|
|
|
|||
|
|
@ -26,10 +26,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
astonish: {
|
||||
inherit: true,
|
||||
basePowerCallback(pokemon, target) {
|
||||
if (target.volatiles['minimize']) return 60;
|
||||
return 30;
|
||||
},
|
||||
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1, minimize: 1 },
|
||||
},
|
||||
beatup: {
|
||||
inherit: true,
|
||||
|
|
@ -44,15 +41,16 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
duration: 1,
|
||||
onModifySpAPriority: -101,
|
||||
onModifySpA(atk, pokemon, defender, move) {
|
||||
// https://www.smogon.com/forums/posts/8992145/
|
||||
// this.add('-activate', pokemon, 'move: Beat Up', '[of] ' + move.allies![0].name);
|
||||
if (!this.ruleTable.has('beatupnicknamesmod')) {
|
||||
this.add('-activate', pokemon, 'move: Beat Up', '[of] ' + move.allies![0].name);
|
||||
}
|
||||
this.event.modifier = 1;
|
||||
return move.allies!.shift()!.species.baseStats.atk;
|
||||
return this.dex.species.get(move.allies!.shift()!.set.species).baseStats.atk;
|
||||
},
|
||||
onFoeModifySpDPriority: -101,
|
||||
onFoeModifySpD(def, pokemon) {
|
||||
this.event.modifier = 1;
|
||||
return pokemon.species.baseStats.def;
|
||||
return this.dex.species.get(pokemon.set.species).baseStats.def;
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -61,18 +59,8 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
accuracy: 100,
|
||||
priority: 0,
|
||||
condition: {
|
||||
duration: 3,
|
||||
onLockMove: 'bide',
|
||||
onStart(pokemon) {
|
||||
this.effectState.totalDamage = 0;
|
||||
this.add('-start', pokemon, 'move: Bide');
|
||||
},
|
||||
onDamagePriority: -101,
|
||||
onDamage(damage, target, source, move) {
|
||||
if (!move || move.effectType !== 'Move' || !source) return;
|
||||
this.effectState.totalDamage += damage;
|
||||
this.effectState.lastDamageSource = source;
|
||||
},
|
||||
inherit: true,
|
||||
onAfterSetStatus: undefined, // no inherit
|
||||
onBeforeMove(pokemon, target, move) {
|
||||
if (this.effectState.duration === 1) {
|
||||
this.add('-end', pokemon, 'move: Bide');
|
||||
|
|
@ -110,17 +98,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
}
|
||||
this.add('-activate', pokemon, 'move: Bide');
|
||||
},
|
||||
onMoveAborted(pokemon) {
|
||||
pokemon.removeVolatile('bide');
|
||||
},
|
||||
onEnd(pokemon) {
|
||||
this.add('-end', pokemon, 'move: Bide', '[silent]');
|
||||
},
|
||||
},
|
||||
},
|
||||
blizzard: {
|
||||
inherit: true,
|
||||
onModifyMove() { },
|
||||
onModifyMove: undefined, // no inherit
|
||||
},
|
||||
brickbreak: {
|
||||
inherit: true,
|
||||
|
|
@ -133,7 +115,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
charge: {
|
||||
inherit: true,
|
||||
boosts: null,
|
||||
boosts: undefined, // no inherit
|
||||
},
|
||||
conversion: {
|
||||
inherit: true,
|
||||
|
|
@ -154,20 +136,39 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
this.add('-start', target, 'typechange', type);
|
||||
},
|
||||
},
|
||||
conversion2: {
|
||||
inherit: true,
|
||||
onHit(target, source) {
|
||||
if (!target.lastMoveUsed) {
|
||||
return false;
|
||||
}
|
||||
const possibleTypes = [];
|
||||
const lastMoveUsed = target.lastMoveUsed;
|
||||
const attackType = lastMoveUsed.id === 'struggle' ? 'Normal' : lastMoveUsed.type;
|
||||
for (const typeName of this.dex.types.names()) {
|
||||
const typeCheck = this.dex.types.get(typeName).damageTaken[attackType];
|
||||
if (typeCheck === 2 || typeCheck === 3) {
|
||||
possibleTypes.push(typeName);
|
||||
}
|
||||
}
|
||||
if (!possibleTypes.length) {
|
||||
return false;
|
||||
}
|
||||
const randomType = this.sample(possibleTypes);
|
||||
|
||||
if (!source.setType(randomType)) return false;
|
||||
this.add('-start', source, 'typechange', randomType);
|
||||
},
|
||||
},
|
||||
counter: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
duration: 1,
|
||||
noCopy: true,
|
||||
onStart(target, source, move) {
|
||||
this.effectState.slot = null;
|
||||
this.effectState.damage = 0;
|
||||
},
|
||||
onRedirectTargetPriority: -1,
|
||||
inherit: true,
|
||||
onRedirectTarget(target, source, source2) {
|
||||
if (source !== this.effectState.target || !this.effectState.slot) return;
|
||||
return this.getAtSlot(this.effectState.slot);
|
||||
},
|
||||
onDamagingHit: undefined, // no inherit
|
||||
onDamagePriority: -101,
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (
|
||||
|
|
@ -201,48 +202,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
accuracy: 55,
|
||||
flags: { protect: 1, mirror: 1, bypasssub: 1, metronome: 1 },
|
||||
volatileStatus: 'disable',
|
||||
condition: {
|
||||
inherit: true,
|
||||
durationCallback() {
|
||||
return this.random(2, 6);
|
||||
},
|
||||
noCopy: true,
|
||||
onStart(pokemon) {
|
||||
if (!this.queue.willMove(pokemon)) {
|
||||
this.effectState.duration!++;
|
||||
}
|
||||
if (!pokemon.lastMove) {
|
||||
return false;
|
||||
}
|
||||
for (const moveSlot of pokemon.moveSlots) {
|
||||
if (moveSlot.id === pokemon.lastMove.id) {
|
||||
if (!moveSlot.pp) {
|
||||
return false;
|
||||
} else {
|
||||
this.add('-start', pokemon, 'Disable', moveSlot.move);
|
||||
this.effectState.move = pokemon.lastMove.id;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
onEnd(pokemon) {
|
||||
this.add('-end', pokemon, 'move: Disable');
|
||||
},
|
||||
onBeforeMove(attacker, defender, move) {
|
||||
if (move.id === this.effectState.move) {
|
||||
this.add('cant', attacker, 'Disable', move);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onDisableMove(pokemon) {
|
||||
for (const moveSlot of pokemon.moveSlots) {
|
||||
if (moveSlot.id === this.effectState.move) {
|
||||
pokemon.disableMove(moveSlot.id);
|
||||
}
|
||||
}
|
||||
},
|
||||
"onResidualOrder": undefined, // no inherit
|
||||
"onResidualSubOrder": undefined, // no inherit
|
||||
},
|
||||
},
|
||||
dive: {
|
||||
|
|
@ -286,56 +252,15 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
volatileStatus: 'encore',
|
||||
condition: {
|
||||
inherit: true,
|
||||
durationCallback() {
|
||||
return this.random(3, 7);
|
||||
},
|
||||
onStart(target, source) {
|
||||
const moveIndex = target.lastMove ? target.moves.indexOf(target.lastMove.id) : -1;
|
||||
if (
|
||||
!target.lastMove || target.lastMove.flags['failencore'] ||
|
||||
!target.moveSlots[moveIndex] || target.moveSlots[moveIndex].pp <= 0
|
||||
) {
|
||||
// it failed
|
||||
return false;
|
||||
}
|
||||
this.effectState.move = target.lastMove.id;
|
||||
this.add('-start', target, 'Encore');
|
||||
},
|
||||
onOverrideAction(pokemon) {
|
||||
return this.effectState.move;
|
||||
},
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 14,
|
||||
onResidual(target) {
|
||||
if (
|
||||
target.moves.includes(this.effectState.move) &&
|
||||
target.moveSlots[target.moves.indexOf(this.effectState.move)].pp <= 0
|
||||
) {
|
||||
// early termination if you run out of PP
|
||||
target.removeVolatile('encore');
|
||||
}
|
||||
},
|
||||
onEnd(target) {
|
||||
this.add('-end', target, 'Encore');
|
||||
},
|
||||
onDisableMove(pokemon) {
|
||||
if (!this.effectState.move || !pokemon.hasMove(this.effectState.move)) {
|
||||
return;
|
||||
}
|
||||
for (const moveSlot of pokemon.moveSlots) {
|
||||
if (moveSlot.id !== this.effectState.move) {
|
||||
pokemon.disableMove(moveSlot.id);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
extrasensory: {
|
||||
inherit: true,
|
||||
basePowerCallback(pokemon, target) {
|
||||
if (target.volatiles['minimize']) return 160;
|
||||
return 80;
|
||||
},
|
||||
flags: { protect: 1, mirror: 1, metronome: 1, minimize: 1 },
|
||||
},
|
||||
fakeout: {
|
||||
inherit: true,
|
||||
|
|
@ -377,15 +302,14 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
followme: {
|
||||
inherit: true,
|
||||
volatileStatus: undefined,
|
||||
volatileStatus: undefined, // no inherit
|
||||
slotCondition: 'followme',
|
||||
condition: {
|
||||
duration: 1,
|
||||
inherit: true,
|
||||
onStart(target, source, effect) {
|
||||
this.add('-singleturn', target, 'move: Follow Me');
|
||||
this.effectState.slot = target.getSlot();
|
||||
},
|
||||
onFoeRedirectTargetPriority: 1,
|
||||
onFoeRedirectTarget(target, source, source2, move) {
|
||||
const userSlot = this.getAtSlot(this.effectState.slot);
|
||||
if (this.validTarget(userSlot, source, move.target)) {
|
||||
|
|
@ -412,6 +336,15 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
ignoreImmunity: false,
|
||||
},
|
||||
haze: {
|
||||
inherit: true,
|
||||
onHitField() {
|
||||
this.add('-clearallboost');
|
||||
for (const pokemon of this.getAllActive()) {
|
||||
pokemon.clearBoosts();
|
||||
}
|
||||
},
|
||||
},
|
||||
hiddenpower: {
|
||||
inherit: true,
|
||||
category: "Physical",
|
||||
|
|
@ -474,17 +407,12 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
mirrorcoat: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
duration: 1,
|
||||
noCopy: true,
|
||||
onStart(target, source, move) {
|
||||
this.effectState.slot = null;
|
||||
this.effectState.damage = 0;
|
||||
},
|
||||
onRedirectTargetPriority: -1,
|
||||
inherit: true,
|
||||
onRedirectTarget(target, source, source2) {
|
||||
if (source !== this.effectState.target || !this.effectState.slot) return;
|
||||
return this.getAtSlot(this.effectState.slot);
|
||||
},
|
||||
onDamagingHit: undefined, // no inherit
|
||||
onDamagePriority: -101,
|
||||
onDamage(damage, target, source, effect) {
|
||||
if (
|
||||
|
|
@ -500,7 +428,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
mirrormove: {
|
||||
inherit: true,
|
||||
flags: { metronome: 1, failencore: 1, nosleeptalk: 1, noassist: 1 },
|
||||
onTryHit() { },
|
||||
onTryHit: undefined, // no inherit
|
||||
onHit(pokemon) {
|
||||
const noMirror = [
|
||||
'assist', 'curse', 'doomdesire', 'focuspunch', 'futuresight', 'magiccoat', 'metronome', 'mimic', 'mirrormove', 'naturepower', 'psychup', 'roleplay', 'sketch', 'sleeptalk', 'spikes', 'spitup', 'taunt', 'teeterdance', 'transform',
|
||||
|
|
@ -525,10 +453,7 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
needlearm: {
|
||||
inherit: true,
|
||||
basePowerCallback(pokemon, target) {
|
||||
if (target.volatiles['minimize']) return 120;
|
||||
return 60;
|
||||
},
|
||||
flags: { contact: 1, protect: 1, mirror: 1, metronome: 1, minimize: 1 },
|
||||
},
|
||||
nightmare: {
|
||||
inherit: true,
|
||||
|
|
@ -550,6 +475,20 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
basePower: 70,
|
||||
},
|
||||
pursuit: {
|
||||
inherit: true,
|
||||
beforeTurnCallback(pokemon, target) {
|
||||
if (['frz', 'slp'].includes(pokemon.status) ||
|
||||
(pokemon.hasAbility('truant') && pokemon.truantTurn)) return;
|
||||
if (pokemon.isAlly(target)) return;
|
||||
target.addVolatile('pursuit');
|
||||
const data = target.volatiles['pursuit'];
|
||||
if (!data.sources) {
|
||||
data.sources = [];
|
||||
}
|
||||
data.sources.push(pokemon);
|
||||
},
|
||||
},
|
||||
recover: {
|
||||
inherit: true,
|
||||
pp: 20,
|
||||
|
|
@ -653,28 +592,13 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
inherit: true,
|
||||
flags: { protect: 1, bypasssub: 1, metronome: 1 },
|
||||
condition: {
|
||||
inherit: true,
|
||||
duration: 2,
|
||||
onStart(target) {
|
||||
this.add('-start', target, 'move: Taunt');
|
||||
},
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 15,
|
||||
durationCallback: undefined, // no inherit
|
||||
onEnd(target) {
|
||||
this.add('-end', target, 'move: Taunt', '[silent]');
|
||||
},
|
||||
onDisableMove(pokemon) {
|
||||
for (const moveSlot of pokemon.moveSlots) {
|
||||
if (this.dex.moves.get(moveSlot.move).category === 'Status') {
|
||||
pokemon.disableMove(moveSlot.id);
|
||||
}
|
||||
}
|
||||
},
|
||||
onBeforeMove(attacker, defender, move) {
|
||||
if (move.category === 'Status') {
|
||||
this.add('cant', attacker, 'move: Taunt', move);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onBeforeMovePriority: undefined, // no inherit
|
||||
},
|
||||
},
|
||||
teeterdance: {
|
||||
|
|
@ -688,37 +612,9 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
uproar: {
|
||||
inherit: true,
|
||||
condition: {
|
||||
onStart(target) {
|
||||
this.add('-start', target, 'Uproar');
|
||||
// 2-5 turns
|
||||
this.effectState.duration = this.random(2, 6);
|
||||
},
|
||||
onResidual(target) {
|
||||
if (target.volatiles['throatchop']) {
|
||||
target.removeVolatile('uproar');
|
||||
return;
|
||||
}
|
||||
if (target.lastMove && target.lastMove.id === 'struggle') {
|
||||
// don't lock
|
||||
delete target.volatiles['uproar'];
|
||||
}
|
||||
this.add('-start', target, 'Uproar', '[upkeep]');
|
||||
},
|
||||
onResidualOrder: 10,
|
||||
onResidualSubOrder: 11,
|
||||
onEnd(target) {
|
||||
this.add('-end', target, 'Uproar');
|
||||
},
|
||||
onLockMove: 'uproar',
|
||||
onAnySetStatus(status, pokemon) {
|
||||
if (status.id === 'slp') {
|
||||
if (pokemon === this.effectState.target) {
|
||||
this.add('-fail', pokemon, 'slp', '[from] Uproar', '[msg]');
|
||||
} else {
|
||||
this.add('-fail', pokemon, 'slp', '[from] Uproar');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
inherit: true,
|
||||
durationCallback() {
|
||||
return this.random(2, 6);
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -728,11 +624,11 @@ export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
|||
},
|
||||
volttackle: {
|
||||
inherit: true,
|
||||
secondary: null,
|
||||
secondary: undefined, // no inherit
|
||||
},
|
||||
waterfall: {
|
||||
inherit: true,
|
||||
secondary: null,
|
||||
secondary: undefined, // no inherit
|
||||
},
|
||||
weatherball: {
|
||||
inherit: true,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,23 @@ export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable
|
|||
standard: {
|
||||
effectType: 'ValidatorRule',
|
||||
name: 'Standard',
|
||||
desc: "The standard ruleset for all offical Smogon singles tiers (Ubers, OU, etc.)",
|
||||
ruleset: ['Obtainable', 'Sleep Clause Mod', 'Switch Priority Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Items Clause', 'Evasion Moves Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod'],
|
||||
desc: "The standard ruleset for all official Smogon singles tiers (Ubers, OU, etc.)",
|
||||
ruleset: [
|
||||
'Standard AG',
|
||||
'Sleep Clause Mod', 'Switch Priority Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Items Clause', 'Evasion Moves Clause',
|
||||
],
|
||||
},
|
||||
standarddraft: {
|
||||
effectType: 'ValidatorRule',
|
||||
name: 'Standard Draft',
|
||||
desc: "The custom Draft League ruleset",
|
||||
ruleset: [
|
||||
'Obtainable', 'Nickname Clause', 'Beat Up Nicknames Mod', '+Unreleased', 'Sleep Clause Mod', 'OHKO Clause', 'Evasion Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod',
|
||||
'One Boost Passer Clause', 'Freeze Clause Mod', 'Accuracy Moves Clause', 'Baton Pass Trap Clause',
|
||||
],
|
||||
banlist: [
|
||||
'Uber', 'Smeargle + Ingrain', 'Swagger', 'Focus Band', 'King\'s Rock', 'Quick Claw', 'Baton Pass + Ancient Power', 'Baton Pass + Silver Wind',
|
||||
],
|
||||
// timer: {starting: 60 * 60, grace: 0, addPerTurn: 10, maxPerTurn: 100, timeoutAutoChoose: true},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
// In Generation 3, the spread move modifier is 0.5x instead of 0.75x. Moves that hit both foes
|
||||
// and the user's ally, like Earthquake and Explosion, don't get affected by spread modifiers
|
||||
if (move.spreadHit && move.target === 'allAdjacentFoes') {
|
||||
const spreadModifier = move.spreadModifier || 0.5;
|
||||
const spreadModifier = 0.5;
|
||||
this.battle.debug(`Spread modifier: ${spreadModifier}`);
|
||||
baseDamage = this.battle.modify(baseDamage, spreadModifier);
|
||||
}
|
||||
|
|
@ -162,7 +162,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
|
||||
let movename = move.name;
|
||||
if (move.id === 'hiddenpower') movename = 'Hidden Power';
|
||||
if (sourceEffect) attrs += `|[from]${this.dex.conditions.get(sourceEffect)}`;
|
||||
if (sourceEffect) attrs += `|[from] ${this.dex.conditions.get(sourceEffect).name}`;
|
||||
this.battle.addMove('move', pokemon, movename, `${target}${attrs}`);
|
||||
|
||||
if (!target) {
|
||||
|
|
@ -256,7 +256,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!move.negateSecondary && !(move.hasSheerForce && pokemon.hasAbility('sheerforce'))) {
|
||||
if (!(move.hasSheerForce && pokemon.hasAbility('sheerforce'))) {
|
||||
this.battle.singleEvent('AfterMoveSecondarySelf', move, null, pokemon, target, move);
|
||||
this.battle.runEvent('AfterMoveSecondarySelf', pokemon, target, move);
|
||||
}
|
||||
|
|
@ -308,10 +308,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
move.ignoreImmunity = (move.category === 'Status');
|
||||
}
|
||||
|
||||
if (
|
||||
(!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) &&
|
||||
!target.runImmunity(move.type)
|
||||
) {
|
||||
if (!target.runImmunity(move)) {
|
||||
naturalImmunity = true;
|
||||
} else {
|
||||
hitResult = this.battle.singleEvent('TryImmunity', move, {}, target, pokemon, move);
|
||||
|
|
@ -412,6 +409,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
for (i = 0; i < hits && target.hp && pokemon.hp; i++) {
|
||||
if (pokemon.status === 'slp' && !isSleepUsable) break;
|
||||
move.hit = i + 1;
|
||||
move.lastHit = move.hit === hits;
|
||||
|
||||
if (move.multiaccuracy && i > 0) {
|
||||
accuracy = move.accuracy;
|
||||
|
|
@ -471,7 +469,7 @@ export const Scripts: ModdedBattleScriptsData = {
|
|||
|
||||
this.battle.eachEvent('Update');
|
||||
|
||||
if (target && !move.negateSecondary) {
|
||||
if (target) {
|
||||
this.battle.singleEvent('AfterMoveSecondary', move, null, target, pokemon, move);
|
||||
this.battle.runEvent('AfterMoveSecondary', target, pokemon, move);
|
||||
}
|
||||
|
|
|
|||
25
data/mods/gen3colosseum/moves.ts
Normal file
25
data/mods/gen3colosseum/moves.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* Gen 3 colosseum modifications (perish song should fail if it effects all remaining pokemon)
|
||||
*/
|
||||
export const Moves: import('../../../sim/dex-moves').ModdedMoveDataTable = {
|
||||
perishsong: {
|
||||
inherit: true,
|
||||
onTryMove(attacker, defender, move) {
|
||||
if (attacker.side.pokemonLeft === 1) {
|
||||
this.add('-fail', attacker, 'move: Perish Song');
|
||||
this.hint("Self KO Clause: The last pokemon on a team cannot use moves that force fainting");
|
||||
return false;
|
||||
}
|
||||
},
|
||||
},
|
||||
destinybond: {
|
||||
inherit: true,
|
||||
onTryMove(attacker, defender, move) {
|
||||
if (attacker.side.pokemonLeft === 1) {
|
||||
this.add('-fail', attacker, 'move: Perish Song');
|
||||
this.hint("Self KO Clause: The last pokemon on a team cannot use moves that force fainting");
|
||||
return false;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
27
data/mods/gen3colosseum/scripts.ts
Normal file
27
data/mods/gen3colosseum/scripts.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
export const Scripts: ModdedBattleScriptsData = {
|
||||
inherit: 'gen3',
|
||||
gen: 3,
|
||||
|
||||
checkWin(faintData?: Battle['faintQueue'][0]) {
|
||||
if (this.sides.every(side => !side.pokemonLeft)) {
|
||||
let isSelfKo = false;
|
||||
if (faintData?.effect) {
|
||||
isSelfKo = isSelfKo || this.dex.moves.getByID(faintData?.effect?.id).selfdestruct !== undefined;
|
||||
isSelfKo = isSelfKo || this.dex.moves.getByID(faintData?.effect?.id).recoil !== undefined;
|
||||
}
|
||||
if (isSelfKo) {
|
||||
this.win(faintData ? faintData.target.side : null);
|
||||
return true;
|
||||
} else {
|
||||
this.win(undefined);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (const side of this.sides) {
|
||||
if (!side.foePokemonLeft()) {
|
||||
this.win(side);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
63
data/mods/gen3frlg/abilities.ts
Normal file
63
data/mods/gen3frlg/abilities.ts
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
function attemptStatuses(battle: Battle, target: Pokemon, source: Pokemon, move: ActiveMove, status: string) {
|
||||
const attackerStatused = source.trySetStatus(status, target);
|
||||
if (move.multihit && move.id !== 'triplekick' &&
|
||||
(move.lastHit || (attackerStatused && status === 'slp')) &&
|
||||
battle.randomChance(1, 100)) {
|
||||
const defenderStatused = target.trySetStatus(status, target, move);
|
||||
if (defenderStatused) {
|
||||
battle.hint("In Pokemon Ruby, Sapphire, FireRed, LeafGreen, and Colosseum, if the final hit of a multihit move (except for Triple Kick) that makes contact triggers an ability that inflicts status, then there is a 1% chance that the defender is afflicted by the same status.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTable = {
|
||||
effectspore: {
|
||||
inherit: true,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (damage && move.flags['contact'] && !source.status) {
|
||||
const r = this.random(300);
|
||||
let status = null;
|
||||
if (r < 10) {
|
||||
status = 'slp';
|
||||
} else if (r < 20) {
|
||||
status = 'par';
|
||||
} else if (r < 30) {
|
||||
status = 'psn';
|
||||
}
|
||||
if (status) {
|
||||
attemptStatuses(this, target, source, move, status);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
flamebody: {
|
||||
inherit: true,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (damage && move.flags['contact']) {
|
||||
if (this.randomChance(1, 3)) {
|
||||
attemptStatuses(this, target, source, move, 'brn');
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
poisonpoint: {
|
||||
inherit: true,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (damage && move.flags['contact']) {
|
||||
if (this.randomChance(1, 3)) {
|
||||
attemptStatuses(this, target, source, move, 'psn');
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
static: {
|
||||
inherit: true,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (damage && move.flags['contact']) {
|
||||
if (this.randomChance(1, 3)) {
|
||||
attemptStatuses(this, target, source, move, 'par');
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
1354
data/mods/gen3frlg/formats-data.ts
Normal file
1354
data/mods/gen3frlg/formats-data.ts
Normal file
File diff suppressed because it is too large
Load Diff
146
data/mods/gen3frlg/items.ts
Normal file
146
data/mods/gen3frlg/items.ts
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
export const Items: import('../../../sim/dex-items').ModdedItemDataTable = {
|
||||
aguavberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
apicotberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
brightpowder: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
choiceband: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
clawfossil: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
cornnberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
deepseascale: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
deepseatooth: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
diveball: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
enigmaberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
figyberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
ganlonberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
grepaberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
hondewberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
kelpsyberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
lansatberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
liechiberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
lightball: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
magoberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
magostberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
mentalherb: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
nomelberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
petayaberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
pomegberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
premierball: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
qualotberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
rabutaberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
rootfossil: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
salacberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
scopelens: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
shellbell: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
souldew: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
starfberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
tamatoberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
whiteherb: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
wikiberry: {
|
||||
inherit: true,
|
||||
isNonstandard: "Unobtainable",
|
||||
},
|
||||
};
|
||||
9336
data/mods/gen3frlg/learnsets.ts
Normal file
9336
data/mods/gen3frlg/learnsets.ts
Normal file
File diff suppressed because it is too large
Load Diff
40
data/mods/gen3frlg/rulesets.ts
Normal file
40
data/mods/gen3frlg/rulesets.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
export const Rulesets: import('../../../sim/dex-formats').ModdedFormatDataTable = {
|
||||
standard: {
|
||||
effectType: 'ValidatorRule',
|
||||
name: 'Standard',
|
||||
desc: "The standard ruleset for all official Smogon singles tiers (Ubers, OU, etc.)",
|
||||
ruleset: [
|
||||
'Standard AG',
|
||||
'Sleep Clause Mod', 'Switch Priority Clause Mod', 'Species Clause', 'Nickname Clause', 'OHKO Clause', 'Evasion Items Clause', 'Evasion Moves Clause',
|
||||
],
|
||||
},
|
||||
standarddraft: {
|
||||
effectType: 'ValidatorRule',
|
||||
name: 'Standard Draft',
|
||||
desc: "The custom Draft League ruleset",
|
||||
ruleset: [
|
||||
'Obtainable', 'Nickname Clause', 'Beat Up Nicknames Mod', '+Unreleased', 'Sleep Clause Mod', 'OHKO Clause', 'Evasion Clause', 'Endless Battle Clause', 'HP Percentage Mod', 'Cancel Mod',
|
||||
'One Boost Passer Clause', 'Freeze Clause Mod', 'Accuracy Moves Clause', 'Baton Pass Trap Clause',
|
||||
],
|
||||
banlist: [
|
||||
'Uber', 'Smeargle + Ingrain', 'Swagger', 'Focus Band', 'King\'s Rock', 'Quick Claw', 'Baton Pass + Ancient Power', 'Baton Pass + Silver Wind',
|
||||
],
|
||||
// timer: {starting: 60 * 60, grace: 0, addPerTurn: 10, maxPerTurn: 100, timeoutAutoChoose: true},
|
||||
},
|
||||
obtainable: {
|
||||
inherit: true,
|
||||
onValidateSet(set) {
|
||||
const species = this.dex.species.get(set.species);
|
||||
if (['entei', 'raikou', 'suicune'].includes(species.id)) {
|
||||
if (!set.ivs) set.ivs = { hp: 31, atk: 31, def: 31, spa: 31, spd: 31, spe: 31 };
|
||||
for (const stat in set.ivs) {
|
||||
if ((stat === 'atk' && set.ivs[stat] > 7) || (stat !== 'hp' && set.ivs[stat as 'def'] > 0)) {
|
||||
return [
|
||||
`${set.name} must have 7 or fewer Attack IVs and 0 IVs in all other stats except HP, due to the Roaming IVs glitch.`,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
export const Scripts: ModdedBattleScriptsData = {
|
||||
inherit: 'gen7',
|
||||
gen: 7,
|
||||
inherit: 'gen3',
|
||||
};
|
||||
63
data/mods/gen3rs/abilities.ts
Normal file
63
data/mods/gen3rs/abilities.ts
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
function attemptStatuses(battle: Battle, target: Pokemon, source: Pokemon, move: ActiveMove, status: string) {
|
||||
const attackerStatused = source.trySetStatus(status, target);
|
||||
if (move.multihit && move.id !== 'triplekick' &&
|
||||
(move.lastHit || (attackerStatused && status === 'slp')) &&
|
||||
battle.randomChance(1, 100)) {
|
||||
const defenderStatused = target.trySetStatus(status, target, move);
|
||||
if (defenderStatused) {
|
||||
battle.hint("In Pokemon Ruby, Sapphire, FireRed, LeafGreen, and Colosseum, if the final hit of a multihit move (except for Triple Kick) that makes contact triggers an ability that inflicts status, then there is a 1% chance that the defender is afflicted by the same status.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTable = {
|
||||
effectspore: {
|
||||
inherit: true,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (damage && move.flags['contact'] && !source.status) {
|
||||
const r = this.random(300);
|
||||
let status = null;
|
||||
if (r < 10) {
|
||||
status = 'slp';
|
||||
} else if (r < 20) {
|
||||
status = 'par';
|
||||
} else if (r < 30) {
|
||||
status = 'psn';
|
||||
}
|
||||
if (status) {
|
||||
attemptStatuses(this, target, source, move, status);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
flamebody: {
|
||||
inherit: true,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (damage && move.flags['contact']) {
|
||||
if (this.randomChance(1, 3)) {
|
||||
attemptStatuses(this, target, source, move, 'brn');
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
poisonpoint: {
|
||||
inherit: true,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (damage && move.flags['contact']) {
|
||||
if (this.randomChance(1, 3)) {
|
||||
attemptStatuses(this, target, source, move, 'psn');
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
static: {
|
||||
inherit: true,
|
||||
onDamagingHit(damage, target, source, move) {
|
||||
if (damage && move.flags['contact']) {
|
||||
if (this.randomChance(1, 3)) {
|
||||
attemptStatuses(this, target, source, move, 'par');
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
1364
data/mods/gen3rs/formats-data.ts
Normal file
1364
data/mods/gen3rs/formats-data.ts
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user