forked from mirrors/cobblemon
Compare commits
686
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1fde1e4428 | ||
|
|
a2d574300c | ||
|
|
2d9d6e172c | ||
|
|
3c03b0e210 | ||
|
|
724c674992 | ||
|
|
99eb317a87 | ||
|
|
43a2c2f55d | ||
|
|
4db9a35f2b | ||
|
|
8228ac517b | ||
|
|
c7ae41bf7b | ||
|
|
1653be5fa8 | ||
|
|
b0497065f4 | ||
|
|
dfc1a39f58 | ||
|
|
9a92e074a2 | ||
|
|
44b195f0a6 | ||
|
|
7c21e6feb5 | ||
|
|
3b653b745e | ||
|
|
f246d90e4c | ||
|
|
df22cc5b3e | ||
|
|
3fbe2102a0 | ||
|
|
21b667f5d8 | ||
|
|
eb88a43769 | ||
|
|
c41a6766ef | ||
|
|
842de0e92c | ||
|
|
04b516765d | ||
|
|
3faad69484 | ||
|
|
74e2f8429c | ||
|
|
10219fbf38 | ||
|
|
cf68ccc29e | ||
|
|
f78847f917 | ||
|
|
8768c4c541 | ||
|
|
2bf0fd625b | ||
|
|
65e3052e69 | ||
|
|
be7192ae2c | ||
|
|
1c921a372b | ||
|
|
cf3587557d | ||
|
|
bbd44c0010 | ||
|
|
bb05177985 | ||
|
|
31143359ee | ||
|
|
c8f0140870 | ||
|
|
0b9ca3a97c | ||
|
|
d03541ff6f | ||
|
|
0d7aff0349 | ||
|
|
c904888c6a | ||
|
|
450ebfc44e | ||
|
|
253bde945f | ||
|
|
3622946974 | ||
|
|
4077feca35 | ||
|
|
bf330c112b | ||
|
|
c07d7d304e | ||
|
|
5797a2e568 | ||
|
|
5f94999b4f | ||
|
|
8b8fa06472 | ||
|
|
0459780171 | ||
|
|
e27bf7fc4b | ||
|
|
36007caf16 | ||
|
|
f00b16ab1a | ||
|
|
ac93c89d2c | ||
|
|
1c5f6a8f54 | ||
|
|
f66358e358 | ||
|
|
446706e6cd | ||
|
|
967fd2e0ec | ||
|
|
57d2b51264 | ||
|
|
4baa43ccb4 | ||
|
|
c9be0104dd | ||
|
|
55a179f548 | ||
|
|
beaea0e88c | ||
|
|
fb54ff8054 | ||
|
|
c273192ba2 | ||
|
|
acfc3b1acc | ||
|
|
e45e7a589b | ||
|
|
0fc3bf9de7 | ||
|
|
b6af9381f0 | ||
|
|
ee64810970 | ||
|
|
a7152f3e35 | ||
|
|
46290554c5 | ||
|
|
771a2c0727 | ||
|
|
4e456e030d | ||
|
|
9d69c593b8 | ||
|
|
6e58f4be59 | ||
|
|
f1807dc27c | ||
|
|
cb8e96230e | ||
|
|
dc6b3ada9b | ||
|
|
ccdb8803b2 | ||
|
|
fd917438a1 | ||
|
|
4a0e567554 | ||
|
|
bb6b67e4aa | ||
|
|
6515bfa108 | ||
|
|
8bf5492409 | ||
|
|
e6573f3c3b | ||
|
|
86d8fa1806 | ||
|
|
de65320610 | ||
|
|
3828991a71 | ||
|
|
129ea86829 | ||
|
|
216270b798 | ||
|
|
ad1674a1bc | ||
|
|
2b80d99614 | ||
|
|
723302ed39 | ||
|
|
79bec94f55 | ||
|
|
d7a7d421a0 | ||
|
|
49632b6f85 | ||
|
|
308a41a5fc | ||
|
|
a5486be16f | ||
|
|
94c9f865e7 | ||
|
|
3385b9c8bf | ||
|
|
cdfc894d49 | ||
|
|
784e2c0fb8 | ||
|
|
e6a487dc52 | ||
|
|
bdb79a32cc | ||
|
|
5d6a227c49 | ||
|
|
2bca651f75 | ||
|
|
cbde864cc1 | ||
|
|
4b3a5d7ca9 | ||
|
|
e55c08648f | ||
|
|
052f8fd94a | ||
|
|
cd4f7fc7aa | ||
|
|
c90400bba6 | ||
|
|
d390764717 | ||
|
|
0880d127a7 | ||
|
|
30466a6063 | ||
|
|
fd59b81bff | ||
|
|
ba82a6bc56 | ||
|
|
abf64e6047 | ||
|
|
c463278498 | ||
|
|
a37fdf709a | ||
|
|
5023f28d04 | ||
|
|
c502fec709 | ||
|
|
49444eea50 | ||
|
|
470fb80e08 | ||
|
|
a2aa6deddb | ||
|
|
0d4ef20b4a | ||
|
|
67de28386a | ||
|
|
cd37d3538e | ||
|
|
137fed9152 | ||
|
|
42ea462937 | ||
|
|
f32852db9d | ||
|
|
4294360cb9 | ||
|
|
d54565dbb5 | ||
|
|
0e005ea1ba | ||
|
|
d2e32bc26a | ||
|
|
92d5005a62 | ||
|
|
3d03ee5eb3 | ||
|
|
0b685ed453 | ||
|
|
115e990df6 | ||
|
|
2ee38f0a29 | ||
|
|
756ef48ba2 | ||
|
|
2c4df6622a | ||
|
|
99dc9930b8 | ||
|
|
425c41bc4b | ||
|
|
9f7a99b583 | ||
|
|
f1213abdf4 | ||
|
|
9b1d847f59 | ||
|
|
bf900a0167 | ||
|
|
7b008fe0ec | ||
|
|
ffa9ae4e86 | ||
|
|
d60d828e93 | ||
|
|
fcbc7ee72b | ||
|
|
7319fdf29b | ||
|
|
703282eca1 | ||
|
|
5d7e6f6487 | ||
|
|
4e3e6405d0 | ||
|
|
d8ad55506d | ||
|
|
adef71c23f | ||
|
|
9b49f5e01f | ||
|
|
23c52fd106 | ||
|
|
d118fe4ee8 | ||
|
|
7b2b860e52 | ||
|
|
d733eaae2f | ||
|
|
0c8fe42087 | ||
|
|
5e88116e08 | ||
|
|
1e161a52ee | ||
|
|
65b2204783 | ||
|
|
76d9137ae4 | ||
|
|
9f6c44fd75 | ||
|
|
6c086f5555 | ||
|
|
ef96814900 | ||
|
|
f6161d8687 | ||
|
|
8aa5d3a72c | ||
|
|
353de8b8a3 | ||
|
|
0423dd4939 | ||
|
|
fe02ea6fa9 | ||
|
|
90f7454ffb | ||
|
|
04f53040a3 | ||
|
|
69e21672eb | ||
|
|
4f2e3ecb0f | ||
|
|
1acc41da8c | ||
|
|
a6917162a7 | ||
|
|
a9115bfb15 | ||
|
|
111cb3a2f3 | ||
|
|
f2c5113f0b | ||
|
|
e29a2402e9 | ||
|
|
aa4857abbb | ||
|
|
d29653233d | ||
|
|
1b51a128d7 | ||
|
|
245011cf5e | ||
|
|
8ac9f38b06 | ||
|
|
48193160b9 | ||
|
|
83100dec11 | ||
|
|
100bf7fee4 | ||
|
|
be043a0ea1 | ||
|
|
a902f4a8a3 | ||
|
|
442f54839f | ||
|
|
a87b5090b0 | ||
|
|
20a97984a2 | ||
|
|
d1517548bd | ||
|
|
3e1f9dc9b0 | ||
|
|
f0c8d08a04 | ||
|
|
4fdc738b9e | ||
|
|
fd19e65f79 | ||
|
|
6b10d81bc8 | ||
|
|
920c5fd01a | ||
|
|
f3b9c03fc2 | ||
|
|
7d8c8a724f | ||
|
|
0f5f5d4eed | ||
|
|
30744c42a4 | ||
|
|
821bb79c14 | ||
|
|
f5171a4a8a | ||
|
|
061c9a1c52 | ||
|
|
da45f7d040 | ||
|
|
92653c1307 | ||
|
|
c372114da5 | ||
|
|
230ab53369 | ||
|
|
ac43853baa | ||
|
|
0de5f82971 | ||
|
|
2b95138c46 | ||
|
|
864e6be461 | ||
|
|
ec084cffbc | ||
|
|
f8ae312c0a | ||
|
|
abce88fab6 | ||
|
|
c02fa1f85e | ||
|
|
503b1069fd | ||
|
|
f1d593d53c | ||
|
|
69fb39f148 | ||
|
|
70838464d5 | ||
|
|
3cdb6e05c3 | ||
|
|
87822bc2f7 | ||
|
|
55dd486044 | ||
|
|
dffb944f3e | ||
|
|
613f3044bc | ||
|
|
342b9cb31e | ||
|
|
4679cfb07f | ||
|
|
9bb701abc8 | ||
|
|
d070a7b75a | ||
|
|
00a4b88437 | ||
|
|
005a98742e | ||
|
|
94168a65f0 | ||
|
|
39d626b349 | ||
|
|
3263837137 | ||
|
|
db6852134c | ||
|
|
a471fcd948 | ||
|
|
a14bfd55d1 | ||
|
|
725e819e89 | ||
|
|
b52b843206 | ||
|
|
74c65e22cb | ||
|
|
c348520a9b | ||
|
|
78dd5f334a | ||
|
|
67318c9307 | ||
|
|
31c48407df | ||
|
|
7170825848 | ||
|
|
43da7ecece | ||
|
|
5b1531b894 | ||
|
|
0957de86c7 | ||
|
|
daae444fa9 | ||
|
|
79423ef5ee | ||
|
|
6255f7dc31 | ||
|
|
af9f1accf8 | ||
|
|
ff10306372 | ||
|
|
aaf7daa45b | ||
|
|
3b87846562 | ||
|
|
dfd4450e11 | ||
|
|
7c42f8e37f | ||
|
|
ae550f78c4 | ||
|
|
66e4194a3e | ||
|
|
12e6b76504 | ||
|
|
93861af71f | ||
|
|
0c80748012 | ||
|
|
4060dbd596 | ||
|
|
fcf832c22c | ||
|
|
a065aff744 | ||
|
|
d77f424a83 | ||
|
|
d5d2a2cec3 | ||
|
|
036e150191 | ||
|
|
0bf1d84675 | ||
|
|
b1b8e658b2 | ||
|
|
f984b21929 | ||
|
|
0a5193b209 | ||
|
|
43f1f1c30d | ||
|
|
c16597ae41 | ||
|
|
f76e7582d2 | ||
|
|
40761d87db | ||
|
|
89a9ad0bfb | ||
|
|
20291c54a5 | ||
|
|
04b7500887 | ||
|
|
d6fdfe6ebc | ||
|
|
fe3d2a29b9 | ||
|
|
ad81202d49 | ||
|
|
acbacfa8cf | ||
|
|
9740267f91 | ||
|
|
fcca3b1d68 | ||
|
|
9f63b62651 | ||
|
|
392632b7d4 | ||
|
|
767e279cf1 | ||
|
|
6ace08aaa6 | ||
|
|
0d377dcbe0 | ||
|
|
88c31bcb7b | ||
|
|
8efea17ae6 | ||
|
|
cdbf569bbc | ||
|
|
8b81b13d01 | ||
|
|
f19d9410c0 | ||
|
|
9ac3a9249d | ||
|
|
4f340b2eee | ||
|
|
7dc00c3e88 | ||
|
|
d000790996 | ||
|
|
0415cf8a69 | ||
|
|
663624c434 | ||
|
|
79af092888 | ||
|
|
5cff52df5f | ||
|
|
ca311fa97c | ||
|
|
27020d3068 | ||
|
|
3ac4b8622f | ||
|
|
acd7a0583c | ||
|
|
e341948bd4 | ||
|
|
1a465abf9d | ||
|
|
e56a6e5b1a | ||
|
|
33d707a73b | ||
|
|
ba8e40d5a7 | ||
|
|
e3c3cd380c | ||
|
|
578ce789b1 | ||
|
|
460e8f7501 | ||
|
|
2fee86e7bc | ||
|
|
f73e631f81 | ||
|
|
0ca0c1a552 | ||
|
|
b3bf2c5ded | ||
|
|
7875006c8e | ||
|
|
67bb63b638 | ||
|
|
511f97b963 | ||
|
|
54c426f5ff | ||
|
|
f89902ece8 | ||
|
|
52c6bbd842 | ||
|
|
8246a822cf | ||
|
|
54202bed98 | ||
|
|
e6313cf4c5 | ||
|
|
00eca1c019 | ||
|
|
babfb43750 | ||
|
|
3aa94fcd2a | ||
|
|
20a866a0e3 | ||
|
|
67f2146c3c | ||
|
|
ad49106132 | ||
|
|
064df9c26e | ||
|
|
7debc6e047 | ||
|
|
bf9b69a143 | ||
|
|
d7f34972c1 | ||
|
|
fa7356d2ed | ||
|
|
812d42a42f | ||
|
|
3f114706fa | ||
|
|
8d1f41919d | ||
|
|
b40c21d99e | ||
|
|
461d8bd282 | ||
|
|
84d34709a3 | ||
|
|
b6c04e8746 | ||
|
|
81a96afaa6 | ||
|
|
724332dd34 | ||
|
|
f5bfd64495 | ||
|
|
bf8f7f628f | ||
|
|
898fdf983f | ||
|
|
a547e0f535 | ||
|
|
564ced926c | ||
|
|
a93dd14fd8 | ||
|
|
f0535901cb | ||
|
|
7a42df591f | ||
|
|
616419880f | ||
|
|
9fa38430c0 | ||
|
|
26012278e7 | ||
|
|
2c0967d293 | ||
|
|
885fc72d93 | ||
|
|
8130cd0998 | ||
|
|
447d35f28b | ||
|
|
bf82def925 | ||
|
|
dace364701 | ||
|
|
d737444ac9 | ||
|
|
95f58ba557 | ||
|
|
8993b007a5 | ||
|
|
c84f9dd112 | ||
|
|
eea7477f7f | ||
|
|
241abd79d7 | ||
|
|
35618cea46 | ||
|
|
31b97d391d | ||
|
|
7769a73246 | ||
|
|
65bf9507d3 | ||
|
|
6d336fc27b | ||
|
|
9514a1d470 | ||
|
|
16df7695c4 | ||
|
|
8fd63912a3 | ||
|
|
04941a9a38 | ||
|
|
1853a1677a | ||
|
|
94f8de8ddc | ||
|
|
7ea866d82a | ||
|
|
ea529a52c2 | ||
|
|
1f6dd03064 | ||
|
|
d62ea394ee | ||
|
|
d0b8a3368c | ||
|
|
6d23e762d6 | ||
|
|
6edb0c19c4 | ||
|
|
71e9adae1f | ||
|
|
35b53daa09 | ||
|
|
937c30fca5 | ||
|
|
141249e6c7 | ||
|
|
94f9bf9f50 | ||
|
|
4638b01279 | ||
|
|
e39d59c37a | ||
|
|
072071d679 | ||
|
|
aa4400395b | ||
|
|
09ad3d0a4d | ||
|
|
de7df10f36 | ||
|
|
897bcf6fc0 | ||
|
|
1e14042455 | ||
|
|
8583c9af4d | ||
|
|
ce756997d6 | ||
|
|
4efc5b6748 | ||
|
|
7ed6075410 | ||
|
|
320d995672 | ||
|
|
8ae91587aa | ||
|
|
61362fa1b1 | ||
|
|
d010129864 | ||
|
|
282f002895 | ||
|
|
863f6de059 | ||
|
|
8ddf628f19 | ||
|
|
8762d518c1 | ||
|
|
46798d694e | ||
|
|
056dd0fd4b | ||
|
|
3ac00d976b | ||
|
|
b30a76855b | ||
|
|
e976556ae3 | ||
|
|
9f16eca621 | ||
|
|
f4a94bd732 | ||
|
|
b6c964e03b | ||
|
|
aed2204483 | ||
|
|
3ed46cb7af | ||
|
|
cf9efe9b8c | ||
|
|
02b9431731 | ||
|
|
a30ae0ccef | ||
|
|
a2905f4d37 | ||
|
|
b3aba1532c | ||
|
|
6369bdb612 | ||
|
|
b5db5605ef | ||
|
|
ea2936f204 | ||
|
|
9d7eef9bcd | ||
|
|
0207459a0f | ||
|
|
0e2fdfbce8 | ||
|
|
8c9da885c7 | ||
|
|
a5b6529f3c | ||
|
|
6e9bdb6019 | ||
|
|
b430b7db76 | ||
|
|
8015ff0e20 | ||
|
|
ee78657e3d | ||
|
|
6cc84cd38c | ||
|
|
31d6ff541e | ||
|
|
841a40c973 | ||
|
|
e1a4086f24 | ||
|
|
df049a315c | ||
|
|
9ce5486189 | ||
|
|
b1992a94d3 | ||
|
|
167a1ea8eb | ||
|
|
f95beaa7a1 | ||
|
|
1c0f7bbf8f | ||
|
|
34cc2cda46 | ||
|
|
696e58bd1a | ||
|
|
10412b80ca | ||
|
|
458c2ce0ed | ||
|
|
6182715644 | ||
|
|
b41c4c21a8 | ||
|
|
e1893f50ae | ||
|
|
a1bdf3ded6 | ||
|
|
a458b31c9f | ||
|
|
03b5336eb8 | ||
|
|
9e2d00df63 | ||
|
|
e8003bb29a | ||
|
|
a248d661fa | ||
|
|
59390f4d84 | ||
|
|
99b7e4a89e | ||
|
|
fb37e543cf | ||
|
|
c0c75a9735 | ||
|
|
3febee21b6 | ||
|
|
c3a017687c | ||
|
|
afd082c966 | ||
|
|
a6a1f7b75b | ||
|
|
72738a45e6 | ||
|
|
8a0076acb4 | ||
|
|
f7e1def555 | ||
|
|
c13f6ae627 | ||
|
|
c24ab2049d | ||
|
|
b7b1850a4e | ||
|
|
8995c107f7 | ||
|
|
d6a412b91a | ||
|
|
5984d7a126 | ||
|
|
6d8e645092 | ||
|
|
55f0db2263 | ||
|
|
411788a07e | ||
|
|
f6151041c5 | ||
|
|
f99168f1c3 | ||
|
|
adce1d8838 | ||
|
|
e95c82b5af | ||
|
|
dd273ffef2 | ||
|
|
ac65910380 | ||
|
|
ba6847be9a | ||
|
|
5ddbcd1830 | ||
|
|
47605646d0 | ||
|
|
d9fdf089c2 | ||
|
|
e9a405694c | ||
|
|
8555168a6a | ||
|
|
1b5c0be975 | ||
|
|
5924398eff | ||
|
|
a08855ab37 | ||
|
|
91abe39cdd | ||
|
|
ad8aab7c19 | ||
|
|
aa6b196c29 | ||
|
|
5268447fa3 | ||
|
|
acf467c8a3 | ||
|
|
0ff5b95c44 | ||
|
|
818b39e945 | ||
|
|
30666349a1 | ||
|
|
fb34d4bd23 | ||
|
|
6ca1337ff9 | ||
|
|
98106cad12 | ||
|
|
0d344337dd | ||
|
|
3d27681aaa | ||
|
|
352202203a | ||
|
|
62cfbd7087 | ||
|
|
5a64e8ea1b | ||
|
|
8dc9863a5d | ||
|
|
9280258413 | ||
|
|
51a11163dd | ||
|
|
82548b5383 | ||
|
|
8d7ebeef4f | ||
|
|
d5ad84a495 | ||
|
|
ad73202e17 | ||
|
|
1560b142d2 | ||
|
|
2965a04742 | ||
|
|
b01086270a | ||
|
|
8d5eb5883d | ||
|
|
d5fa693f43 | ||
|
|
0d12bf1190 | ||
|
|
4f773f63cb | ||
|
|
3f3ae74535 | ||
|
|
7429fea802 | ||
|
|
ac5cd47715 | ||
|
|
9901d39f9b | ||
|
|
c635a1d331 | ||
|
|
cf2173a281 | ||
|
|
710d37f453 | ||
|
|
1fb3416211 | ||
|
|
f49f2a7305 | ||
|
|
b0e9c1ab28 | ||
|
|
ac1c7d8b78 | ||
|
|
dec5151eb8 | ||
|
|
196edc2711 | ||
|
|
18015a26fd | ||
|
|
aa296a79a9 | ||
|
|
92dd85643e | ||
|
|
8849de1bfd | ||
|
|
2a349697b4 | ||
|
|
a4055e6206 | ||
|
|
03bda4e27d | ||
|
|
5d8abbd4c7 | ||
|
|
6b167a7a17 | ||
|
|
5c64bc94ff | ||
|
|
d36c24075c | ||
|
|
d1a8122296 | ||
|
|
a8e6e684ab | ||
|
|
188fc2b5d9 | ||
|
|
2bc2e3f020 | ||
|
|
7a15e6b004 | ||
|
|
6ee6beddeb | ||
|
|
b92960da77 | ||
|
|
99618184e7 | ||
|
|
fcdff126fd | ||
|
|
3b285cc8bd | ||
|
|
4dead98e6b | ||
|
|
db36f8da2a | ||
|
|
3a448071d7 | ||
|
|
7215860d74 | ||
|
|
dc899ffc1b | ||
|
|
88fe55bbb9 | ||
|
|
3d3c421b5c | ||
|
|
3c2cfa4ffc | ||
|
|
89a4edb327 | ||
|
|
ab37580258 | ||
|
|
c116c01fd6 | ||
|
|
e3ad8f8079 | ||
|
|
a491d508b6 | ||
|
|
3e11d0550f | ||
|
|
e8b50f8115 | ||
|
|
02fb825328 | ||
|
|
8df6eea107 | ||
|
|
1376bb68f4 | ||
|
|
beb8f2ccf1 | ||
|
|
d9de8f2678 | ||
|
|
510dfec0e5 | ||
|
|
e54932c876 | ||
|
|
dd14c3bbdd | ||
|
|
5ea237f8a0 | ||
|
|
fb154ba457 | ||
|
|
f7812896a8 | ||
|
|
b0d57dd875 | ||
|
|
6c09e2b553 | ||
|
|
593104fb0a | ||
|
|
e314664731 | ||
|
|
d0a38a9704 | ||
|
|
6e155d7651 | ||
|
|
ae8f8a2fb8 | ||
|
|
5a6a83aac1 | ||
|
|
e8236b55a4 | ||
|
|
2ea07899ea | ||
|
|
d0ce03cd5e | ||
|
|
8ae0c409a3 | ||
|
|
2782cb5f34 | ||
|
|
2f10707211 | ||
|
|
f40a9d762a | ||
|
|
17587f97e5 | ||
|
|
5230820657 | ||
|
|
61c55e136f | ||
|
|
22cced74f5 | ||
|
|
3cd2dec8e0 | ||
|
|
cea930893a | ||
|
|
8662364ca8 | ||
|
|
1fd079b1b4 | ||
|
|
244876a26c | ||
|
|
e7790f530f | ||
|
|
04a9ab0e67 | ||
|
|
3f338d27c3 | ||
|
|
5da3dfb451 | ||
|
|
fd329e00cd | ||
|
|
6da47a8b2c | ||
|
|
860c73fac9 | ||
|
|
e26fdd4bdd | ||
|
|
8e642f71b8 | ||
|
|
f17884b4e1 | ||
|
|
c40b456948 | ||
|
|
7e74e85315 | ||
|
|
21fd4d7cbf | ||
|
|
908bff9892 | ||
|
|
fa14f70bbb | ||
|
|
188ae2ac85 | ||
|
|
346559f292 | ||
|
|
331b282fcf | ||
|
|
7f97eeafed | ||
|
|
51f5a1f5a8 | ||
|
|
7c0535b8bd | ||
|
|
4f15ac0cbc | ||
|
|
35a0d8a80d | ||
|
|
c0270d3ef0 | ||
|
|
82a1eb2a55 | ||
|
|
a528ea952a | ||
|
|
af2df51a2a | ||
|
|
95a0f9603c | ||
|
|
d38aa6b1a2 | ||
|
|
4566e1b33f | ||
|
|
f2d16ca9b7 | ||
|
|
d6fbb70db0 | ||
|
|
150a5c668a | ||
|
|
1bf01a2826 | ||
|
|
4d1bf677a1 | ||
|
|
069f56acfd | ||
|
|
19cdc8fbef | ||
|
|
1408b94f06 | ||
|
|
de081dc514 | ||
|
|
1538f12934 | ||
|
|
857f67604c | ||
|
|
ae49e3f977 | ||
|
|
ec01a03820 | ||
|
|
96cc3671da | ||
|
|
ad7c9c560c | ||
|
|
ee15ff6b35 | ||
|
|
ca83103703 | ||
|
|
1aeb894b09 | ||
|
|
8e9ab26963 | ||
|
|
44b4fbcfe3 | ||
|
|
42cc1dd8a9 | ||
|
|
d69310e52c | ||
|
|
a0f89274d1 | ||
|
|
65aec87382 | ||
|
|
21198eab29 | ||
|
|
c4c060cbbf | ||
|
|
6cf7c681d4 | ||
|
|
c420fd4705 | ||
|
|
1278654e9f |
+256
-6
@@ -1,8 +1,9 @@
|
||||
# Changelog
|
||||
## [1.5.0](#1-5-0)
|
||||
|
||||
### Additions
|
||||
- Added over (number here) ruin structures, where you can find Pokémon-themed Armor Trims and Pottery Sherds, Tumblestones, and more.
|
||||
- Added (number here) fossil structures, where you can brush Suspicious Sand/Gravel for Fossils.
|
||||
- Added 17 ruin structures, where you can find Pokémon-themed Armor Trims and Pottery Sherds, Tumblestones, and more.
|
||||
- Added 22 fossil structures, where you can brush Suspicious Sand/Gravel for Fossils.
|
||||
- Added the Data Monitor, Fossil Compartment, and Restoration Tank. Placed in the correct formation, you can use these to create a Restoration Machine where you can bring fossils back to life.
|
||||
- Added 3 variants of Tumblestones, which can be planted near Lava or Magma to grow harvestable Tumblestone Clusters.
|
||||
- Added Tumblestone Blocks, a storage block crafted from 9 Tumblestones.
|
||||
@@ -14,23 +15,240 @@
|
||||
- Added the hidden "True Vivillionaire" advancement.
|
||||
- The "Poké Ball" Vivillon variant is now obtainable by evolving a Spewpa after obtaining the "Aspiring Vivillionaire" advancement.
|
||||
- Added dynamic lighting support for any Species or Forms when using [LambDynamicLights](https://modrinth.com/mod/lambdynamiclights) or [Dynamic Lights Reforged](https://www.curseforge.com/minecraft/mc-mods/dynamiclights-reforged), at this time we don't ship with any defaults for this feature but addon creators can make use of this feature.
|
||||
- Added a Display Case block! Use it to display your archaeological findings, or other items.
|
||||
- Added 6 Pokémon-themed Pottery Sherds, obtained from ruin structures.
|
||||
- Added a Pokémon-themed armor trim, obtained from ruin structures.
|
||||
- You can now find Nether Fire Stone Ore in, surprisingly, the Nether.
|
||||
- You'll also find Terracotta Sun Stone Ore in Badlands biomes.
|
||||
- Added effects for many Poké Balls when sending out Pokémon or capturing.
|
||||
- Added a new send-out ball toss animation that showcases the ball used for the Pokémon.
|
||||
- Added simple move animations for Pokémon in battle with a proof of concept for more complicated animations.
|
||||
- Added the EV Boosting Feathers.
|
||||
- Added Type Gems.
|
||||
- Added various new tags for searchability and better compatibility.
|
||||
- Added the [Ability Capsule](https://bulbapedia.bulbagarden.net/wiki/Ability_Capsule) and [Patch](https://bulbapedia.bulbagarden.net/wiki/Ability_Patch), these have no acquisition method for now and only work as intended with the traditional ability format of 1 to 2 common abilities and 1 hidden ability.
|
||||
- Added Gilded Chests, available in all Apricorn colors.
|
||||
- Added Relic Coins, Relic Coin Pouches, and Relic Coin Sacks.
|
||||
- Added Gimmighoul.
|
||||
- Added Type Gems. These items hold no functionality for now. Start collecting though...
|
||||
- Added cries to Meowth, Alolan Meowth, Galaraian Meowth,
|
||||
- Completed the advancement for placing a Tumblestone near Lava or Magma to make it grow.
|
||||
- Added new held items: Ability Shield, Absorb Bulb, Air Balloon, Binding Band, Blunder Policy, Cell Battery, Covert Cloak, Damp Rock, Eject Button, Eviolite, Expert Belt, Float Stone, Focus Sash, Heat Rock, Icy Rock, Iron Ball, Light Ball, Loaded Dice, Red Card, Shell Bell, Sticky Barb, Smooth Rock, Soothe Bell and Weakness Policy.
|
||||
- Added Hisui starters to the starter selection menu.
|
||||
- Added bubble quirk to Krabby that only play during clear sunset's.
|
||||
- Added forfeit option to PVP battles.
|
||||
- Added visual changes for entities affected by Illusion, Imposter, or Transform in battle.
|
||||
- Added shoulder mounting for Squirtle, Ralts, Roggenrola, Charcadet, Sizzlipede, Litwick, Cutiefly, Flabebe, Flittle, and Scatterbug
|
||||
|
||||
### Pokémon Added
|
||||
#### Gen 2
|
||||
- Sentret
|
||||
- Furret
|
||||
- Qwilfish
|
||||
- Heracross
|
||||
- Skarmory
|
||||
- Larvitar
|
||||
- Pupitar
|
||||
- Tyranitar
|
||||
|
||||
#### Gen 3
|
||||
- Lileep
|
||||
- Cradily
|
||||
- Anorith
|
||||
- Armaldo
|
||||
- Tropius
|
||||
- Roselia
|
||||
- Aron
|
||||
- Lairon
|
||||
- Aggron
|
||||
- Solrock
|
||||
- Lunatone
|
||||
- Makuhita
|
||||
- Hariyama
|
||||
- Trapinch
|
||||
- Vibrava
|
||||
- Flygon
|
||||
|
||||
#### Gen 4
|
||||
- Shieldon
|
||||
- Bastiodon
|
||||
- Cranidos
|
||||
- Rampardos
|
||||
- Budew
|
||||
- Roserade
|
||||
- Hippopotas
|
||||
- Hippowdon
|
||||
|
||||
#### Gen 5
|
||||
- Tirtouga
|
||||
- Carracosta
|
||||
- Archen
|
||||
- Archeops
|
||||
- Zorua
|
||||
- Zoroark
|
||||
- Petilil
|
||||
- Lilligant
|
||||
- Darumaka
|
||||
- Darmanitan
|
||||
- Woobat
|
||||
- Swoobat
|
||||
- Sandile
|
||||
- Krokorok
|
||||
- Krookodile
|
||||
- Frillish
|
||||
- Jellicent
|
||||
- Cubchoo
|
||||
- Beartic
|
||||
- Deino
|
||||
- Zweilous
|
||||
- Hydreigon
|
||||
- Larvesta
|
||||
- Volcarona
|
||||
- Alomomola
|
||||
- Ferroseed
|
||||
- Ferrothorn
|
||||
|
||||
#### Gen 6
|
||||
- Tyrunt
|
||||
- Tyrantrum
|
||||
- Amaura
|
||||
- Aurorus
|
||||
- Goomy
|
||||
- Sliggoo
|
||||
- Goodra
|
||||
- Carbink
|
||||
- Flabébé
|
||||
- Floette
|
||||
- Florges
|
||||
- Klefki
|
||||
|
||||
#### Gen 7
|
||||
- Turtonator
|
||||
- Fomantis
|
||||
- Lurantis
|
||||
- Salandit
|
||||
- Salazzle
|
||||
- Jangmo-o
|
||||
- Hakamo-o
|
||||
- Kommo-o
|
||||
- Alolan Diglett
|
||||
- Alolan Dugtrio
|
||||
|
||||
#### Gen 8
|
||||
- Gossifleur
|
||||
- Eldegoss
|
||||
- Arctozolt
|
||||
- Arctovish
|
||||
- Dracozolt
|
||||
- Dracovish
|
||||
- Basculegion
|
||||
- Hisuian Decidueye
|
||||
- Hisuian Typhlosion
|
||||
- Hisuian Samurott
|
||||
- Hisuian Lilligant
|
||||
- Hisuian Sliggoo
|
||||
- Hisuian Goodra
|
||||
- Hisuian Zorua
|
||||
- Hisuian Zoroark
|
||||
- Hisuian Voltorb
|
||||
- Hisuian Electrode
|
||||
- Hisuian Qwilfish
|
||||
- Overqwil
|
||||
- Hisuian Sneasel
|
||||
- Sneasler
|
||||
- Stonjourner
|
||||
- Cufant
|
||||
- Copperajah
|
||||
- Dreepy
|
||||
- Drakloak
|
||||
- Dragapult
|
||||
- Impidimp
|
||||
- Morgrem
|
||||
- Grimmsnarl
|
||||
|
||||
#### Gen 9
|
||||
- Gimmighoul
|
||||
- Using Relic Coins, you can increase Gimmighoul's Coin Stash. Upon reaching 999, it can be evolved into Gholdengo.
|
||||
- Additionally, if you give Gimmighoul a Netherite Scrap, you can increase its Netherite Stash. Who knows what might happen if it fills up?
|
||||
- Gholdengo
|
||||
|
||||
#### Cobblemon Exclusives
|
||||
- Hisui Bias Rowlet
|
||||
- Hisui Bias Dartrix
|
||||
- Hisui Bias Cyndaquil
|
||||
- Hisui Bias Quilava
|
||||
- Hisui Bias Oshawott
|
||||
- Hisui Bias Dewott
|
||||
- Hisui Bias Goomy
|
||||
- Hisui Bias Petilil
|
||||
|
||||
### Added cries to the following Pokémon
|
||||
- Alolan Raticate
|
||||
- Vulpix, Ninetales
|
||||
- Zubat, Golbat, Crobat
|
||||
- Meowth, Persian
|
||||
- Psyduck, Golduck
|
||||
- Growlithe, Arcanine
|
||||
- Geodude, Graveler, Golem
|
||||
- Doduo, Dodrio
|
||||
- Seel, Dewgong
|
||||
- Muk, Grimer
|
||||
- Krabby, Kingler
|
||||
- Voltorb, Electrode, Hisuian Voltorb, Hisuian Electrode
|
||||
- Tangela, Tangrowth
|
||||
- Snorlax
|
||||
- Cubone, Marowak
|
||||
- Koffing, Weezing
|
||||
- Aerodactyl
|
||||
- Elekid, Electabuzz, Electivire
|
||||
- Omanyte, Omastar
|
||||
- Kabuto, Kabutops
|
||||
- Lapras
|
||||
- Scyther
|
||||
- Hisui Bias Cyndaquil, Hisui Bias Quilava
|
||||
- Igglybuff
|
||||
- Yanma, Yanmega
|
||||
- Gligar, Gliscor
|
||||
- Qwilfish, Hisuian Qwilfish, Overqwil
|
||||
- Sneasel, Hisuian Sneasel, Weavile, Sneasler
|
||||
- Larvitar, Pupitar, Tyranitar
|
||||
- Swinub, Piloswine, Mamoswine
|
||||
- Aron, Lairon, Aggron
|
||||
- Trapinch, Vibrava, Flygon
|
||||
- Cacnea, Cacturne
|
||||
- Barboach, Whiscash
|
||||
- Lileep, Cradily
|
||||
- Anorith, Armaldo
|
||||
- Tropius
|
||||
- Chimecho
|
||||
- Bidoof, Bibarel
|
||||
- Buizel, Floatzel
|
||||
- Gible, Gabite, Garchomp
|
||||
- Hisui Bias Oshawott, Hisui Bias Dewott
|
||||
- Petilil, Lilligant, Hisui Bias Petilil, Hisuian Lilligant
|
||||
- Basculin, Basculegion
|
||||
- Sandile, Krokolok, Krookodile
|
||||
- Darumaka, Darmanitan
|
||||
- Archen, Archeops
|
||||
- Zorua, Zoroark, Hisuian Zorua, Hisuian Zoroark
|
||||
- Tyrunt, Tyrantrum
|
||||
- Amaura Aurorus
|
||||
- Carbink
|
||||
- Goomy, Sliggoo, Goodra, Hisui Bias Goomy, Hisuian Sliggoo, Hisuian Goodra
|
||||
- Klefki
|
||||
- Hisui Bias Rowlet, Hisui Bias Dartrix
|
||||
- Komala
|
||||
- Impidimp, Morgrem, Grimmsnarl
|
||||
- Cufant, Copperajah
|
||||
- Dreepy, Drakloak, Dragapult
|
||||
- Dracozolt, Arctozolt, Dracovish, Arctovish
|
||||
- Lechonk, Oinkologne
|
||||
- Maushold family of three and four
|
||||
|
||||
|
||||
### Changes
|
||||
- Alolan Pikachu and Exeggcute changed to Alola bias.
|
||||
- Pokémon now transition more smoothly between different poses.
|
||||
- Updated models for Mimikyu, Alcremie, Squirtle, Wartortle, Blastoise, Pidgey, Pidgeotto, Pidgeot, Omanyte, Omastar, Growlithe, Arcanine, Nidoran Male, Nidoran Female, Lapras, Swinub, Piloswine, Basculin, Rowlet, Dartrix, Decidueye, Kabuto, Kabutops, Piplup, Prinplup, Elekid, Electabuzz, Cubone, Marowak, Paras, Mawile, Drifloon, Drifblim, Venonat, Venomoth, Yanma, Yanmega, Psyduck, Dusknoir, Diglett, Dugtrio, Natu, Xatu, Oshawott, Samurott, Torchic, Grovyle, Sceptile, Sizzlipede, and Raboot.
|
||||
- Updated animations for Squirtle, Wartortle, Blastoise, Pidgey, Pidgeotto, Diglett, Dugtrio, Magikarp, Dragonite, Omanyte, Omastar, Kabuto, Pinsir, Chinchou, Lanturn, Ralts, Kirlia, Gardevoir, Gallade, Buizel, Garchomp, Pumpkaboo, Falinks, Lechonk, Litwick, Lampent, Chandelure, Carnivine, Galarian Meowth, Galarian Rapidash, Venonat, Venomoth, Phanphy, Donphan, Dratini, Dragonair, Happiny, Chansey, Blissey, Volbeat, Illumise, Numel, Sizzlipede, Centiskorch, Obstagoon, Timburr, Gurdurr, Conkeldurr, Drifloon, and Drifblim.
|
||||
- Added more held items to the held item tag, and Metal Coat to the held item tab.
|
||||
- Added all ores to the modloader ore tags, and added tags for each ore type to the mod (both blocks and items).
|
||||
- Changed the Destiny Knot to be crafted with a Ghast Tear, rather than a diamond.
|
||||
@@ -41,11 +259,26 @@
|
||||
- Apricorn Sprouts can now be planted directly on Apricorn leaves to create a new Apricorn of the same color.
|
||||
- Added tooltips to interaction GUIs to make it clearer what they do.
|
||||
- Poké Ball recipes now use tags for their center ingredient, rather than specificied Copper Ingot, Iron Ingot, Gold Ingot, and Diamond, allowing for further datapack customisation.
|
||||
- Starter Toast now closes once corresponding button is pressed once.
|
||||
- Moved some items in the vanilla Food & Drinks category.
|
||||
- Stacked Cobblemon Potion Bases can now be quick moved into Brewing Stands.
|
||||
- Changed Healer recipe to swap the Max Revive for a Revive.
|
||||
- Upped the rate that Gastly drop Ghast Tears from 2.5% to 5%.
|
||||
- Pokémon with a low Blaze Powder drop chance now drop it more frequently in the Nether.
|
||||
- Reorganised a few advancements.
|
||||
- Pokémon entity shadows now scale when the Pokémon is being sent out or recalled.
|
||||
- Remade Torkoal particles, now they only appear when in battle.
|
||||
- Updated shiny icon within summary and PC interfaces.
|
||||
- Changed the Poison Barb sprite so that it doesn't look like a sword when held.
|
||||
- Moon Stone ore generates more frequently in Taigas and has been added to Magical and Spooky biomes.
|
||||
- Density, Season, and Nether biome tags have been moved and renamed within the biome tags directory.
|
||||
- Added particles to Lucario when in battle.
|
||||
|
||||
### Fixes
|
||||
- Resized Snorlax
|
||||
- Re-added the recipe for the Iron Vitamin.
|
||||
- Cleaned up empty evolutions declaration in species files (no, I'm not listing all 169 by name).
|
||||
- Fixed Exeggcute not being able to evolve.
|
||||
- Fixed Exeggcute and Pikachu not being able to evolve.
|
||||
- Fixed battle lang for Poison Touch Ability
|
||||
- Fixed Cubone not being able to evolve into Alolan Marowak.
|
||||
- Fixed Squawkabilly forms not being recognized.
|
||||
@@ -57,10 +290,17 @@
|
||||
- Fixed very many issues with Bedrock particle effects.
|
||||
- Fixed Arbok patterns not being as specific in spawning as they were intended.
|
||||
- Fixed Pokémon not avoiding danger at all when pathfinding.
|
||||
- Fixed Pokémon pathing over snow layers and carpets.
|
||||
- Fixed Sobble line not being able to swim or breathe underwater.
|
||||
- Fixed incompatibility with [Just Enough Resources](https://modrinth.com/mod/just-enough-resources-jer).
|
||||
- Fixed incompatibility with [Visual Overhaul](https://modrinth.com/mod/visual-overhaul).
|
||||
- Fixed an issue that allowed Pokemon to spawn on rails.
|
||||
- Fixed the data set on Pokémon when abilities are given via properties such as in ``/spawnpokemon``.
|
||||
- Fixed sometimes Pokémon losing hidden abilities when evolving, this fix will only take effect to newly created Pokémon.
|
||||
- Fixed capture messages not displaying.
|
||||
- Fixed illusion ability causing the wrong Pokémon to be targeted in battle.
|
||||
- Battles starting with fainted party members no longer cause a softlock on defeat.
|
||||
- Fixed some issues with eyes in the faint animations for Hitmonlee and Phantump
|
||||
|
||||
### Developer
|
||||
- Significantly changed the way properties in PokemonEntity work. This could break some plugins (not in a big way, but changes will be needed).
|
||||
@@ -73,6 +313,14 @@
|
||||
- Added the ``HeldItemEvent``, this comes with 2 implementation ``HeldItemEvent.Pre`` and ``HeldItemEvent.Post``.
|
||||
- API to support dynamic lighting in any mod that implements this feature has been added to all Species & Forms, see LightingData class for details.
|
||||
- Added a Mixin for the BrewingStandScreenHandler to fix the incorrect handling of quickMove in Fabric.
|
||||
- Corrections to the ability implementation have been made that make ``Ability.forced`` function as intended and never reroll an ability for a Pokémon, please check your implementations to ensure the corrected behavior is intended for your use case.
|
||||
- ``Pokemon.ability`` no longer has a public setter, please migrate to using ``Pokemon#updateAbility``, this handles the ability coordinate storage for you when necessary.
|
||||
- ``Ability.forced``, ``Ability.index`` and ``Ability.priority`` have all had their setters internalized, there is no longer any need to manually adjust these migrate to the method mentioned above to handle that process for you.
|
||||
- ``AbilityChanger`` has been added to API alongside some implementations, this is subject to change as the ability capsule and patch currently only expect the traditional behaviour in the Pokémon games of 1 to 2 regular abilities and 1 hidden.
|
||||
- ``Pokemon#rollAbility`` has been added, this rerolls a legal ability for the Pokémon.
|
||||
- `docs/cobblemon-tags` tags and spawn-presets can now be auto-generated from the current tags in the cobblemon mod with the `generateSpawnPresetList.py` and `generateTagList.py` scripts.
|
||||
- `public_spawns_to_json.py` script has been added to give the powerful spawn.json generator a simplistic UI.
|
||||
- Updated Showdown with Gen 9 DLC.
|
||||
|
||||
### Datapack & Resourcepack Creators
|
||||
- The maximum amount of fossils that can fit in the Fossil Analyzer can be adjusted in the config.
|
||||
@@ -107,6 +355,8 @@
|
||||
}
|
||||
```
|
||||
- Following up on this change ``light_source`` was removed as a possible shoulder effect due to becoming unnecessary and never having had a default implementation.
|
||||
- Added the item tag ``cobblemon:ability_changers``, contains the ``cobblemon:ability_capsule`` & ``cobblemon:ability_patch`` by default.
|
||||
- Added the item tag ``cobblemon:held/is_friendship_booster``, allows items to give the Soothe Bell effect of a boost of 1.5x Friendship gained, contains ``cobblemon:soothe_bell`` by default.
|
||||
|
||||
## [1.4.1 (December 23rd, 2023)](#1-4-1)
|
||||
|
||||
@@ -1042,4 +1292,4 @@ Thank you so much to all of our community translators that bring the mod to the
|
||||
- Added species, ability, and move translations for `ko_ko`, `jp_jp`, `fr_fr`, `es_es`, `it_it`, and `zh_cn`.
|
||||
|
||||
## [1.0.0 (November 12th, 2022)](#1-0-0)
|
||||
- Initial release.
|
||||
- Initial release.
|
||||
@@ -15,4 +15,7 @@ dependencies {
|
||||
implementation(libs.shadow)
|
||||
implementation(libs.loom)
|
||||
implementation(libs.architecturyPlugin)
|
||||
|
||||
implementation(libs.blossom)
|
||||
implementation(libs.ideaExt)
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
import extensions.VersionType
|
||||
import extensions.writeVersion
|
||||
|
||||
plugins {
|
||||
java
|
||||
`java-library`
|
||||
@@ -31,7 +34,7 @@ publishing {
|
||||
|
||||
groupId = "com.cobblemon"
|
||||
artifactId = project.findProperty("maven.artifactId")?.toString() ?: project.name
|
||||
version = rootProject.version.toString()
|
||||
version = project.writeVersion(VersionType.PUBLISHING)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package extensions
|
||||
|
||||
import org.gradle.api.Project
|
||||
|
||||
fun Project.version(): String {
|
||||
return rootProject.property("mod_version").toString()
|
||||
}
|
||||
|
||||
fun Project.isSnapshot(): Boolean {
|
||||
return rootProject.property("snapshot") == "true"
|
||||
}
|
||||
|
||||
fun Project.writeVersion(type: VersionType = VersionType.FULL): String {
|
||||
val version = "${rootProject.property("mod_version")}+${rootProject.property("mc_version")}"
|
||||
return when (type) {
|
||||
VersionType.PUBLISHING -> if(this.isSnapshot()) "$version-SNAPSHOT" else version
|
||||
VersionType.FULL -> if(this.isSnapshot()) rootProject.version.toString() else version
|
||||
}
|
||||
}
|
||||
|
||||
enum class VersionType {
|
||||
PUBLISHING,
|
||||
FULL
|
||||
}
|
||||
+2
-2
@@ -9,5 +9,5 @@ version = "${project.property("mod_version")}+${project.property("mc_version")}"
|
||||
|
||||
val isSnapshot = project.property("snapshot")?.equals("true") ?: false
|
||||
if (isSnapshot) {
|
||||
version = "$version-SNAPSHOT-${versioning.info.branch}-${versioning.info.build}"
|
||||
}
|
||||
version = "$version-${versioning.info.branch}-${versioning.info.build}"
|
||||
}
|
||||
|
||||
+43
-5
@@ -1,3 +1,9 @@
|
||||
import extensions.isSnapshot
|
||||
import extensions.version
|
||||
import java.time.OffsetDateTime
|
||||
import java.time.ZoneOffset
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
/*
|
||||
*
|
||||
* * Copyright (C) 2023 Cobblemon Contributors
|
||||
@@ -11,6 +17,10 @@
|
||||
plugins {
|
||||
id("cobblemon.base-conventions")
|
||||
id("cobblemon.publish-conventions")
|
||||
|
||||
id("net.kyori.blossom")
|
||||
id("org.jetbrains.gradle.plugin.idea-ext")
|
||||
id ("net.nemerosa.versioning") version "2.8.2"
|
||||
}
|
||||
|
||||
architectury {
|
||||
@@ -29,10 +39,8 @@ dependencies {
|
||||
|
||||
modImplementation(libs.fabricLoader)
|
||||
//Flywheel has no common dep so just pick one and don't use any platform specific code in common
|
||||
// modCompileOnly(libs.flywheelFabric)
|
||||
//modCompileOnly(libs.flywheelFabric)
|
||||
modApi(libs.molang)
|
||||
compileOnlyApi(libs.jeiApi)
|
||||
modCompileOnly(libs.adornFabric)
|
||||
modCompileOnly(libs.lambDynamicLights) { isTransitive = false }
|
||||
|
||||
// For Showdown
|
||||
@@ -44,8 +52,7 @@ dependencies {
|
||||
modCompileOnly(libs.mongoDriverCore)
|
||||
modCompileOnly(libs.mongoDriverSync)
|
||||
|
||||
testRuntimeOnly(libs.junitEngine)
|
||||
testImplementation(libs.junitApi)
|
||||
testImplementation(libs.fabricJunit)
|
||||
testImplementation(libs.junitParams)
|
||||
testImplementation(libs.mockito)
|
||||
testImplementation(libs.mockk)
|
||||
@@ -59,3 +66,34 @@ tasks.withType<Test> {
|
||||
setExceptionFormat("full")
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
blossom {
|
||||
kotlinSources {
|
||||
fun generateLicenseHeader() : String {
|
||||
val builder = StringBuilder()
|
||||
builder.append("/*\n")
|
||||
rootProject.file("HEADER").forEachLine {
|
||||
if(it.isEmpty()) {
|
||||
builder.append(" *").append("\n")
|
||||
} else {
|
||||
builder.append(" * ").append(it).append("\n")
|
||||
}
|
||||
}
|
||||
|
||||
return builder.append(" */").append("\n").toString()
|
||||
}
|
||||
|
||||
property("license", generateLicenseHeader())
|
||||
property("modid", "cobblemon")
|
||||
property("version", project.version())
|
||||
property("isSnapshot", if(rootProject.isSnapshot()) "true" else "false")
|
||||
property("gitCommit", versioning.info.commit)
|
||||
property("branch", versioning.info.branch)
|
||||
System.getProperty("buildNumber")?.let { property("buildNumber", it) }
|
||||
property("timestamp", OffsetDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ofPattern("MM/dd/yyyy hh:mm:ss")) + " UTC")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBuildDetails;
|
||||
import net.minecraft.util.crash.CrashReport;
|
||||
import net.minecraft.util.crash.CrashReportSection;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(CrashReport.class)
|
||||
public final class CrashReportMixin {
|
||||
|
||||
@Inject(method = "addStackTrace", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/SystemDetails;writeTo(Ljava/lang/StringBuilder;)V"))
|
||||
public void cobblemon$printCobblemonDetails(StringBuilder builder, CallbackInfo callback) {
|
||||
CrashReportSection cobblemon = new CrashReportSection("Cobblemon");
|
||||
cobblemon.add("Version", CobblemonBuildDetails.VERSION);
|
||||
cobblemon.add("Is Snapshot", CobblemonBuildDetails.SNAPSHOT);
|
||||
cobblemon.add("Git Commit", CobblemonBuildDetails.INSTANCE.smallCommitHash() + " (" + "https://gitlab.com/cable-mc/cobblemon/-/commit/" + CobblemonBuildDetails.GIT_COMMIT + ")");
|
||||
cobblemon.add("Branch", CobblemonBuildDetails.BRANCH);
|
||||
cobblemon.add("Timestamp", CobblemonBuildDetails.TIMESTAMP);
|
||||
|
||||
cobblemon.addStackTrace(builder);
|
||||
builder.append("\n\n");
|
||||
}
|
||||
|
||||
}
|
||||
+3
-2
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.mixin;
|
||||
import com.cobblemon.mod.common.client.CobblemonClient;
|
||||
import net.minecraft.client.render.entity.EntityRenderDispatcher;
|
||||
import net.minecraft.client.render.entity.EntityRenderer;
|
||||
import net.minecraft.client.util.SkinTextures;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.resource.ResourceManager;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
@@ -24,7 +25,7 @@ import java.util.Map;
|
||||
@Mixin(EntityRenderDispatcher.class)
|
||||
public class EntityRenderDispatcherMixin {
|
||||
|
||||
@Shadow private Map<String, EntityRenderer<? extends PlayerEntity>> modelRenderers;
|
||||
@Shadow private Map<SkinTextures.Model, EntityRenderer<? extends PlayerEntity>> modelRenderers;
|
||||
|
||||
@Inject(
|
||||
method = "reload",
|
||||
@@ -33,4 +34,4 @@ public class EntityRenderDispatcherMixin {
|
||||
public void resourceManagerReloadHook(ResourceManager resourceManager, CallbackInfo ci) {
|
||||
CobblemonClient.INSTANCE.onAddLayer(this.modelRenderers);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,13 +21,13 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
@Mixin(Mouse.class)
|
||||
public class PartyScrollMixin {
|
||||
@Shadow
|
||||
private double eventDeltaWheel;
|
||||
private double eventDeltaVerticalWheel;
|
||||
|
||||
@Inject(
|
||||
method = "onMouseScroll",
|
||||
at = @At(
|
||||
value = "FIELD",
|
||||
target="Lnet/minecraft/client/Mouse;eventDeltaWheel:D",
|
||||
target="Lnet/minecraft/client/Mouse;eventDeltaVerticalWheel:D",
|
||||
opcode = Opcodes.PUTFIELD,
|
||||
ordinal = 2,
|
||||
shift = At.Shift.BEFORE
|
||||
@@ -36,18 +36,18 @@ public class PartyScrollMixin {
|
||||
)
|
||||
public void onMouseScroll(long window, double horizontal, double vertical, CallbackInfo ci) {
|
||||
if (PartySendBinding.INSTANCE.getWasDown()) {
|
||||
int i = (int)eventDeltaWheel;
|
||||
int i = (int)eventDeltaVerticalWheel;
|
||||
if (i > 0) {
|
||||
while (i-- > 0) CobblemonClient.INSTANCE.getStorage().shiftSelected(false);
|
||||
ci.cancel();
|
||||
eventDeltaWheel = 0;
|
||||
eventDeltaVerticalWheel = 0;
|
||||
PartySendBinding.INSTANCE.actioned();
|
||||
} else if (i < 0) {
|
||||
while (i++ < 0) CobblemonClient.INSTANCE.getStorage().shiftSelected(true);
|
||||
ci.cancel();
|
||||
eventDeltaWheel = 0;
|
||||
eventDeltaVerticalWheel = 0;
|
||||
PartySendBinding.INSTANCE.actioned();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,18 +9,23 @@
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonItems;
|
||||
import net.minecraft.entity.EquipmentSlot;
|
||||
import net.minecraft.entity.mob.PiglinEntity;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(PiglinEntity.class)
|
||||
public class PiglinEntityMixin {
|
||||
@Redirect(method = "equipToOffHand", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;isOf(Lnet/minecraft/item/Item;)Z"))
|
||||
public boolean cobblemon$isValidBarteringItem(ItemStack stack, Item item) {
|
||||
//TODO: Make a tag?
|
||||
return stack.isOf(item) || stack.isOf(CobblemonItems.RELIC_COIN_POUCH);
|
||||
public abstract class PiglinEntityMixin {
|
||||
@Inject(method = "equipToOffHand", at = @At(value = "HEAD"), cancellable = true)
|
||||
public void cobblemon$isValidBarteringItem(ItemStack stack, CallbackInfo ci) {
|
||||
PiglinEntity entity = (PiglinEntity)(Object) this;
|
||||
if (stack.isOf(CobblemonItems.RELIC_COIN_POUCH)) {
|
||||
entity.equipStack(EquipmentSlot.OFFHAND, stack);
|
||||
entity.updateDropChances(EquipmentSlot.OFFHAND);
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+39
-49
@@ -15,15 +15,8 @@ import net.minecraft.structure.StructureTemplateManager;
|
||||
import net.minecraft.structure.pool.*;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
import net.minecraft.util.shape.VoxelShape;
|
||||
import net.minecraft.world.HeightLimitView;
|
||||
import net.minecraft.world.gen.chunk.ChunkGenerator;
|
||||
import net.minecraft.world.gen.noise.NoiseConfig;
|
||||
import org.apache.commons.lang3.mutable.MutableObject;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||
@@ -33,9 +26,6 @@ import java.util.*;
|
||||
|
||||
@Mixin(StructurePoolBasedGenerator.StructurePoolGenerator.class)
|
||||
public abstract class StructurePoolGeneratorMixin {
|
||||
@Final
|
||||
@Mutable
|
||||
@Shadow Deque<StructurePoolBasedGenerator.ShapedPoolStructurePiece> structurePieces;
|
||||
|
||||
Map<String, Integer> generatedStructureGroupCounts;
|
||||
|
||||
@@ -103,7 +93,7 @@ public abstract class StructurePoolGeneratorMixin {
|
||||
generatedStructureGroupCounts = new HashMap<>();
|
||||
}
|
||||
|
||||
@ModifyVariable(method = "generatePiece", at = @At("STORE"), ordinal = 1)
|
||||
@ModifyVariable(method = "generatePiece(Lnet/minecraft/structure/PoolStructurePiece;Lorg/apache/commons/lang3/mutable/MutableObject;IZLnet/minecraft/world/HeightLimitView;Lnet/minecraft/world/gen/noise/NoiseConfig;Lnet/minecraft/structure/pool/alias/StructurePoolAliasLookup;)V", at = @At("STORE"), ordinal = 1)
|
||||
private Iterator<StructurePoolElement> reduceStructurePoolElementIterator(Iterator<StructurePoolElement> iterator) {
|
||||
List<StructurePoolElement> reducedList = new ArrayList<>();
|
||||
|
||||
@@ -123,7 +113,7 @@ public abstract class StructurePoolGeneratorMixin {
|
||||
return reducedList.iterator();
|
||||
}
|
||||
|
||||
@ModifyVariable(method = "generatePiece", at = @At("STORE"), ordinal = 1)
|
||||
@ModifyVariable(method = "generatePiece(Lnet/minecraft/structure/PoolStructurePiece;Lorg/apache/commons/lang3/mutable/MutableObject;IZLnet/minecraft/world/HeightLimitView;Lnet/minecraft/world/gen/noise/NoiseConfig;Lnet/minecraft/structure/pool/alias/StructurePoolAliasLookup;)V", at = @At("HEAD"), ordinal = 0, argsOnly = true)
|
||||
private PoolStructurePiece injected(PoolStructurePiece poolStructurePiece) {
|
||||
Identifier structureLocationKey = getCobblemonOnlyLocation(poolStructurePiece.getPoolElement());
|
||||
if (structureLocationKey != null) {
|
||||
@@ -133,42 +123,42 @@ public abstract class StructurePoolGeneratorMixin {
|
||||
}
|
||||
|
||||
// This doesn't SEEM necessary? It appears to work without.
|
||||
@Inject(method = "generatePiece", at = @At("HEAD"))
|
||||
private void beforeGeneratePiece(PoolStructurePiece piece, MutableObject<VoxelShape> pieceShape, int minY, boolean modifyBoundingBox, HeightLimitView world, NoiseConfig noiseConfig, CallbackInfo ci) {
|
||||
// Identifier structureLocationKey = getCobblemonOnlyLocation(piece.getPoolElement());
|
||||
//
|
||||
// if (structureLocationKey != null) {
|
||||
// Integer currentlyGenerated = generatedStructureCounts.get(structureLocationKey);
|
||||
// if (currentlyGenerated == null) currentlyGenerated = 0;
|
||||
// generatedStructureCounts.put(structureLocationKey, currentlyGenerated + 1);
|
||||
// }
|
||||
//
|
||||
// List<StructurePoolBasedGenerator.ShapedPoolStructurePiece> reducedStructurePiecesList = structurePieces.stream().toList();
|
||||
//
|
||||
// for (Identifier maxStructureLocationKey : structureMaxes.keySet()) {
|
||||
// Integer maxAllowed = structureMaxes.get(maxStructureLocationKey);
|
||||
//
|
||||
// Integer currentlyGenerated = generatedStructureCounts.get(maxStructureLocationKey);
|
||||
// if (currentlyGenerated == null) currentlyGenerated = 0;
|
||||
// if (currentlyGenerated < maxAllowed) {
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// //Already have max so need to remove
|
||||
// reducedStructurePiecesList = reducedStructurePiecesList.stream()
|
||||
// .filter(shapedStructurePiece -> {
|
||||
// Identifier locationKey = getCobblemonOnlyLocation(shapedStructurePiece.piece.getPoolElement());
|
||||
// if (locationKey == null) {
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// return !locationKey.equals(maxStructureLocationKey);
|
||||
// })
|
||||
// .collect(Collectors.toList());
|
||||
// }
|
||||
//
|
||||
// structurePieces = new ArrayDeque<>(reducedStructurePiecesList);
|
||||
}
|
||||
// @Inject(method = "generatePiece", at = @At("HEAD"))
|
||||
// private void beforeGeneratePiece(PoolStructurePiece piece, MutableObject<VoxelShape> pieceShape, int minY, boolean modifyBoundingBox, HeightLimitView world, NoiseConfig noiseConfig, CallbackInfo ci) {
|
||||
//// Identifier structureLocationKey = getCobblemonOnlyLocation(piece.getPoolElement());
|
||||
////
|
||||
//// if (structureLocationKey != null) {
|
||||
//// Integer currentlyGenerated = generatedStructureCounts.get(structureLocationKey);
|
||||
//// if (currentlyGenerated == null) currentlyGenerated = 0;
|
||||
//// generatedStructureCounts.put(structureLocationKey, currentlyGenerated + 1);
|
||||
//// }
|
||||
////
|
||||
//// List<StructurePoolBasedGenerator.ShapedPoolStructurePiece> reducedStructurePiecesList = structurePieces.stream().toList();
|
||||
////
|
||||
//// for (Identifier maxStructureLocationKey : structureMaxes.keySet()) {
|
||||
//// Integer maxAllowed = structureMaxes.get(maxStructureLocationKey);
|
||||
////
|
||||
//// Integer currentlyGenerated = generatedStructureCounts.get(maxStructureLocationKey);
|
||||
//// if (currentlyGenerated == null) currentlyGenerated = 0;
|
||||
//// if (currentlyGenerated < maxAllowed) {
|
||||
//// continue;
|
||||
//// }
|
||||
////
|
||||
//// //Already have max so need to remove
|
||||
//// reducedStructurePiecesList = reducedStructurePiecesList.stream()
|
||||
//// .filter(shapedStructurePiece -> {
|
||||
//// Identifier locationKey = getCobblemonOnlyLocation(shapedStructurePiece.piece.getPoolElement());
|
||||
//// if (locationKey == null) {
|
||||
//// return true;
|
||||
//// }
|
||||
////
|
||||
//// return !locationKey.equals(maxStructureLocationKey);
|
||||
//// })
|
||||
//// .collect(Collectors.toList());
|
||||
//// }
|
||||
////
|
||||
//// structurePieces = new ArrayDeque<>(reducedStructurePiecesList);
|
||||
// }
|
||||
|
||||
private static Identifier getCobblemonOnlyLocation(StructurePoolElement structurePoolElement) {
|
||||
Identifier location = getLocationIfAvailable(structurePoolElement);
|
||||
@@ -214,4 +204,4 @@ public abstract class StructurePoolGeneratorMixin {
|
||||
//
|
||||
// return reducedList;
|
||||
// }
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@
|
||||
package com.cobblemon.mod.common.mixin.invoker;
|
||||
|
||||
import net.minecraft.block.*;
|
||||
import net.minecraft.resource.featuretoggle.FeatureFlag;
|
||||
import net.minecraft.sound.BlockSoundGroup;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
@@ -19,23 +18,23 @@ import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
public interface BlocksInvoker {
|
||||
|
||||
@Invoker("createLogBlock")
|
||||
static PillarBlock createLogBlock(MapColor topMapColor, MapColor sideMapColor) {
|
||||
static Block createLogBlock(MapColor topMapColor, MapColor sideMapColor) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Invoker("createLeavesBlock")
|
||||
static LeavesBlock createLeavesBlock(BlockSoundGroup soundGroup) {
|
||||
static Block createLeavesBlock(BlockSoundGroup soundGroup) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Invoker("createWoodenButtonBlock")
|
||||
static ButtonBlock createWoodenButtonBlock(BlockSetType blockSetType, FeatureFlag... requiredFeatures) {
|
||||
static Block createWoodenButtonBlock(BlockSetType blockSetType) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Invoker("createFlowerPotBlock")
|
||||
static FlowerPotBlock createFlowerPotBlock(Block flower, FeatureFlag... requiredFeatures) {
|
||||
static Block createFlowerPotBlock(Block flower) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -11,14 +11,13 @@ package com.cobblemon.mod.common.mixin.invoker;
|
||||
import net.minecraft.block.AbstractBlock;
|
||||
import net.minecraft.block.BlockSetType;
|
||||
import net.minecraft.block.DoorBlock;
|
||||
import net.minecraft.sound.SoundEvent;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@Mixin(DoorBlock.class)
|
||||
public interface DoorBlockInvoker {
|
||||
@Invoker("<init>")
|
||||
static DoorBlock cobblemon$create(AbstractBlock.Settings settings, BlockSetType blockSetType) {
|
||||
static DoorBlock cobblemon$create(BlockSetType blockSetType, AbstractBlock.Settings settings) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -11,14 +11,13 @@ package com.cobblemon.mod.common.mixin.invoker;
|
||||
import net.minecraft.block.AbstractBlock;
|
||||
import net.minecraft.block.BlockSetType;
|
||||
import net.minecraft.block.PressurePlateBlock;
|
||||
import net.minecraft.sound.SoundEvent;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@Mixin(PressurePlateBlock.class)
|
||||
public interface PressurePlateBlockInvoker {
|
||||
@Invoker("<init>")
|
||||
static PressurePlateBlock cobblemon$create(PressurePlateBlock.ActivationRule type, AbstractBlock.Settings settings, BlockSetType blockSetType) {
|
||||
static PressurePlateBlock cobblemon$create(BlockSetType type, AbstractBlock.Settings settings) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -11,14 +11,13 @@ package com.cobblemon.mod.common.mixin.invoker;
|
||||
import net.minecraft.block.AbstractBlock;
|
||||
import net.minecraft.block.BlockSetType;
|
||||
import net.minecraft.block.TrapdoorBlock;
|
||||
import net.minecraft.sound.SoundEvent;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@Mixin(TrapdoorBlock.class)
|
||||
public interface TrapdoorBlockInvoker {
|
||||
@Invoker("<init>")
|
||||
static TrapdoorBlock cobblemon$create(AbstractBlock.Settings settings, BlockSetType blockSetType) {
|
||||
static TrapdoorBlock cobblemon$create(BlockSetType blockSetType, AbstractBlock.Settings settings) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{{ license }}
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
object CobblemonBuildDetails {
|
||||
|
||||
const val MOD_ID = "{{ modid }}"
|
||||
const val VERSION = "{{ version }}"
|
||||
const val SNAPSHOT = {{ isSnapshot }}
|
||||
|
||||
const val GIT_COMMIT = "{{ gitCommit | default("Not Specified") }}"
|
||||
const val BRANCH = "{{ branch | default("Not Specified") }}"
|
||||
const val TIMESTAMP = "{{ timestamp }}"
|
||||
|
||||
fun smallCommitHash(): String {
|
||||
return this.GIT_COMMIT.substring(0, 7)
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBuildDetails.smallCommitHash
|
||||
import com.cobblemon.mod.common.advancement.CobblemonCriteria
|
||||
import com.cobblemon.mod.common.advancement.criterion.EvolvePokemonContext
|
||||
import com.cobblemon.mod.common.api.Priority
|
||||
@@ -16,10 +17,10 @@ import com.cobblemon.mod.common.api.data.DataProvider
|
||||
import com.cobblemon.mod.common.api.drop.CommandDropEntry
|
||||
import com.cobblemon.mod.common.api.drop.DropEntry
|
||||
import com.cobblemon.mod.common.api.drop.ItemDropEntry
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.BATTLE_VICTORY
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.DATA_SYNCHRONIZED
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.EVOLUTION_COMPLETE
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.HELD_ITEM_UPDATED
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.LEVEL_UP_EVENT
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.POKEMON_CAPTURED
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.TRADE_COMPLETED
|
||||
@@ -35,7 +36,10 @@ import com.cobblemon.mod.common.api.pokemon.effect.ShoulderEffectRegistry
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceCalculator
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.ExperienceGroups
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.StandardExperienceCalculator
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.*
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.ChoiceSpeciesFeatureProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.FlagSpeciesFeatureProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.IntSpeciesFeatureProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
|
||||
import com.cobblemon.mod.common.api.pokemon.helditem.HeldItemProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.EvCalculator
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Generation8EvCalculator
|
||||
@@ -62,6 +66,7 @@ import com.cobblemon.mod.common.api.storage.player.PlayerDataStoreManager
|
||||
import com.cobblemon.mod.common.api.storage.player.factory.JsonPlayerDataStoreFactory
|
||||
import com.cobblemon.mod.common.api.storage.player.factory.MongoPlayerDataStoreFactory
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonEntityTypeTags
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import com.cobblemon.mod.common.battles.BagItems
|
||||
import com.cobblemon.mod.common.battles.BattleFormat
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
@@ -93,7 +98,6 @@ import com.cobblemon.mod.common.pokemon.aspects.SHINY_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.BlockClickEvolution
|
||||
import com.cobblemon.mod.common.pokemon.feature.TagSeasonResolver
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
import com.cobblemon.mod.common.pokemon.misc.GimmighoulStashHandler
|
||||
import com.cobblemon.mod.common.pokemon.properties.HiddenAbilityPropertyType
|
||||
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.tags.PokemonFlagProperty
|
||||
@@ -115,31 +119,32 @@ import com.mongodb.ConnectionString
|
||||
import com.mongodb.MongoClientSettings
|
||||
import com.mongodb.client.MongoClient
|
||||
import com.mongodb.client.MongoClients
|
||||
import java.io.File
|
||||
import java.io.FileReader
|
||||
import java.io.FileWriter
|
||||
import java.io.PrintWriter
|
||||
import java.util.UUID
|
||||
import kotlin.properties.Delegates
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
import kotlin.reflect.jvm.javaField
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.command.argument.serialize.ConstantArgumentSerializer
|
||||
import net.minecraft.entity.data.TrackedDataHandlerRegistry
|
||||
import net.minecraft.item.Items
|
||||
import net.minecraft.item.NameTagItem
|
||||
import net.minecraft.registry.RegistryKey
|
||||
import net.minecraft.sound.SoundCategory
|
||||
import net.minecraft.util.WorldSavePath
|
||||
import net.minecraft.world.World
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.apache.logging.log4j.Logger
|
||||
import java.io.File
|
||||
import java.io.FileReader
|
||||
import java.io.FileWriter
|
||||
import java.io.PrintWriter
|
||||
import java.util.*
|
||||
import kotlin.properties.Delegates
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
import kotlin.reflect.jvm.javaField
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
object Cobblemon {
|
||||
const val MODID = "cobblemon"
|
||||
const val VERSION = "1.4.0"
|
||||
const val MODID = CobblemonBuildDetails.MOD_ID
|
||||
const val VERSION = CobblemonBuildDetails.VERSION
|
||||
const val CONFIG_PATH = "config/$MODID/main.json"
|
||||
val LOGGER = LogManager.getLogger()
|
||||
val LOGGER: Logger = LogManager.getLogger()
|
||||
|
||||
lateinit var implementation: CobblemonImplementation
|
||||
@Deprecated("This field is now a config value", ReplaceWith("Cobblemon.config.captureCalculator"))
|
||||
@@ -169,6 +174,14 @@ object Cobblemon {
|
||||
|
||||
fun preInitialize(implementation: CobblemonImplementation) {
|
||||
this.implementation = implementation
|
||||
|
||||
this.LOGGER.info("Launching Cobblemon ${CobblemonBuildDetails.VERSION}${if(CobblemonBuildDetails.SNAPSHOT) "-SNAPSHOT" else ""} ")
|
||||
if(CobblemonBuildDetails.SNAPSHOT) {
|
||||
this.LOGGER.info(" - Git Commit: ${smallCommitHash()} (https://gitlab.com/cable-mc/cobblemon/-/commit/${CobblemonBuildDetails.GIT_COMMIT})")
|
||||
this.LOGGER.info(" - Branch: ${CobblemonBuildDetails.BRANCH}")
|
||||
this.LOGGER.info(" - Timestamp: ${CobblemonBuildDetails.TIMESTAMP}")
|
||||
}
|
||||
|
||||
implementation.registerPermissionValidator()
|
||||
implementation.registerSoundEvents()
|
||||
implementation.registerBlocks()
|
||||
@@ -231,6 +244,9 @@ object Cobblemon {
|
||||
}
|
||||
}
|
||||
|
||||
// Register the grow_tumblestone advancement
|
||||
PlatformEvents.RIGHT_CLICK_BLOCK.subscribe { AdvancementHandler.onTumbleStonePlaced(it) }
|
||||
|
||||
PlatformEvents.CHANGE_DIMENSION.subscribe {
|
||||
it.player.party().forEach { pokemon -> pokemon.entity?.recallWithAnimation() }
|
||||
}
|
||||
@@ -240,6 +256,16 @@ object Cobblemon {
|
||||
TrackedDataHandlerRegistry.register(PoseTypeDataSerializer)
|
||||
TrackedDataHandlerRegistry.register(IdentifierDataSerializer)
|
||||
|
||||
// Lowest priority because this applies after luxury ball bonus as of gen 4
|
||||
CobblemonEvents.FRIENDSHIP_UPDATED.subscribe(Priority.LOWEST) { event ->
|
||||
var increment = (event.newFriendship - event.pokemon.friendship).toFloat()
|
||||
// Our Luxury ball spec is diff from official, but we will still assume these stack
|
||||
if (event.pokemon.heldItemNoCopy().isIn(CobblemonItemTags.IS_FRIENDSHIP_BOOSTER)) {
|
||||
increment += increment * 0.5F
|
||||
}
|
||||
event.newFriendship = event.pokemon.friendship + increment.roundToInt()
|
||||
}
|
||||
|
||||
HeldItemProvider.register(CobblemonHeldItemManager, Priority.LOWEST)
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import com.cobblemon.mod.common.block.entity.FossilMultiblockEntity
|
||||
import com.cobblemon.mod.common.block.entity.RestorationTankBlockEntity
|
||||
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockBuilder
|
||||
import com.cobblemon.mod.common.block.entity.*
|
||||
import com.cobblemon.mod.common.block.entity.DisplayCaseBlockEntity
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import net.minecraft.block.entity.BlockEntityType
|
||||
import net.minecraft.registry.Registries
|
||||
@@ -77,4 +78,9 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
|
||||
CobblemonBlocks.FOSSIL_ANALYZER
|
||||
).build(null)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val DISPLAY_CASE: BlockEntityType<DisplayCaseBlockEntity> = this.create("display_case",
|
||||
BlockEntityType.Builder.create(::DisplayCaseBlockEntity, CobblemonBlocks.DISPLAY_CASE).build(null)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -72,6 +72,8 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
@JvmField
|
||||
val SUN_STONE_ORE = evolutionStoneOre("sun_stone_ore")
|
||||
@JvmField
|
||||
val TERRACOTTA_SUN_STONE_ORE = evolutionStoneOre("terracotta_sun_stone_ore")
|
||||
@JvmField
|
||||
val THUNDER_STONE_ORE = evolutionStoneOre("thunder_stone_ore")
|
||||
@JvmField
|
||||
val WATER_STONE_ORE = evolutionStoneOre("water_stone_ore")
|
||||
@@ -113,11 +115,11 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
@JvmField
|
||||
val APRICORN_FENCE = this.create("apricorn_fence", FenceBlock(AbstractBlock.Settings.create().mapColor(APRICORN_PLANKS.defaultMapColor).instrument(Instrument.BASS).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
|
||||
@JvmField
|
||||
val APRICORN_FENCE_GATE = this.create("apricorn_fence_gate", FenceGateBlock(AbstractBlock.Settings.create().mapColor(APRICORN_PLANKS.defaultMapColor).instrument(Instrument.BASS).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD), APRICORN_WOOD_TYPE))
|
||||
val APRICORN_FENCE_GATE = this.create("apricorn_fence_gate", FenceGateBlock(APRICORN_WOOD_TYPE, AbstractBlock.Settings.create().mapColor(APRICORN_PLANKS.defaultMapColor).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
|
||||
@JvmField // Note At the time of 1.20.0 we don't need our own BlockSetType for Apricorn wood
|
||||
val APRICORN_BUTTON = this.create("apricorn_button", BlocksInvoker.createWoodenButtonBlock(BlockSetType.OAK))
|
||||
@JvmField
|
||||
val APRICORN_PRESSURE_PLATE = this.create("apricorn_pressure_plate", PressurePlateBlockInvoker.`cobblemon$create`(PressurePlateBlock.ActivationRule.EVERYTHING, AbstractBlock.Settings.create().mapColor(APRICORN_PLANKS.defaultMapColor).instrument(Instrument.BASS).noCollision().strength(0.5f).sounds(BlockSoundGroup.WOOD), APRICORN_BLOCK_SET_TYPE))
|
||||
val APRICORN_PRESSURE_PLATE = this.create("apricorn_pressure_plate", PressurePlateBlockInvoker.`cobblemon$create`(APRICORN_BLOCK_SET_TYPE, AbstractBlock.Settings.create().mapColor(APRICORN_PLANKS.defaultMapColor).noCollision().strength(0.5f).sounds(BlockSoundGroup.WOOD)))
|
||||
@JvmField
|
||||
val APRICORN_SIGN = this.create("apricorn_sign", CobblemonSignBlock(AbstractBlock.Settings.copy(Blocks.OAK_SIGN), APRICORN_WOOD_TYPE))
|
||||
@JvmField
|
||||
@@ -131,9 +133,9 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
@JvmField
|
||||
val APRICORN_STAIRS = this.create("apricorn_stairs", StairsBlockInvoker.`cobblemon$create`(APRICORN_PLANKS.defaultState, AbstractBlock.Settings.copy(APRICORN_PLANKS)))
|
||||
@JvmField
|
||||
val APRICORN_DOOR = this.create("apricorn_door", DoorBlockInvoker.`cobblemon$create`(AbstractBlock.Settings.create().mapColor(APRICORN_PLANKS.defaultMapColor).instrument(Instrument.BASS).strength(3.0F).sounds(BlockSoundGroup.WOOD).nonOpaque(), APRICORN_BLOCK_SET_TYPE))
|
||||
val APRICORN_DOOR = this.create("apricorn_door", DoorBlockInvoker.`cobblemon$create`(APRICORN_BLOCK_SET_TYPE, AbstractBlock.Settings.create().mapColor(APRICORN_PLANKS.defaultMapColor).instrument(Instrument.BASS).strength(3.0F).sounds(BlockSoundGroup.WOOD).nonOpaque()))
|
||||
@JvmField
|
||||
val APRICORN_TRAPDOOR = this.create("apricorn_trapdoor", TrapdoorBlockInvoker.`cobblemon$create`(AbstractBlock.Settings.create().mapColor(MapColor.OAK_TAN).instrument(Instrument.BASS).strength(3.0F).sounds(BlockSoundGroup.WOOD).nonOpaque().allowsSpawning { _, _, _, _ -> false }, APRICORN_BLOCK_SET_TYPE))
|
||||
val APRICORN_TRAPDOOR = this.create("apricorn_trapdoor", TrapdoorBlockInvoker.`cobblemon$create`(APRICORN_BLOCK_SET_TYPE, AbstractBlock.Settings.create().mapColor(MapColor.OAK_TAN).instrument(Instrument.BASS).strength(3.0F).sounds(BlockSoundGroup.WOOD).nonOpaque().allowsSpawning { _, _, _, _ -> false }))
|
||||
|
||||
private val PLANT_PROPERTIES = AbstractBlock.Settings.create().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.GRASS).pistonBehavior(PistonBehavior.DESTROY)
|
||||
@JvmField
|
||||
@@ -158,7 +160,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
@JvmField
|
||||
val BIG_ROOT = this.create("big_root", BigRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.BIG_ROOT_SOUNDS)))
|
||||
@JvmField
|
||||
val REVIVAL_HERB = this.create("revival_herb", RevivalHerbBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).mapColor(MapColor.DARK_GREEN).burnable().noCollision().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
||||
val REVIVAL_HERB = this.create("revival_herb", RevivalHerbBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).mapColor(MapColor.DARK_GREEN).burnable().noCollision().breakInstantly().sounds(CobblemonSounds.REVIVAL_HERB_SOUNDS)))
|
||||
|
||||
@JvmField
|
||||
val TUMBLESTONE_CLUSTER = tumblestoneBlock("tumblestone_cluster", GrowableStoneBlock.STAGE_3, 7, 3, null)
|
||||
@@ -387,6 +389,18 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val DISPLAY_CASE = create(
|
||||
"display_case",
|
||||
DisplayCaseBlock(
|
||||
AbstractBlock.Settings.create()
|
||||
.sounds(CobblemonSounds.DISPLAY_CASE_SOUNDS)
|
||||
.nonOpaque()
|
||||
.pistonBehavior(PistonBehavior.BLOCK)
|
||||
.mapColor(MapColor.STONE_GRAY)
|
||||
.strength(0.3f)
|
||||
)
|
||||
)
|
||||
|
||||
val RED_MINT = create("red_mint", MintBlock(MintType.RED, AbstractBlock.Settings.create().mapColor(MapColor.RED).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
|
||||
@JvmField
|
||||
val BLUE_MINT = create("blue_mint", MintBlock(MintType.BLUE, AbstractBlock.Settings.create().mapColor(MapColor.BLUE).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
|
||||
@@ -414,7 +428,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val VIVICHOKE_SEEDS = this.create("vivichoke_seeds", VivichokeBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
||||
val VIVICHOKE_SEEDS = this.create("vivichoke_seeds", VivichokeBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.VIVICHOKE_SOUNDS)))
|
||||
@JvmField
|
||||
val PEP_UP_FLOWER = this.create("pep_up_flower", FlowerBlock(StatusEffects.LEVITATION, 10, AbstractBlock.Settings.create().mapColor(MapColor.DARK_GREEN).noCollision().breakInstantly().sounds(BlockSoundGroup.GRASS).offset(AbstractBlock.OffsetType.XZ).pistonBehavior(PistonBehavior.DESTROY)))
|
||||
@JvmField
|
||||
@@ -546,7 +560,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
/**
|
||||
* Calls helper method from Vanilla
|
||||
*/
|
||||
private fun log(name: String, arg: MapColor = MapColor.DIRT_BROWN, arg2: MapColor = MapColor.DIRT_BROWN): PillarBlock {
|
||||
private fun log(name: String, arg: MapColor = MapColor.DIRT_BROWN, arg2: MapColor = MapColor.DIRT_BROWN): Block {
|
||||
val block = BlocksInvoker.createLogBlock(arg, arg2)
|
||||
return this.create(name, block)
|
||||
}
|
||||
@@ -566,16 +580,16 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
return block
|
||||
}
|
||||
|
||||
private fun evolutionStoneOre(name: String) = this.create(name, ExperienceDroppingBlock(AbstractBlock.Settings.copy(Blocks.IRON_ORE), UniformIntProvider.create(1, 2)))
|
||||
private fun evolutionStoneOre(name: String) = this.create(name, ExperienceDroppingBlock(UniformIntProvider.create(1, 2), AbstractBlock.Settings.copy(Blocks.IRON_ORE)))
|
||||
|
||||
private fun deepslateEvolutionStoneOre(name: String) = this.create(name, ExperienceDroppingBlock(AbstractBlock.Settings.copy(Blocks.DEEPSLATE_IRON_ORE), UniformIntProvider.create(1, 2)))
|
||||
private fun deepslateEvolutionStoneOre(name: String) = this.create(name, ExperienceDroppingBlock(UniformIntProvider.create(1, 2), AbstractBlock.Settings.copy(Blocks.DEEPSLATE_IRON_ORE)))
|
||||
|
||||
/**
|
||||
* Helper method for creating leaves
|
||||
* copied over from Vanilla
|
||||
*/
|
||||
private fun leaves(name: String): LeavesBlock {
|
||||
private fun leaves(name: String): Block {
|
||||
val block = BlocksInvoker.createLeavesBlock(BlockSoundGroup.GRASS)
|
||||
return this.create(name, block)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,5 +48,9 @@ object CobblemonCommands {
|
||||
PokemonRestartCommand.register(dispatcher)
|
||||
BedrockParticleCommand.register(dispatcher)
|
||||
OpenDialogueCommand.register(dispatcher)
|
||||
|
||||
// Possibly lock down registration if and only if under dev environment or running in an environment
|
||||
// with a certain system environment variable set
|
||||
CobblemonInfoCommand.register(dispatcher)
|
||||
}
|
||||
}
|
||||
@@ -146,7 +146,7 @@ interface CobblemonImplementation {
|
||||
* @param criteria
|
||||
* @return
|
||||
*/
|
||||
fun <T : Criterion<*>> registerCriteria(criteria: T): T
|
||||
fun <T : Criterion<*>> registerCriteria(id: String, criteria: T): T
|
||||
|
||||
/**
|
||||
* TODO
|
||||
@@ -240,4 +240,4 @@ enum class Environment {
|
||||
CLIENT,
|
||||
SERVER
|
||||
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.api.item.ability.AbilityChanger
|
||||
import com.cobblemon.mod.common.api.mulch.MulchVariant
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.api.pokemon.Natures
|
||||
@@ -29,6 +30,8 @@ import com.cobblemon.mod.common.item.berry.PortionHealingBerryItem
|
||||
import com.cobblemon.mod.common.item.berry.StatusCuringBerryItem
|
||||
import com.cobblemon.mod.common.item.berry.VolatileCuringBerryItem
|
||||
import com.cobblemon.mod.common.item.interactive.*
|
||||
import com.cobblemon.mod.common.item.interactive.PotionItem
|
||||
import com.cobblemon.mod.common.item.interactive.ability.AbilityChangeItem
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import com.cobblemon.mod.common.pokeball.PokeBall
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
@@ -37,14 +40,7 @@ import net.minecraft.block.Block
|
||||
import net.minecraft.entity.LivingEntity
|
||||
import net.minecraft.entity.effect.StatusEffectInstance
|
||||
import net.minecraft.entity.effect.StatusEffects
|
||||
import net.minecraft.item.BlockItem
|
||||
import net.minecraft.item.FoodComponent
|
||||
import net.minecraft.item.HangingSignItem
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.item.SignItem
|
||||
import net.minecraft.item.SmithingTemplateItem
|
||||
import net.minecraft.item.StewItem
|
||||
import net.minecraft.item.*
|
||||
import net.minecraft.registry.Registries
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.RegistryKey
|
||||
@@ -258,6 +254,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
val PC = blockItem("pc", CobblemonBlocks.PC)
|
||||
@JvmField
|
||||
val PASTURE = blockItem("pasture", CobblemonBlocks.PASTURE)
|
||||
@JvmField
|
||||
val DISPLAY_CASE = blockItem("display_case", CobblemonBlocks.DISPLAY_CASE)
|
||||
|
||||
// Evolution items
|
||||
@JvmField val LINK_CABLE = create("link_cable", LinkCableItem())
|
||||
@@ -285,6 +283,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
@JvmField val RIBBON_SWEET = noSettingsItem("ribbon_sweet")
|
||||
@JvmField val CHIPPED_POT = noSettingsItem("chipped_pot")
|
||||
@JvmField val CRACKED_POT = noSettingsItem("cracked_pot")
|
||||
@JvmField val MASTERPIECE_TEACUP = noSettingsItem("masterpiece_teacup")
|
||||
@JvmField val UNREMARKABLE_TEACUP = noSettingsItem("unremarkable_teacup")
|
||||
@JvmField val SWEET_APPLE = noSettingsItem("sweet_apple")
|
||||
@JvmField val TART_APPLE = noSettingsItem("tart_apple")
|
||||
@JvmField val GALARICA_CUFF = noSettingsItem("galarica_cuff")
|
||||
@@ -408,7 +408,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
@JvmField
|
||||
val CLEVER_FEATHER = create("clever_feather", FeatherItem(Stats.SPECIAL_DEFENCE))
|
||||
@JvmField
|
||||
val MEDICINAL_LEEK = create("medicinal_leek", MedicinalLeekItem(CobblemonBlocks.MEDICINAL_LEEK, Item.Settings().food(FoodComponent.Builder().snack().hunger(1).saturationModifier(0.2f).build())))
|
||||
val MEDICINAL_LEEK = heldItem("medicinal_leek", MedicinalLeekItem(CobblemonBlocks.MEDICINAL_LEEK, Item.Settings().food(FoodComponent.Builder().snack().hunger(1).saturationModifier(0.2f).build())), "leek")
|
||||
@JvmField
|
||||
val ROASTED_LEEK = create("roasted_leek", Item(Item.Settings().food(FoodComponent.Builder().snack().hunger(3).saturationModifier(0.3f).build())))
|
||||
@JvmField
|
||||
@@ -558,6 +558,11 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
@JvmField val ELIXIR = create("elixir", ElixirItem(max = false))
|
||||
@JvmField val MAX_ELIXIR = create("max_elixir", ElixirItem(max = true))
|
||||
|
||||
@JvmField
|
||||
val ABILITY_CAPSULE = this.create("ability_capsule", AbilityChangeItem(AbilityChanger.COMMON_ABILITY))
|
||||
@JvmField
|
||||
val ABILITY_PATCH = this.create("ability_patch", AbilityChangeItem(AbilityChanger.HIDDEN_ABILITY))
|
||||
|
||||
/**
|
||||
* Evolution Ores and Stones
|
||||
*/
|
||||
@@ -578,6 +583,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
@JvmField
|
||||
val SUN_STONE_ORE = blockItem("sun_stone_ore", CobblemonBlocks.SUN_STONE_ORE)
|
||||
@JvmField
|
||||
val TERRACOTTA_SUN_STONE_ORE = blockItem("terracotta_sun_stone_ore", CobblemonBlocks.TERRACOTTA_SUN_STONE_ORE)
|
||||
@JvmField
|
||||
val THUNDER_STONE_ORE = blockItem("thunder_stone_ore", CobblemonBlocks.THUNDER_STONE_ORE)
|
||||
@JvmField
|
||||
val WATER_STONE_ORE = blockItem("water_stone_ore", CobblemonBlocks.WATER_STONE_ORE)
|
||||
@@ -629,16 +636,28 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
|
||||
// Held Items
|
||||
@JvmField
|
||||
val ABILITY_SHIELD = heldItem("ability_shield")
|
||||
@JvmField
|
||||
val ABSORB_BULB = heldItem("absorb_bulb")
|
||||
@JvmField
|
||||
val AIR_BALLOON = heldItem("air_balloon")
|
||||
@JvmField
|
||||
val ASSAULT_VEST = heldItem("assault_vest")
|
||||
@JvmField
|
||||
val BIG_ROOT = blockItem("big_root", CobblemonBlocks.BIG_ROOT)
|
||||
@JvmField
|
||||
val BINDING_BAND = heldItem("binding_band")
|
||||
@JvmField
|
||||
val BLACK_BELT = heldItem("black_belt")
|
||||
@JvmField
|
||||
val BLACK_GLASSES = heldItem("black_glasses")
|
||||
@JvmField
|
||||
val BLACK_SLUDGE = heldItem("black_sludge")
|
||||
@JvmField
|
||||
val BLUNDER_POLICY = heldItem("blunder_policy")
|
||||
@JvmField
|
||||
val CELL_BATTERY = heldItem("cell_battery")
|
||||
@JvmField
|
||||
val CHARCOAL = heldItem("charcoal_stick", remappedName = "charcoal")
|
||||
@JvmField
|
||||
val CHOICE_BAND = heldItem("choice_band")
|
||||
@@ -649,26 +668,64 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
@JvmField
|
||||
val CLEANSE_TAG = heldItem("cleanse_tag")
|
||||
@JvmField
|
||||
val CLEAR_AMULET = heldItem("clear_amulet")
|
||||
@JvmField
|
||||
val COVERT_CLOAK = heldItem("covert_cloak")
|
||||
@JvmField
|
||||
val DESTINY_KNOT = heldItem("destiny_knot")
|
||||
@JvmField
|
||||
val DRAGON_FANG = heldItem("dragon_fang")
|
||||
@JvmField
|
||||
val EJECT_BUTTON = heldItem("eject_button")
|
||||
@JvmField
|
||||
val EJECT_PACK = heldItem("eject_pack")
|
||||
@JvmField
|
||||
val EVERSTONE = heldItem("everstone")
|
||||
@JvmField
|
||||
val EVIOLITE = heldItem("eviolite")
|
||||
@JvmField
|
||||
val EXP_SHARE = heldItem("exp_share")
|
||||
@JvmField
|
||||
val EXPERT_BELT = heldItem("expert_belt")
|
||||
@JvmField
|
||||
val FAIRY_FEATHER = heldItem("fairy_feather")
|
||||
@JvmField
|
||||
val FLAME_ORB = heldItem("flame_orb")
|
||||
@JvmField
|
||||
val FLOAT_STONE = heldItem("float_stone")
|
||||
@JvmField
|
||||
val FOCUS_BAND = heldItem("focus_band")
|
||||
@JvmField
|
||||
val FOCUS_SASH = heldItem("focus_sash")
|
||||
@JvmField
|
||||
val GRIP_CLAW = heldItem("grip_claw")
|
||||
@JvmField
|
||||
val HARD_STONE = heldItem("hard_stone")
|
||||
@JvmField
|
||||
val HEAVY_DUTY_BOOTS = heldItem("heavy_duty_boots")
|
||||
@JvmField
|
||||
val IRON_BALL = heldItem("iron_ball")
|
||||
@JvmField
|
||||
val LAGGING_TAIL = heldItem("lagging_tail")
|
||||
@JvmField
|
||||
val LEFTOVERS = heldItem("leftovers")
|
||||
@JvmField
|
||||
val LIFE_ORB = heldItem("life_orb")
|
||||
@JvmField
|
||||
val LIGHT_BALL = heldItem("light_ball")
|
||||
@JvmField
|
||||
val LIGHT_CLAY = heldItem("light_clay")
|
||||
@JvmField
|
||||
val LOADED_DICE = heldItem("loaded_dice")
|
||||
@JvmField
|
||||
val LUCKY_EGG = heldItem("lucky_egg")
|
||||
@JvmField
|
||||
val LUMINOUS_MOSS = heldItem("luminous_moss")
|
||||
@JvmField
|
||||
val MAGNET = heldItem("magnet")
|
||||
@JvmField
|
||||
val METRONOME = heldItem("metronome")
|
||||
@JvmField
|
||||
val MIRACLE_SEED = heldItem("miracle_seed")
|
||||
@JvmField
|
||||
val MUSCLE_BAND = heldItem("muscle_band")
|
||||
@@ -679,14 +736,42 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
@JvmField
|
||||
val POISON_BARB = heldItem("poison_barb")
|
||||
@JvmField
|
||||
val POWER_ANKLET = heldItem("power_anklet")
|
||||
@JvmField
|
||||
val POWER_BAND = heldItem("power_band")
|
||||
@JvmField
|
||||
val POWER_BELT = heldItem("power_belt")
|
||||
@JvmField
|
||||
val POWER_BRACER = heldItem("power_bracer")
|
||||
@JvmField
|
||||
val POWER_LENS = heldItem("power_lens")
|
||||
@JvmField
|
||||
val POWER_WEIGHT = heldItem("power_weight")
|
||||
@JvmField
|
||||
val PROTECTIVE_PADS = heldItem("protective_pads")
|
||||
@JvmField
|
||||
val PUNCHING_GLOVE = heldItem("punching_glove")
|
||||
@JvmField
|
||||
val QUICK_CLAW = heldItem("quick_claw")
|
||||
@JvmField
|
||||
val RED_CARD = heldItem("red_card")
|
||||
@JvmField
|
||||
val RING_TARGET = heldItem("ring_target")
|
||||
@JvmField
|
||||
val ROCKY_HELMET = heldItem("rocky_helmet")
|
||||
@JvmField
|
||||
val ROOM_SERVICE = heldItem("room_service")
|
||||
@JvmField
|
||||
val SAFETY_GOGGLES = heldItem("safety_goggles")
|
||||
@JvmField
|
||||
val SCOPE_LENS = heldItem("scope_lens")
|
||||
@JvmField
|
||||
val SHARP_BEAK = heldItem("sharp_beak")
|
||||
@JvmField
|
||||
val SHED_SHELL = heldItem("shed_shell")
|
||||
@JvmField
|
||||
val SHELL_BELL = heldItem("shell_bell")
|
||||
@JvmField
|
||||
val SILK_SCARF = heldItem("silk_scarf")
|
||||
@JvmField
|
||||
val SILVER_POWDER = heldItem("silver_powder")
|
||||
@@ -695,10 +780,30 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
@JvmField
|
||||
val SPELL_TAG = heldItem("spell_tag")
|
||||
@JvmField
|
||||
val SMOKE_BALL = heldItem("smoke_ball")
|
||||
@JvmField
|
||||
val SOOTHE_BELL = heldItem("soothe_bell")
|
||||
@JvmField
|
||||
val STICKY_BARB = heldItem("sticky_barb")
|
||||
@JvmField
|
||||
val TERRAIN_EXTENDER = heldItem("terrain_extender")
|
||||
@JvmField
|
||||
val THROAT_SPRAY = heldItem("throat_spray")
|
||||
@JvmField
|
||||
val TOXIC_ORB = heldItem("toxic_orb")
|
||||
@JvmField
|
||||
val TWISTED_SPOON = heldItem("twisted_spoon")
|
||||
@JvmField
|
||||
val UTILITY_UMBRELLA = heldItem("utility_umbrella")
|
||||
@JvmField
|
||||
val WEAKNESS_POLICY = heldItem("weakness_policy")
|
||||
@JvmField
|
||||
val WIDE_LENS = heldItem("wide_lens")
|
||||
@JvmField
|
||||
val WISE_GLASSES = heldItem("wise_glasses")
|
||||
@JvmField
|
||||
val ZOOM_LENS = heldItem("zoom_lens")
|
||||
@JvmField
|
||||
val MENTAL_HERB = compostableHeldItem("mental_herb", null, 1F)
|
||||
@JvmField
|
||||
val MIRROR_HERB = compostableHeldItem("mirror_herb", null, 1F)
|
||||
@@ -713,29 +818,13 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
@JvmField
|
||||
val QUICK_POWDER = heldItem("quick_powder")
|
||||
@JvmField
|
||||
val DESTINY_KNOT = heldItem("destiny_knot")
|
||||
val DAMP_ROCK = heldItem("damp_rock")
|
||||
@JvmField
|
||||
val EVERSTONE = heldItem("everstone")
|
||||
val HEAT_ROCK = heldItem("heat_rock")
|
||||
@JvmField
|
||||
val POWER_ANKLET = heldItem("power_anklet")
|
||||
val SMOOTH_ROCK = heldItem("smooth_rock")
|
||||
@JvmField
|
||||
val POWER_BAND = heldItem("power_band")
|
||||
@JvmField
|
||||
val POWER_BELT = heldItem("power_belt")
|
||||
@JvmField
|
||||
val POWER_BRACER = heldItem("power_bracer")
|
||||
@JvmField
|
||||
val POWER_LENS = heldItem("power_lens")
|
||||
@JvmField
|
||||
val POWER_WEIGHT = heldItem("power_weight")
|
||||
@JvmField
|
||||
val FLAME_ORB = heldItem("flame_orb")
|
||||
@JvmField
|
||||
val LIFE_ORB = heldItem("life_orb")
|
||||
@JvmField
|
||||
val TOXIC_ORB = heldItem("toxic_orb")
|
||||
@JvmField
|
||||
val SMOKE_BALL = heldItem("smoke_ball")
|
||||
val ICY_ROCK = heldItem("icy_rock")
|
||||
|
||||
// Mulch
|
||||
@JvmField
|
||||
@@ -922,6 +1011,16 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
}
|
||||
}
|
||||
)
|
||||
private fun heldItem(name: String, item: Item, remappedName: String? = null) = create(
|
||||
name = name,
|
||||
entry = item.also {
|
||||
if (remappedName != null) {
|
||||
CobblemonHeldItemManager.registerRemap(it, remappedName)
|
||||
CobblemonHeldItemManager.registerRemap(Items.BONE, "thickclub")
|
||||
CobblemonHeldItemManager.registerRemap(Items.SNOWBALL, "snowball")
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
private fun compostable(item: Item, increaseLevelChance: Float) = Cobblemon.implementation.registerCompostable(item, increaseLevelChance)
|
||||
|
||||
|
||||
@@ -14,25 +14,7 @@ import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.PlayerInteractOptionsHandler
|
||||
import com.cobblemon.mod.common.client.net.SetClientPlayerDataHandler
|
||||
import com.cobblemon.mod.common.client.net.animation.PlayPoseableAnimationHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleApplyPassResponseHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleCaptureEndHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleCaptureShakeHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleCaptureStartHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleChallengeExpiredHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleChallengeNotificationHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleEndHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleFaintHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleHealthChangeHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleInitializeHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleMadeInvalidChoiceHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleMakeChoiceHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleMessageHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleMusicHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattlePersistentStatusHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleQueueRequestHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleSetTeamPokemonHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleSwitchPokemonHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.BattleUpdateTeamPokemonHandler
|
||||
import com.cobblemon.mod.common.client.net.battle.*
|
||||
import com.cobblemon.mod.common.client.net.callback.move.OpenMoveCallbackHandler
|
||||
import com.cobblemon.mod.common.client.net.callback.party.OpenPartyCallbackHandler
|
||||
import com.cobblemon.mod.common.client.net.callback.partymove.OpenPartyMoveCallbackHandler
|
||||
@@ -305,6 +287,8 @@ object CobblemonNetwork : NetworkManager {
|
||||
this.createClientBound(BattleMadeInvalidChoicePacket.ID, BattleMadeInvalidChoicePacket::decode, BattleMadeInvalidChoiceHandler)
|
||||
this.createClientBound(BattleMusicPacket.ID, BattleMusicPacket::decode, BattleMusicHandler)
|
||||
this.createClientBound(BattleChallengeExpiredPacket.ID, BattleChallengeExpiredPacket::decode, BattleChallengeExpiredHandler)
|
||||
this.createClientBound(BattleReplacePokemonPacket.ID, BattleReplacePokemonPacket::decode, BattleReplacePokemonHandler)
|
||||
this.createClientBound(BattleTransformPokemonPacket.ID, BattleTransformPokemonPacket::decode, BattleTransformPokemonHandler)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -99,27 +99,27 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
||||
val MULCH_REMOVE = this.create("mulch.remove")
|
||||
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_ACTIVATE = this.create("fossilmachine.activate")
|
||||
val FOSSIL_MACHINE_ACTIVATE = this.create("fossil_machine.activate")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_ACTIVE_LOOP = this.create("fossilmachine.active_loop")
|
||||
val FOSSIL_MACHINE_ACTIVE_LOOP = this.create("fossil_machine.active_loop")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_ASSEMBLE = this.create("fossilmachine.assemble")
|
||||
val FOSSIL_MACHINE_ASSEMBLE = this.create("fossil_machine.assemble")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_DNA_FULL = this.create("fossilmachine.dna_full")
|
||||
val FOSSIL_MACHINE_DNA_FULL = this.create("fossil_machine.dna_full")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_FINISHED = this.create("fossilmachine.finished")
|
||||
val FOSSIL_MACHINE_FINISHED = this.create("fossil_machine.finished")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_INSERT_DNA = this.create("fossilmachine.insert_dna")
|
||||
val FOSSIL_MACHINE_INSERT_DNA = this.create("fossil_machine.insert_dna")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_INSERT_DNA_SMALL = this.create("fossilmachine.insert_dna_small")
|
||||
val FOSSIL_MACHINE_INSERT_DNA_SMALL = this.create("fossil_machine.insert_dna_small")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_INSERT_FOSSIL = this.create("fossilmachine.insert_fossil")
|
||||
val FOSSIL_MACHINE_INSERT_FOSSIL = this.create("fossil_machine.insert_fossil")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_RETRIEVE_FOSSIL = this.create("fossilmachine.retrieve_fossil")
|
||||
val FOSSIL_MACHINE_RETRIEVE_FOSSIL = this.create("fossil_machine.retrieve_fossil")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_RETRIEVE_POKEMON = this.create("fossilmachine.retrieve_pokemon")
|
||||
val FOSSIL_MACHINE_RETRIEVE_POKEMON = this.create("fossil_machine.retrieve_pokemon")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_UNPROTECTED = this.create("fossilmachine.unprotected")
|
||||
val FOSSIL_MACHINE_UNPROTECTED = this.create("fossil_machine.unprotected")
|
||||
|
||||
@JvmField
|
||||
val COIN_POUCH_BREAK = this.create("coin_pouch.break")
|
||||
@@ -155,11 +155,21 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
||||
@JvmField
|
||||
val ENERGY_ROOT_PLACE = this.create("energy_root.place")
|
||||
|
||||
@JvmField
|
||||
val VIVICHOKE_BREAK = this.create("vivichoke.break")
|
||||
@JvmField
|
||||
val VIVICHOKE_PLACE = this.create("vivichoke.place")
|
||||
|
||||
@JvmField
|
||||
val MINT_BREAK = this.create("mint.break")
|
||||
@JvmField
|
||||
val MINT_PLACE = this.create("mint.place")
|
||||
|
||||
@JvmField
|
||||
val REVIVAL_HERB_BREAK = this.create("revival_herb.break")
|
||||
@JvmField
|
||||
val REVIVAL_HERB_PLACE = this.create("revival_herb.place")
|
||||
|
||||
@JvmField
|
||||
val MEDICINAL_LEEK_BREAK = this.create("medicinal_leek.break")
|
||||
@JvmField
|
||||
@@ -277,6 +287,15 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
||||
SoundEvents.BLOCK_GRASS_FALL
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val VIVICHOKE_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
VIVICHOKE_BREAK,
|
||||
SoundEvents.BLOCK_GRASS_STEP,
|
||||
VIVICHOKE_PLACE,
|
||||
SoundEvents.BLOCK_GRASS_HIT,
|
||||
SoundEvents.BLOCK_GRASS_FALL
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val MINT_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
MINT_BREAK,
|
||||
@@ -286,6 +305,15 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
||||
SoundEvents.BLOCK_GRASS_FALL
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val REVIVAL_HERB_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
REVIVAL_HERB_BREAK,
|
||||
SoundEvents.BLOCK_GRASS_STEP,
|
||||
REVIVAL_HERB_PLACE,
|
||||
SoundEvents.BLOCK_GRASS_HIT,
|
||||
SoundEvents.BLOCK_GRASS_FALL
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val GILDED_CHEST_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
GILDED_CHEST_BREAK,
|
||||
@@ -295,5 +323,27 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
||||
GILDED_CHEST_STEP
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val DISPLAY_CASE_ADD_ITEM = this.create("display_case.add_item")
|
||||
@JvmField
|
||||
val DISPLAY_CASE_REMOVE_ITEM = this.create("display_case.remove_item")
|
||||
@JvmField
|
||||
val DISPLAY_CASE_BREAK = this.create("display_case.break")
|
||||
@JvmField
|
||||
val DISPLAY_CASE_HIT = this.create("display_case.hit")
|
||||
@JvmField
|
||||
val DISPLAY_CASE_PLACE = this.create("display_case.place")
|
||||
@JvmField
|
||||
val DISPLAY_CASE_STEP = this.create("display_case.step")
|
||||
|
||||
@JvmField
|
||||
val DISPLAY_CASE_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
DISPLAY_CASE_BREAK,
|
||||
DISPLAY_CASE_STEP,
|
||||
DISPLAY_CASE_PLACE,
|
||||
DISPLAY_CASE_HIT,
|
||||
DISPLAY_CASE_STEP
|
||||
)
|
||||
|
||||
private fun create(name: String): SoundEvent = this.create(name, SoundEvent.of(cobblemonResource(name)))
|
||||
}
|
||||
@@ -9,8 +9,18 @@
|
||||
package com.cobblemon.mod.common.advancement
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.advancement.criterion.*
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.advancement.criterion.AspectCriterion
|
||||
import com.cobblemon.mod.common.advancement.criterion.BattleCountableCriterion
|
||||
import com.cobblemon.mod.common.advancement.criterion.CaughtPokemonCriterion
|
||||
import com.cobblemon.mod.common.advancement.criterion.CountableCriterion
|
||||
import com.cobblemon.mod.common.advancement.criterion.EvolvePokemonCriterion
|
||||
import com.cobblemon.mod.common.advancement.criterion.LevelUpCriterion
|
||||
import com.cobblemon.mod.common.advancement.criterion.PartyCheckCriterion
|
||||
import com.cobblemon.mod.common.advancement.criterion.PlantTumblestoneCriterion
|
||||
import com.cobblemon.mod.common.advancement.criterion.PokemonCriterion
|
||||
import com.cobblemon.mod.common.advancement.criterion.PokemonInteractCriterion
|
||||
import com.cobblemon.mod.common.advancement.criterion.SimpleCriterionTrigger
|
||||
import com.cobblemon.mod.common.advancement.criterion.TradePokemonCriterion
|
||||
import net.minecraft.advancement.criterion.Criterion
|
||||
|
||||
/**
|
||||
@@ -20,99 +30,37 @@ import net.minecraft.advancement.criterion.Criterion
|
||||
* @since October 26th, 2022
|
||||
*/
|
||||
object CobblemonCriteria {
|
||||
val PICK_STARTER = this.create(
|
||||
SimpleCriterionTrigger(
|
||||
cobblemonResource("pick_starter"),
|
||||
PickStarterCriterionCondition::class.java
|
||||
)
|
||||
)
|
||||
val CATCH_POKEMON = this.create(
|
||||
SimpleCriterionTrigger(
|
||||
cobblemonResource("catch_pokemon"),
|
||||
CaughtPokemonCriterionCondition::class.java
|
||||
)
|
||||
)
|
||||
val CATCH_SHINY_POKEMON = this.create(
|
||||
SimpleCriterionTrigger(
|
||||
cobblemonResource("catch_shiny_pokemon"),
|
||||
SimpleCountableCriterionCondition::class.java
|
||||
)
|
||||
)
|
||||
val EGG_HATCH = this.create(
|
||||
SimpleCriterionTrigger(
|
||||
cobblemonResource("eggs_hatched"),
|
||||
SimpleCountableCriterionCondition::class.java
|
||||
)
|
||||
)
|
||||
val EVOLVE_POKEMON = this.create(
|
||||
SimpleCriterionTrigger(
|
||||
cobblemonResource("pokemon_evolved"),
|
||||
EvolvePokemonCriterionCondition::class.java
|
||||
)
|
||||
)
|
||||
val WIN_BATTLE = this.create(
|
||||
BattleCountableCriterionTrigger(
|
||||
cobblemonResource("battles_won"),
|
||||
BattleCountableCriterionCondition::class.java
|
||||
)
|
||||
)
|
||||
val PICK_STARTER = this.create("pick_starter", SimpleCriterionTrigger(PokemonCriterion.CODEC))
|
||||
|
||||
val DEFEAT_POKEMON = this.create(
|
||||
SimpleCriterionTrigger(
|
||||
cobblemonResource("pokemon_defeated"),
|
||||
SimpleCountableCriterionCondition::class.java
|
||||
)
|
||||
)
|
||||
val CATCH_POKEMON = this.create("catch_pokemon", SimpleCriterionTrigger(CaughtPokemonCriterion.CODEC))
|
||||
|
||||
val COLLECT_ASPECT = this.create(
|
||||
AspectCriterionTrigger(
|
||||
cobblemonResource("aspects_collected"),
|
||||
AspectCriterionCondition::class.java
|
||||
)
|
||||
)
|
||||
val CATCH_SHINY_POKEMON = this.create("catch_shiny_pokemon", SimpleCriterionTrigger(CountableCriterion.CODEC))
|
||||
|
||||
val POKEMON_INTERACT = this.create(
|
||||
SimpleCriterionTrigger(
|
||||
cobblemonResource("pokemon_interact"),
|
||||
PokemonInteractCriterion::class.java
|
||||
)
|
||||
)
|
||||
val EGG_HATCH = this.create("eggs_hatched", SimpleCriterionTrigger(CountableCriterion.CODEC))
|
||||
|
||||
val PARTY_CHECK = this.create(
|
||||
SimpleCriterionTrigger(
|
||||
cobblemonResource("party"),
|
||||
PartyCheckCriterion::class.java
|
||||
)
|
||||
)
|
||||
val EVOLVE_POKEMON = this.create("pokemon_evolved", SimpleCriterionTrigger(EvolvePokemonCriterion.CODEC))
|
||||
|
||||
val LEVEL_UP = this.create(
|
||||
SimpleCriterionTrigger(
|
||||
cobblemonResource("level_up"),
|
||||
LevelUpCriterionCondition::class.java
|
||||
)
|
||||
)
|
||||
val WIN_BATTLE = this.create("battles_won", SimpleCriterionTrigger(BattleCountableCriterion.CODEC))
|
||||
|
||||
val PASTURE_USE = this.create(
|
||||
SimpleCriterionTrigger(
|
||||
cobblemonResource("pasture_use"),
|
||||
PickStarterCriterionCondition::class.java
|
||||
)
|
||||
)
|
||||
val DEFEAT_POKEMON = this.create("pokemon_defeated", SimpleCriterionTrigger(CountableCriterion.CODEC))
|
||||
|
||||
val RESURRECT_POKEMON = this.create(
|
||||
SimpleCriterionTrigger(
|
||||
cobblemonResource("resurrect_pokemon"),
|
||||
PickStarterCriterionCondition::class.java
|
||||
)
|
||||
)
|
||||
val COLLECT_ASPECT = this.create("aspects_collected", SimpleCriterionTrigger(AspectCriterion.CODEC))
|
||||
|
||||
val TRADE_POKEMON = this.create(
|
||||
SimpleCriterionTrigger(
|
||||
cobblemonResource("trade_pokemon"),
|
||||
TradePokemonCriterionCondition::class.java
|
||||
)
|
||||
)
|
||||
val POKEMON_INTERACT = this.create("pokemon_interact", SimpleCriterionTrigger(PokemonInteractCriterion.CODEC))
|
||||
|
||||
private fun <T : Criterion<*>> create(criteria: T): T = Cobblemon.implementation.registerCriteria(criteria)
|
||||
val PARTY_CHECK = this.create("party", SimpleCriterionTrigger(PartyCheckCriterion.CODEC))
|
||||
|
||||
val LEVEL_UP = this.create("level_up", SimpleCriterionTrigger(LevelUpCriterion.CODEC))
|
||||
|
||||
val PASTURE_USE = this.create("pasture_use", SimpleCriterionTrigger(PokemonCriterion.CODEC))
|
||||
|
||||
val RESURRECT_POKEMON = this.create("resurrect_pokemon", SimpleCriterionTrigger(PokemonCriterion.CODEC))
|
||||
|
||||
val TRADE_POKEMON = this.create("trade_pokemon", SimpleCriterionTrigger(TradePokemonCriterion.CODEC))
|
||||
|
||||
// Advancement criteria for [grow_tumblestone.json]
|
||||
val PLANT_TUMBLESTONE = this.create("plant_tumblestone", SimpleCriterionTrigger(PlantTumblestoneCriterion.CODEC))
|
||||
|
||||
private fun <T : Criterion<*>> create(id: String, criteria: T): T = Cobblemon.implementation.registerCriteria(id, criteria)
|
||||
|
||||
}
|
||||
+44
-23
@@ -8,38 +8,59 @@
|
||||
|
||||
package com.cobblemon.mod.common.advancement.criterion
|
||||
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.predicate.entity.LootContextPredicate
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.dynamic.Codecs
|
||||
import java.util.Optional
|
||||
|
||||
open class AspectCriterionTrigger(identifier: Identifier, criterionClass: Class<AspectCriterionCondition>) : SimpleCriterionTrigger<MutableMap<Identifier, MutableSet<String>>, AspectCriterionCondition>(identifier, criterionClass) {
|
||||
class AspectCriterion(
|
||||
playerCtx: Optional<LootContextPredicate>,
|
||||
val pokemon: Identifier,
|
||||
val aspects: List<String>
|
||||
): SimpleCriterionCondition<MutableMap<Identifier, MutableSet<String>>>(playerCtx) {
|
||||
|
||||
}
|
||||
|
||||
class AspectCriterionCondition(id: Identifier, predicate: LootContextPredicate) : SimpleCriterionCondition<MutableMap<Identifier, MutableSet<String>>>(id, predicate) {
|
||||
var pokemon = Identifier("cobblemon:pikachu")
|
||||
var aspects = mutableListOf<String>()
|
||||
override fun toJson(json: JsonObject) {
|
||||
json.add("aspects", JsonArray(aspects.size).also {
|
||||
aspects.forEach { aspect -> it.add(aspect) }
|
||||
})
|
||||
json.addProperty("pokemon", pokemon.toString())
|
||||
}
|
||||
|
||||
override fun fromJson(json: JsonObject) {
|
||||
aspects.clear()
|
||||
json.getAsJsonArray("aspects").forEach { element ->
|
||||
aspects.add(element.asString)
|
||||
}
|
||||
pokemon = json.get("pokemon").asString.asIdentifierDefaultingNamespace()
|
||||
companion object {
|
||||
val CODEC: Codec<AspectCriterion> = RecordCodecBuilder.create { it.group(
|
||||
Codecs.createStrictOptionalFieldCodec(LootContextPredicate.CODEC, "player").forGetter(AspectCriterion::playerCtx),
|
||||
Codecs.createStrictOptionalFieldCodec(Identifier.CODEC, "pokemon", Identifier("cobblemon:pikachu")).forGetter(AspectCriterion::pokemon),
|
||||
Codecs.createStrictOptionalFieldCodec(Codec.STRING.listOf(), "aspects", listOf()).forGetter(AspectCriterion::aspects)
|
||||
) .apply(it, ::AspectCriterion) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayerEntity, context: MutableMap<Identifier, MutableSet<String>>): Boolean {
|
||||
val caughtAspects = context.getOrDefault(pokemon, mutableSetOf())
|
||||
return this.aspects.all { it in caughtAspects }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//open class AspectCriterionTrigger(identifier: Identifier, criterionClass: Class<AspectCriterionCondition>) : SimpleCriterionTrigger<MutableMap<Identifier, MutableSet<String>>, AspectCriterionCondition>(identifier, criterionClass) {
|
||||
//
|
||||
//}
|
||||
//
|
||||
//class AspectCriterionCondition(id: Identifier, predicate: LootContextPredicate) : SimpleCriterionCondition<MutableMap<Identifier, MutableSet<String>>>(id, predicate) {
|
||||
// var pokemon = Identifier("cobblemon:pikachu")
|
||||
// var aspects = mutableListOf<String>()
|
||||
// override fun toJson(json: JsonObject) {
|
||||
// json.add("aspects", JsonArray(aspects.size).also {
|
||||
// aspects.forEach { aspect -> it.add(aspect) }
|
||||
// })
|
||||
// json.addProperty("pokemon", pokemon.toString())
|
||||
// }
|
||||
//
|
||||
// override fun fromJson(json: JsonObject) {
|
||||
// aspects.clear()
|
||||
// json.getAsJsonArray("aspects").forEach { element ->
|
||||
// aspects.add(element.asString)
|
||||
// }
|
||||
// pokemon = json.get("pokemon").asString.asIdentifierDefaultingNamespace()
|
||||
// }
|
||||
//
|
||||
// override fun matches(player: ServerPlayerEntity, context: MutableMap<Identifier, MutableSet<String>>): Boolean {
|
||||
// val caughtAspects = context.getOrDefault(pokemon, mutableSetOf())
|
||||
// return this.aspects.all { it in caughtAspects }
|
||||
// }
|
||||
//
|
||||
//}
|
||||
+71
-24
@@ -10,58 +10,105 @@ package com.cobblemon.mod.common.advancement.criterion
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.util.toJsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.predicate.entity.LootContextPredicate
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.dynamic.Codecs
|
||||
import java.util.Optional
|
||||
|
||||
open class BattleCountableCriterionTrigger(identifier: Identifier, criterionClass: Class<BattleCountableCriterionCondition>) : SimpleCriterionTrigger<BattleCountableContext, BattleCountableCriterionCondition>(identifier, criterionClass) {
|
||||
open class BattleCountableContext(var battle : PokemonBattle, times : Int) : CountableContext(times)
|
||||
|
||||
}
|
||||
class BattleCountableCriterion(
|
||||
playerCtx: Optional<LootContextPredicate>,
|
||||
val battleTypes: List<String>,
|
||||
count: Int
|
||||
): CountableCriterion<BattleCountableContext>(playerCtx, count) {
|
||||
|
||||
class BattleCountableCriterionCondition(id: Identifier, predicate: LootContextPredicate) : CountableCriterionCondition<BattleCountableContext>(id, predicate) {
|
||||
|
||||
private var battleTypes = mutableListOf("any")
|
||||
|
||||
override fun fromJson(json: JsonObject) {
|
||||
super.fromJson(json)
|
||||
if(!json.get("battle_types").isJsonNull) {
|
||||
battleTypes.clear()
|
||||
json.get("battle_types").asJsonArray.asList().forEach() {
|
||||
battleTypes.add(it.asString)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun toJson(json: JsonObject) {
|
||||
super.toJson(json)
|
||||
json.add("battle_types", battleTypes.toJsonArray())
|
||||
companion object {
|
||||
val CODEC: Codec<BattleCountableCriterion> = RecordCodecBuilder.create { it.group(
|
||||
Codecs.createStrictOptionalFieldCodec(LootContextPredicate.CODEC, "player").forGetter(BattleCountableCriterion::playerCtx),
|
||||
Codecs.createStrictOptionalFieldCodec(Codec.STRING.listOf(), "battle_types", listOf("any")).forGetter(BattleCountableCriterion::battleTypes),
|
||||
Codecs.createStrictOptionalFieldCodec(Codec.INT, "count", 0).forGetter(BattleCountableCriterion::count)
|
||||
).apply(it, ::BattleCountableCriterion) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayerEntity, context: BattleCountableContext): Boolean {
|
||||
var typeCheck = false
|
||||
val advancementData = Cobblemon.playerData.get(player).advancementData
|
||||
|
||||
if (battleTypes.isEmpty() || battleTypes.contains("any")) {
|
||||
typeCheck = true
|
||||
}
|
||||
|
||||
if (battleTypes.contains("pvp")) {
|
||||
typeCheck = context.battle.isPvP
|
||||
context.times = advancementData.totalPvPBattleVictoryCount
|
||||
}
|
||||
|
||||
if (battleTypes.contains("pvw")) {
|
||||
typeCheck = context.battle.isPvW
|
||||
context.times = advancementData.totalPvWBattleVictoryCount
|
||||
}
|
||||
|
||||
if (battleTypes.contains("pvn")) {
|
||||
typeCheck = context.battle.isPvN
|
||||
context.times = advancementData.totalPvWBattleVictoryCount
|
||||
}
|
||||
|
||||
if (battleTypes.size > 1) {
|
||||
context.times = advancementData.totalBattleVictoryCount
|
||||
}
|
||||
return context.times >= count && typeCheck
|
||||
|
||||
return typeCheck && super.matches(player, context)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
open class BattleCountableContext(times : Int, var battle : PokemonBattle) : CountableContext(times)
|
||||
//open class BattleCountableCriterionTrigger(identifier: Identifier, criterionClass: Class<BattleCountableCriterion>) : SimpleCriterionTrigger<BattleCountableContext, BattleCountableCriterion>(identifier, criterionClass) {
|
||||
//
|
||||
//}
|
||||
//
|
||||
//class BattleCountableCriterion(id: Identifier, predicate: LootContextPredicate) : CountableCriterion<BattleCountableContext>(id, predicate) {
|
||||
//
|
||||
// private var battleTypes = mutableListOf("any")
|
||||
//
|
||||
// override fun fromJson(json: JsonObject) {
|
||||
// super.fromJson(json)
|
||||
// if(!json.get("battle_types").isJsonNull) {
|
||||
// battleTypes.clear()
|
||||
// json.get("battle_types").asJsonArray.asList().forEach() {
|
||||
// battleTypes.add(it.asString)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// override fun toJson(json: JsonObject) {
|
||||
// super.toJson(json)
|
||||
// json.add("battle_types", battleTypes.toJsonArray())
|
||||
// }
|
||||
//
|
||||
// override fun matches(player: ServerPlayerEntity, context: BattleCountableContext): Boolean {
|
||||
// var typeCheck = false
|
||||
// val advancementData = Cobblemon.playerData.get(player).advancementData
|
||||
// if (battleTypes.isEmpty() || battleTypes.contains("any")) {
|
||||
// typeCheck = true
|
||||
// }
|
||||
// if (battleTypes.contains("pvp")) {
|
||||
// typeCheck = context.battle.isPvP
|
||||
// context.times = advancementData.totalPvPBattleVictoryCount
|
||||
// }
|
||||
// if (battleTypes.contains("pvw")) {
|
||||
// typeCheck = context.battle.isPvW
|
||||
// context.times = advancementData.totalPvWBattleVictoryCount
|
||||
// }
|
||||
// if (battleTypes.contains("pvn")) {
|
||||
// typeCheck = context.battle.isPvN
|
||||
// context.times = advancementData.totalPvWBattleVictoryCount
|
||||
// }
|
||||
// if (battleTypes.size > 1) {
|
||||
// context.times = advancementData.totalBattleVictoryCount
|
||||
// }
|
||||
// return context.times >= count && typeCheck
|
||||
// }
|
||||
//}
|
||||
+34
-12
@@ -8,10 +8,13 @@
|
||||
|
||||
package com.cobblemon.mod.common.advancement.criterion
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.predicate.entity.EntityPredicate
|
||||
import net.minecraft.predicate.entity.LootContextPredicate
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.dynamic.Codecs
|
||||
import java.util.Optional
|
||||
|
||||
/**
|
||||
* A context that is used when you require a [CountableContext] along with some type string.
|
||||
@@ -21,19 +24,38 @@ import net.minecraft.util.Identifier
|
||||
*/
|
||||
open class CountablePokemonTypeContext(times: Int, var type: String) : CountableContext(times)
|
||||
|
||||
class CaughtPokemonCriterionCondition(id: Identifier, predicate: LootContextPredicate) : CountableCriterionCondition<CountablePokemonTypeContext>(id, predicate) {
|
||||
var type = "any"
|
||||
override fun toJson(json: JsonObject) {
|
||||
super.toJson(json)
|
||||
json.addProperty("type", type)
|
||||
}
|
||||
class CaughtPokemonCriterion(
|
||||
playerCtx: Optional<LootContextPredicate>,
|
||||
val type: String,
|
||||
count: Int
|
||||
): CountableCriterion<CountablePokemonTypeContext>(playerCtx, count) {
|
||||
|
||||
override fun fromJson(json: JsonObject) {
|
||||
super.fromJson(json)
|
||||
type = json.get("type")?.asString ?: "any"
|
||||
companion object {
|
||||
val CODEC: Codec<CaughtPokemonCriterion> = RecordCodecBuilder.create { it.group(
|
||||
Codecs.createStrictOptionalFieldCodec(EntityPredicate.LOOT_CONTEXT_PREDICATE_CODEC, "player").forGetter(CaughtPokemonCriterion::playerCtx),
|
||||
Codecs.createStrictOptionalFieldCodec(Codec.STRING, "type", "any").forGetter(CaughtPokemonCriterion::type),
|
||||
Codecs.createStrictOptionalFieldCodec(Codec.INT, "count", 0).forGetter(CaughtPokemonCriterion::count)
|
||||
).apply(it, ::CaughtPokemonCriterion) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayerEntity, context: CountablePokemonTypeContext): Boolean {
|
||||
return super.matches(player, context) && (context.type == type || type == "any")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//class CaughtPokemonCriterionCondition(id: Identifier, predicate: LootContextPredicate) : CountableCriterionCondition<CountablePokemonTypeContext>(id, predicate) {
|
||||
// var type = "any"
|
||||
// override fun toJson(json: JsonObject) {
|
||||
// super.toJson(json)
|
||||
// json.addProperty("type", type)
|
||||
// }
|
||||
//
|
||||
// override fun fromJson(json: JsonObject) {
|
||||
// super.fromJson(json)
|
||||
// type = json.get("type")?.asString ?: "any"
|
||||
// }
|
||||
//
|
||||
// override fun matches(player: ServerPlayerEntity, context: CountablePokemonTypeContext): Boolean {
|
||||
// return super.matches(player, context) && (context.type == type || type == "any")
|
||||
// }
|
||||
//}
|
||||
+57
-36
@@ -8,48 +8,69 @@
|
||||
|
||||
package com.cobblemon.mod.common.advancement.criterion
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.predicate.entity.EntityPredicate
|
||||
import net.minecraft.predicate.entity.LootContextPredicate
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.dynamic.Codecs
|
||||
import java.util.Optional
|
||||
|
||||
/**
|
||||
* A type of advancement criterion condition that requires some number of completions. This can be extended to add
|
||||
* more conditions than just the count.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since November 4th, 2022
|
||||
*/
|
||||
abstract class CountableCriterionCondition<T : CountableContext>(id: Identifier, predicate: LootContextPredicate) : SimpleCriterionCondition<T>(id, predicate) {
|
||||
var count = 0
|
||||
override fun fromJson(json: JsonObject) {
|
||||
count = json.get("count")?.asInt ?: 0
|
||||
}
|
||||
open class CountableContext(var times: Int)
|
||||
|
||||
override fun toJson(json: JsonObject) {
|
||||
json.addProperty("count", count)
|
||||
open class CountableCriterion<T : CountableContext>(
|
||||
playerCtx: Optional<LootContextPredicate>,
|
||||
val count: Int
|
||||
): SimpleCriterionCondition<T>(playerCtx) {
|
||||
|
||||
companion object {
|
||||
val CODEC: Codec<CountableCriterion<CountableContext>> = RecordCodecBuilder.create { it.group(
|
||||
Codecs.createStrictOptionalFieldCodec(EntityPredicate.LOOT_CONTEXT_PREDICATE_CODEC, "player").forGetter(CountableCriterion<CountableContext>::playerCtx),
|
||||
Codecs.createStrictOptionalFieldCodec(Codec.INT, "count", 0).forGetter(CountableCriterion<CountableContext>::count)
|
||||
).apply(it, ::CountableCriterion) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayerEntity, context: T) = context.times >= count
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A concrete subclass of [CountableCriterionCondition] so that you can have advancements that really just need the
|
||||
* count and nothing else.
|
||||
*
|
||||
* This is just a quirk of using generics like this, don't worry about it. The criterion conditions that get used must
|
||||
* not be generic typed.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since November 4th, 2022
|
||||
*/
|
||||
class SimpleCountableCriterionCondition(id: Identifier, predicate: LootContextPredicate) : CountableCriterionCondition<CountableContext>(id, predicate)
|
||||
fun SimpleCriterionTrigger<CountableContext, SimpleCountableCriterionCondition>.trigger(player: ServerPlayerEntity, times: Int) = trigger(player, CountableContext(times))
|
||||
|
||||
/**
|
||||
* Some type of context that has a count associated with it, representing how many times the trigger has occurred.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since November 4th, 2022
|
||||
*/
|
||||
open class CountableContext(var times: Int)
|
||||
///**
|
||||
// * A type of advancement criterion condition that requires some number of completions. This can be extended to add
|
||||
// * more conditions than just the count.
|
||||
// *
|
||||
// * @author Hiroku
|
||||
// * @since November 4th, 2022
|
||||
// */
|
||||
//abstract class CountableCriterionCondition<T : CountableContext>(id: Identifier, predicate: LootContextPredicate) : SimpleCriterionCondition<T>(id, predicate) {
|
||||
// var count = 0
|
||||
// override fun fromJson(json: JsonObject) {
|
||||
// count = json.get("count")?.asInt ?: 0
|
||||
// }
|
||||
//
|
||||
// override fun toJson(json: JsonObject) {
|
||||
// json.addProperty("count", count)
|
||||
// }
|
||||
//
|
||||
// override fun matches(player: ServerPlayerEntity, context: T) = context.times >= count
|
||||
//}
|
||||
//
|
||||
///**
|
||||
// * A concrete subclass of [CountableCriterionCondition] so that you can have advancements that really just need the
|
||||
// * count and nothing else.
|
||||
// *
|
||||
// * This is just a quirk of using generics like this, don't worry about it. The criterion conditions that get used must
|
||||
// * not be generic typed.
|
||||
// *
|
||||
// * @author Hiroku
|
||||
// * @since November 4th, 2022
|
||||
// */
|
||||
//class SimpleCountableCriterionCondition(id: Identifier, predicate: LootContextPredicate) : CountableCriterionCondition<CountableContext>(id, predicate)
|
||||
//fun SimpleCriterionTrigger<CountableContext, SimpleCountableCriterionCondition>.trigger(player: ServerPlayerEntity, times: Int) = trigger(player, CountableContext(times))
|
||||
//
|
||||
///**
|
||||
// * Some type of context that has a count associated with it, representing how many times the trigger has occurred.
|
||||
// *
|
||||
// * @author Hiroku
|
||||
// * @since November 4th, 2022
|
||||
// */
|
||||
//open class CountableContext(var times: Int)
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.advancement.criterion
|
||||
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.predicate.entity.LootContextPredicate
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.dynamic.Codecs
|
||||
import java.util.Optional
|
||||
|
||||
class EvolvePokemonContext(val species : Identifier, val evolution : Identifier, times: Int) : CountableContext(times)
|
||||
|
||||
class EvolvePokemonCriterion(
|
||||
playerCtx: Optional<LootContextPredicate>,
|
||||
val species: String,
|
||||
val evolution: String,
|
||||
count: Int
|
||||
): CountableCriterion<EvolvePokemonContext>(playerCtx, count) {
|
||||
|
||||
companion object {
|
||||
val CODEC: Codec<EvolvePokemonCriterion> = RecordCodecBuilder.create { it.group(
|
||||
Codecs.createStrictOptionalFieldCodec(LootContextPredicate.CODEC, "player").forGetter(EvolvePokemonCriterion::playerCtx),
|
||||
Codecs.createStrictOptionalFieldCodec(Codec.STRING, "species", "any").forGetter(EvolvePokemonCriterion::species),
|
||||
Codecs.createStrictOptionalFieldCodec(Codec.STRING, "evolution", "any").forGetter(EvolvePokemonCriterion::evolution),
|
||||
Codecs.createStrictOptionalFieldCodec(Codec.INT, "count", 0).forGetter(EvolvePokemonCriterion::count)
|
||||
).apply(it, ::EvolvePokemonCriterion) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayerEntity, context: EvolvePokemonContext): Boolean {
|
||||
return context.times >= count && (context.species == species.asIdentifierDefaultingNamespace() || species == "any") &&
|
||||
(context.evolution == evolution.asIdentifierDefaultingNamespace() || evolution == "any")
|
||||
}
|
||||
}
|
||||
|
||||
//class EvolvePokemonCriterion(id: Identifier, entity: LootContextPredicate) : CountableCriterion<EvolvePokemonContext>(id, entity) {
|
||||
// var species = "any"
|
||||
// var evolution = "any"
|
||||
// override fun toJson(json: JsonObject) {
|
||||
// super.toJson(json)
|
||||
// json.addProperty("species", species)
|
||||
// json.addProperty("evolution", evolution)
|
||||
// }
|
||||
//
|
||||
// override fun fromJson(json: JsonObject) {
|
||||
// super.fromJson(json)
|
||||
// species = json.get("species")?.asString ?: "any"
|
||||
// evolution = json.get("evolution")?.asString ?: "any"
|
||||
// }
|
||||
//
|
||||
// override fun matches(player: ServerPlayerEntity, context: EvolvePokemonContext): Boolean {
|
||||
// return context.times >= count && (context.species == species.asIdentifierDefaultingNamespace() || species == "any") &&
|
||||
// (context.evolution == evolution.asIdentifierDefaultingNamespace() || evolution == "any")
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//open class EvolvePokemonContext(val species : Identifier, val evolution : Identifier, times: Int) : CountableContext(times)
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.advancement.criterion
|
||||
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.google.gson.JsonObject
|
||||
import net.minecraft.predicate.entity.LootContextPredicate
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
class EvolvePokemonCriterionCondition(id: Identifier, entity: LootContextPredicate) : CountableCriterionCondition<EvolvePokemonContext>(id, entity) {
|
||||
var species = "any"
|
||||
var evolution = "any"
|
||||
override fun toJson(json: JsonObject) {
|
||||
super.toJson(json)
|
||||
json.addProperty("species", species)
|
||||
json.addProperty("evolution", evolution)
|
||||
}
|
||||
|
||||
override fun fromJson(json: JsonObject) {
|
||||
super.fromJson(json)
|
||||
species = json.get("species")?.asString ?: "any"
|
||||
evolution = json.get("evolution")?.asString ?: "any"
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayerEntity, context: EvolvePokemonContext): Boolean {
|
||||
return context.times >= count && (context.species == species.asIdentifierDefaultingNamespace() || species == "any") &&
|
||||
(context.evolution == evolution.asIdentifierDefaultingNamespace() || evolution == "any")
|
||||
}
|
||||
}
|
||||
|
||||
open class EvolvePokemonContext(val species : Identifier, val evolution : Identifier, times: Int) : CountableContext(times)
|
||||
+35
-6
@@ -9,12 +9,43 @@
|
||||
package com.cobblemon.mod.common.advancement.criterion
|
||||
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.google.gson.JsonObject
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.predicate.entity.EntityPredicate
|
||||
import net.minecraft.predicate.entity.LootContextPredicate
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.dynamic.Codecs
|
||||
import java.util.Optional
|
||||
|
||||
class LevelUpCriterionCondition(id: Identifier, entity: LootContextPredicate) : SimpleCriterionCondition<LevelUpContext>(id, entity) {
|
||||
class LevelUpContext(val level: Int, val pokemon: Pokemon)
|
||||
|
||||
class LevelUpCriterion(
|
||||
playerCtx: Optional<LootContextPredicate>,
|
||||
val level: Int,
|
||||
val evolved: Boolean
|
||||
): SimpleCriterionCondition<LevelUpContext>(playerCtx) {
|
||||
|
||||
companion object {
|
||||
val CODEC: Codec<LevelUpCriterion> = RecordCodecBuilder.create { it.group(
|
||||
Codecs.createStrictOptionalFieldCodec(EntityPredicate.LOOT_CONTEXT_PREDICATE_CODEC, "player").forGetter(LevelUpCriterion::playerCtx),
|
||||
Codecs.createStrictOptionalFieldCodec(Codec.INT, "level", 0).forGetter(LevelUpCriterion::level),
|
||||
Codecs.createStrictOptionalFieldCodec(Codec.BOOL, "evolved", true).forGetter(LevelUpCriterion::evolved)
|
||||
).apply(it, ::LevelUpCriterion) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayerEntity, context: LevelUpContext): Boolean {
|
||||
val preEvo = context.pokemon.preEvolution == null
|
||||
val hasEvolution = !context.pokemon.evolutions.none()
|
||||
var evolutionCheck = true
|
||||
if (preEvo || hasEvolution) {
|
||||
evolutionCheck = preEvo != hasEvolution
|
||||
}
|
||||
return level == context.level && evolutionCheck == evolved
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*class LevelUpCriterionCondition(id: Identifier, entity: LootContextPredicate) : SimpleCriterionCondition<LevelUpContext>(id, entity) {
|
||||
var level = 0
|
||||
var evolved = true
|
||||
override fun toJson(json: JsonObject) {
|
||||
@@ -36,6 +67,4 @@ class LevelUpCriterionCondition(id: Identifier, entity: LootContextPredicate) :
|
||||
}
|
||||
return level == context.level && evolutionCheck == evolved
|
||||
}
|
||||
}
|
||||
|
||||
open class LevelUpContext(var level : Int, var pokemon : Pokemon)
|
||||
}*/
|
||||
+53
-5
@@ -10,14 +10,62 @@ package com.cobblemon.mod.common.advancement.criterion
|
||||
|
||||
import com.cobblemon.mod.common.api.storage.party.PlayerPartyStore
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.cobblemon.mod.common.util.party
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.predicate.entity.EntityPredicate
|
||||
import net.minecraft.predicate.entity.LootContextPredicate
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.dynamic.Codecs
|
||||
import java.util.Optional
|
||||
|
||||
class PartyCheckCriterion(id: Identifier, entity: LootContextPredicate) : SimpleCriterionCondition<PartyCheckContext>(id, entity){
|
||||
class PartyCheckCriterion(
|
||||
playerCtx: Optional<LootContextPredicate>,
|
||||
val party: List<Identifier>,
|
||||
): SimpleCriterionCondition<PlayerPartyStore>(playerCtx) {
|
||||
|
||||
companion object {
|
||||
val CODEC: Codec<PartyCheckCriterion> = RecordCodecBuilder.create { it.group(
|
||||
Codecs.createStrictOptionalFieldCodec(EntityPredicate.LOOT_CONTEXT_PREDICATE_CODEC, "player").forGetter(PartyCheckCriterion::playerCtx),
|
||||
Codecs.createStrictOptionalFieldCodec(Identifier.CODEC.listOf(), "id", listOf()).forGetter(PartyCheckCriterion::party)
|
||||
).apply(it, ::PartyCheckCriterion) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayerEntity, context: PlayerPartyStore): Boolean {
|
||||
val matches = mutableListOf<Identifier>()
|
||||
party.forEach {
|
||||
if (it == "any".asIdentifierDefaultingNamespace()) {
|
||||
matches.add(it)
|
||||
}
|
||||
}
|
||||
val partyCount = context.count()
|
||||
if (matches.containsAll(party) && party.size == partyCount && matches.size == partyCount) return true
|
||||
context.iterator().forEach {
|
||||
if (party.contains(it.species.resourceIdentifier)) {
|
||||
matches.add(it.species.resourceIdentifier)
|
||||
}
|
||||
}
|
||||
return matches.containsAll(party) && matches.size == partyCount
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*class PartyCheckCriterion(id: Identifier, entity: LootContextPredicate) : SimpleCriterionCondition<PartyCheckContext>(id, entity){
|
||||
val party = mutableListOf<Identifier>()
|
||||
override fun toJson(json: JsonObject) {
|
||||
json.add("party", JsonArray(party.size).also {
|
||||
@@ -51,4 +99,4 @@ class PartyCheckCriterion(id: Identifier, entity: LootContextPredicate) : Simple
|
||||
}
|
||||
}
|
||||
|
||||
open class PartyCheckContext(val party : PlayerPartyStore)
|
||||
open class PartyCheckContext(val party : PlayerPartyStore)*/
|
||||
+17
-16
@@ -10,26 +10,27 @@ package com.cobblemon.mod.common.advancement.criterion
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.google.gson.JsonObject
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.predicate.entity.EntityPredicate
|
||||
import net.minecraft.predicate.entity.LootContextPredicate
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.dynamic.Codecs
|
||||
import java.util.Optional
|
||||
|
||||
/**
|
||||
* A criteria that is triggered when a player picks a starter.
|
||||
*
|
||||
* @author Licious, Hiroku
|
||||
* @since October 26th, 2022
|
||||
*/
|
||||
class PickStarterCriterionCondition(id: Identifier, predicate: LootContextPredicate) : SimpleCriterionCondition<Pokemon>(id, predicate) {
|
||||
var properties = PokemonProperties()
|
||||
override fun toJson(json: JsonObject) {
|
||||
json.addProperty("properties", properties.originalString)
|
||||
class PokemonCriterion(
|
||||
playerCtx: Optional<LootContextPredicate>,
|
||||
val properties: PokemonProperties
|
||||
): SimpleCriterionCondition<Pokemon>(playerCtx) {
|
||||
|
||||
companion object {
|
||||
val CODEC: Codec<PokemonCriterion> = RecordCodecBuilder.create { it.group(
|
||||
Codecs.createStrictOptionalFieldCodec(EntityPredicate.LOOT_CONTEXT_PREDICATE_CODEC, "player").forGetter(PokemonCriterion::playerCtx),
|
||||
Codecs.createStrictOptionalFieldCodec(PokemonProperties.CODEC, "properties", PokemonProperties()).forGetter(PokemonCriterion::properties)
|
||||
).apply(it, ::PokemonCriterion) }
|
||||
}
|
||||
|
||||
override fun fromJson(json: JsonObject) {
|
||||
properties = PokemonProperties.parse(json.get("properties")?.asString ?: "")
|
||||
override fun matches(player: ServerPlayerEntity, context: Pokemon): Boolean {
|
||||
return properties.matches(context)
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayerEntity, context: Pokemon) = properties.matches(context)
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.advancement.criterion
|
||||
|
||||
import com.cobblemon.mod.common.block.TumblestoneBlock
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.predicate.entity.LootContextPredicate
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.dynamic.Codecs
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import java.util.Optional
|
||||
|
||||
class PlantTumblestoneContext(val pos: BlockPos, val block: TumblestoneBlock)
|
||||
|
||||
class PlantTumblestoneCriterion(
|
||||
playerCtx: Optional<LootContextPredicate>
|
||||
): SimpleCriterionCondition<PlantTumblestoneContext>(playerCtx) {
|
||||
|
||||
companion object {
|
||||
val CODEC: Codec<PlantTumblestoneCriterion> = RecordCodecBuilder.create { it.group(
|
||||
Codecs.createStrictOptionalFieldCodec(LootContextPredicate.CODEC, "player").forGetter(PlantTumblestoneCriterion::playerCtx)
|
||||
).apply(it, ::PlantTumblestoneCriterion) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayerEntity, context: PlantTumblestoneContext): Boolean {
|
||||
return context.block.canGrow(context.pos, player.world)
|
||||
}
|
||||
}
|
||||
|
||||
///**
|
||||
// * A criterion condition for when a tumblestone block is planted
|
||||
// * @param id The identifier of the criterion
|
||||
// * @param predicate The predicate for the criterion
|
||||
// *
|
||||
// * @author Aethen
|
||||
// * @since 02/28/2024
|
||||
// */
|
||||
//class PlantTumblestoneCriterionCondition(id: Identifier, predicate: LootContextPredicate) :
|
||||
// SimpleCriterionCondition<PlantTumblestoneContext>(id, predicate) {
|
||||
// override fun toJson(json: JsonObject) {
|
||||
// // Add properties to json if needed. None needed for this criterion
|
||||
// }
|
||||
//
|
||||
// override fun fromJson(json: JsonObject) {
|
||||
// // Parse properties from json if needed. None needed for this criterion
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Checks if the tumblestone block can grow at the given position
|
||||
// * @param player The player that planted the tumblestone block
|
||||
// * @param context The context of the criterion
|
||||
// * @return True if the tumblestone block can grow at the given position, false otherwise
|
||||
// */
|
||||
// override fun matches(player: ServerPlayerEntity, context: PlantTumblestoneContext): Boolean {
|
||||
// return context.tumbleStoneBlock.canGrow(context.pos, player.world)
|
||||
// }
|
||||
//}
|
||||
//
|
||||
///**
|
||||
// * The context of the [PlantTumblestoneCriterionCondition]
|
||||
// * @param pos The position of the tumblestone block
|
||||
// * @param tumbleStoneBlock The tumblestone block
|
||||
// */
|
||||
//open class PlantTumblestoneContext(var pos: BlockPos, var tumbleStoneBlock: TumblestoneBlock)
|
||||
+20
-13
@@ -9,26 +9,33 @@
|
||||
package com.cobblemon.mod.common.advancement.criterion
|
||||
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.google.gson.JsonObject
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.predicate.entity.EntityPredicate
|
||||
import net.minecraft.predicate.entity.LootContextPredicate
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.dynamic.Codecs
|
||||
import java.util.Optional
|
||||
|
||||
open class PokemonInteractContext(var type: Identifier, var item : Identifier)
|
||||
class PokemonInteractCriterion(id: Identifier, entity: LootContextPredicate) : SimpleCriterionCondition<PokemonInteractContext>(id, entity) {
|
||||
var type = "any"
|
||||
var item = "any"
|
||||
override fun toJson(json: JsonObject) {
|
||||
json.addProperty("type", type)
|
||||
json.addProperty("item", item)
|
||||
}
|
||||
class PokemonInteractContext(val type: Identifier, val item: Identifier)
|
||||
|
||||
override fun fromJson(json: JsonObject) {
|
||||
type = json.get("type")?.asString ?: "any"
|
||||
item = json.get("item")?.asString ?: "any"
|
||||
class PokemonInteractCriterion(
|
||||
playerCtx: Optional<LootContextPredicate>,
|
||||
val type: Optional<String>,
|
||||
val item: Optional<String>
|
||||
): SimpleCriterionCondition<PokemonInteractContext>(playerCtx) {
|
||||
companion object {
|
||||
val CODEC: Codec<PokemonInteractCriterion> = RecordCodecBuilder.create { it.group(
|
||||
Codecs.createStrictOptionalFieldCodec(EntityPredicate.LOOT_CONTEXT_PREDICATE_CODEC, "player").forGetter(PokemonInteractCriterion::playerCtx),
|
||||
Codecs.createStrictOptionalFieldCodec(Codec.STRING, "type").forGetter(PokemonInteractCriterion::type),
|
||||
Codecs.createStrictOptionalFieldCodec(Codec.STRING, "item").forGetter(PokemonInteractCriterion::item)
|
||||
).apply(it, ::PokemonInteractCriterion) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayerEntity, context: PokemonInteractContext): Boolean {
|
||||
return (context.type == type.asIdentifierDefaultingNamespace() || type == "any") && (context.item == item.asIdentifierDefaultingNamespace() || item == "any")
|
||||
val otherType = this.type.orElse("any")
|
||||
val otherItem = this.item.orElse("any")
|
||||
return (context.type == otherType.asIdentifierDefaultingNamespace() || otherType == "any") && (context.type == otherItem.asIdentifierDefaultingNamespace() || otherItem == "any")
|
||||
}
|
||||
}
|
||||
+13
-46
@@ -8,61 +8,28 @@
|
||||
|
||||
package com.cobblemon.mod.common.advancement.criterion
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.advancement.criterion.AbstractCriterion
|
||||
import net.minecraft.advancement.criterion.AbstractCriterionConditions
|
||||
import net.minecraft.predicate.entity.AdvancementEntityPredicateDeserializer
|
||||
import net.minecraft.predicate.entity.AdvancementEntityPredicateSerializer
|
||||
import net.minecraft.predicate.entity.LootContextPredicate
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
import java.util.Optional
|
||||
|
||||
/**
|
||||
* A wrapping around the AbstractCriterion system of Minecraft. This allows the same base class to be used
|
||||
* for all advancements by wrapping the advancement-specific contextual data in the generic T, the instance of
|
||||
* the advancement conditions in the generic C, and allowing the condition to do all serialization, deserialization,
|
||||
* and matching of context against conditions.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since November 4th, 2022
|
||||
*/
|
||||
open class SimpleCriterionTrigger<T, C : SimpleCriterionCondition<T>>(
|
||||
val _id: Identifier,
|
||||
val criterionClass: Class<C>
|
||||
class SimpleCriterionTrigger<T, C : SimpleCriterionCondition<T>>(
|
||||
val codec: Codec<C>,
|
||||
) : AbstractCriterion<C>() {
|
||||
override fun getId() = _id
|
||||
override fun conditionsFromJson(
|
||||
obj: JsonObject,
|
||||
playerPredicate: LootContextPredicate,
|
||||
predicateDeserializer: AdvancementEntityPredicateDeserializer
|
||||
): C {
|
||||
val instance = criterionClass.getConstructor(Identifier::class.java, LootContextPredicate::class.java).newInstance(id, playerPredicate)
|
||||
instance.fromJson(obj)
|
||||
return instance
|
||||
}
|
||||
override fun getConditionsCodec() = codec
|
||||
|
||||
fun trigger(player: ServerPlayerEntity, context: T) = this.trigger(player) { it.matches(player, context) }
|
||||
fun trigger(player: ServerPlayerEntity, context: T) {
|
||||
return this.trigger(player) {
|
||||
it.matches(player, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The base of the conditions for Cobblemon's wrapping around Minecraft advancements. This is parameterized by whatever
|
||||
* contextual information this condition needs to be checked, and must handle serialization and deserialization from JSON.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since November 4th, 2022
|
||||
*/
|
||||
abstract class SimpleCriterionCondition<T>(
|
||||
id: Identifier,
|
||||
playerPredicate: LootContextPredicate
|
||||
): AbstractCriterionConditions(id, playerPredicate) {
|
||||
override fun toJson(predicateSerializer: AdvancementEntityPredicateSerializer): JsonObject {
|
||||
val json = super.toJson(predicateSerializer)
|
||||
toJson(json)
|
||||
return json
|
||||
}
|
||||
|
||||
abstract fun toJson(json: JsonObject)
|
||||
abstract fun fromJson(json: JsonObject)
|
||||
val playerCtx: Optional<LootContextPredicate>
|
||||
) : AbstractCriterion.Conditions {
|
||||
override fun player() = playerCtx
|
||||
|
||||
abstract fun matches(player: ServerPlayerEntity, context: T): Boolean
|
||||
}
|
||||
+51
-4
@@ -10,12 +10,59 @@ package com.cobblemon.mod.common.advancement.criterion
|
||||
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.google.gson.JsonObject
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.predicate.entity.EntityPredicate
|
||||
import net.minecraft.predicate.entity.LootContextPredicate
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.dynamic.Codecs
|
||||
import java.util.Optional
|
||||
|
||||
class TradePokemonCriterionCondition(id: Identifier, entity: LootContextPredicate) : SimpleCriterionCondition<TradePokemonContext>(id, entity) {
|
||||
class TradePokemonContext(val traded: Pokemon, val received: Pokemon)
|
||||
|
||||
class TradePokemonCriterion(
|
||||
playerCtx: Optional<LootContextPredicate>,
|
||||
val traded: String,
|
||||
val received: String,
|
||||
val tradedHeldItem: String,
|
||||
val receivedHeldItem: String
|
||||
): SimpleCriterionCondition<TradePokemonContext>(playerCtx) {
|
||||
|
||||
companion object {
|
||||
val CODEC: Codec<TradePokemonCriterion> = RecordCodecBuilder.create { it.group(
|
||||
Codecs.createStrictOptionalFieldCodec(EntityPredicate.LOOT_CONTEXT_PREDICATE_CODEC, "player").forGetter(TradePokemonCriterion::playerCtx),
|
||||
Codecs.createStrictOptionalFieldCodec(Codec.STRING, "traded", "any").forGetter(TradePokemonCriterion::traded),
|
||||
Codecs.createStrictOptionalFieldCodec(Codec.STRING, "received", "any").forGetter(TradePokemonCriterion::received),
|
||||
Codecs.createStrictOptionalFieldCodec(Codec.STRING, "traded_held_item", "minecraft:air").forGetter(TradePokemonCriterion::tradedHeldItem),
|
||||
Codecs.createStrictOptionalFieldCodec(Codec.STRING, "received_held_item", "minecraft:air").forGetter(TradePokemonCriterion::receivedHeldItem)
|
||||
).apply(it, ::TradePokemonCriterion) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayerEntity, context: TradePokemonContext): Boolean {
|
||||
val heldItem1 = context.traded.heldItem().item.registryEntry.registryKey().value
|
||||
val heldItem2 = context.received.heldItem().item.registryEntry.registryKey().value
|
||||
|
||||
if (traded != "any" && context.traded.species.resourceIdentifier != traded.asIdentifierDefaultingNamespace()) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (received != "any" && context.received.species.resourceIdentifier != received.asIdentifierDefaultingNamespace()) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (heldItem1 != tradedHeldItem.asIdentifierDefaultingNamespace() && heldItem1 != "minecraft:air".asIdentifierDefaultingNamespace()) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (heldItem2 != receivedHeldItem.asIdentifierDefaultingNamespace() && heldItem2 != "minecraft:air".asIdentifierDefaultingNamespace()) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
/*class TradePokemonCriterionCondition(id: Identifier, entity: LootContextPredicate) : SimpleCriterionCondition<TradePokemonContext>(id, entity) {
|
||||
var traded = "any"
|
||||
var received = "any"
|
||||
var tradedHeldItem = "any"
|
||||
@@ -44,4 +91,4 @@ class TradePokemonCriterionCondition(id: Identifier, entity: LootContextPredicat
|
||||
}
|
||||
}
|
||||
|
||||
open class TradePokemonContext(val traded: Pokemon, val received: Pokemon)
|
||||
open class TradePokemonContext(val traded: Pokemon, val received: Pokemon)*/
|
||||
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.api.abilities
|
||||
|
||||
import com.cobblemon.mod.common.api.Priority
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.google.gson.JsonObject
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
@@ -21,7 +22,7 @@ import net.minecraft.nbt.NbtCompound
|
||||
* @author Qu
|
||||
* @since January 9th, 2022
|
||||
*/
|
||||
open class Ability internal constructor(var template: AbilityTemplate, var forced: Boolean) {
|
||||
open class Ability internal constructor(var template: AbilityTemplate, forced: Boolean) {
|
||||
|
||||
val name: String
|
||||
get() = template.name
|
||||
@@ -34,16 +35,26 @@ open class Ability internal constructor(var template: AbilityTemplate, var force
|
||||
|
||||
/**
|
||||
* This represents the last known index of this backing ability in the species data.
|
||||
* If -1 the ability will attempt to find the correct index or reroll itself, this is done in order to be compatible with existing data
|
||||
* The value can be mutated however this is not recommended by API users.
|
||||
* @see [Pokemon.updateAbility].
|
||||
*/
|
||||
var forced: Boolean = forced
|
||||
internal set
|
||||
|
||||
/**
|
||||
* This represents the last known index of this backing ability in the species data.
|
||||
*
|
||||
* @see [Pokemon.updateAbility].
|
||||
*/
|
||||
var index: Int = -1
|
||||
internal set
|
||||
|
||||
/**
|
||||
* The last known priority of this ability in the species data.
|
||||
* The value can be mutated however this is not recommended by API users.
|
||||
*
|
||||
* @see [Pokemon.updateAbility].
|
||||
*/
|
||||
var priority = Priority.LOWEST
|
||||
internal set
|
||||
|
||||
open fun saveToNBT(nbt: NbtCompound): NbtCompound {
|
||||
nbt.putString(DataKeys.POKEMON_ABILITY_NAME, name)
|
||||
@@ -62,19 +73,23 @@ open class Ability internal constructor(var template: AbilityTemplate, var force
|
||||
}
|
||||
|
||||
open fun loadFromNBT(nbt: NbtCompound): Ability {
|
||||
forced = nbt.getBoolean(DataKeys.POKEMON_ABILITY_FORCED)
|
||||
this.template = Abilities.getOrException(nbt.getString(DataKeys.POKEMON_ABILITY_NAME))
|
||||
this.forced = nbt.getBoolean(DataKeys.POKEMON_ABILITY_FORCED)
|
||||
if (nbt.contains(DataKeys.POKEMON_ABILITY_INDEX) && nbt.contains(DataKeys.POKEMON_ABILITY_PRIORITY)) {
|
||||
this.index = nbt.getInt(DataKeys.POKEMON_ABILITY_INDEX)
|
||||
this.priority = Priority.valueOf(nbt.getString(DataKeys.POKEMON_ABILITY_PRIORITY))
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
open fun loadFromJSON(json: JsonObject): Ability {
|
||||
forced = json.get(DataKeys.POKEMON_ABILITY_FORCED)?.asBoolean ?: false
|
||||
this.template = Abilities.getOrException(json.get(DataKeys.POKEMON_ABILITY_NAME).asString)
|
||||
this.forced = json.get(DataKeys.POKEMON_ABILITY_FORCED)?.asBoolean ?: false
|
||||
if (json.has(DataKeys.POKEMON_ABILITY_INDEX) && json.has(DataKeys.POKEMON_ABILITY_PRIORITY)) {
|
||||
this.index = json.get(DataKeys.POKEMON_ABILITY_INDEX).asInt
|
||||
this.priority = Priority.valueOf(json.get(DataKeys.POKEMON_ABILITY_PRIORITY).asString)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
}
|
||||
@@ -28,7 +28,6 @@ class AbilityTemplate(
|
||||
*/
|
||||
fun create(forced: Boolean = false) = builder(this, forced)
|
||||
|
||||
|
||||
/**
|
||||
* Returns the Ability and loads the given NBT Tag into it.
|
||||
*
|
||||
@@ -42,4 +41,5 @@ class AbilityTemplate(
|
||||
* Ability extensions need to write and read their needed data from here.
|
||||
*/
|
||||
fun create(json: JsonObject) = create().loadFromJSON(json)
|
||||
|
||||
}
|
||||
@@ -13,8 +13,13 @@ import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.block.ApricornBlock
|
||||
import com.cobblemon.mod.common.block.ApricornSaplingBlock
|
||||
import com.cobblemon.mod.common.item.ApricornItem
|
||||
import com.cobblemon.mod.common.world.feature.CobblemonConfiguredFeatures
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.block.MapColor
|
||||
import net.minecraft.item.BlockItem
|
||||
import net.minecraft.registry.RegistryKey
|
||||
import net.minecraft.util.StringIdentifiable
|
||||
import net.minecraft.world.gen.feature.ConfiguredFeature
|
||||
|
||||
/**
|
||||
* Contains the different Apricorn variants and util methods to get their item, block, seedling and sapling form.
|
||||
@@ -22,7 +27,7 @@ import net.minecraft.item.BlockItem
|
||||
* @author Licious
|
||||
* @since October 29th, 2022
|
||||
*/
|
||||
enum class Apricorn {
|
||||
enum class Apricorn : StringIdentifiable {
|
||||
|
||||
BLACK,
|
||||
BLUE,
|
||||
@@ -82,4 +87,20 @@ enum class Apricorn {
|
||||
YELLOW -> MapColor.YELLOW
|
||||
}
|
||||
|
||||
fun configuredFeature(): RegistryKey<ConfiguredFeature<*, *>> = when(this) {
|
||||
BLACK -> CobblemonConfiguredFeatures.BLACK_APRICORN_TREE_KEY
|
||||
BLUE -> CobblemonConfiguredFeatures.BLUE_APRICORN_TREE_KEY
|
||||
GREEN -> CobblemonConfiguredFeatures.GREEN_APRICORN_TREE_KEY
|
||||
PINK -> CobblemonConfiguredFeatures.PINK_APRICORN_TREE_KEY
|
||||
RED -> CobblemonConfiguredFeatures.RED_APRICORN_TREE_KEY
|
||||
WHITE -> CobblemonConfiguredFeatures.WHITE_APRICORN_TREE_KEY
|
||||
YELLOW -> CobblemonConfiguredFeatures.YELLOW_APRICORN_TREE_KEY
|
||||
}
|
||||
|
||||
override fun asString() = this.name.lowercase()
|
||||
|
||||
companion object {
|
||||
val CODEC: Codec<Apricorn> = StringIdentifiable.createBasicCodec(::values)
|
||||
}
|
||||
|
||||
}
|
||||
+24
-21
@@ -135,28 +135,31 @@ class BattleMessage(rawMessage: String) {
|
||||
return this.actorAndActivePokemon(pnx, battle)
|
||||
}
|
||||
|
||||
/*
|
||||
Example:
|
||||
|-curestatus|p1: a8e5710e-6835-4387-99d3-331b45f848e6|slp|[msg]
|
||||
|-curestatus|p1: 0686b20d-3019-4167-92e2-786834245743|slp|[msg]
|
||||
// Function used to grab BattlePokemon (As we need to be able to grab non active pokemon to cure their status)
|
||||
// by using playerNumber(actorID) and pokemon uuid(pokemonID)
|
||||
/**
|
||||
* Queries an argument at the given [index] for a 'pnx' and uuid that will be parsed into a [BattlePokemon].
|
||||
*
|
||||
* @param index The index of the argument referencing the [BattlePokemon].
|
||||
* @param battle The [PokemonBattle] being queried.
|
||||
* @return The [BattlePokemon] if the argument exists and is successfully parsed; otherwise null.
|
||||
*/
|
||||
fun getBattlePokemon(index: Int, battle: PokemonBattle): BattlePokemon? {
|
||||
val actorAndPokemonID = this.argumentAt(index)?.takeIf { it.length >= 2 }?.split(": ") ?: return null
|
||||
if (actorAndPokemonID.count() < 2) return null
|
||||
val actorID = actorAndPokemonID[0]
|
||||
val pokemonID = actorAndPokemonID[1]
|
||||
return this.getBattlePokemon(actorID, pokemonID, battle)
|
||||
fun battlePokemon(index: Int, battle: PokemonBattle): BattlePokemon? {
|
||||
val (actorID, pokemonID) = this.pnxAndUuid(index) ?: return null
|
||||
return this.battlePokemon(actorID, pokemonID, battle)
|
||||
}
|
||||
|
||||
fun getSourceBattlePokemon(battle: PokemonBattle): BattlePokemon? {
|
||||
val sourcePokemonArgument = this.optionalArguments.get("of") ?: return null
|
||||
val actorAndPokemonID = sourcePokemonArgument.takeIf { it.length >= 2 }?.split(": ") ?: return null
|
||||
if (actorAndPokemonID.count() < 2) return null
|
||||
val actorID = actorAndPokemonID[0]
|
||||
val pokemonID = actorAndPokemonID[1]
|
||||
return this.getBattlePokemon(actorID, pokemonID, battle)
|
||||
/**
|
||||
* Queries an optional argument identified by [optionalArg] for a 'pnx' and uuid that will be parsed into a [BattlePokemon].
|
||||
*
|
||||
* @param optionalArg The id of the optional argument referencing the [BattlePokemon].
|
||||
* @param battle The [PokemonBattle] being queried.
|
||||
* @return The [BattlePokemon] if the argument exists and is successfully parsed; otherwise null.
|
||||
*/
|
||||
fun battlePokemonFromOptional(battle: PokemonBattle, optionalArg: String = "of"): BattlePokemon? {
|
||||
val optional = this.optionalArguments.get(optionalArg) ?: return null
|
||||
val pokemonID = optional.takeIf { it.length >= 2 }?.split(":")?.takeIf { it.size == 2 } ?: return null
|
||||
val pnx = pokemonID[0].takeIf { it.matches(PNX_MATCHER) || it.matches(PN_MATCHER) } ?: return null
|
||||
val uuid = pokemonID[1].trim()
|
||||
return this.battlePokemon(pnx, uuid, battle)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,7 +170,7 @@ class BattleMessage(rawMessage: String) {
|
||||
*/
|
||||
fun pnxAndUuid(index: Int): Pair<String, String>? {
|
||||
val argument = this.argumentAt(index)?.takeIf { it.length >= 2 }?.split(":")?.takeIf { it.size == 2 } ?: return null
|
||||
val pnx = argument[0].takeIf { it.matches(PNX_MATCHER) } ?: return null
|
||||
val pnx = argument[0].takeIf { it.matches(PNX_MATCHER) || it.matches(PN_MATCHER) } ?: return null
|
||||
val uuid = argument[1].trim()
|
||||
return pnx to uuid
|
||||
}
|
||||
@@ -234,7 +237,7 @@ class BattleMessage(rawMessage: String) {
|
||||
null
|
||||
}
|
||||
|
||||
private fun getBattlePokemon(pnx: String, pokemonID: String, battle: PokemonBattle): BattlePokemon? = try {
|
||||
private fun battlePokemon(pnx: String, pokemonID: String, battle: PokemonBattle): BattlePokemon? = try {
|
||||
battle.getBattlePokemon(pnx, pokemonID)
|
||||
} catch (_: Exception) {
|
||||
null
|
||||
|
||||
+28
-10
@@ -8,13 +8,11 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.battles.model
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangEnvironment
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.CobblemonNetwork
|
||||
import com.cobblemon.mod.common.Environment
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
@@ -22,8 +20,6 @@ import com.cobblemon.mod.common.api.battles.model.actor.EntityBackedBattleActor
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.FleeableBattleActor
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleFledEvent
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunction
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
@@ -41,10 +37,10 @@ import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
|
||||
import com.cobblemon.mod.common.battles.interpreter.ContextManager
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||
import com.cobblemon.mod.common.battles.ForfeitActionResponse
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleEndPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleMessagePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleMusicPacket
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.DefeatEvolutionProgress
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.LastBattleCriticalHitsEvolutionProgress
|
||||
import com.cobblemon.mod.common.pokemon.evolution.requirements.DefeatRequirement
|
||||
@@ -107,6 +103,11 @@ open class PokemonBattle(
|
||||
var turn: Int = 1
|
||||
private set
|
||||
|
||||
private var ticks: Int = 0
|
||||
set(value) { field = value.coerceAtMost(Int.MAX_VALUE) } // go outside
|
||||
|
||||
/** The current duration of the battle in seconds. */
|
||||
val time: Int get() = ticks % 20
|
||||
|
||||
var dispatchResult = GO
|
||||
val dispatches = ConcurrentLinkedDeque<BattleDispatch>()
|
||||
@@ -166,7 +167,7 @@ open class PokemonBattle(
|
||||
fun getActor(player: ServerPlayerEntity) = actors.firstOrNull { it.isForPlayer(player) }
|
||||
|
||||
/**
|
||||
* Gets a BattleActor and an [ActiveBattlePokemon] from a pnx key, e.g. p2a
|
||||
* Gets a [BattleActor] and an [ActiveBattlePokemon] from a pnx key, e.g. p2a
|
||||
*
|
||||
* Returns null if either the pn or x is invalid.
|
||||
*/
|
||||
@@ -179,6 +180,11 @@ open class PokemonBattle(
|
||||
return actor to pokemon
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a [BattlePokemon] from a pnx key and uuid.
|
||||
*
|
||||
* Returns null if the pnx key is invalid or the uuid does not exist.
|
||||
*/
|
||||
fun getBattlePokemon(pnx: String, pokemonID: String): BattlePokemon {
|
||||
val actor = actors.find { it.showdownId == pnx.substring(0, 2) }
|
||||
?: throw IllegalStateException("Invalid pnx: $pnx - unknown actor")
|
||||
@@ -390,8 +396,9 @@ open class PokemonBattle(
|
||||
return
|
||||
}
|
||||
|
||||
if (started && isPvW && !ended && dispatches.isEmpty()) {
|
||||
checkFlee()
|
||||
if (started) {
|
||||
ticks++
|
||||
if (isPvW && !ended && dispatches.isEmpty()) checkFlee()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,13 +440,24 @@ open class PokemonBattle(
|
||||
}
|
||||
|
||||
fun checkForInputDispatch() {
|
||||
val readyToInput = actors.any { !it.mustChoose && it.responses.isNotEmpty() } && actors.none { it.mustChoose }
|
||||
if (checkForfeit()) return // ignore actors that are still choosing, their choices don't matter anymore
|
||||
val readyToInput = (actors.any { !it.mustChoose && it.responses.isNotEmpty() } && actors.none { it.mustChoose })
|
||||
if (readyToInput && captureActions.isEmpty()) {
|
||||
actors.filter { it.responses.isNotEmpty() }.forEach { it.writeShowdownResponse() }
|
||||
actors.forEach { it.responses.clear() ; it.request = null }
|
||||
}
|
||||
}
|
||||
|
||||
/** Forces Showdown to end the battle when a [BattleActor] chooses to forfeit. */
|
||||
private fun checkForfeit(): Boolean {
|
||||
val forfeit = actors.find { it.responses.any { it is ForfeitActionResponse } }
|
||||
return forfeit?.let {
|
||||
this.dispatchWaiting { this.broadcastChatMessage(battleLang("forfeit", it.getName()).red()) }
|
||||
writeShowdownAction(">forcelose ${it.showdownId}")
|
||||
true
|
||||
} ?: false
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a [Text] representation of an error to interpret a battle message.
|
||||
* This also logs the error, the goal of this function is to make sure users see missing interpretations and report them to us.
|
||||
@@ -479,4 +497,4 @@ open class PokemonBattle(
|
||||
|
||||
return queryStruct
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ object Berries : JsonDataRegistry<Berry> {
|
||||
.disableHtmlEscaping()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(MulchVariant::class.java, MulchVariantAdapter)
|
||||
.registerTypeAdapter(NumberRange.FloatRange::class.java, FloatNumberRangeAdapter)
|
||||
.registerTypeAdapter(NumberRange.DoubleRange::class.java, FloatNumberRangeAdapter)
|
||||
.registerTypeAdapter(Status::class.java, StatusAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(Collection::class.java, Box::class.java).type, BoxCollectionAdapter)
|
||||
.registerTypeAdapter(Box::class.java, BoxAdapter)
|
||||
@@ -103,4 +103,4 @@ object Berries : JsonDataRegistry<Berry> {
|
||||
*/
|
||||
fun getByName(name: String): Berry? = this.getByIdentifier(cobblemonResource(name))
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.entity.pokemon
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.effects.IllusionEffect
|
||||
import com.cobblemon.mod.common.entity.pokemon.effects.TransformEffect
|
||||
import com.cobblemon.mod.common.pokemon.FormData
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Represents a temporary alteration to how a [PokemonEntity] is rendered and behaves. May include a temporary visual effect
|
||||
* when applied.
|
||||
*
|
||||
* @author Segfault Guy
|
||||
* @since March 5th, 2024
|
||||
*/
|
||||
interface EntityEffect {
|
||||
|
||||
/**
|
||||
* Starts this effect for the provided [PokemonEntity].
|
||||
*
|
||||
* @return A [CompletableFuture] that completes after the effect has been applied. Or null if the effect failed to start.
|
||||
*/
|
||||
fun start(entity: PokemonEntity): CompletableFuture<PokemonEntity>?
|
||||
|
||||
/**
|
||||
* Ends this effect for the provided [PokemonEntity].
|
||||
*
|
||||
* @return A [CompletableFuture] that completes after the effect has been reverted. Or null if the effect failed to end.
|
||||
*/
|
||||
fun end(entity: PokemonEntity): CompletableFuture<PokemonEntity>?
|
||||
|
||||
/** Saves this effect to NBT. */
|
||||
fun saveToNbt(): NbtCompound
|
||||
|
||||
/** Loads this effect from NBT. */
|
||||
fun loadFromNBT(nbt: NbtCompound)
|
||||
|
||||
companion object {
|
||||
|
||||
private val effects = mutableMapOf<String, KClass<out EntityEffect>>()
|
||||
private val defaults = mutableMapOf<String, () -> EntityEffect>()
|
||||
|
||||
init {
|
||||
register(IllusionEffect.ID, IllusionEffect::class, ::IllusionEffect)
|
||||
register(TransformEffect.ID, TransformEffect::class, ::TransformEffect)
|
||||
}
|
||||
|
||||
fun <T : EntityEffect> register(id: String, type: KClass<T>, default: () -> T) {
|
||||
effects[id] = type
|
||||
defaults[id] = default
|
||||
}
|
||||
|
||||
fun createDefault(id: String): EntityEffect? = defaults[id]?.invoke()
|
||||
|
||||
fun loadFromNbt(nbt: NbtCompound): EntityEffect? {
|
||||
if (nbt.contains(DataKeys.ENTITY_EFFECT_ID)) {
|
||||
val id = nbt.getString(DataKeys.ENTITY_EFFECT_ID)
|
||||
return createDefault(id)?.also { it.loadFromNBT(nbt) }
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** An [EntityEffect] that modifies the dimensions of a [PokemonEntity]. */
|
||||
interface PhysicalEffect : EntityEffect {
|
||||
val scale: Float
|
||||
}
|
||||
|
||||
/** An [EntityEffect] that alters the physical appearance of a [PokemonEntity] to match a [mock]. */
|
||||
interface MocKEffect : PhysicalEffect {
|
||||
val mock: PokemonProperties
|
||||
|
||||
val exposedSpecies: Species?
|
||||
get() = this.mock.species?.let { PokemonSpecies.getByIdentifier(it.asIdentifierDefaultingNamespace()) }
|
||||
|
||||
val exposedForm: FormData?
|
||||
get() = this.mock.form?.let {
|
||||
formID -> this.exposedSpecies?.forms?.firstOrNull { it.formOnlyShowdownId().equals(formID, true) } }
|
||||
?: this.exposedSpecies?.standardForm
|
||||
}
|
||||
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.api.fossil
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.pokemon.evolution.predicate.NbtItemPredicate
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.registry.Registries
|
||||
import net.minecraft.text.MutableText
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
@@ -48,7 +47,7 @@ class Fossil(
|
||||
}
|
||||
|
||||
return this.fossils.all { fossil ->
|
||||
ingredients.any { fossil.item.fits(it.item, Registries.ITEM) && fossil.nbt.test(it) }
|
||||
ingredients.any { fossil.test(it) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +63,7 @@ class Fossil(
|
||||
|
||||
return ingredients.all { ingredient ->
|
||||
ingredients.count { item -> ingredient.itemMatches(item.registryEntry) } <=
|
||||
this.fossils.count { fossil -> fossil.item.fits(ingredient.item, Registries.ITEM) && fossil.nbt.test(ingredient) }
|
||||
this.fossils.count { fossil -> fossil.test(ingredient) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +73,7 @@ class Fossil(
|
||||
* @return True if the [ItemStack] is an ingredient, false otherwise.
|
||||
*/
|
||||
fun isIngredient(itemStack: ItemStack): Boolean {
|
||||
return this.fossils.any { it.item.fits(itemStack.item, Registries.ITEM) && it.nbt.test(itemStack) }
|
||||
return this.fossils.any { it.test(itemStack) }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -47,10 +47,10 @@ abstract class ParentWidget(
|
||||
super.mouseMoved(pMouseX, pMouseY)
|
||||
}
|
||||
|
||||
override fun mouseScrolled(pMouseX: Double, pMouseY: Double, pDelta: Double): Boolean {
|
||||
override fun mouseScrolled(mouseX: Double, mouseY: Double, horizontalAmount: Double, verticalAmount: Double): Boolean {
|
||||
return children.any {
|
||||
it.mouseScrolled(pMouseX, pMouseY, pDelta)
|
||||
} || super.mouseScrolled(pMouseX, pMouseY, pDelta)
|
||||
it.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount)
|
||||
} || super.mouseScrolled(mouseX, mouseY, horizontalAmount, verticalAmount)
|
||||
}
|
||||
|
||||
override fun mouseClicked(pMouseX: Double, pMouseY: Double, pButton: Int): Boolean {
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.item.ability
|
||||
|
||||
import com.cobblemon.mod.common.api.abilities.*
|
||||
import com.cobblemon.mod.common.item.interactive.ability.AbilityTypeChanger
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.abilities.HiddenAbility
|
||||
import com.cobblemon.mod.common.pokemon.abilities.HiddenAbilityType
|
||||
|
||||
/**
|
||||
* Represents a change operation for a [Pokemon.ability].
|
||||
* This is backed by the associated [PotentialAbility].
|
||||
*
|
||||
* @param T The type of [PotentialAbility].
|
||||
*/
|
||||
interface AbilityChanger<T : PotentialAbility> {
|
||||
|
||||
/**
|
||||
* The [PotentialAbilityType] of type [T].
|
||||
*/
|
||||
val type: PotentialAbilityType<T>
|
||||
|
||||
/**
|
||||
* Collects all the possible targets for the [type] and the given [pokemon].
|
||||
*
|
||||
* @param pokemon The [Pokemon] being queried.
|
||||
* @return A set containing all their legal abilities associated with [type], can be empty.
|
||||
*/
|
||||
fun queryPossible(pokemon: Pokemon): Set<AbilityTemplate>
|
||||
|
||||
/**
|
||||
* Attempts to update the ability of the given [pokemon].
|
||||
*
|
||||
* @param pokemon The [Pokemon] attempting to change an ability.
|
||||
* @return If the operation was successful.
|
||||
*/
|
||||
fun performChange(pokemon: Pokemon): Boolean
|
||||
|
||||
/**
|
||||
* Checks if the current [PotentialAbilityType] of a [Pokemon.ability] is possible to swap from with this.
|
||||
*
|
||||
* @param type The [PotentialAbilityType] or null if the ability is forced and/or illegal.
|
||||
* @return If the operation can be performed.
|
||||
*/
|
||||
fun canChangeFrom(type: PotentialAbilityType<*>?): Boolean
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* An implementation of [AbilityChanger] for [CommonAbility].
|
||||
*
|
||||
* While this can be used in custom data scenarios this functions most "game-like" if the Pokémon only has 2 common abilities.
|
||||
*/
|
||||
@JvmStatic
|
||||
val COMMON_ABILITY: AbilityChanger<CommonAbility> = AbilityTypeChanger(CommonAbilityType) { other -> other == CommonAbilityType }
|
||||
|
||||
/**
|
||||
* An implementation of [AbilityChanger] for [HiddenAbility].
|
||||
*
|
||||
* While this can be used in custom data scenarios this functions most "game-like" if the Pokémon only has 1 hidden ability.
|
||||
*/
|
||||
@JvmStatic
|
||||
val HIDDEN_ABILITY: AbilityChanger<HiddenAbility> = AbilityTypeChanger(HiddenAbilityType) { other -> other == CommonAbilityType || other == HiddenAbilityType }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,8 +19,8 @@ import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.dialogue.PlayerDialogueFaceProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.WaveFunction
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.WaveFunctions
|
||||
import com.cobblemon.mod.common.util.effectiveName
|
||||
import com.cobblemon.mod.common.util.isInt
|
||||
import com.cobblemon.mod.common.util.itemRegistry
|
||||
import net.minecraft.block.Block
|
||||
@@ -102,7 +102,7 @@ object MoLangFunctions {
|
||||
fun ServerPlayerEntity.asMoLangValue(): ObjectValue<ServerPlayerEntity> {
|
||||
val value = ObjectValue(
|
||||
obj = this,
|
||||
stringify = { it.entityName }
|
||||
stringify = { it.effectiveName().string }
|
||||
)
|
||||
value.addFunctions(playerFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
|
||||
return value
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@ object ActionEffects : JsonDataRegistry<ActionEffectTimeline> {
|
||||
.disableHtmlEscaping()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(ActionEffectKeyframe::class.java, ActionEffectKeyframeAdapter)
|
||||
.registerTypeAdapter(NumberRange.FloatRange::class.java, FloatNumberRangeAdapter)
|
||||
.registerTypeAdapter(NumberRange.DoubleRange::class.java, FloatNumberRangeAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(Collection::class.java, Box::class.java).type, BoxCollectionAdapter)
|
||||
.registerTypeAdapter(Box::class.java, BoxAdapter)
|
||||
.registerTypeAdapter(Vec3d::class.java, VerboseVec3dAdapter)
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ class MoveToTargetActionEffectKeyframe : ActionEffectKeyframe {
|
||||
|
||||
var timedOut = false
|
||||
|
||||
val proximity = this.proximity.takeIf { it != -1F } ?: (sqrt(2 * user.boundingBox.xLength.pow(2)) + 1.5F + sqrt(2 * target.boundingBox.xLength.pow(2))).toFloat()
|
||||
val proximity = this.proximity.takeIf { it != -1F } ?: (sqrt(2 * user.boundingBox.lengthX.pow(2)) + 1.5F + sqrt(2 * target.boundingBox.lengthX.pow(2))).toFloat()
|
||||
|
||||
if (target.distanceTo(user) !in proximity..20F) {
|
||||
future.complete(Unit)
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
package com.cobblemon.mod.common.api.multiblock
|
||||
|
||||
import com.cobblemon.mod.common.block.entity.FossilMultiblockEntity
|
||||
import net.minecraft.block.*
|
||||
import net.minecraft.block.BlockRenderType
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.block.BlockWithEntity
|
||||
import net.minecraft.block.entity.BlockEntity
|
||||
import net.minecraft.entity.LivingEntity
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
@@ -19,8 +21,8 @@ import net.minecraft.util.ActionResult
|
||||
import net.minecraft.util.Hand
|
||||
import net.minecraft.util.hit.BlockHitResult
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.world.BlockView
|
||||
import net.minecraft.world.World
|
||||
import net.minecraft.world.WorldView
|
||||
|
||||
/**
|
||||
* A block that can be part of a [MultiblockStructure]
|
||||
@@ -35,8 +37,8 @@ abstract class MultiblockBlock(properties: Settings) : BlockWithEntity(propertie
|
||||
itemStack: ItemStack?
|
||||
) {
|
||||
if (world is ServerWorld) {
|
||||
val multiblockEntity = world.getBlockEntity(pos) as MultiblockEntity
|
||||
multiblockEntity.multiblockBuilder?.validate(world)
|
||||
val multiblockEntity = world.getBlockEntity(pos) as? MultiblockEntity
|
||||
multiblockEntity?.multiblockBuilder?.validate(world)
|
||||
}
|
||||
super.onPlaced(world, pos, state, placer, itemStack)
|
||||
}
|
||||
@@ -52,21 +54,22 @@ abstract class MultiblockBlock(properties: Settings) : BlockWithEntity(propertie
|
||||
if(hand == Hand.OFF_HAND) {
|
||||
return ActionResult.SUCCESS
|
||||
}
|
||||
val entity = world.getBlockEntity(pos) as MultiblockEntity
|
||||
if (entity.multiblockStructure != null) {
|
||||
val entity = world.getBlockEntity(pos) as MultiblockEntity?
|
||||
if (entity?.multiblockStructure != null) {
|
||||
return entity.multiblockStructure!!.onUse(state, world, pos, player, hand, hit)
|
||||
}
|
||||
return super.onUse(state, world, pos, player, hand, hit)
|
||||
}
|
||||
|
||||
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity?) {
|
||||
super.onBreak(world, pos, state, player)
|
||||
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity?): BlockState {
|
||||
val result = super.onBreak(world, pos, state, player)
|
||||
if (!world.isClient) {
|
||||
val entity = world.getBlockEntity(pos)
|
||||
if (entity is MultiblockEntity && entity.multiblockStructure != null) {
|
||||
entity.multiblockStructure!!.onBreak(world, pos, state, player)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override fun createBlockEntity(pos: BlockPos, state: BlockState): BlockEntity? {
|
||||
@@ -78,11 +81,11 @@ abstract class MultiblockBlock(properties: Settings) : BlockWithEntity(propertie
|
||||
return BlockRenderType.MODEL
|
||||
}
|
||||
|
||||
override fun getPickStack(world: BlockView, pos: BlockPos, state: BlockState): ItemStack {
|
||||
override fun getPickStack(world: WorldView, pos: BlockPos, state: BlockState): ItemStack {
|
||||
val blockEntity = world.getBlockEntity(pos) as? MultiblockEntity ?: return ItemStack.EMPTY
|
||||
return if (blockEntity.multiblockStructure == null) super.getPickStack(world, pos, state) else ItemStack.EMPTY
|
||||
}
|
||||
|
||||
abstract fun createMultiBlockEntity(pos: BlockPos, state: BlockState): FossilMultiblockEntity
|
||||
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -43,6 +43,6 @@ interface MultiblockStructure {
|
||||
return 0
|
||||
}
|
||||
|
||||
fun markRemoved(world: World):Unit
|
||||
fun markRemoved(world: World)
|
||||
fun onTriggerEvent(state: BlockState?, world: ServerWorld?, pos: BlockPos?, random: Random?)
|
||||
}
|
||||
@@ -205,8 +205,8 @@ object PokeBalls : JsonDataRegistry<PokeBall> {
|
||||
createDefault("ancient_wing_ball", throwPower = 2.5f, ancient = true)
|
||||
createDefault("ancient_jet_ball", throwPower = 2.5f, ancient = true)
|
||||
createDefault("ancient_origin_ball", GuaranteedModifier(), ancient = true)
|
||||
// Luxury ball effect
|
||||
CobblemonEvents.FRIENDSHIP_UPDATED.subscribe(priority = Priority.LOWEST) { event ->
|
||||
// Luxury ball effect, low priority as it must be triggered before soothe bell as of gen 4
|
||||
CobblemonEvents.FRIENDSHIP_UPDATED.subscribe(priority = Priority.LOW) { event ->
|
||||
var increment = (event.newFriendship - event.pokemon.friendship).toFloat()
|
||||
if (increment <= 1F) {
|
||||
event.pokemon.caughtBall.effects.filterIsInstance<FriendshipEarningBoostEffect>()
|
||||
|
||||
@@ -13,18 +13,21 @@ import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.abilities.Abilities
|
||||
import com.cobblemon.mod.common.api.abilities.Ability
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.api.types.tera.TeraTypes
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.*
|
||||
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import com.mojang.serialization.Codec
|
||||
import kotlin.random.Random
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.nbt.NbtElement
|
||||
@@ -52,6 +55,11 @@ import java.util.UUID
|
||||
*/
|
||||
open class PokemonProperties {
|
||||
companion object {
|
||||
val CODEC: Codec<PokemonProperties> = Codec.STRING.xmap(
|
||||
{ parse(it) },
|
||||
{ it.originalString }
|
||||
)
|
||||
|
||||
@JvmOverloads
|
||||
fun parse(string: String, delimiter: String = " ", assigner: String = "="): PokemonProperties {
|
||||
val props = PokemonProperties()
|
||||
@@ -294,6 +302,18 @@ open class PokemonProperties {
|
||||
)
|
||||
|
||||
fun apply(pokemon: Pokemon) {
|
||||
// Custom properties check could be duplicated but can't assume 3rd party hasn't done anything type specific
|
||||
this.customProperties.forEach { it.apply(pokemon) }
|
||||
this.commonApply(pokemon)
|
||||
}
|
||||
|
||||
fun apply(pokemonEntity: PokemonEntity) {
|
||||
// Custom properties check could be duplicated but can't assume 3rd party hasn't done anything type specific
|
||||
this.customProperties.forEach { it.apply(pokemonEntity) }
|
||||
this.commonApply(pokemonEntity.pokemon)
|
||||
}
|
||||
|
||||
private fun commonApply(pokemon: Pokemon) {
|
||||
species?.let {
|
||||
return@let try {
|
||||
if (it == "random") {
|
||||
@@ -313,8 +333,8 @@ open class PokemonProperties {
|
||||
friendship?.let { pokemon.setFriendship(it) }
|
||||
pokeball?.let { PokeBalls.getPokeBall(it.asIdentifierDefaultingNamespace())?.let { pokeball -> pokemon.caughtBall = pokeball } }
|
||||
nature?.let { Natures.getNature(it.asIdentifierDefaultingNamespace())?.let { nature -> pokemon.nature = nature } }
|
||||
ability?.let { Abilities.getOrException(it).create(true).let { ability -> pokemon.ability = ability } }
|
||||
status?.let { Statuses.getStatus(it)?.let { pokemon.applyStatus(it as PersistentStatus) } }
|
||||
ability?.let { this.createAbility(it, pokemon.form)?.let(pokemon::updateAbility) }
|
||||
status?.let { Statuses.getStatus(it)?.let { status -> if (status is PersistentStatus) pokemon.applyStatus(status) } }
|
||||
customProperties.forEach { it.apply(pokemon) }
|
||||
ivs?.let { ivs ->
|
||||
ivs.forEach { stat ->
|
||||
@@ -326,7 +346,7 @@ open class PokemonProperties {
|
||||
pokemon.setEV(stat.key, stat.value)
|
||||
}
|
||||
}
|
||||
teraType?.let { ElementalTypes.get(it)?.let { type -> pokemon.teraType = type } }
|
||||
teraType?.let { TeraTypes.get(it.asIdentifierDefaultingNamespace())?.let { type -> pokemon.teraType = type } }
|
||||
dmaxLevel?.let { pokemon.dmaxLevel = it }
|
||||
gmaxFactor?.let { pokemon.gmaxFactor = it }
|
||||
tradeable?.let { pokemon.tradeable = it }
|
||||
@@ -355,69 +375,17 @@ open class PokemonProperties {
|
||||
pokemon.updateAspects()
|
||||
}
|
||||
|
||||
fun apply(pokemonEntity: PokemonEntity) {
|
||||
species?.let {
|
||||
return@let try {
|
||||
if (it == "random") {
|
||||
PokemonSpecies.species.random()
|
||||
} else {
|
||||
PokemonSpecies.getByIdentifier(it.asIdentifierDefaultingNamespace())
|
||||
}
|
||||
} catch (e: InvalidIdentifierException) {
|
||||
null
|
||||
}
|
||||
}?.let { pokemonEntity.pokemon.species = it }
|
||||
nickname?.let { pokemonEntity.pokemon.nickname = it }
|
||||
form?.let { formID -> pokemonEntity.pokemon.species.forms.firstOrNull { it.formOnlyShowdownId().equals(formID, true) } }?.let { form -> pokemonEntity.pokemon.form = form }
|
||||
level?.let { pokemonEntity.pokemon.level = it }
|
||||
shiny?.let { pokemonEntity.pokemon.shiny = it }
|
||||
gender?.let { pokemonEntity.pokemon.gender = it }
|
||||
friendship?.let { pokemonEntity.pokemon.setFriendship(it) }
|
||||
pokeball?.let { PokeBalls.getPokeBall(it.asIdentifierDefaultingNamespace())?.let { pokeball -> pokemonEntity.pokemon.caughtBall = pokeball } }
|
||||
nature?.let { Natures.getNature(it.asIdentifierDefaultingNamespace())?.let { nature -> pokemonEntity.pokemon.nature = nature } }
|
||||
ability?.let { Abilities.getOrException(it).create(true).let { ability -> pokemonEntity.pokemon.ability = ability } }
|
||||
status?.let { Statuses.getStatus(it)?.let { pokemonEntity.pokemon.applyStatus(it as PersistentStatus) } }
|
||||
customProperties.forEach { it.apply(pokemonEntity) }
|
||||
ivs?.let { ivs ->
|
||||
ivs.forEach { stat ->
|
||||
pokemonEntity.pokemon.setIV(stat.key, stat.value)
|
||||
}
|
||||
}
|
||||
evs?.let { evs ->
|
||||
evs.forEach { stat ->
|
||||
pokemonEntity.pokemon.setEV(stat.key, stat.value)
|
||||
}
|
||||
}
|
||||
teraType?.let { ElementalTypes.get(it)?.let { type -> pokemonEntity.pokemon.teraType = type } }
|
||||
dmaxLevel?.let { pokemonEntity.pokemon.dmaxLevel = it }
|
||||
gmaxFactor?.let { pokemonEntity.pokemon.gmaxFactor = it }
|
||||
tradeable?.let { pokemonEntity.pokemon.tradeable = it }
|
||||
// If it has been explicitly set to NONE, clear the stored information, including the originalTrainer property
|
||||
originalTrainerType?.let {
|
||||
if (it == OriginalTrainerType.NONE) {
|
||||
pokemonEntity.pokemon.removeOriginalTrainer()
|
||||
originalTrainer = null
|
||||
}
|
||||
}
|
||||
originalTrainer?.let { ot ->
|
||||
val type = originalTrainerType ?: pokemonEntity.pokemon.originalTrainerType
|
||||
when (type) {
|
||||
OriginalTrainerType.PLAYER -> {
|
||||
when (ot.length) {
|
||||
in 3..16 -> server()?.userCache?.findByName(ot)?.get()?.id // OT is a Username
|
||||
36 -> UUID.fromString(ot) // OT is a UUID
|
||||
else -> null // OT is invalid
|
||||
}?.let { uuid -> pokemonEntity.pokemon.setOriginalTrainer(uuid) }
|
||||
}
|
||||
OriginalTrainerType.NPC -> pokemonEntity.pokemon.setOriginalTrainer(ot)
|
||||
else -> {}
|
||||
}
|
||||
pokemonEntity.pokemon.refreshOriginalTrainer()
|
||||
}
|
||||
pokemonEntity.pokemon.updateAspects()
|
||||
fun matches(pokemon: Pokemon): Boolean {
|
||||
// Custom properties check could be duplicated but can't assume 3rd party hasn't done anything type specific
|
||||
return this.commonMatches(pokemon) && this.customProperties.none { !it.matches(pokemon) }
|
||||
}
|
||||
|
||||
fun matches(pokemon: Pokemon): Boolean {
|
||||
fun matches(pokemonEntity: PokemonEntity): Boolean {
|
||||
// Custom properties check could be duplicated but can't assume 3rd party hasn't done anything type specific
|
||||
return this.commonMatches(pokemonEntity.pokemon) && this.customProperties.none { !it.matches(pokemonEntity) }
|
||||
}
|
||||
|
||||
private fun commonMatches(pokemon: Pokemon): Boolean {
|
||||
level?.takeIf { it != pokemon.level }?.let { return false }
|
||||
shiny?.takeIf { it != pokemon.shiny }?.let { return false }
|
||||
gender?.takeIf { it != pokemon.gender }?.let { return false }
|
||||
@@ -435,7 +403,7 @@ open class PokemonProperties {
|
||||
return false
|
||||
}
|
||||
}
|
||||
nickname?.takeIf { it != pokemon.nickname }?.let { return false }
|
||||
nickname?.takeIf { it.string != pokemon.nickname?.string }?.let { return false }
|
||||
form?.takeIf { !it.equals(pokemon.form.name, true) }?.let { return false }
|
||||
friendship?.takeIf { it != pokemon.friendship }?.let { return false }
|
||||
pokeball?.takeIf { it != pokemon.caughtBall.name.toString() }?.let { return false }
|
||||
@@ -448,59 +416,23 @@ open class PokemonProperties {
|
||||
evs?.forEach{ stat ->
|
||||
if (stat.value != pokemon.evs[stat.key]) { return false }
|
||||
}
|
||||
teraType?.takeIf { it != pokemon.teraType.name }?.let { return false }
|
||||
teraType?.takeIf { it.asIdentifierDefaultingNamespace() != pokemon.teraType.id }?.let { return false }
|
||||
dmaxLevel?.takeIf { it != pokemon.dmaxLevel }?.let { return false }
|
||||
gmaxFactor?.takeIf { it != pokemon.gmaxFactor }?.let { return false }
|
||||
tradeable?.takeIf { it != pokemon.tradeable }?.let { return false }
|
||||
originalTrainer?.takeIf { it != pokemon.originalTrainer }?.let{ return false }
|
||||
originalTrainerType?.takeIf { it != pokemon.originalTrainerType }?.let{ return false }
|
||||
return customProperties.none { !it.matches(pokemon) }
|
||||
}
|
||||
|
||||
fun matches(pokemonEntity: PokemonEntity): Boolean {
|
||||
level?.takeIf { it != pokemonEntity.pokemon.level }?.let { return false }
|
||||
shiny?.takeIf { it != ("shiny" in pokemonEntity.pokemon.aspects) }?.let { return false }
|
||||
gender?.takeIf { it != pokemonEntity.pokemon.gender }?.let { return false }
|
||||
species?.run {
|
||||
try {
|
||||
val species = if (this == "random") {
|
||||
PokemonSpecies.species.random()
|
||||
} else {
|
||||
PokemonSpecies.getByIdentifier(this.asIdentifierDefaultingNamespace()) ?: return@run
|
||||
}
|
||||
if (pokemonEntity.pokemon.species != species) {
|
||||
return false
|
||||
}
|
||||
} catch (e: InvalidIdentifierException) {}
|
||||
}
|
||||
nickname?.takeIf { it != pokemonEntity.pokemon.nickname }?.let { return false }
|
||||
form?.takeIf { !it.equals(pokemonEntity.pokemon.form.name, true) }?.let { return false }
|
||||
friendship?.takeIf { it != pokemonEntity.pokemon.friendship }?.let { return false }
|
||||
pokeball?.takeIf { it != pokemonEntity.pokemon.caughtBall.name.toString() }?.let { return false }
|
||||
nature?.takeIf { it != pokemonEntity.pokemon.nature.name.toString() }?.let { return false }
|
||||
ability?.takeIf { it != pokemonEntity.pokemon.ability.name }?.let { return false }
|
||||
status?.takeIf { it != pokemonEntity.pokemon.status?.status?.showdownName }?.let { return false }
|
||||
ivs?.forEach{ stat ->
|
||||
if (stat.value != pokemonEntity.pokemon.ivs[stat.key]) { return false }
|
||||
}
|
||||
evs?.forEach{ stat ->
|
||||
if (stat.value != pokemonEntity.pokemon.evs[stat.key]) { return false }
|
||||
}
|
||||
teraType?.takeIf { it != pokemonEntity.pokemon.teraType.name }?.let { return false }
|
||||
dmaxLevel?.takeIf { it != pokemonEntity.pokemon.dmaxLevel }?.let { return false }
|
||||
gmaxFactor?.takeIf { it != pokemonEntity.pokemon.gmaxFactor }?.let { return false }
|
||||
tradeable?.takeIf { it != pokemonEntity.pokemon.tradeable }?.let { return false }
|
||||
originalTrainer?.takeIf { it != pokemonEntity.pokemon.originalTrainer }?.let{ return false }
|
||||
originalTrainerType?.takeIf { it != pokemonEntity.pokemon.originalTrainerType }?.let{ return false }
|
||||
return customProperties.none { !it.matches(pokemonEntity) }
|
||||
return true
|
||||
}
|
||||
|
||||
// TODO Review the need for this, usage for us is in commands that deviate from the behavior established by multiple Pokémon query equivalent
|
||||
fun isSubSetOf(properties: PokemonProperties): Boolean {
|
||||
level?.takeIf { it != properties.level }?.let { return false }
|
||||
shiny?.takeIf { it != ("shiny" in properties.aspects) }?.let { return false }
|
||||
gender?.takeIf { it != properties.gender }?.let { return false }
|
||||
species?.run {
|
||||
try {
|
||||
// TODO get context on this bit, it's highly unlikely two randoms would result in the same Pokémon, doesn't mean the prop is not equal?
|
||||
val species = if (this == "random") {
|
||||
PokemonSpecies.species.random()
|
||||
} else {
|
||||
@@ -509,9 +441,9 @@ open class PokemonProperties {
|
||||
if (properties.species != species.toString()) {
|
||||
return false
|
||||
}
|
||||
} catch (e: InvalidIdentifierException) {}
|
||||
} catch (_: InvalidIdentifierException) {}
|
||||
}
|
||||
nickname?.takeIf { it != properties.nickname }?.let { return false }
|
||||
nickname?.takeIf { it.string != properties.nickname?.string }?.let { return false }
|
||||
form?.takeIf { !it.equals(properties.form, true) }?.let { return false }
|
||||
friendship?.takeIf { it != properties.friendship }?.let { return false }
|
||||
pokeball?.takeIf { it != properties.pokeball }?.let { return false }
|
||||
@@ -551,20 +483,18 @@ open class PokemonProperties {
|
||||
|
||||
// TEST YOUR LUCK!
|
||||
fun roll(pokemon: Pokemon) {
|
||||
val baseTypes = pokemon.species.types.toList()
|
||||
val baseTypes = pokemon.form.types.toList()
|
||||
if (this.shiny == null) pokemon.shiny = Cobblemon.config.shinyRate.checkRate()
|
||||
if (this.teraType == null) pokemon.teraType =
|
||||
if (Cobblemon.config.teraTypeRate.checkRate()) ElementalTypes.all().filter { !baseTypes.contains(it) }.random()
|
||||
else baseTypes.random()
|
||||
if (Cobblemon.config.teraTypeRate.checkRate()) TeraTypes.random(true)
|
||||
else TeraTypes.forElementalType(baseTypes.random())
|
||||
}
|
||||
|
||||
// If the config value is at least 1, then do 1/x and use that as the property chance
|
||||
private fun Float.checkRate(): Boolean = this >= 1 && (Random.Default.nextFloat() < 1 / this)
|
||||
|
||||
fun createEntity(world: World): PokemonEntity {
|
||||
return PokemonEntity(world, create())
|
||||
}
|
||||
|
||||
// TODO Codecs at some point
|
||||
fun saveToNBT(): NbtCompound {
|
||||
val nbt = NbtCompound()
|
||||
originalString.let { nbt.putString(DataKeys.POKEMON_PROPERTIES_ORIGINAL_TEXT, it) }
|
||||
@@ -572,7 +502,7 @@ open class PokemonProperties {
|
||||
shiny?.let { nbt.putBoolean(DataKeys.POKEMON_SHINY, it) }
|
||||
gender?.let { nbt.putString(DataKeys.POKEMON_GENDER, it.name) }
|
||||
species?.let { nbt.putString(DataKeys.POKEMON_SPECIES_TEXT, it) }
|
||||
nickname?.let { nbt.putString(DataKeys.POKEMON_NICKNAME, Text.Serializer.toJson(it)) }
|
||||
nickname?.let { nbt.putString(DataKeys.POKEMON_NICKNAME, Text.Serialization.toJsonString(it)) }
|
||||
form?.let { nbt.putString(DataKeys.POKEMON_FORM_ID, it) }
|
||||
friendship?.let { nbt.putInt(DataKeys.POKEMON_FRIENDSHIP, it) }
|
||||
pokeball?.let { nbt.putString(DataKeys.POKEMON_CAUGHT_BALL, it) }
|
||||
@@ -593,13 +523,14 @@ open class PokemonProperties {
|
||||
return nbt
|
||||
}
|
||||
|
||||
// TODO Codecs at some point
|
||||
fun loadFromNBT(tag: NbtCompound): PokemonProperties {
|
||||
originalString = tag.getString(DataKeys.POKEMON_PROPERTIES_ORIGINAL_TEXT)
|
||||
level = if (tag.contains(DataKeys.POKEMON_LEVEL)) tag.getInt(DataKeys.POKEMON_LEVEL) else null
|
||||
shiny = if (tag.contains(DataKeys.POKEMON_SHINY)) tag.getBoolean(DataKeys.POKEMON_SHINY) else null
|
||||
gender = if (tag.contains(DataKeys.POKEMON_GENDER)) Gender.valueOf(tag.getString(DataKeys.POKEMON_GENDER)) else null
|
||||
species = if (tag.contains(DataKeys.POKEMON_SPECIES_TEXT)) tag.getString(DataKeys.POKEMON_SPECIES_TEXT) else null
|
||||
nickname = if (tag.contains(DataKeys.POKEMON_NICKNAME)) Text.Serializer.fromJson(tag.getString(DataKeys.POKEMON_NICKNAME)) else null
|
||||
nickname = if (tag.contains(DataKeys.POKEMON_NICKNAME)) Text.Serialization.fromJson(tag.getString(DataKeys.POKEMON_NICKNAME)) else null
|
||||
form = if (tag.contains(DataKeys.POKEMON_FORM_ID)) tag.getString(DataKeys.POKEMON_FORM_ID) else null
|
||||
friendship = if (tag.contains(DataKeys.POKEMON_FRIENDSHIP)) tag.getInt(DataKeys.POKEMON_FRIENDSHIP) else null
|
||||
pokeball = if (tag.contains(DataKeys.POKEMON_CAUGHT_BALL)) tag.getString(DataKeys.POKEMON_CAUGHT_BALL) else null
|
||||
@@ -621,6 +552,7 @@ open class PokemonProperties {
|
||||
return this
|
||||
}
|
||||
|
||||
// TODO Codecs at some point
|
||||
fun saveToJSON(): JsonObject {
|
||||
val json = JsonObject()
|
||||
originalString.let { json.addProperty(DataKeys.POKEMON_PROPERTIES_ORIGINAL_TEXT, it) }
|
||||
@@ -628,7 +560,7 @@ open class PokemonProperties {
|
||||
shiny?.let { json.addProperty(DataKeys.POKEMON_SHINY, it) }
|
||||
gender?.let { json.addProperty(DataKeys.POKEMON_GENDER, it.name) }
|
||||
species?.let { json.addProperty(DataKeys.POKEMON_SPECIES_TEXT, it) }
|
||||
nickname?.let { json.addProperty(DataKeys.POKEMON_NICKNAME, Text.Serializer.toJson(it)) }
|
||||
nickname?.let { json.addProperty(DataKeys.POKEMON_NICKNAME, Text.Serialization.toJsonString(it)) }
|
||||
form?.let { json.addProperty(DataKeys.POKEMON_FORM_ID, it) }
|
||||
friendship?.let { json.addProperty(DataKeys.POKEMON_FRIENDSHIP, it) }
|
||||
pokeball?.let { json.addProperty(DataKeys.POKEMON_CAUGHT_BALL, it) }
|
||||
@@ -650,13 +582,14 @@ open class PokemonProperties {
|
||||
return json
|
||||
}
|
||||
|
||||
// TODO Codecs at some point
|
||||
fun loadFromJSON(json: JsonObject): PokemonProperties {
|
||||
originalString = json.get(DataKeys.POKEMON_PROPERTIES_ORIGINAL_TEXT)?.asString ?: ""
|
||||
level = json.get(DataKeys.POKEMON_LEVEL)?.asInt
|
||||
shiny = json.get(DataKeys.POKEMON_SHINY)?.asBoolean
|
||||
gender = json.get(DataKeys.POKEMON_GENDER)?.asString?.let { Gender.valueOf(it) }
|
||||
species = json.get(DataKeys.POKEMON_SPECIES_TEXT)?.asString
|
||||
nickname = json.get(DataKeys.POKEMON_NICKNAME)?.asString?.let { Text.Serializer.fromJson(it) }
|
||||
nickname = json.get(DataKeys.POKEMON_NICKNAME)?.asString?.let { Text.Serialization.fromJson(it) }
|
||||
form = json.get(DataKeys.POKEMON_FORM_ID)?.asString
|
||||
friendship = json.get(DataKeys.POKEMON_FRIENDSHIP)?.asInt
|
||||
pokeball = json.get(DataKeys.POKEMON_CAUGHT_BALL)?.asString
|
||||
@@ -727,4 +660,21 @@ open class PokemonProperties {
|
||||
fun copy(): PokemonProperties {
|
||||
return PokemonProperties().loadFromJSON(saveToJSON())
|
||||
}
|
||||
}
|
||||
|
||||
// If the config value is at least 1, then do 1/x and use that as the property chance
|
||||
private fun Float.checkRate(): Boolean = this >= 1 && (Random.Default.nextFloat() < 1 / this)
|
||||
|
||||
/**
|
||||
* Attempts to find an ability by ID and resolve if it should be forced or if it's legal for the given form.
|
||||
*
|
||||
* @param id The literal ID of the [Ability] being mapped.
|
||||
* @param form The [FormData] whose [FormData.abilities] is queried for legality.
|
||||
* @return The [Ability] with the [Ability.forced] state necessary for the given [form].
|
||||
*/
|
||||
private fun createAbility(id: String, form: FormData): Ability? {
|
||||
val ability = Abilities.get(id) ?: return null
|
||||
val potentialAbility = form.abilities.firstOrNull { potential -> potential.template == ability } ?: return ability.create(true)
|
||||
return potentialAbility.template.create(false)
|
||||
}
|
||||
|
||||
}
|
||||
+5
@@ -48,6 +48,11 @@ fun interface PokemonPropertyExtractor {
|
||||
@JvmField
|
||||
val STATUS = add { pokemon, properties -> properties.status = pokemon.status?.status?.showdownName }
|
||||
|
||||
@JvmField
|
||||
val ILLUSION = mutableListOf(SPECIES, FORM, ASPECTS, GENDER, NICKNAME, SHINY)
|
||||
@JvmField
|
||||
val TRANSFORM = mutableListOf(SPECIES, FORM, ASPECTS, GENDER)
|
||||
|
||||
fun add(extractor: PokemonPropertyExtractor): PokemonPropertyExtractor {
|
||||
ALL.add(extractor)
|
||||
return extractor
|
||||
|
||||
@@ -49,6 +49,25 @@ enum class Stats(override val identifier: Identifier, override val displayName:
|
||||
*/
|
||||
val BATTLE_ONLY: Set<Stat> = EnumSet.of(EVASION, ACCURACY)
|
||||
|
||||
/** Gets the [Stat] from the respective Showdown id. */
|
||||
fun getStat(statKey: String) = when(statKey) {
|
||||
"atk" -> ATTACK
|
||||
"def" -> DEFENCE
|
||||
"spa" -> SPECIAL_ATTACK
|
||||
"spd" -> SPECIAL_DEFENCE
|
||||
"spe" -> SPEED
|
||||
"evasion" -> EVASION
|
||||
else -> ACCURACY
|
||||
}
|
||||
|
||||
/** Gets the severity lang key from the respective boost/unboost stage. */
|
||||
fun getSeverity(stages: Int) = when(stages) {
|
||||
0 -> "cap.single"
|
||||
1 -> "slight"
|
||||
2 -> "sharp"
|
||||
else -> "severe"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,7 +20,6 @@ import com.mojang.serialization.codecs.PrimitiveCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.Vec3d
|
||||
|
||||
/**
|
||||
* Effect details for the actual particles of a particle effect.
|
||||
@@ -44,48 +43,106 @@ class BedrockParticle(
|
||||
var cameraMode: ParticleCameraMode = RotateXYZCameraMode(),
|
||||
var tinting: ParticleTinting = ExpressionParticleTinting(),
|
||||
var collision: ParticleCollision = ParticleCollision(),
|
||||
var environmentLighting: Boolean = false
|
||||
var environmentLighting: Boolean = false,
|
||||
var creationEvents: MutableList<SimpleEventTrigger> = mutableListOf(),
|
||||
var expirationEvents: MutableList<SimpleEventTrigger> = mutableListOf(),
|
||||
var timeline: EventTriggerTimeline = EventTriggerTimeline(mutableMapOf())
|
||||
) {
|
||||
class ExpressionSet(
|
||||
val sizeX: Expression,
|
||||
val sizeY: Expression,
|
||||
val maxAge: Expression,
|
||||
val killExpression: Expression,
|
||||
val updateExpressions: MutableList<Expression>,
|
||||
val renderExpressions: MutableList<Expression>
|
||||
)
|
||||
|
||||
/*
|
||||
"creation_event": "event_sendspark",
|
||||
"expiration_event": ["event_spark", "event_afterspark", "event_capturestar"],
|
||||
"timeline": {
|
||||
"21.00": "event_spark"
|
||||
}
|
||||
*/
|
||||
|
||||
class EventSet(
|
||||
val creationEvents: MutableList<SimpleEventTrigger>,
|
||||
val expirationEvents: MutableList<SimpleEventTrigger>,
|
||||
val timeline: EventTriggerTimeline
|
||||
)
|
||||
|
||||
// kill plane maybe
|
||||
companion object {
|
||||
val CODEC: Codec<BedrockParticle> = RecordCodecBuilder.create { instance ->
|
||||
val EXPRESSION_SET_CODEC = RecordCodecBuilder.create<ExpressionSet> { instance ->
|
||||
instance.group(
|
||||
Identifier.CODEC.fieldOf("texture").forGetter { it.texture },
|
||||
PrimitiveCodec.STRING.fieldOf("material").forGetter { it.material.name },
|
||||
ParticleUVMode.codec.fieldOf("uvMode").forGetter { it.uvMode },
|
||||
EXPRESSION_CODEC.fieldOf("sizeX").forGetter { it.sizeX },
|
||||
EXPRESSION_CODEC.fieldOf("sizeY").forGetter { it.sizeY },
|
||||
EXPRESSION_CODEC.fieldOf("maxAge").forGetter { it.maxAge },
|
||||
EXPRESSION_CODEC.fieldOf("killExpression").forGetter { it.killExpression },
|
||||
ListCodec(EXPRESSION_CODEC).fieldOf("updateExpressions").forGetter { it.updateExpressions },
|
||||
ListCodec(EXPRESSION_CODEC).fieldOf("renderExpressions").forGetter { it.renderExpressions },
|
||||
ListCodec(EXPRESSION_CODEC).fieldOf("renderExpressions").forGetter { it.renderExpressions }
|
||||
).apply(instance, ::ExpressionSet)
|
||||
}
|
||||
|
||||
val EVENT_SET_CODEC = RecordCodecBuilder.create<EventSet> { instance ->
|
||||
instance.group(
|
||||
ListCodec(SimpleEventTrigger.CODEC).fieldOf("creationEvents").forGetter { it.creationEvents },
|
||||
ListCodec(SimpleEventTrigger.CODEC).fieldOf("expirationEvents").forGetter { it.expirationEvents },
|
||||
EventTriggerTimeline.CODEC.fieldOf("timeline").forGetter { it.timeline }
|
||||
).apply(instance, ::EventSet)
|
||||
}
|
||||
|
||||
val CODEC: Codec<BedrockParticle> = RecordCodecBuilder.create { instance ->
|
||||
instance.group(
|
||||
Identifier.CODEC.fieldOf("texture").forGetter { it.texture },
|
||||
PrimitiveCodec.STRING.fieldOf("material").forGetter { it.material.name },
|
||||
ParticleUVMode.codec.fieldOf("uvMode").forGetter { it.uvMode },
|
||||
EXPRESSION_SET_CODEC.fieldOf("expressionSet").forGetter {
|
||||
ExpressionSet(
|
||||
it.sizeX,
|
||||
it.sizeY,
|
||||
it.maxAge,
|
||||
it.killExpression,
|
||||
it.updateExpressions,
|
||||
it.renderExpressions
|
||||
)
|
||||
},
|
||||
ParticleMotion.codec.fieldOf("motion").forGetter { it.motion },
|
||||
ParticleRotation.codec.fieldOf("rotation").forGetter { it.rotation },
|
||||
ParticleViewDirection.codec.fieldOf("viewDirection").forGetter { it.viewDirection },
|
||||
ParticleCameraMode.codec.fieldOf("cameraMode").forGetter { it.cameraMode },
|
||||
ParticleTinting.codec.fieldOf("tinting").forGetter { it.tinting },
|
||||
ParticleCollision.CODEC.fieldOf("collision").forGetter { it.collision },
|
||||
PrimitiveCodec.BOOL.fieldOf("environmentLighting").forGetter { it.environmentLighting }
|
||||
PrimitiveCodec.BOOL.fieldOf("environmentLighting").forGetter { it.environmentLighting },
|
||||
EVENT_SET_CODEC.fieldOf("eventSet").forGetter {
|
||||
EventSet(
|
||||
it.creationEvents,
|
||||
it.expirationEvents,
|
||||
it.timeline
|
||||
)
|
||||
}
|
||||
).apply(instance) {
|
||||
texture, materialStr, uvMode, sizeX, sizeY, maxAge, killExpression, updateExpressions,
|
||||
renderExpressions, motion, rotation, viewDirection, cameraMode, tinting, collision, environmentLighting ->
|
||||
texture, materialStr, uvMode, expressionSet, motion, rotation, viewDirection, cameraMode, tinting, collision, environmentLighting, eventSet ->
|
||||
BedrockParticle(
|
||||
texture = texture,
|
||||
material = ParticleMaterial.valueOf(materialStr),
|
||||
uvMode = uvMode,
|
||||
sizeX = sizeX,
|
||||
sizeY = sizeY,
|
||||
maxAge = maxAge,
|
||||
killExpression = killExpression,
|
||||
updateExpressions = updateExpressions,
|
||||
renderExpressions = renderExpressions,
|
||||
sizeX = expressionSet.sizeX,
|
||||
sizeY = expressionSet.sizeY,
|
||||
maxAge = expressionSet.maxAge,
|
||||
killExpression = expressionSet.killExpression,
|
||||
updateExpressions = expressionSet.updateExpressions,
|
||||
renderExpressions = expressionSet.renderExpressions,
|
||||
motion = motion,
|
||||
rotation = rotation,
|
||||
viewDirection = viewDirection,
|
||||
cameraMode = cameraMode,
|
||||
tinting = tinting,
|
||||
collision = collision,
|
||||
environmentLighting = environmentLighting
|
||||
environmentLighting = environmentLighting,
|
||||
creationEvents = eventSet.creationEvents,
|
||||
expirationEvents = eventSet.expirationEvents,
|
||||
timeline = eventSet.timeline
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -108,6 +165,9 @@ class BedrockParticle(
|
||||
ParticleTinting.writeToBuffer(buffer, tinting)
|
||||
collision.writeToBuffer(buffer)
|
||||
buffer.writeBoolean(environmentLighting)
|
||||
buffer.writeCollection(creationEvents) { pb, event -> event.encode(pb) }
|
||||
buffer.writeCollection(expirationEvents) { pb, event -> event.encode(pb) }
|
||||
timeline.encode(buffer)
|
||||
}
|
||||
|
||||
fun readFromBuffer(buffer: PacketByteBuf) {
|
||||
@@ -127,5 +187,8 @@ class BedrockParticle(
|
||||
tinting = ParticleTinting.readFromBuffer(buffer)
|
||||
collision.readFromBuffer(buffer)
|
||||
environmentLighting = buffer.readBoolean()
|
||||
creationEvents = buffer.readList { SimpleEventTrigger("").also { it.decode(buffer) } }
|
||||
expirationEvents = buffer.readList { SimpleEventTrigger("").also { it.decode(buffer) } }
|
||||
timeline.decode(buffer)
|
||||
}
|
||||
}
|
||||
+11
-4
@@ -10,7 +10,9 @@ package com.cobblemon.mod.common.api.snowstorm
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.ListCodec
|
||||
import com.mojang.serialization.codecs.PrimitiveCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import com.mojang.serialization.codecs.UnboundedMapCodec
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
@@ -27,7 +29,8 @@ class BedrockParticleEffect(
|
||||
var emitter: BedrockParticleEmitter = BedrockParticleEmitter(),
|
||||
var particle: BedrockParticle = BedrockParticle(),
|
||||
var curves: MutableList<MoLangCurve> = mutableListOf(),
|
||||
var space: ParticleSpace = ParticleSpace()
|
||||
var space: ParticleSpace = ParticleSpace(),
|
||||
var events: MutableMap<String, ParticleEvent> = mutableMapOf()
|
||||
) {
|
||||
companion object {
|
||||
val CODEC: Codec<BedrockParticleEffect> = RecordCodecBuilder.create { instance ->
|
||||
@@ -36,14 +39,16 @@ class BedrockParticleEffect(
|
||||
BedrockParticleEmitter.CODEC.fieldOf("emitter").forGetter { it.emitter },
|
||||
BedrockParticle.CODEC.fieldOf("particle").forGetter { it.particle },
|
||||
ListCodec(MoLangCurve.codec).fieldOf("curves").forGetter { it.curves },
|
||||
ParticleSpace.CODEC.fieldOf("space").forGetter { it.space }
|
||||
).apply(instance) { id, emitter, particle, curves, space ->
|
||||
ParticleSpace.CODEC.fieldOf("space").forGetter { it.space },
|
||||
UnboundedMapCodec(PrimitiveCodec.STRING, ParticleEvent.CODEC).fieldOf("events").forGetter { it.events }
|
||||
).apply(instance) { id, emitter, particle, curves, space, events ->
|
||||
BedrockParticleEffect(
|
||||
id = id,
|
||||
emitter = emitter,
|
||||
particle = particle,
|
||||
curves = curves.toMutableList(),
|
||||
space = space
|
||||
space = space,
|
||||
events = events
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -55,6 +60,7 @@ class BedrockParticleEffect(
|
||||
particle.writeToBuffer(buffer)
|
||||
buffer.writeCollection(curves) { pb, curve -> MoLangCurve.writeToBuffer(buffer, curve) }
|
||||
space.writeToBuffer(buffer)
|
||||
buffer.writeMap(events, { _, v -> buffer.writeString(v) }) { _, event -> event.encode(buffer) }
|
||||
}
|
||||
|
||||
fun readFromBuffer(buffer: PacketByteBuf) {
|
||||
@@ -63,5 +69,6 @@ class BedrockParticleEffect(
|
||||
particle.readFromBuffer(buffer)
|
||||
curves = buffer.readList { MoLangCurve.readFromBuffer(buffer) }
|
||||
space.readFromBuffer(buffer)
|
||||
events = buffer.readMap({ buffer.readString() }) { ParticleEvent().also { it.decode(buffer) } }
|
||||
}
|
||||
}
|
||||
+29
-4
@@ -29,7 +29,12 @@ class BedrockParticleEmitter(
|
||||
var updateExpressions: MutableList<Expression> = mutableListOf(),
|
||||
var rate: ParticleEmitterRate = InstantParticleEmitterRate(),
|
||||
var shape: ParticleEmitterShape = SphereParticleEmitterShape(),
|
||||
var lifetime: ParticleEmitterLifetime = OnceEmitterLifetime(NumberExpression(1.0))
|
||||
var lifetime: ParticleEmitterLifetime = OnceEmitterLifetime(NumberExpression(1.0)),
|
||||
var eventTimeline: EventTriggerTimeline = EventTriggerTimeline(mutableMapOf()),
|
||||
var creationEvents: MutableList<SimpleEventTrigger> = mutableListOf(),
|
||||
var expirationEvents: MutableList<SimpleEventTrigger> = mutableListOf(),
|
||||
var travelDistanceEvents: EventTriggerTimeline = EventTriggerTimeline(mutableMapOf()),
|
||||
var loopingTravelDistanceEvents: MutableList<LoopingTravelDistanceEventTrigger> = mutableListOf()
|
||||
) {
|
||||
companion object {
|
||||
val CODEC: Codec<BedrockParticleEmitter> = RecordCodecBuilder.create { instance ->
|
||||
@@ -38,14 +43,24 @@ class BedrockParticleEmitter(
|
||||
ListCodec(EXPRESSION_CODEC).fieldOf("updateExpressions").forGetter { it.updateExpressions },
|
||||
ParticleEmitterRate.codec.fieldOf("rate").forGetter { it.rate },
|
||||
ParticleEmitterShape.codec.fieldOf("shape").forGetter { it.shape },
|
||||
ParticleEmitterLifetime.codec.fieldOf("lifetime").forGetter { it.lifetime }
|
||||
).apply(instance) { startExpressions, updateExpressions, rate, shape, lifetime ->
|
||||
ParticleEmitterLifetime.codec.fieldOf("lifetime").forGetter { it.lifetime },
|
||||
EventTriggerTimeline.CODEC.fieldOf("eventTimeline").forGetter { it.eventTimeline },
|
||||
ListCodec(SimpleEventTrigger.CODEC).fieldOf("creationEvents").forGetter { it.creationEvents },
|
||||
ListCodec(SimpleEventTrigger.CODEC).fieldOf("expirationEvents").forGetter { it.expirationEvents },
|
||||
EventTriggerTimeline.CODEC.fieldOf("travelDistanceEvents").forGetter { it.travelDistanceEvents },
|
||||
ListCodec(LoopingTravelDistanceEventTrigger.CODEC).fieldOf("loopingTravelDistanceEvents").forGetter { it.loopingTravelDistanceEvents }
|
||||
).apply(instance) { startExpressions, updateExpressions, rate, shape, lifetime, eventTimeline, creationEvents, expirationEvents, travelDistanceEvents, loopingTravelDistanceEvents ->
|
||||
BedrockParticleEmitter(
|
||||
startExpressions = startExpressions,
|
||||
updateExpressions = updateExpressions,
|
||||
shape = shape,
|
||||
rate = rate,
|
||||
lifetime = lifetime
|
||||
lifetime = lifetime,
|
||||
eventTimeline = eventTimeline,
|
||||
creationEvents = creationEvents,
|
||||
expirationEvents = expirationEvents,
|
||||
travelDistanceEvents = travelDistanceEvents,
|
||||
loopingTravelDistanceEvents = loopingTravelDistanceEvents
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -57,6 +72,11 @@ class BedrockParticleEmitter(
|
||||
ParticleEmitterRate.writeToBuffer(buffer, rate)
|
||||
ParticleEmitterShape.writeToBuffer(buffer, shape)
|
||||
ParticleEmitterLifetime.writeToBuffer(buffer, lifetime)
|
||||
eventTimeline.encode(buffer)
|
||||
buffer.writeCollection(creationEvents) { pb, event -> event.encode(pb) }
|
||||
buffer.writeCollection(expirationEvents) { pb, event -> event.encode(pb) }
|
||||
travelDistanceEvents.encode(buffer)
|
||||
buffer.writeCollection(loopingTravelDistanceEvents) { pb, event -> event.encode(pb) }
|
||||
}
|
||||
|
||||
fun readFromBuffer(buffer: PacketByteBuf) {
|
||||
@@ -65,5 +85,10 @@ class BedrockParticleEmitter(
|
||||
rate = ParticleEmitterRate.readFromBuffer(buffer)
|
||||
shape = ParticleEmitterShape.readFromBuffer(buffer)
|
||||
lifetime = ParticleEmitterLifetime.readFromBuffer(buffer)
|
||||
eventTimeline.decode(buffer)
|
||||
creationEvents = buffer.readList { SimpleEventTrigger("").also { it.decode(buffer) } }
|
||||
expirationEvents = buffer.readList { SimpleEventTrigger("").also { it.decode(buffer) } }
|
||||
travelDistanceEvents.decode(buffer)
|
||||
loopingTravelDistanceEvents = buffer.readList { LoopingTravelDistanceEventTrigger(0.0, mutableListOf()).also { it.decode(buffer) } }
|
||||
}
|
||||
}
|
||||
@@ -123,10 +123,8 @@ class RotateYCameraMode : ParticleCameraMode {
|
||||
viewDirection: Vec3d
|
||||
): Quaternionf {
|
||||
val i = if (angle == 0F) 0F else MathHelper.lerp(deltaTicks, prevAngle, angle)
|
||||
|
||||
val q2 = RotationAxis.POSITIVE_Y.rotationDegrees(/*180 - */cameraYaw)
|
||||
val q2 = RotationAxis.POSITIVE_Y.rotationDegrees(-cameraYaw)
|
||||
q2.hamiltonProduct(RotationAxis.POSITIVE_Z.rotationDegrees(i))
|
||||
|
||||
return q2
|
||||
}
|
||||
|
||||
@@ -191,9 +189,10 @@ class LookAtY : ParticleCameraMode {
|
||||
cameraPitch: Float,
|
||||
viewDirection: Vec3d
|
||||
): Quaternionf {
|
||||
val rotation = Quaternionf(0F, 0F, 0F, 1F)
|
||||
rotation.hamiltonProduct(RotationAxis.POSITIVE_Y.rotationDegrees(-cameraYaw))
|
||||
return rotation
|
||||
val i = if (angle == 0F) 0F else MathHelper.lerp(deltaTicks, prevAngle, angle)
|
||||
val q2 = RotationAxis.POSITIVE_Y.rotationDegrees(-cameraYaw)
|
||||
q2.hamiltonProduct(RotationAxis.POSITIVE_Z.rotationDegrees(i))
|
||||
return q2
|
||||
}
|
||||
|
||||
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
||||
|
||||
+5
@@ -136,6 +136,11 @@ class LoopingEmitterLifetime(var activeTime: Expression = 1.0.asExpression(), va
|
||||
val interval = activeTimeValue + sleepTime
|
||||
val displacement = emitterAge % interval
|
||||
runtime.environment.setSimpleVariable("emitter_lifetime", activeTime)
|
||||
|
||||
if (emitterAge > activeTimeValue && sleepTime == 0.0) {
|
||||
return ParticleEmitterAction.STOP
|
||||
}
|
||||
|
||||
return if (displacement < activeTimeValue) {
|
||||
ParticleEmitterAction.GO
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -145,7 +145,7 @@ class PointParticleEmitterShape(
|
||||
override val type = ParticleEmitterShapeType.POINT
|
||||
override fun getNewParticlePosition(runtime: MoLangRuntime, entity: Entity?) = runtime.resolveVec3d(offset)
|
||||
override fun getCenter(runtime: MoLangRuntime, entity: Entity?): Vec3d {
|
||||
return getNewParticlePosition(runtime, entity) // Questionable
|
||||
return Vec3d.ZERO
|
||||
}
|
||||
|
||||
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.snowstorm
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.net.Decodable
|
||||
import com.cobblemon.mod.common.api.net.Encodable
|
||||
import com.cobblemon.mod.common.client.particle.BedrockParticleEffectRepository
|
||||
import com.cobblemon.mod.common.client.particle.ParticleStorm
|
||||
import com.cobblemon.mod.common.client.render.MatrixWrapper
|
||||
import com.cobblemon.mod.common.client.render.SnowstormParticle
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.PrimitiveCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
import net.minecraft.sound.SoundCategory
|
||||
import net.minecraft.sound.SoundEvent
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.Vec3d
|
||||
|
||||
/**
|
||||
* An event that can be referenced from various particle event triggers. The events are not necessarily particles,
|
||||
* but can be combinations of particles, sounds, and MoLang expressions.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since March 2nd, 2024
|
||||
*/
|
||||
class ParticleEvent(
|
||||
var particleEffect: EventParticleEffect? = null,
|
||||
var soundEffect: EventSoundEffect? = null,
|
||||
var expression: ExpressionLike? = null
|
||||
): Encodable, Decodable {
|
||||
companion object {
|
||||
val CODEC: Codec<ParticleEvent> = RecordCodecBuilder.create { instance ->
|
||||
instance.group(
|
||||
EventParticleEffect.CODEC.optionalFieldOf("particle_effect", null).forGetter { it.particleEffect },
|
||||
EventSoundEffect.CODEC.optionalFieldOf("sound_effect", null).forGetter { it.soundEffect },
|
||||
PrimitiveCodec.STRING.optionalFieldOf("expression", null).forGetter { it.expression?.toString() }
|
||||
).apply(instance) { particleEffect, soundEffect, expression ->
|
||||
ParticleEvent(
|
||||
particleEffect,
|
||||
soundEffect,
|
||||
expression?.asExpressionLike()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun encode(buffer: PacketByteBuf) {
|
||||
buffer.writeNullable(particleEffect) { pb, effect ->
|
||||
pb.writeIdentifier(effect.effect)
|
||||
pb.writeEnumConstant(effect.type)
|
||||
pb.writeNullable(effect.expression) { pb, expr -> pb.writeString(expr.toString()) }
|
||||
}
|
||||
buffer.writeNullable(soundEffect) { pb, effect -> pb.writeIdentifier(effect.sound) }
|
||||
buffer.writeNullable(expression) { pb, expr -> pb.writeString(expr.toString()) }
|
||||
}
|
||||
override fun decode(buffer: PacketByteBuf) {
|
||||
particleEffect = buffer.readNullable { pb -> EventParticleEffect(
|
||||
pb.readIdentifier(),
|
||||
pb.readEnumConstant(EventParticleEffect.EventParticleType::class.java),
|
||||
pb.readNullable { pb.readString().asExpressionLike() }
|
||||
) }
|
||||
soundEffect = buffer.readNullable { pb -> EventSoundEffect(pb.readIdentifier()) }
|
||||
expression = buffer.readNullable { pb -> pb.readString().asExpressionLike() }
|
||||
}
|
||||
|
||||
fun run(storm: ParticleStorm, particle: SnowstormParticle?) {
|
||||
particleEffect?.let { effect ->
|
||||
val bedrockParticleEffect = BedrockParticleEffectRepository.getEffect(effect.effect) ?: return@let
|
||||
val rootMatrix = when (effect.type) {
|
||||
EventParticleEffect.EventParticleType.EMITTER -> MatrixWrapper().updatePosition(storm.matrixWrapper.getOrigin())
|
||||
EventParticleEffect.EventParticleType.EMITTER_BOUND -> storm.matrixWrapper
|
||||
EventParticleEffect.EventParticleType.PARTICLE,
|
||||
EventParticleEffect.EventParticleType.PARTICLE_WITH_VELOCITY -> (particle?.let { Vec3d(it.getX(), it.getY(), it.getZ()) } ?: Vec3d(storm.getX(), storm.getY(), storm.getZ())).let { MatrixWrapper().updatePosition(it) }
|
||||
}
|
||||
|
||||
val sourceVelocity = when (effect.type) {
|
||||
EventParticleEffect.EventParticleType.EMITTER -> storm.sourceVelocity().let { { it } }
|
||||
EventParticleEffect.EventParticleType.EMITTER_BOUND -> storm.sourceVelocity
|
||||
EventParticleEffect.EventParticleType.PARTICLE -> { { Vec3d.ZERO } }
|
||||
EventParticleEffect.EventParticleType.PARTICLE_WITH_VELOCITY -> (particle?.let { Vec3d(it.getVelocityX(), it.getVelocityY(), it.getVelocityZ()) } ?: Vec3d.ZERO).let { { it } }
|
||||
}
|
||||
|
||||
val newStorm = ParticleStorm(
|
||||
effect = bedrockParticleEffect,
|
||||
matrixWrapper = rootMatrix,
|
||||
world = storm.world,
|
||||
sourceVelocity = sourceVelocity,
|
||||
sourceAlive = storm.sourceAlive,
|
||||
sourceVisible = storm.sourceVisible,
|
||||
onDespawn = {},
|
||||
runtime = MoLangRuntime().setup().also { it.environment.structs["query"] = storm.runtime.environment.getQueryStruct() },
|
||||
entity = storm.entity
|
||||
)
|
||||
|
||||
effect.expression?.resolve(newStorm.runtime)
|
||||
|
||||
newStorm.spawn()
|
||||
}
|
||||
soundEffect?.let { effect ->
|
||||
val position = particle?.let { Vec3d(it.getX(), it.getY(), it.getZ()) } ?: Vec3d(storm.getX(), storm.getY(), storm.getZ())
|
||||
val world = storm.world
|
||||
val soundEvent = SoundEvent.of(effect.sound)
|
||||
world.playSound(position.x, position.y, position.z, soundEvent, SoundCategory.NEUTRAL, 1F, 1F, true)
|
||||
}
|
||||
expression?.resolve(storm.runtime)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A particle component of a [ParticleEvent]. It contains the effect to play, the spawning type, and a pre-run
|
||||
* expression to run in the new storm's runtime.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since March 2nd, 2024
|
||||
*/
|
||||
class EventParticleEffect(
|
||||
val effect: Identifier,
|
||||
val type: EventParticleType,
|
||||
val expression: ExpressionLike? = null
|
||||
) {
|
||||
companion object {
|
||||
val CODEC = RecordCodecBuilder.create<EventParticleEffect> { instance ->
|
||||
instance.group(
|
||||
Identifier.CODEC.fieldOf("effect").forGetter { it.effect },
|
||||
PrimitiveCodec.STRING.fieldOf("type").forGetter { it.type.name },
|
||||
PrimitiveCodec.STRING.optionalFieldOf("expression", null).forGetter { it.expression?.toString() }
|
||||
).apply(instance) { effect, type, expression ->
|
||||
EventParticleEffect(
|
||||
effect,
|
||||
EventParticleType.valueOf(type),
|
||||
expression?.asExpressionLike()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class EventParticleType {
|
||||
EMITTER,
|
||||
EMITTER_BOUND,
|
||||
PARTICLE,
|
||||
PARTICLE_WITH_VELOCITY
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple sound effect component of a [ParticleEvent]. Plays a sound at the particle location, or if run from an
|
||||
* emitter event, at the emitter's location.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since March 2nd, 2024
|
||||
*/
|
||||
class EventSoundEffect(
|
||||
val sound: Identifier,
|
||||
) {
|
||||
companion object {
|
||||
val CODEC = RecordCodecBuilder.create<EventSoundEffect> { instance ->
|
||||
instance.group(
|
||||
Identifier.CODEC.fieldOf("sound").forGetter { it.sound }
|
||||
).apply(instance, ::EventSoundEffect)
|
||||
}
|
||||
}
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.snowstorm
|
||||
|
||||
import com.cobblemon.mod.common.api.net.Decodable
|
||||
import com.cobblemon.mod.common.api.net.Encodable
|
||||
import com.cobblemon.mod.common.client.particle.ParticleStorm
|
||||
import com.cobblemon.mod.common.client.render.SnowstormParticle
|
||||
import com.mojang.serialization.codecs.PrimitiveCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import com.mojang.serialization.codecs.UnboundedMapCodec
|
||||
import net.minecraft.network.PacketByteBuf
|
||||
|
||||
/*
|
||||
* The different references to events that can be triggered by an effect.
|
||||
*/
|
||||
|
||||
/**
|
||||
* It really is simple.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since March 2nd, 2024
|
||||
*/
|
||||
class SimpleEventTrigger(var event: String): Encodable, Decodable {
|
||||
companion object {
|
||||
val CODEC = RecordCodecBuilder.create<SimpleEventTrigger> { instance ->
|
||||
instance.group(
|
||||
PrimitiveCodec.STRING.fieldOf("event").forGetter { it.event }
|
||||
).apply(instance, ::SimpleEventTrigger)
|
||||
}
|
||||
}
|
||||
|
||||
override fun encode(buffer: PacketByteBuf) {
|
||||
buffer.writeString(event)
|
||||
}
|
||||
|
||||
override fun decode(buffer: PacketByteBuf) {
|
||||
event = buffer.readString()
|
||||
}
|
||||
|
||||
fun trigger(storm: ParticleStorm, particle: SnowstormParticle?) {
|
||||
val event = storm.effect.events[event] ?: return
|
||||
event.run(storm, particle)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An event trigger that outlines specific times at which point groups of effects will play. This can be used
|
||||
* on the basis of time but is also used in the case of travel distance.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since March 2nd, 2024
|
||||
*/
|
||||
class EventTriggerTimeline(var map: MutableMap<Double, MutableList<String>>): Encodable, Decodable {
|
||||
companion object {
|
||||
val CODEC = RecordCodecBuilder.create<EventTriggerTimeline> { instance ->
|
||||
instance.group(
|
||||
UnboundedMapCodec(PrimitiveCodec.DOUBLE, PrimitiveCodec.STRING.listOf()).fieldOf("map").forGetter { it.map }
|
||||
).apply(instance, ::EventTriggerTimeline)
|
||||
}
|
||||
}
|
||||
|
||||
override fun encode(buffer: PacketByteBuf) {
|
||||
buffer.writeMap(map, { pb, k -> pb.writeDouble(k) }, { pb, v -> pb.writeCollection(v) { _, s -> pb.writeString(s) } })
|
||||
}
|
||||
|
||||
override fun decode(buffer: PacketByteBuf) {
|
||||
map = buffer.readMap({ pb -> pb.readDouble() }, { pb -> pb.readList { pb.readString() } })
|
||||
}
|
||||
|
||||
fun check(storm: ParticleStorm, particle: SnowstormParticle?, previousTime: Double, newTime: Double) {
|
||||
val events = map.entries.filter { it.key in previousTime..newTime }.flatMap { it.value }
|
||||
events.forEach { event ->
|
||||
val event = storm.effect.events[event] ?: return
|
||||
event.run(storm, particle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An event trigger that takes the total distance travelled by the emitter and modulos it across [distance] to know
|
||||
* if we need to play it again.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since March 2nd, 2024
|
||||
*/
|
||||
class LoopingTravelDistanceEventTrigger(var distance: Double, var events: MutableList<String>): Encodable, Decodable {
|
||||
companion object {
|
||||
val CODEC = RecordCodecBuilder.create<LoopingTravelDistanceEventTrigger> { instance ->
|
||||
instance.group(
|
||||
PrimitiveCodec.DOUBLE.fieldOf("distance").forGetter { it.distance },
|
||||
PrimitiveCodec.STRING.listOf().fieldOf("events").forGetter { it.events }
|
||||
).apply(instance, ::LoopingTravelDistanceEventTrigger)
|
||||
}
|
||||
}
|
||||
|
||||
override fun encode(buffer: PacketByteBuf) {
|
||||
buffer.writeDouble(distance)
|
||||
buffer.writeCollection(events) { _, s -> buffer.writeString(s) }
|
||||
}
|
||||
|
||||
override fun decode(buffer: PacketByteBuf) {
|
||||
distance = buffer.readDouble()
|
||||
events = buffer.readList { buffer.readString() }
|
||||
}
|
||||
|
||||
fun check(storm: ParticleStorm, particle: SnowstormParticle?, previousDistance: Double, currentDistance: Double) {
|
||||
if (previousDistance < distance && currentDistance >= distance) {
|
||||
events.mapNotNull { storm.effect.events[it] }.forEach { it.run(storm, particle) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -140,7 +140,7 @@ class InwardsMotionDirection : ParticleMotionDirection {
|
||||
return if (particlePos == emitterPos) {
|
||||
Vec3d(storm.world.random.nextDouble() - 0.5, storm.world.random.nextDouble() - 0.5, storm.world.random.nextDouble() - 0.5)
|
||||
} else {
|
||||
particlePos.subtract(emitterPos)
|
||||
emitterPos.subtract(particlePos)
|
||||
}.normalize()
|
||||
}
|
||||
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
||||
|
||||
@@ -65,7 +65,7 @@ class DynamicParticleRotation(
|
||||
override val type = ParticleRotationType.DYNAMIC
|
||||
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
||||
override fun getInitialRotation(runtime: MoLangRuntime) = runtime.resolveDouble(startRotation)
|
||||
override fun getInitialAngularVelocity(runtime: MoLangRuntime) = runtime.resolveDouble(speed)
|
||||
override fun getInitialAngularVelocity(runtime: MoLangRuntime) = runtime.resolveDouble(speed) / 20
|
||||
override fun getAngularAcceleration(runtime: MoLangRuntime, angularVelocity: Double): Double {
|
||||
val acceleration = runtime.resolveDouble(acceleration)
|
||||
val nextVelocity = angularVelocity + acceleration
|
||||
|
||||
+3
-1
@@ -12,6 +12,8 @@ import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawnerFactory
|
||||
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
|
||||
import java.util.UUID
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
|
||||
@@ -34,7 +36,7 @@ object CobblemonWorldSpawnerManager : SpawnerManager() {
|
||||
|
||||
fun onPlayerLogin(player: ServerPlayerEntity) {
|
||||
// Disables spawning
|
||||
if (!Cobblemon.config.enableSpawning) {
|
||||
if (!Cobblemon.config.enableSpawning || server()?.gameRules?.getBoolean(CobblemonGameRules.DO_POKEMON_SPAWNING) == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.TickingSpawner
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules.DO_POKEMON_SPAWNING
|
||||
|
||||
/**
|
||||
* A manager of various spawners. This is a class in which you should register
|
||||
@@ -49,7 +51,7 @@ open class SpawnerManager {
|
||||
|
||||
open fun onServerTick() {
|
||||
// Disables spawning
|
||||
if (!Cobblemon.config.enableSpawning) {
|
||||
if (!Cobblemon.config.enableSpawning || server()?.gameRules?.getBoolean(DO_POKEMON_SPAWNING) == false) {
|
||||
return
|
||||
}
|
||||
influences.removeIf { it.isExpired() }
|
||||
|
||||
+10
-3
@@ -30,9 +30,16 @@ abstract class SingleEntitySpawnAction<T : Entity>(
|
||||
override fun run(): EntitySpawnResult? {
|
||||
val e = createEntity() ?: return null
|
||||
e.setPosition(ctx.position.toVec3d().add(0.5, 1.0, 0.5))
|
||||
entity.emit(e)
|
||||
CobblemonEvents.ENTITY_SPAWN.postThen(SpawnEvent(e, ctx), ifSucceeded = { ctx.world.spawnEntity(e) })
|
||||
return EntitySpawnResult(listOf(e))
|
||||
var shouldSpawn = false
|
||||
CobblemonEvents.ENTITY_SPAWN.postThen(SpawnEvent(e, ctx), ifSucceeded = {
|
||||
ctx.world.spawnEntity(e)
|
||||
shouldSpawn = true
|
||||
})
|
||||
|
||||
return if (shouldSpawn) {
|
||||
this.entity.emit(e)
|
||||
EntitySpawnResult(listOf(e))
|
||||
} else null
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -63,9 +63,6 @@ abstract class AreaSpawner(
|
||||
|
||||
override fun run(cause: SpawnCause): Pair<SpawningContext, SpawnDetail>? {
|
||||
val area = getArea(cause)
|
||||
if (area?.world?.gameRules?.getBoolean(DO_POKEMON_SPAWNING) == false) {
|
||||
return null
|
||||
}
|
||||
val constrainedArea = if (area != null) constrainArea(area) else null
|
||||
if (constrainedArea != null) {
|
||||
|
||||
|
||||
+5
-3
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.storage.adapter.conversions
|
||||
|
||||
import com.cobblemon.mod.common.api.abilities.Abilities
|
||||
import com.cobblemon.mod.common.api.moves.Moves
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.api.pokemon.Natures
|
||||
@@ -45,7 +46,7 @@ class ReforgedConversion(val base: Path) : CobblemonConverter<NbtCompound> {
|
||||
return null
|
||||
}
|
||||
|
||||
val nbt = NbtIo.read(target.toFile())
|
||||
val nbt = NbtIo.read(target)
|
||||
if(nbt != null) {
|
||||
return (if (extension == "pk") party(uuid, nbt) else pc(uuid, nbt)) as T
|
||||
}
|
||||
@@ -98,8 +99,9 @@ class ReforgedConversion(val base: Path) : CobblemonConverter<NbtCompound> {
|
||||
result.level = nbt.getInt("Level")
|
||||
result.addExperience(SidemodExperienceSource("Reforged"), nbt.getInt("EXP"))
|
||||
result.setFriendship(nbt.getInt("Friendship"))
|
||||
result.ability = (result.form.abilities.find { it.template.name == nbt.getString("Ability") } ?: result.form.abilities.first())
|
||||
.template.create()
|
||||
Abilities.get(nbt.getString("Ability"))?.let { template ->
|
||||
result.updateAbility(template.create(forced = result.form.abilities.none { it.template == template }))
|
||||
}
|
||||
result.nature = Natures.getNature(Identifier(ReforgedNatures.values()[nbt.getInt("Nature")].name.lowercase())) ?: Natures.getRandomNature()
|
||||
result.mintedNature = Natures.getNature(Identifier(ReforgedNatures.values()[nbt.getInt("MintNature")].name.lowercase()))
|
||||
result.currentHealth = nbt.getInt("Health")
|
||||
|
||||
+3
-2
@@ -14,6 +14,7 @@ import java.io.File
|
||||
import java.util.UUID
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.nbt.NbtIo
|
||||
import net.minecraft.nbt.NbtSizeTracker
|
||||
|
||||
/**
|
||||
* A [OneToOneFileStoreAdapter] that can arbitrarily save a single [PokemonStore] into an [NbtCompound] with the
|
||||
@@ -29,7 +30,7 @@ open class NBTStoreAdapter(
|
||||
folderPerClass: Boolean,
|
||||
) : OneToOneFileStoreAdapter<NbtCompound>(rootFolder, useNestedFolders, folderPerClass, "dat") {
|
||||
override fun <E : StorePosition, T : PokemonStore<E>> serialize(store: T) = store.saveToNBT(NbtCompound())
|
||||
override fun save(file: File, serialized: NbtCompound) = NbtIo.writeCompressed(serialized, file)
|
||||
override fun save(file: File, serialized: NbtCompound) = NbtIo.writeCompressed(serialized, file.toPath())
|
||||
override fun <E, T : PokemonStore<E>> load(file: File, storeClass: Class<out T>, uuid: UUID): T? {
|
||||
val store = try {
|
||||
storeClass.getConstructor(UUID::class.java).newInstance(uuid)
|
||||
@@ -37,7 +38,7 @@ open class NBTStoreAdapter(
|
||||
storeClass.getConstructor(UUID::class.java).newInstance(uuid)
|
||||
}
|
||||
return try {
|
||||
val nbt = NbtIo.readCompressed(file)
|
||||
val nbt = NbtIo.readCompressed(file.toPath(), NbtSizeTracker.ofUnlimitedBytes())
|
||||
store.loadFromNBT(nbt)
|
||||
store
|
||||
} catch (e: Exception) {
|
||||
|
||||
+5
-4
@@ -16,6 +16,7 @@ import java.nio.file.Path
|
||||
import java.util.UUID
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.nbt.NbtIo
|
||||
import net.minecraft.nbt.NbtSizeTracker
|
||||
import net.minecraft.util.WorldSavePath
|
||||
|
||||
object NbtMoLangDataStoreFactory : MoLangDataStoreFactory {
|
||||
@@ -61,13 +62,13 @@ object NbtMoLangDataStoreFactory : MoLangDataStoreFactory {
|
||||
cache[uuid]!!
|
||||
else {
|
||||
val file = this.file(uuid)
|
||||
if (!file.exists()) {
|
||||
if (!file.toFile().exists()) {
|
||||
val data = VariableStruct()
|
||||
cache[uuid] = data
|
||||
return data
|
||||
}
|
||||
|
||||
val nbt = NbtIo.readCompressed(file(uuid))
|
||||
val nbt = NbtIo.readCompressed(file(uuid), NbtSizeTracker.ofUnlimitedBytes())
|
||||
|
||||
// If it's not a VariableStruct then someone's fucked around and will subsequently find out
|
||||
val data = readMoValueFromNBT(nbt) as VariableStruct
|
||||
@@ -80,10 +81,10 @@ object NbtMoLangDataStoreFactory : MoLangDataStoreFactory {
|
||||
val file = file(uuid)
|
||||
val data = cache[uuid] ?: return
|
||||
val nbt = writeMoValueToNBT(data)!! as NbtCompound
|
||||
file.parentFile.mkdirs()
|
||||
file.toFile().parentFile.mkdirs()
|
||||
NbtIo.writeCompressed(nbt, file)
|
||||
dirty -= uuid
|
||||
}
|
||||
|
||||
private fun file(uuid: UUID) = savePath.resolve("playermolangdata/${uuid.toString().substring(0, 2)}/$uuid.dat").toFile()
|
||||
private fun file(uuid: UUID) = savePath.resolve("playermolangdata/${uuid.toString().substring(0, 2)}/$uuid.dat")
|
||||
}
|
||||
@@ -260,7 +260,7 @@ open class PartyStore(override val uuid: UUID) : PokemonStore<PartyPosition>() {
|
||||
return@mapNotNull if (clone) {
|
||||
BattlePokemon.safeCopyOf(it)
|
||||
} else {
|
||||
BattlePokemon(it)
|
||||
BattlePokemon.playerOwned(it)
|
||||
}
|
||||
}.sortedBy { if (it.uuid == leadingPokemon) 0 else (indexOf(it.originalPokemon) + 1) }
|
||||
|
||||
|
||||
+5
-6
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.api.storage.party
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.advancement.CobblemonCriteria
|
||||
import com.cobblemon.mod.common.advancement.criterion.PartyCheckContext
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.PassiveEvolution
|
||||
import com.cobblemon.mod.common.api.storage.pc.PCStore
|
||||
@@ -63,7 +62,7 @@ open class PlayerPartyStore(
|
||||
pokemon.refreshOriginalTrainer()
|
||||
|
||||
return if (super.add(pokemon)) {
|
||||
pokemon.getOwnerPlayer()?.let { CobblemonCriteria.PARTY_CHECK.trigger(it, PartyCheckContext(this)) }
|
||||
pokemon.getOwnerPlayer()?.let { CobblemonCriteria.PARTY_CHECK.trigger(it, this) }
|
||||
true
|
||||
} else {
|
||||
val player = playerUUID.getPlayer()
|
||||
@@ -179,21 +178,21 @@ open class PlayerPartyStore(
|
||||
if (pokemon1 != null && pokemon2 != null) {
|
||||
val player = pokemon1.getOwnerPlayer()
|
||||
if (player != null) {
|
||||
CobblemonCriteria.PARTY_CHECK.trigger(player, PartyCheckContext(this))
|
||||
CobblemonCriteria.PARTY_CHECK.trigger(player, this)
|
||||
}
|
||||
} else if (pokemon1 != null || pokemon2 != null) {
|
||||
var player = pokemon1?.getOwnerPlayer()
|
||||
if (player != null) {
|
||||
CobblemonCriteria.PARTY_CHECK.trigger(player, PartyCheckContext(this))
|
||||
CobblemonCriteria.PARTY_CHECK.trigger(player, this)
|
||||
} else {
|
||||
player = pokemon2!!.getOwnerPlayer()
|
||||
CobblemonCriteria.PARTY_CHECK.trigger(player!!, PartyCheckContext(this))
|
||||
CobblemonCriteria.PARTY_CHECK.trigger(player!!, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun set(position: PartyPosition, pokemon: Pokemon) {
|
||||
super.set(position, pokemon)
|
||||
pokemon.getOwnerPlayer()?.let { CobblemonCriteria.PARTY_CHECK.trigger(it, PartyCheckContext(this)) }
|
||||
pokemon.getOwnerPlayer()?.let { CobblemonCriteria.PARTY_CHECK.trigger(it, this) }
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -8,7 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.storage.player
|
||||
|
||||
import com.cobblemon.mod.common.advancement.criterion.AspectCriterionCondition
|
||||
import com.cobblemon.mod.common.advancement.criterion.AspectCriterion
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
@@ -103,9 +103,9 @@ class PlayerAdvancementData {
|
||||
|
||||
fun updateAspectsCollected(player: ServerPlayerEntity, pokemon: Pokemon) {
|
||||
val aspectConditions = player.advancementTracker.progress.keys
|
||||
.flatMap { it.criteria.values }
|
||||
.flatMap { it.value.criteria.values }
|
||||
.mapNotNull { it.conditions }
|
||||
.filterIsInstance<AspectCriterionCondition>()
|
||||
.filterIsInstance<AspectCriterion>()
|
||||
|
||||
val trackedAspects = aspectConditions
|
||||
.filter { it.pokemon == pokemon.species.resourceIdentifier }
|
||||
|
||||
@@ -22,107 +22,15 @@ import net.minecraft.registry.tag.TagKey
|
||||
object CobblemonBiomeTags {
|
||||
|
||||
@JvmField
|
||||
val IS_DEEP_DARK = create("is_deep_dark")
|
||||
val IS_AUTUMN = create("has_season/autumn")
|
||||
@JvmField
|
||||
val IS_ARID = create("is_arid")
|
||||
val IS_SPRING = create("has_season/spring")
|
||||
@JvmField
|
||||
val IS_AUTUMN = create("is_autumn")
|
||||
@JvmField
|
||||
val IS_BADLANDS = create("is_badlands")
|
||||
@JvmField
|
||||
val IS_BAMBOO = create("is_bamboo")
|
||||
@JvmField
|
||||
val IS_CAVE = create("is_cave")
|
||||
@JvmField
|
||||
val IS_COAST = create("is_coast")
|
||||
@JvmField
|
||||
val IS_COLD = create("is_cold")
|
||||
@JvmField
|
||||
val IS_DEEP_OCEAN = create("is_deep_ocean")
|
||||
@JvmField
|
||||
val IS_DESERT = create("is_desert")
|
||||
@JvmField
|
||||
val IS_DRIPSTONE = create("is_dripstone")
|
||||
@JvmField
|
||||
val IS_FLORAL = create("is_floral")
|
||||
@JvmField
|
||||
val IS_FOREST = create("is_forest")
|
||||
@JvmField
|
||||
val IS_FREEZING = create("is_freezing")
|
||||
@JvmField
|
||||
val IS_FRESHWATER = create("is_freshwater")
|
||||
@JvmField
|
||||
val IS_COLD_OCEAN = create("is_cold_ocean")
|
||||
@JvmField
|
||||
val IS_FROZEN_OCEAN = create("is_frozen_ocean")
|
||||
@JvmField
|
||||
val IS_GLACIAL = create("is_glacial")
|
||||
@JvmField
|
||||
val IS_GRASSLAND = create("is_grassland")
|
||||
@JvmField
|
||||
val IS_HIGHLANDS = create("is_highlands")
|
||||
@JvmField
|
||||
val IS_HILLS = create("is_hills")
|
||||
@JvmField
|
||||
val IS_ISLAND = create("is_island")
|
||||
@JvmField
|
||||
val IS_JUNGLE = create("is_jungle")
|
||||
@JvmField
|
||||
val IS_LUKEWARM_OCEAN = create("is_lukewarm_ocean")
|
||||
@JvmField
|
||||
val IS_LUSH = create("is_lush")
|
||||
@JvmField
|
||||
val IS_MAGICAL = create("is_magical")
|
||||
@JvmField
|
||||
val IS_MOUNTAIN = create("is_mountain")
|
||||
@JvmField
|
||||
val IS_MUSHROOM = create("is_mushroom")
|
||||
@JvmField
|
||||
val IS_OVERWORLD = create("is_overworld")
|
||||
@JvmField
|
||||
val IS_PEAK = create("is_peak")
|
||||
@JvmField
|
||||
val IS_PLAINS = create("is_plains")
|
||||
@JvmField
|
||||
val IS_PLATEAU = create("is_plateau")
|
||||
@JvmField
|
||||
val IS_WARM_OCEAN = create("is_warm_ocean")
|
||||
@JvmField
|
||||
val IS_RIVER = create("is_river")
|
||||
@JvmField
|
||||
val IS_SANDY = create("is_sandy")
|
||||
@JvmField
|
||||
val IS_SAVANNA = create("is_savanna")
|
||||
@JvmField
|
||||
val IS_SKY = create("is_sky")
|
||||
@JvmField
|
||||
val IS_SNOWY_FOREST = create("is_snowy_forest")
|
||||
@JvmField
|
||||
val IS_SPOOKY = create("is_spooky")
|
||||
@JvmField
|
||||
val IS_SPRING = create("is_spring")
|
||||
@JvmField
|
||||
val IS_SUMMER = create("is_summer")
|
||||
@JvmField
|
||||
val IS_SWAMP = create("is_swamp")
|
||||
@JvmField
|
||||
val IS_TAIGA = create("is_taiga")
|
||||
val IS_SUMMER = create("has_season/summer")
|
||||
@JvmField
|
||||
val IS_TEMPERATE = create("is_temperate")
|
||||
@JvmField
|
||||
val IS_THERMAL = create("is_thermal")
|
||||
@JvmField
|
||||
val IS_TUNDRA = create("is_tundra")
|
||||
@JvmField
|
||||
val IS_VOID = create("is_void")
|
||||
@JvmField
|
||||
val IS_VOlCANIC = create("is_volcanic")
|
||||
@JvmField
|
||||
val IS_WINTER = create("is_winter")
|
||||
@JvmField
|
||||
val IS_SPARSE = create("is_sparse")
|
||||
@JvmField
|
||||
val IS_DENSE = create("is_dense")
|
||||
val IS_WINTER = create("has_season/winter")
|
||||
|
||||
// Has Feature tags
|
||||
@JvmField
|
||||
@@ -180,16 +88,5 @@ object CobblemonBiomeTags {
|
||||
@JvmField
|
||||
val HAS_WATER_STONE_ORE_RARE = create("has_ore/ore_water_stone_rare")
|
||||
|
||||
// ToDo remove in 1.3
|
||||
@Deprecated(message = "This tag no longer exists", level = DeprecationLevel.ERROR)
|
||||
@JvmField
|
||||
val IS_CRAG = create("is_crag")
|
||||
@Deprecated(message = "This tag no longer exists", level = DeprecationLevel.ERROR)
|
||||
@JvmField
|
||||
val IS_ICY = create("is_icy")
|
||||
@Deprecated(message = "This tag no longer exists", replaceWith = ReplaceWith("com.cobblemon.mod.common.api.tags.CobblemonBiomeTags.IS_CAVE"), level = DeprecationLevel.ERROR)
|
||||
@JvmField
|
||||
val IS_UNDERGROUND = create("is_underground")
|
||||
|
||||
private fun create(path: String) = TagKey.of(RegistryKeys.BIOME, cobblemonResource(path))
|
||||
}
|
||||
@@ -144,6 +144,12 @@ object CobblemonItemTags {
|
||||
@JvmField
|
||||
val POTTERY_SHERDS = create("decorated_pot_sherds")
|
||||
|
||||
@JvmField
|
||||
val ABILITY_CHANGERS = create("ability_changers")
|
||||
|
||||
@JvmField
|
||||
val IS_FRIENDSHIP_BOOSTER = create("is_friendship_booster")
|
||||
|
||||
private fun create(path: String) = TagKey.of(RegistryKeys.ITEM, cobblemonResource(path))
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.types.tera
|
||||
|
||||
import com.cobblemon.mod.common.api.data.ShowdownIdentifiable
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* The representation of the Pokémons Tera type.
|
||||
*
|
||||
* @see [Bulbapedia](https://bulbapedia.bulbagarden.net/wiki/Terastal_phenomenon)
|
||||
*
|
||||
*/
|
||||
interface TeraType : ShowdownIdentifiable {
|
||||
|
||||
/**
|
||||
* The [Identifier] associated to this type.
|
||||
*/
|
||||
val id: Identifier
|
||||
|
||||
/**
|
||||
* If this tera type can be selected naturally.
|
||||
*/
|
||||
val legalAsStatic: Boolean
|
||||
|
||||
/**
|
||||
* The display name of this type.
|
||||
*/
|
||||
val displayName: Text
|
||||
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.types.tera
|
||||
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.api.types.tera.elemental.ElementalTypeTeraType
|
||||
import com.cobblemon.mod.common.api.types.tera.gimmick.StellarTeraType
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* The registry of all [TeraType]s.
|
||||
*/
|
||||
@Suppress("unused")
|
||||
object TeraTypes {
|
||||
private val types = hashMapOf<Identifier, TeraType>()
|
||||
|
||||
@JvmStatic
|
||||
val NORMAL = this.create(cobblemonResource("normal"), ElementalTypeTeraType(ElementalTypes.NORMAL))
|
||||
|
||||
@JvmStatic
|
||||
val FIRE = this.create(cobblemonResource("fire"), ElementalTypeTeraType(ElementalTypes.FIRE))
|
||||
|
||||
@JvmStatic
|
||||
val WATER = this.create(cobblemonResource("water"), ElementalTypeTeraType(ElementalTypes.WATER))
|
||||
|
||||
@JvmStatic
|
||||
val GRASS = this.create(cobblemonResource("grass"), ElementalTypeTeraType(ElementalTypes.GRASS))
|
||||
|
||||
@JvmStatic
|
||||
val ELECTRIC = this.create(cobblemonResource("electric"), ElementalTypeTeraType(ElementalTypes.ELECTRIC))
|
||||
|
||||
@JvmStatic
|
||||
val ICE = this.create(cobblemonResource("ice"), ElementalTypeTeraType(ElementalTypes.ICE))
|
||||
|
||||
@JvmStatic
|
||||
val FIGHTING = this.create(cobblemonResource("fighting"), ElementalTypeTeraType(ElementalTypes.FIGHTING))
|
||||
|
||||
@JvmStatic
|
||||
val POISON = this.create(cobblemonResource("poison"), ElementalTypeTeraType(ElementalTypes.POISON))
|
||||
|
||||
@JvmStatic
|
||||
val GROUND = this.create(cobblemonResource("ground"), ElementalTypeTeraType(ElementalTypes.GROUND))
|
||||
|
||||
@JvmStatic
|
||||
val FLYING = this.create(cobblemonResource("flying"), ElementalTypeTeraType(ElementalTypes.FLYING))
|
||||
|
||||
@JvmStatic
|
||||
val PSYCHIC = this.create(cobblemonResource("psychic"), ElementalTypeTeraType(ElementalTypes.PSYCHIC))
|
||||
|
||||
@JvmStatic
|
||||
val BUG = this.create(cobblemonResource("bug"), ElementalTypeTeraType(ElementalTypes.BUG))
|
||||
|
||||
@JvmStatic
|
||||
val ROCK = this.create(cobblemonResource("rock"), ElementalTypeTeraType(ElementalTypes.ROCK))
|
||||
|
||||
@JvmStatic
|
||||
val GHOST = this.create(cobblemonResource("ghost"), ElementalTypeTeraType(ElementalTypes.GHOST))
|
||||
|
||||
@JvmStatic
|
||||
val DRAGON = this.create(cobblemonResource("dragon"), ElementalTypeTeraType(ElementalTypes.DRAGON))
|
||||
|
||||
@JvmStatic
|
||||
val DARK = this.create(cobblemonResource("dark"), ElementalTypeTeraType(ElementalTypes.DARK))
|
||||
|
||||
@JvmStatic
|
||||
val STEEL = this.create(cobblemonResource("steel"), ElementalTypeTeraType(ElementalTypes.STEEL))
|
||||
|
||||
@JvmStatic
|
||||
val FAIRY = this.create(cobblemonResource("fairy"), ElementalTypeTeraType(ElementalTypes.FAIRY))
|
||||
|
||||
@JvmStatic
|
||||
val STELLAR = this.create(StellarTeraType.ID, StellarTeraType())
|
||||
|
||||
/**
|
||||
* Pick a random [TeraType].
|
||||
*
|
||||
* @param legalOnly If [TeraType.legalAsStatic] should be respected.
|
||||
* @return The selected [TeraType].
|
||||
*/
|
||||
@JvmStatic
|
||||
fun random(legalOnly: Boolean): TeraType {
|
||||
val possible = this.types.values
|
||||
if (legalOnly) {
|
||||
return possible.filter(TeraType::legalAsStatic).random()
|
||||
}
|
||||
return possible.random()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a [TeraType] by its [id].
|
||||
*
|
||||
* @param id The [Identifier] expected to match against a [TeraType.id].
|
||||
* @return The found [TeraType] or null.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun get(id: Identifier): TeraType? = this.types[id]
|
||||
|
||||
/**
|
||||
* Gets a [TeraType] by its [id].
|
||||
*
|
||||
* @param id The string representation of a [Identifier] if no namespace is present assumes Cobblemon' instead of Minecraft'.
|
||||
* @return The found [TeraType] or null.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun get(id: String): TeraType? = this.get(cobblemonResource(id))
|
||||
|
||||
/**
|
||||
* Gets the corresponding tera type for a [ElementalType].
|
||||
*
|
||||
* @param type The [ElementalType] being checked.
|
||||
* @return The associated [TeraType].
|
||||
*/
|
||||
@JvmStatic
|
||||
fun forElementalType(type: ElementalType): TeraType = this.get(cobblemonResource(type.name))!! // it's safe to do
|
||||
|
||||
private fun create(id: Identifier, type: TeraType): TeraType {
|
||||
this.types[id] = type
|
||||
return type
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.types.tera.elemental
|
||||
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.api.types.tera.TeraType
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
class ElementalTypeTeraType(val type: ElementalType) : TeraType {
|
||||
override val legalAsStatic: Boolean = true
|
||||
|
||||
override val id: Identifier = cobblemonResource(this.type.name)
|
||||
|
||||
override val displayName: Text = this.type.displayName
|
||||
|
||||
override fun showdownId(): String = this.type.name
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.types.tera.gimmick
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.types.tera.TeraType
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
class StellarTeraType : TeraType {
|
||||
override val id: Identifier = ID
|
||||
|
||||
override val legalAsStatic: Boolean = false
|
||||
|
||||
override val displayName: Text = LANG
|
||||
|
||||
override fun showdownId(): String = ID.path
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("stellar")
|
||||
private val LANG = Text.translatable("${Cobblemon.MODID}.terra_type.stellar")
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,8 @@ class ActiveBattlePokemon(val actor: BattleActor, var battlePokemon: BattlePokem
|
||||
fun getSide() = actor.getSide()
|
||||
var position: Pair<ServerWorld, Vec3d>? = null
|
||||
|
||||
var illusion: BattlePokemon? = null
|
||||
|
||||
override fun getAllActivePokemon() = battle.activePokemon
|
||||
override fun getActorShowdownId() = actor.showdownId
|
||||
override fun getActorPokemon() = actor.activePokemon
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
package com.cobblemon.mod.common.battles
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.api.storage.party.PartyStore
|
||||
@@ -18,15 +17,15 @@ import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.effectiveName
|
||||
import com.cobblemon.mod.common.util.getBattleTheme
|
||||
import com.cobblemon.mod.common.util.getPlayer
|
||||
import com.cobblemon.mod.common.util.party
|
||||
import java.util.Optional
|
||||
import java.util.UUID
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.text.MutableText
|
||||
import net.minecraft.text.Text
|
||||
import java.util.UUID
|
||||
|
||||
object BattleBuilder {
|
||||
@JvmOverloads
|
||||
@@ -100,11 +99,19 @@ object BattleBuilder {
|
||||
fleeDistance: Float = Cobblemon.config.defaultFleeDistance,
|
||||
party: PartyStore = player.party()
|
||||
): BattleStartResult {
|
||||
val playerTeam = party.toBattleTeam(clone = cloneParties, checkHealth = !healFirst, leadingPokemon = leadingPokemon)
|
||||
val playerTeam = party.toBattleTeam(clone = cloneParties, checkHealth = !healFirst, leadingPokemon = leadingPokemon).sortedBy { it.health <= 0 }
|
||||
val playerActor = PlayerBattleActor(player.uuid, playerTeam)
|
||||
val wildActor = PokemonBattleActor(pokemonEntity.pokemon.uuid, BattlePokemon(pokemonEntity.pokemon), fleeDistance)
|
||||
val errors = ErroredBattleStart()
|
||||
|
||||
if(playerTeam.isNotEmpty() && playerTeam[0].health <= 0){
|
||||
errors.participantErrors[playerActor] += BattleStartError.insufficientPokemon(
|
||||
player = player,
|
||||
requiredCount = battleFormat.battleType.slotsPerActor,
|
||||
hadCount = playerActor.pokemonList.size
|
||||
)
|
||||
}
|
||||
|
||||
if (playerActor.pokemonList.size < battleFormat.battleType.slotsPerActor) {
|
||||
errors.participantErrors[playerActor] += BattleStartError.insufficientPokemon(
|
||||
player = player,
|
||||
@@ -162,8 +169,8 @@ interface BattleStartError {
|
||||
fun getMessageFor(entity: Entity): MutableText
|
||||
|
||||
companion object {
|
||||
fun alreadyInBattle(player: ServerPlayerEntity) = AlreadyInBattleError(player.uuid, player.displayName)
|
||||
fun alreadyInBattle(pokemonEntity: PokemonEntity) = AlreadyInBattleError(pokemonEntity.uuid, pokemonEntity.displayName)
|
||||
fun alreadyInBattle(player: ServerPlayerEntity) = AlreadyInBattleError(player.uuid, player.effectiveName())
|
||||
fun alreadyInBattle(pokemonEntity: PokemonEntity) = AlreadyInBattleError(pokemonEntity.uuid, pokemonEntity.effectiveName())
|
||||
fun alreadyInBattle(actor: BattleActor) = AlreadyInBattleError(actor.uuid, actor.getName())
|
||||
|
||||
fun targetIsBusy(targetName: MutableText) = BusyError(targetName)
|
||||
@@ -203,7 +210,7 @@ class InsufficientPokemonError(
|
||||
} else {
|
||||
battleLang(
|
||||
"error.insufficient_pokemon",
|
||||
player.displayName,
|
||||
player.effectiveName(),
|
||||
requiredCount,
|
||||
hadCount
|
||||
)
|
||||
|
||||
@@ -44,10 +44,10 @@ class BattleCaptureAction(
|
||||
pokeBallEntity.captureFuture.thenAccept { successful ->
|
||||
if (successful) {
|
||||
targetPokemon.battlePokemon?.gone = true
|
||||
battle.dispatchWaiting(2F) { battle.broadcastChatMessage(lang("capture.succeeded", pokemonName).green()) }
|
||||
battle.writeShowdownAction(">capture ${targetPokemon.getPNX()}")
|
||||
battle.broadcastChatMessage(lang("capture.succeeded", pokemonName).green())
|
||||
} else {
|
||||
battle.broadcastChatMessage(lang("capture.broke_free", pokemonName).red())
|
||||
battle.dispatchWaiting(2F) { battle.broadcastChatMessage(lang("capture.broke_free", pokemonName).red()) }
|
||||
}
|
||||
battle.sendUpdate(BattleCaptureEndPacket(targetPokemon.getPNX(), successful))
|
||||
battle.finishCaptureAction(this)
|
||||
|
||||
@@ -22,7 +22,6 @@ import com.cobblemon.mod.common.net.messages.client.battle.BattleChallengeExpire
|
||||
import com.cobblemon.mod.common.util.getPlayer
|
||||
import com.google.gson.GsonBuilder
|
||||
import java.time.Instant
|
||||
import java.util.Optional
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
@@ -139,7 +138,7 @@ object BattleRegistry {
|
||||
// 0 - 9, empty == 10
|
||||
packedTeamBuilder.append("${if (pk.dmaxLevel < 10) pk.dmaxLevel else ""},")
|
||||
// Teratype
|
||||
packedTeamBuilder.append("${pokemon.effectedPokemon.teraType.name},")
|
||||
packedTeamBuilder.append("${pokemon.effectedPokemon.teraType.showdownId()},")
|
||||
|
||||
team.add(packedTeamBuilder.toString())
|
||||
}
|
||||
|
||||
@@ -95,7 +95,8 @@ enum class ShowdownActionResponseType(val loader: (PacketByteBuf) -> ShowdownAct
|
||||
DEFAULT({ DefaultActionResponse() }),
|
||||
FORCE_PASS({ ForcePassActionResponse() }),
|
||||
PASS({ PassActionResponse }),
|
||||
HEAL_ITEM({ HealItemActionResponse("potion") });
|
||||
HEAL_ITEM({ HealItemActionResponse("potion") }),
|
||||
FORFEIT({ ForfeitActionResponse() });
|
||||
}
|
||||
|
||||
abstract class ShowdownActionResponse(val type: ShowdownActionResponseType) {
|
||||
@@ -265,6 +266,11 @@ class BagItemActionResponse(val bagItem: BagItem, val target: BattlePokemon, val
|
||||
}
|
||||
}
|
||||
|
||||
class ForfeitActionResponse : ShowdownActionResponse(ShowdownActionResponseType.FORFEIT) {
|
||||
override fun isValid(activeBattlePokemon: ActiveBattlePokemon, showdownMoveSet: ShowdownMoveset?, forceSwitch: Boolean) = true
|
||||
override fun toShowdownString(activeBattlePokemon: ActiveBattlePokemon, showdownMoveSet: ShowdownMoveset?) = "forfeit"
|
||||
}
|
||||
|
||||
class ShowdownMoveset {
|
||||
lateinit var moves: List<InBattleMove>
|
||||
var trapped = false
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+11
-15
@@ -19,33 +19,29 @@ import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format:
|
||||
* |-ability|POKEMON|ABILITY|(from)EFFECT
|
||||
* Format: |-ability|POKEMON|ABILITY|(from)EFFECT
|
||||
*
|
||||
* The ABILITY of the POKEMON has been changed due to a move/ability EFFECT.
|
||||
* The ABILITY of POKEMON has been changed due to a move/ability EFFECT.
|
||||
*
|
||||
* Format:
|
||||
* |-ability|POKEMON|ABILITY
|
||||
* Alt format: |-ability|POKEMON|ABILITY
|
||||
*
|
||||
* POKEMON has just switched-in, and its ability ABILITY is being announced to have a long-term effect.
|
||||
* POKEMON has just switched-in, and its ABILITY is being announced to have a long-term effect.
|
||||
* @author Xylopia
|
||||
* @since January 31st, 2023
|
||||
*/
|
||||
class AbilityInstruction(val instructionSet: InstructionSet, val message: BattleMessage) : InterpreterInstruction, CauserInstruction {
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val pokemon = message.getBattlePokemon(0, battle) ?: return
|
||||
val pokemonName = pokemon.getName()
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return
|
||||
val effect = message.effectAt(1) ?: return
|
||||
val optionalEffect = message.effect()
|
||||
val optionalPokemon = message.getSourceBattlePokemon(battle)
|
||||
val optionalPokemonName = optionalPokemon?.getName()
|
||||
val optionalPokemon = message.battlePokemonFromOptional(battle)
|
||||
|
||||
// If there is an optional effect causing the activation, broadcast that instead of the standard effect
|
||||
if (optionalEffect != null) {
|
||||
ShowdownInterpreter.broadcastAbility(battle, optionalEffect, pokemonName)
|
||||
} else {
|
||||
ShowdownInterpreter.broadcastAbility(battle, effect, pokemonName)
|
||||
}
|
||||
ShowdownInterpreter.broadcastAbility(battle, optionalEffect ?: effect, pokemon)
|
||||
|
||||
battle.dispatch {
|
||||
val pokemonName = pokemon.getName()
|
||||
val optionalPokemonName = optionalPokemon?.getName()
|
||||
ShowdownInterpreter.lastCauser[battle.battleId] = message
|
||||
|
||||
val lang = when (optionalEffect?.id) {
|
||||
|
||||
+10
-7
@@ -20,21 +20,24 @@ import com.cobblemon.mod.common.util.battleLang
|
||||
import net.minecraft.text.Text
|
||||
|
||||
/**
|
||||
* Format:
|
||||
* |-activate|POKEMON|EFFECT
|
||||
* Format: |-activate|POKEMON|EFFECT
|
||||
*
|
||||
* A miscellaneous effect has activated.This is triggered whenever an effect could not be better described by one of the other minor messages.
|
||||
* A miscellaneous EFFECT has activated for POKEMON. This is triggered whenever an effect could not be better described
|
||||
* by one of the other minor messages.
|
||||
*
|
||||
* @author Hunter
|
||||
* @since September 25th, 2022
|
||||
*/
|
||||
class ActivateInstruction(val instructionSet: InstructionSet, val message: BattleMessage) : InterpreterInstruction, CauserInstruction {
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val pokemon = message.getBattlePokemon(0, battle) ?: return
|
||||
val pokemonName = pokemon.getName()
|
||||
val sourceName = message.getSourceBattlePokemon(battle)?.getName() ?: Text.literal("UNKNOWN")
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return
|
||||
val effect = message.effectAt(1) ?: return
|
||||
val extraEffect = message.effectAt(2)?.typelessData ?: Text.literal("UNKNOWN")
|
||||
ShowdownInterpreter.broadcastOptionalAbility(battle, effect, pokemonName)
|
||||
ShowdownInterpreter.broadcastOptionalAbility(battle, effect, pokemon)
|
||||
|
||||
battle.dispatch{
|
||||
val pokemonName = pokemon.getName()
|
||||
val sourceName = message.battlePokemonFromOptional(battle)?.getName() ?: Text.literal("UNKNOWN")
|
||||
ShowdownInterpreter.lastCauser[battle.battleId] = message
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |bagitem|POKEMON|ITEM
|
||||
*
|
||||
* POKEMON had ITEM used on it from the 'bag'.
|
||||
* @author landonjw
|
||||
* @since July 31st, 2023
|
||||
*/
|
||||
class BagItemInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchGo {
|
||||
val pokemon = message.pokemonByUuid(0, battle)!!
|
||||
val item = message.argumentAt(1)!!
|
||||
|
||||
val ownerName = pokemon.actor.getName()
|
||||
val itemName = item.asTranslated()
|
||||
|
||||
battle.broadcastChatMessage(battleLang("bagitem.use", ownerName, itemName, pokemon.getName()))
|
||||
}
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-block|POKEMON|EFFECT|MOVE|ATTACKER|(of)SOURCE
|
||||
*
|
||||
* An effect targeted at POKEMON was blocked by EFFECT. This may optionally specify that the effect was a MOVE from ATTACKER.
|
||||
*
|
||||
* An optional SOURCE will note the owner of the EFFECT, in the case that it's not EFFECT (for instance, an ally with Aroma Veil.)
|
||||
* @author jeffw773
|
||||
* @since November 6th, 2023
|
||||
*/
|
||||
class BlockInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting(1.5F) {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
val pokemonName = pokemon.getName()
|
||||
val effectID = message.effectAt(1)?.id ?: return@dispatchWaiting
|
||||
val lang = battleLang("block.$effectID", pokemonName)
|
||||
|
||||
battle.broadcastChatMessage(lang)
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-boost|POKEMON|STAT|AMOUNT or |-unboost|POKEMON|STAT|AMOUNT
|
||||
*
|
||||
* POKEMON has gained or lost AMOUNT in STAT, using the standard rules for stat changes in-battle.
|
||||
* STAT is a standard three-letter abbreviation fot the stat in question.
|
||||
* @author Hiroku
|
||||
* @since August 20th, 2022
|
||||
*/
|
||||
class BoostInstruction(val instructionSet: InstructionSet, val message: BattleMessage, val remainingLines: Iterator<BattleMessage>, val isBoost: Boolean = true): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return
|
||||
val statKey = message.argumentAt(1) ?: return
|
||||
val stages = message.argumentAt(2)?.toInt() ?: return
|
||||
val stat = Stats.getStat(statKey).displayName
|
||||
val severity = Stats.getSeverity(stages)
|
||||
val rootKey = if (isBoost) "boost" else "unboost"
|
||||
|
||||
battle.dispatchWaiting(1.5F) {
|
||||
val lang = when {
|
||||
message.hasOptionalArgument("zeffect") -> battleLang("$rootKey.$severity.zeffect", pokemon.getName(), stat)
|
||||
else -> battleLang("$rootKey.$severity", pokemon.getName(), stat)
|
||||
}
|
||||
battle.broadcastChatMessage(lang)
|
||||
|
||||
val boostBucket = if (isBoost) BattleContext.Type.BOOST else BattleContext.Type.UNBOOST
|
||||
val context = ShowdownInterpreter.getContextFromAction(message, boostBucket, battle)
|
||||
// TODO: replace with context that tracks detailed information such as # of stages
|
||||
repeat(stages) { pokemon.contextManager.add(context) }
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
|
||||
/**
|
||||
* Formats: |cant|POKEMON|REASON and |cant|POKEMON|REASON|MOVE
|
||||
*
|
||||
* The POKEMON could not perform a move because of the indicated REASON.
|
||||
* @author Deltric
|
||||
* @since January 22nd, 2022
|
||||
*/
|
||||
class CantInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
val effectID = message.effectAt(1)?.id ?: return@dispatchWaiting
|
||||
val name = pokemon.getName()
|
||||
// Move may be null as it's not always given
|
||||
val moveName = message.moveAt(2)?.displayName ?: run { "(Unrecognized: ${message.argumentAt(2)})".text() }
|
||||
|
||||
val lang = when (effectID) {
|
||||
// TODO: in the games they use a generic image because there is a popup of the ability and the sprite of the mon, it may be good to have a similar system here
|
||||
"armortail", "damp", "dazzling", "queenlymajesty" -> battleLang("cant.generic", name, moveName)
|
||||
"par", "slp", "frz" -> {
|
||||
val status = Statuses.getStatus(effectID)?.name?.path ?: return@dispatchWaiting
|
||||
lang("status.$status.is", name)
|
||||
}
|
||||
else -> battleLang("cant.$effectID", name, moveName)
|
||||
}
|
||||
|
||||
battle.broadcastChatMessage(lang.red())
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-clearallboost|
|
||||
*
|
||||
* Clears all boosts from all Pokémon on both sides.
|
||||
* @author Segfault Guy
|
||||
* @since April 26th, 2023
|
||||
*/
|
||||
class ClearAllBoostInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting(1.5F) {
|
||||
battle.activePokemon.forEach {
|
||||
it.battlePokemon?.contextManager?.clear(BattleContext.Type.BOOST, BattleContext.Type.UNBOOST)
|
||||
}
|
||||
battle.broadcastChatMessage(battleLang("clearallboost"))
|
||||
}
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-clearnegativeboost|POKEMON
|
||||
*
|
||||
* Clear the negative boosts from the target POKEMON (usually as the result of a zeffect).
|
||||
* @author Segfault Guy
|
||||
* @since September 10th, 2023
|
||||
*/
|
||||
class ClearNegativeBoostInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val battlePokemon = message.battlePokemon(0, battle) ?: return
|
||||
|
||||
battle.dispatchWaiting(1.5F) {
|
||||
val pokemonName = battlePokemon.getName()
|
||||
val lang = when {
|
||||
message.hasOptionalArgument("zeffect") -> battleLang("clearallnegativeboost.zeffect", pokemonName)
|
||||
else -> battleLang("clearallnegativeboost", pokemonName)
|
||||
}
|
||||
if (!message.hasOptionalArgument("silent")) {
|
||||
battle.broadcastChatMessage(lang)
|
||||
}
|
||||
|
||||
battlePokemon.contextManager.clear(BattleContext.Type.UNBOOST)
|
||||
battle.minorBattleActions[battlePokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-copyboost|SOURCE|TARGET|(from)EFFECT
|
||||
*
|
||||
* Copies any stat changes from the TARGET Pokémon to the SOURCE Pokémon due to EFFECT.
|
||||
* @author JMMCP
|
||||
* @since November 27th, 2023
|
||||
*/
|
||||
class CopyBoostInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
val pokemonName = pokemon.getName()
|
||||
val targetPokemon = message.battlePokemon(1, battle) ?: return@dispatchWaiting
|
||||
val targetPokemonName = targetPokemon.getName()
|
||||
val lang = battleLang("copyboost.generic", pokemonName, targetPokemonName)
|
||||
battle.broadcastChatMessage(lang)
|
||||
|
||||
pokemon.contextManager.copy(targetPokemon.contextManager, BattleContext.Type.BOOST, BattleContext.Type.UNBOOST)
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.text.yellow
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.LastBattleCriticalHitsEvolutionProgress
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-crit|POKEMON
|
||||
*
|
||||
* POKEMON received a critical hit.
|
||||
* @author Hunter
|
||||
* @since August 18th, 2022
|
||||
*/
|
||||
class CritInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchGo {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchGo
|
||||
battle.broadcastChatMessage(battleLang("crit").yellow())
|
||||
ShowdownInterpreter.lastCauser[battle.battleId]?.let { message ->
|
||||
val battlePokemon = message.battlePokemon(0, battle) ?: return@let
|
||||
if (LastBattleCriticalHitsEvolutionProgress.supports(battlePokemon.effectedPokemon)) {
|
||||
val progress = battlePokemon.effectedPokemon.evolutionProxy.current().progressFirstOrCreate({ it is LastBattleCriticalHitsEvolutionProgress }) { LastBattleCriticalHitsEvolutionProgress() }
|
||||
progress.updateProgress(LastBattleCriticalHitsEvolutionProgress.Progress(progress.currentProgress().amount + 1))
|
||||
}
|
||||
}
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.Effect
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattlePersistentStatusPacket
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
|
||||
/**
|
||||
* Format: |-curestatus|POKEMON|STATUS
|
||||
*
|
||||
* The POKEMON has recovered from its STATUS.
|
||||
* @author Hiroku
|
||||
* @since November 5th, 2022
|
||||
*/
|
||||
class CureStatusInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val maybeActivePokemon = message.actorAndActivePokemon(0, battle)?.second?.battlePokemon
|
||||
val maybePartyPokemon = message.battlePokemon(0, battle)
|
||||
val pokemon = maybeActivePokemon ?: maybePartyPokemon ?: return
|
||||
val status = message.argumentAt(1)?.let(Statuses::getStatus) ?: return
|
||||
val effect = message.effect()
|
||||
ShowdownInterpreter.broadcastOptionalAbility(battle, effect, pokemon)
|
||||
|
||||
battle.dispatchWaiting {
|
||||
val pokemonName = pokemon.getName()
|
||||
pokemon.effectedPokemon.status = null
|
||||
pokemon.sendUpdate()
|
||||
|
||||
if (maybeActivePokemon != null) {
|
||||
message.pnxAndUuid(0)?.let {
|
||||
battle.sendUpdate(BattlePersistentStatusPacket(it.first, null))
|
||||
}
|
||||
}
|
||||
val lang = when (effect?.type) {
|
||||
Effect.Type.ABILITY -> battleLang("curestatus.${effect.id}", pokemonName)
|
||||
else -> status.removeMessage.asTranslated(pokemonName)
|
||||
}
|
||||
battle.broadcastChatMessage(lang)
|
||||
pokemon.contextManager.remove(status.showdownName, BattleContext.Type.STATUS)
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user