forked from mirrors/cobblemon
Compare commits
678
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1e261966ed | ||
|
|
a270371632 | ||
|
|
a9caf92d2f | ||
|
|
ff4d9ae208 | ||
|
|
a87d522f6d | ||
|
|
dca6b5273d | ||
|
|
2e8483cdc7 | ||
|
|
6b1c2e2074 | ||
|
|
8af5b5e07a | ||
|
|
7ae19ca774 | ||
|
|
830f00553e | ||
|
|
c87f56c83f | ||
|
|
4478532bcb | ||
|
|
184348d6fa | ||
|
|
04d288ed7e | ||
|
|
0d5cce730e | ||
|
|
3e01535203 | ||
|
|
f0d99a9d83 | ||
|
|
b4eb46d632 | ||
|
|
7e52336255 | ||
|
|
2b40b5b689 | ||
|
|
da889f220b | ||
|
|
41db2a53ce | ||
|
|
85d8779818 | ||
|
|
d817ce1471 | ||
|
|
ce09b66db5 | ||
|
|
d0c666a20d | ||
|
|
04cef915e4 | ||
|
|
e50412443e | ||
|
|
3fe1f87f18 | ||
|
|
5a0fc199ff | ||
|
|
beb769c2a5 | ||
|
|
a7b6fae4ed | ||
|
|
af2ff7bbfa | ||
|
|
4f3575b2c6 | ||
|
|
98c248ef13 | ||
|
|
4a2c69d47c | ||
|
|
c23cb644d9 | ||
|
|
a8b12cfca3 | ||
|
|
b489e747bb | ||
|
|
08f957e33b | ||
|
|
e17d38c53a | ||
|
|
0397e39735 | ||
|
|
6ca1d23f45 | ||
|
|
44def2be76 | ||
|
|
507f70c2d5 | ||
|
|
d91118d05f | ||
|
|
07d8e6ed09 | ||
|
|
64d160020b | ||
|
|
fb4c80f68c | ||
|
|
2b5433f9da | ||
|
|
9bad141c3f | ||
|
|
fe8e4dcaff | ||
|
|
e0bd6766fc | ||
|
|
4da800d396 | ||
|
|
f3246ae14a | ||
|
|
47f87b1be3 | ||
|
|
da6a09c942 | ||
|
|
4217938ada | ||
|
|
4c5f88db06 | ||
|
|
cfd743c4c0 | ||
|
|
1bbfc6dce5 | ||
|
|
6f2235c751 | ||
|
|
50a0f2d858 | ||
|
|
27210512f6 | ||
|
|
53aa124de6 | ||
|
|
a18b54849f | ||
|
|
c868c63a5f | ||
|
|
31df7c92f4 | ||
|
|
3b65d1967e | ||
|
|
f30b15003f | ||
|
|
c4c1b7ac27 | ||
|
|
ea9287cfb5 | ||
|
|
02f845af5c | ||
|
|
3bb3a00cef | ||
|
|
f1ae4163c9 | ||
|
|
05957f2106 | ||
|
|
4b9ea1d4cd | ||
|
|
78dff75db9 | ||
|
|
dbab6404a1 | ||
|
|
e5c4240ae0 | ||
|
|
317112f9bb | ||
|
|
58fda2e261 | ||
|
|
3b442d387a | ||
|
|
2b575c888f | ||
|
|
6e5e572412 | ||
|
|
ce87d0dc48 | ||
|
|
d43c91129c | ||
|
|
d66b9c8d3b | ||
|
|
dc37b381a0 | ||
|
|
1206aaaf13 | ||
|
|
95bcb9a7b8 | ||
|
|
c7d879ec57 | ||
|
|
d5752982d7 | ||
|
|
f1439ec724 | ||
|
|
0cac5714ac | ||
|
|
8529bb119f | ||
|
|
b68b3ad55e | ||
|
|
70c6b74f0f | ||
|
|
5cb7a51163 | ||
|
|
a68b6928aa | ||
|
|
0c26cb026c | ||
|
|
6078e22b14 | ||
|
|
cb1226013d | ||
|
|
0c8318d317 | ||
|
|
8d80bcfd6b | ||
|
|
cfd4fa1785 | ||
|
|
86bd70177c | ||
|
|
ce668b31ff | ||
|
|
943d6e0c55 | ||
|
|
7d82a2f7c8 | ||
|
|
782ba524df | ||
|
|
c571d79035 | ||
|
|
054c22b926 | ||
|
|
d2fce5edb5 | ||
|
|
cba32b7443 | ||
|
|
4a81c24a3d | ||
|
|
776e629850 | ||
|
|
9afb8b04c2 | ||
|
|
90c74eddc8 | ||
|
|
3600178d3b | ||
|
|
66d8a01917 | ||
|
|
68e32b21b5 | ||
|
|
670882bb4d | ||
|
|
9c0708651f | ||
|
|
1b3bb3b5bc | ||
|
|
cd03ef68c3 | ||
|
|
69716b5050 | ||
|
|
015deb4eeb | ||
|
|
96023077ad | ||
|
|
d96c68b5b4 | ||
|
|
dc27867502 | ||
|
|
bfbea377c1 | ||
|
|
f5954fcb33 | ||
|
|
eaa909a9f2 | ||
|
|
5ba4d460b1 | ||
|
|
09143b7ad6 | ||
|
|
aa1e14b4ac | ||
|
|
0f29cdeaf9 | ||
|
|
b976b9dd68 | ||
|
|
fa94ca8033 | ||
|
|
f206352b6e | ||
|
|
cdee981933 | ||
|
|
f2fc32b6a9 | ||
|
|
f46b581327 | ||
|
|
ff1241304b | ||
|
|
dd746e6775 | ||
|
|
44956ec6da | ||
|
|
83e7a1968a | ||
|
|
553ecc8509 | ||
|
|
7b0d488b7c | ||
|
|
3f7a5e1318 | ||
|
|
ce7485f557 | ||
|
|
b5ca5c29d4 | ||
|
|
43f60da22e | ||
|
|
0102c8b392 | ||
|
|
6bb5c5dadf | ||
|
|
dd21fe2ea3 | ||
|
|
656c46817a | ||
|
|
a373f437fa | ||
|
|
0fe3637034 | ||
|
|
4b4be0e2cc | ||
|
|
3e673ae8f0 | ||
|
|
4b3b7443d3 | ||
|
|
70c1b42ede | ||
|
|
b2048bb66f | ||
|
|
9956f1c159 | ||
|
|
25857dafc5 | ||
|
|
80345b3810 | ||
|
|
d4dc24ec49 | ||
|
|
2209ee10b6 | ||
|
|
a91aa9835c | ||
|
|
0e980a846c | ||
|
|
f54bbe754f | ||
|
|
92fff27b4e | ||
|
|
255874cbe4 | ||
|
|
824bc1b080 | ||
|
|
3ee55f24d8 | ||
|
|
c3379ddf21 | ||
|
|
5983b17e87 | ||
|
|
27986d28a7 | ||
|
|
8807f2134e | ||
|
|
d74b1228c1 | ||
|
|
a3dcfe8bfb | ||
|
|
8725ef2b54 | ||
|
|
3074b067dc | ||
|
|
8d0ee6dd6f | ||
|
|
a1c1c9bc90 | ||
|
|
5e52d350c1 | ||
|
|
e3ad34e023 | ||
|
|
f308918fd1 | ||
|
|
82a8257fa9 | ||
|
|
6c06c91cca | ||
|
|
c5e44031a6 | ||
|
|
6be2e14af4 | ||
|
|
5cae25c059 | ||
|
|
87e4f94af5 | ||
|
|
90ac9ae4df | ||
|
|
527518d0c2 | ||
|
|
bcb326cd87 | ||
|
|
43075f1cb8 | ||
|
|
e1b1e3d5e9 | ||
|
|
c226b80430 | ||
|
|
935f7039cf | ||
|
|
a7095b30a3 | ||
|
|
ac5a03eebc | ||
|
|
bd79b58571 | ||
|
|
7c164fc4c8 | ||
|
|
5e1c233493 | ||
|
|
95e95afef3 | ||
|
|
bf9c54e539 | ||
|
|
2ccda57c66 | ||
|
|
846acaef88 | ||
|
|
5fa12ff1c5 | ||
|
|
2b3db32243 | ||
|
|
4b54405017 | ||
|
|
b7addd0203 | ||
|
|
7e64938ec9 | ||
|
|
3824531735 | ||
|
|
618f66c775 | ||
|
|
9eb9c782ce | ||
|
|
49149c9c54 | ||
|
|
fd1d1075db | ||
|
|
1648926aa6 | ||
|
|
7784794689 | ||
|
|
07b41d7c0a | ||
|
|
f5287c7e83 | ||
|
|
63a30dcfd0 | ||
|
|
9cc63b59e6 | ||
|
|
cb17c29be5 | ||
|
|
fd16d59ea2 | ||
|
|
3ce22c0759 | ||
|
|
797eeb09cc | ||
|
|
e6df322556 | ||
|
|
744d1e1263 | ||
|
|
7987713179 | ||
|
|
f8efe0a7d1 | ||
|
|
be558ed0ab | ||
|
|
a786adee9e | ||
|
|
2d6c7f5148 | ||
|
|
f3f3bfead4 | ||
|
|
506ff8d1e4 | ||
|
|
4764264c9a | ||
|
|
7a761003c5 | ||
|
|
f9fa9dcf24 | ||
|
|
dfc4873ce3 | ||
|
|
65bd00033c | ||
|
|
f82fa2b4e6 | ||
|
|
966acecf6d | ||
|
|
2cd09af4d0 | ||
|
|
1bc22f1afc | ||
|
|
3480085a29 | ||
|
|
f5c0bfb40e | ||
|
|
9dc9740363 | ||
|
|
be16d00dd5 | ||
|
|
777ece02cc | ||
|
|
388e03e261 | ||
|
|
1829f7d48a | ||
|
|
bcc3c885d7 | ||
|
|
e2a6dbc709 | ||
|
|
b32ca4af5d | ||
|
|
a2e728905e | ||
|
|
ead232be6f | ||
|
|
feaba85ba0 | ||
|
|
6a8822ca76 | ||
|
|
8fc6d93be4 | ||
|
|
97f8dc562a | ||
|
|
6616cd1d4c | ||
|
|
f9635cf03f | ||
|
|
49db87737f | ||
|
|
a414213255 | ||
|
|
59a8c21429 | ||
|
|
b67fda7a37 | ||
|
|
4392a61ab5 | ||
|
|
a9d96818ec | ||
|
|
6b285e48e9 | ||
|
|
532ef09acd | ||
|
|
f0f7bb96ad | ||
|
|
ecfb6c60c3 | ||
|
|
5be436f25c | ||
|
|
2ddc265b0f | ||
|
|
52af8ceb99 | ||
|
|
14a5060100 | ||
|
|
9d33586b44 | ||
|
|
d4f328157e | ||
|
|
c4331043f7 | ||
|
|
9945d8a069 | ||
|
|
2595d6ee91 | ||
|
|
f16e024bbe | ||
|
|
87a5522acc | ||
|
|
2c812cdc3c | ||
|
|
f6e910038e | ||
|
|
5c7d96897d | ||
|
|
862d892c84 | ||
|
|
9246e1e8ee | ||
|
|
0715cb465f | ||
|
|
2e251972aa | ||
|
|
de89c11f24 | ||
|
|
7a1f96e31e | ||
|
|
d405b099b3 | ||
|
|
a8e4f87c59 | ||
|
|
74322e2f48 | ||
|
|
f16d233693 | ||
|
|
54d2711583 | ||
|
|
e54f179ccf | ||
|
|
40a37fedd2 | ||
|
|
3bc6c50d79 | ||
|
|
1ef9f44a1b | ||
|
|
f1ed339d9d | ||
|
|
f07930ef16 | ||
|
|
c6d18cda44 | ||
|
|
263b86e833 | ||
|
|
953560051d | ||
|
|
bf3904a214 | ||
|
|
c426f4154b | ||
|
|
a326eb3832 | ||
|
|
1708eb9b3e | ||
|
|
0dee18dbfd | ||
|
|
7ee7aaab76 | ||
|
|
3dd4f515dd | ||
|
|
f24310d043 | ||
|
|
61bfe02322 | ||
|
|
7cbcb30aff | ||
|
|
6fc8fa5b60 | ||
|
|
7763a6d3e7 | ||
|
|
1288469172 | ||
|
|
86cf79bff9 | ||
|
|
765e9f2cc3 | ||
|
|
ffda34742c | ||
|
|
c2385edbe7 | ||
|
|
961ad0f4bd | ||
|
|
8851594347 | ||
|
|
3c1ad2bea6 | ||
|
|
e1960792d7 | ||
|
|
23b9f933c7 | ||
|
|
9662699bcb | ||
|
|
32b2d2023b | ||
|
|
22441e0b09 | ||
|
|
c64612859c | ||
|
|
6c97c4c238 | ||
|
|
8c6f7335a5 | ||
|
|
6535d43964 | ||
|
|
234d1dad44 | ||
|
|
da247e9902 | ||
|
|
8418bc87c8 | ||
|
|
c747d089ca | ||
|
|
8c881ab85a | ||
|
|
0655d63dc5 | ||
|
|
81ba5ef615 | ||
|
|
8354c3838a | ||
|
|
80db305aba | ||
|
|
ec43a78ae4 | ||
|
|
60e0314f29 | ||
|
|
5f868630e0 | ||
|
|
762a53923c | ||
|
|
1cf03d4a0d | ||
|
|
48f7be485f | ||
|
|
89364a9fd0 | ||
|
|
b93adae945 | ||
|
|
9f1ed344d8 | ||
|
|
2c256eefde | ||
|
|
b075fce83f | ||
|
|
f2ed332c4c | ||
|
|
e8f083d8bf | ||
|
|
43d965f2a1 | ||
|
|
1684a341a1 | ||
|
|
b4e1bf794d | ||
|
|
c85ad7d60c | ||
|
|
e61e92a5d4 | ||
|
|
a245e9661c | ||
|
|
059152b34c | ||
|
|
e4a698b04b | ||
|
|
0d35157fcf | ||
|
|
302388d0a6 | ||
|
|
ab957f82e1 | ||
|
|
fef82ae6bf | ||
|
|
8b979c1944 | ||
|
|
4bbbaacacf | ||
|
|
eda8e15509 | ||
|
|
d53a71c188 | ||
|
|
d2f02b0d06 | ||
|
|
5c0bb194b6 | ||
|
|
e41562f5ad | ||
|
|
69ea1ac3bf | ||
|
|
7c15f0f924 | ||
|
|
6165e5e871 | ||
|
|
dd8f59e0d0 | ||
|
|
87611795e9 | ||
|
|
d2fe9b1132 | ||
|
|
e95759a710 | ||
|
|
7284f8d35d | ||
|
|
334dd1206e | ||
|
|
e7caab0ae0 | ||
|
|
47f02f6e50 | ||
|
|
3367b0c39c | ||
|
|
0e43d7730c | ||
|
|
b5604686f2 | ||
|
|
e030dbfbf5 | ||
|
|
96647a9398 | ||
|
|
33cfbf7d1c | ||
|
|
9e2c0ab0db | ||
|
|
1bc953f3f3 | ||
|
|
d089eab60f | ||
|
|
09da392c36 | ||
|
|
94ad2f1250 | ||
|
|
d18cab39a9 | ||
|
|
4492666f5a | ||
|
|
6ddf048984 | ||
|
|
6a0985958b | ||
|
|
308c5e6d32 | ||
|
|
bd83cc143b | ||
|
|
c9e6cb1022 | ||
|
|
74c75b7faa | ||
|
|
45819a17f6 | ||
|
|
e3f84248b8 | ||
|
|
0ff518194f | ||
|
|
634a1ad6fc | ||
|
|
41217ebdcc | ||
|
|
f396b63a34 | ||
|
|
a021ec1337 | ||
|
|
b03f95b7da | ||
|
|
d8cee44661 | ||
|
|
5dd2287441 | ||
|
|
1eb6af14c2 | ||
|
|
61b73972d4 | ||
|
|
f8bcf8c291 | ||
|
|
543d408e63 | ||
|
|
2cdc781e93 | ||
|
|
8dc0a7f72d | ||
|
|
8b5231d6f0 | ||
|
|
665c4cc26c | ||
|
|
253cfd55d8 | ||
|
|
7c860d8f91 | ||
|
|
006e86f3c3 | ||
|
|
e75d0c564f | ||
|
|
1e97143a6a | ||
|
|
91dec859e8 | ||
|
|
85f08c9d28 | ||
|
|
d465f465c8 | ||
|
|
a87bd35fd6 | ||
|
|
0c32da0ce1 | ||
|
|
2bdb110c92 | ||
|
|
d21f3747fc | ||
|
|
fb303fcd97 | ||
|
|
7b4e63001b | ||
|
|
31b185b96c | ||
|
|
034a51b904 | ||
|
|
9e1c491d9c | ||
|
|
f695a99705 | ||
|
|
a8567f9190 | ||
|
|
7d455b2dac | ||
|
|
1dffbd1b37 | ||
|
|
332e25fa76 | ||
|
|
f080fb5639 | ||
|
|
769a1862e4 | ||
|
|
bd4df4485e | ||
|
|
127c5e7a8b | ||
|
|
58fba24f01 | ||
|
|
f49265ae52 | ||
|
|
d1a71373c0 | ||
|
|
77def6de43 | ||
|
|
973c6bb05f | ||
|
|
5b83e49669 | ||
|
|
e01bc2eeab | ||
|
|
f6f3070b8e | ||
|
|
0f2301e668 | ||
|
|
80ce5bab58 | ||
|
|
8fb678b0f8 | ||
|
|
c0a77aca23 | ||
|
|
e4c0eab8e2 | ||
|
|
b9ff46e1b2 | ||
|
|
45a998d3d7 | ||
|
|
a108d85531 | ||
|
|
0fae45f811 | ||
|
|
88717d598d | ||
|
|
33123b4a33 | ||
|
|
001864e20c | ||
|
|
0c9fe19da3 | ||
|
|
74e0915ec8 | ||
|
|
39cd5e9726 | ||
|
|
28ebd1dec1 | ||
|
|
94bbc0e574 | ||
|
|
876be2afcf | ||
|
|
d693f452bc | ||
|
|
034e7d315c | ||
|
|
fb785b4204 | ||
|
|
ac807ce25b | ||
|
|
c065f0f8fd | ||
|
|
a1e94b8200 | ||
|
|
9c7d286dd8 | ||
|
|
69d8e4fab9 | ||
|
|
b788fe3984 | ||
|
|
cfd90fac04 | ||
|
|
1cf2359195 | ||
|
|
6868d7f26c | ||
|
|
3e58229a89 | ||
|
|
d76f1524bd | ||
|
|
58b5eb155d | ||
|
|
fd9caa537b | ||
|
|
5262972a8d | ||
|
|
011a095314 | ||
|
|
3520c50541 | ||
|
|
3eccac861f | ||
|
|
7a85b0b690 | ||
|
|
ff3aa5d782 | ||
|
|
8b4552a532 | ||
|
|
41673ba90f | ||
|
|
18f9942dc6 | ||
|
|
875fe46d21 | ||
|
|
66c6f9bdd1 | ||
|
|
9e6dec8605 | ||
|
|
1fe223c772 | ||
|
|
d89ccc110e | ||
|
|
72c337195a | ||
|
|
b72af84c8c | ||
|
|
a5ee270b8b | ||
|
|
c08ef4247d | ||
|
|
9424bafabb | ||
|
|
a96ecfcdf2 | ||
|
|
b1d11e8c22 | ||
|
|
c1fb1379a9 | ||
|
|
5a220e0ef0 | ||
|
|
b379fc62b1 | ||
|
|
d442e4e956 | ||
|
|
bb22c22db9 | ||
|
|
09bc174401 | ||
|
|
e109a1d59f | ||
|
|
3b97a0c847 | ||
|
|
28a2ec3fc0 | ||
|
|
72bba7fdfd | ||
|
|
a258e48582 | ||
|
|
21a15686b2 | ||
|
|
5da7183ae3 | ||
|
|
d847972bb1 | ||
|
|
5e88e73e3f | ||
|
|
87e8fcd7f7 | ||
|
|
b34f8a045d | ||
|
|
e9086ec2bd | ||
|
|
866db464c4 | ||
|
|
4f79b9f8a7 | ||
|
|
d1b651a876 | ||
|
|
b30a67651e | ||
|
|
a1398e9495 | ||
|
|
ca319764f0 | ||
|
|
ac03c68f41 | ||
|
|
0eb4b43b49 | ||
|
|
b49376dba5 | ||
|
|
81f6e7b786 | ||
|
|
574ee1ae4a | ||
|
|
07a83f54a2 | ||
|
|
6f3b530d7b | ||
|
|
4b86dc1e58 | ||
|
|
bb141aee50 | ||
|
|
acb473c01f | ||
|
|
a8dc3f40a4 | ||
|
|
b55f11628d | ||
|
|
150c03d4f5 | ||
|
|
1c092588f4 | ||
|
|
683473c34c | ||
|
|
c7dee1bd53 | ||
|
|
d83a1086d3 | ||
|
|
b34ca3d42b | ||
|
|
3a1389d719 | ||
|
|
e608dc84ae | ||
|
|
c987a5ba19 | ||
|
|
3dbcc2d28c | ||
|
|
d65090ce10 | ||
|
|
206ec25a99 | ||
|
|
ccd376c055 | ||
|
|
b8e95bd210 | ||
|
|
b14465f2a1 | ||
|
|
6214fb1b97 | ||
|
|
a65cee3e24 | ||
|
|
1a0135c1fd | ||
|
|
23dab6546f | ||
|
|
2a60048f7e | ||
|
|
b4787b8db8 | ||
|
|
eefc125f24 | ||
|
|
f95f17d0c6 | ||
|
|
ba7e98e95c | ||
|
|
cdcc071ce0 | ||
|
|
02067929a2 | ||
|
|
0bc3e8465b | ||
|
|
0ebf5712b9 | ||
|
|
4020e28da9 | ||
|
|
dbc074bfde | ||
|
|
17cdedf65f | ||
|
|
f96766505b | ||
|
|
fe96642be4 | ||
|
|
701af6cd8f | ||
|
|
5515fbfeda | ||
|
|
41a0dce7fc | ||
|
|
3b122b7bcc | ||
|
|
2b3500dfc3 | ||
|
|
e921253a57 | ||
|
|
da45797022 | ||
|
|
fc1f68711d | ||
|
|
da9c1f440c | ||
|
|
ae10ca9541 | ||
|
|
80d2f76dfc | ||
|
|
ebf3c9b82f | ||
|
|
af57ac45a2 | ||
|
|
0ad45df8f5 | ||
|
|
1c25ae69a5 | ||
|
|
7f464f2e3e | ||
|
|
d8e209e4a2 | ||
|
|
41a87d0c8a | ||
|
|
45faed038f | ||
|
|
30a78f978d | ||
|
|
d8c1d50aa5 | ||
|
|
03f377cf0a | ||
|
|
eb7bf65e02 | ||
|
|
373092f572 | ||
|
|
c7d3164ff4 | ||
|
|
e6da43be6d | ||
|
|
8bfc0fefaf | ||
|
|
4e44807523 | ||
|
|
36251fea75 | ||
|
|
06206a7447 | ||
|
|
66e901f88d | ||
|
|
05f089d390 | ||
|
|
f52345036d | ||
|
|
bd99ff2bfd | ||
|
|
19510ca8ba | ||
|
|
23df8f70cf | ||
|
|
bd25e8682a | ||
|
|
0ece90bcf1 | ||
|
|
906cd54c98 | ||
|
|
c2894b4bf1 | ||
|
|
8c3958cdf0 | ||
|
|
92cb847755 | ||
|
|
fc4fed42b5 | ||
|
|
ea332515c4 | ||
|
|
49965d6856 | ||
|
|
a1897f69ca | ||
|
|
a88700969d | ||
|
|
91eb9e597e | ||
|
|
e762542e49 | ||
|
|
6e7694d650 | ||
|
|
a301779a42 | ||
|
|
440a07d1de | ||
|
|
b3e5734f39 | ||
|
|
fc7951cbcd | ||
|
|
2d5296288f | ||
|
|
44b58ab9a0 | ||
|
|
cab3f2bf38 | ||
|
|
d24a6fa75c | ||
|
|
fca867a8b8 | ||
|
|
9514c48eaa | ||
|
|
31efdc4254 | ||
|
|
34aace8a1b | ||
|
|
a877ad5a69 | ||
|
|
5a8c090055 | ||
|
|
98ccf39728 | ||
|
|
d029b4380a | ||
|
|
4c29c9726b | ||
|
|
af9fff9793 | ||
|
|
a8d84c4a28 | ||
|
|
5215388e33 | ||
|
|
93c7685ef7 | ||
|
|
5c395a1987 | ||
|
|
755d367760 | ||
|
|
3b26d24958 | ||
|
|
27afe40892 | ||
|
|
fcd4dccdad | ||
|
|
35e206a5d6 | ||
|
|
b51d007341 | ||
|
|
a85fd79818 | ||
|
|
3222e2ebca | ||
|
|
ba89ed1574 | ||
|
|
68ab953644 | ||
|
|
4d3030e20e | ||
|
|
2e324e65a1 | ||
|
|
a34b7481f5 | ||
|
|
d2a3905b03 | ||
|
|
16b3d76504 | ||
|
|
363fe76dd1 | ||
|
|
040a29f66e |
@@ -33,3 +33,7 @@ common/src/main/resources/assets/cobblemon/showdown
|
||||
# Generated files
|
||||
*/generated/resources/*
|
||||
/fabric/src/generated/resources/cobblemon-common.accesswidener
|
||||
/.ignored/
|
||||
|
||||
# MacOS
|
||||
.DS_Store
|
||||
@@ -0,0 +1,30 @@
|
||||
<!-- 1. START HERE: (Before filling all this out, please quickly go to the list of all issues: (https://gitlab.com/cable-mc/cobblemon/-/issues/?sort=created_date&state=all) and do a quick search to see if your issue has already been reported. If it has, please add a comment to the existing issue instead of creating a new one.)-->
|
||||
<!-- 2. If the issue was not already reported, please fill out the following template. -->
|
||||
<!-- 3. If you do not know something, don't worry! Just fill out as much as you can to make sure the issue can get fixed asap. -->
|
||||
|
||||
## Summary
|
||||
(Please summarize the bug encountered concisely)
|
||||
|
||||
## Steps to reproduce
|
||||
(How one can reproduce the issue - this is very important)
|
||||
|
||||
## What is the current bug behavior?
|
||||
(What actually happens)
|
||||
|
||||
## What is the expected correct behavior?
|
||||
(What you should see instead)
|
||||
|
||||
## Cobblemon Version and Mod Loader
|
||||
(Are you using Forge or Fabric? And what version of Cobblemon are you using?)
|
||||
|
||||
## Mods used besides Cobblemon
|
||||
(Did you have any other mods installed besides Cobblemon? If so, please list them here)
|
||||
|
||||
## Relevant logs, screenshots and/or videos
|
||||
(Paste any relevant logs - use code blocks (```) at the start and end to format console output, logs, and code, as
|
||||
it's very hard to read otherwise. Or just put a link here)
|
||||
|
||||
## Additional Information
|
||||
(If you can, link to the line of code that might be responsible for the problem, or any other info that might be useful)
|
||||
|
||||
/label ~bug
|
||||
@@ -0,0 +1,31 @@
|
||||
<!-- 1. START HERE: (Before filling all this out, please quickly go to the list of all issues: (https://gitlab.com/cable-mc/cobblemon/-/issues/?sort=created_date&state=all) and do a quick search to see if your feature was already requested. If it is, please add a comment to the existing issue instead of creating a new one.)-->
|
||||
<!-- 2. If the feature request was not already reported, please fill out the following template. -->
|
||||
<!-- 3. If you do not know something, don't worry! Just fill out as much as you can. -->
|
||||
<!-- 4. The more info you provide here, the greater the chance of it being considered by the Design team. -->
|
||||
|
||||
## Summary
|
||||
(Please summarize your feature request concisely)
|
||||
|
||||
## What are the projected benefits of this feature?
|
||||
- (List)
|
||||
- (benefits)
|
||||
- (here)
|
||||
|
||||
## What could speak against this feature?
|
||||
- (List)
|
||||
- (possible)
|
||||
- (cons)
|
||||
|
||||
## Why do you think the benefits outweigh the cons?
|
||||
(Explain why you think the benefits outweigh the cons)
|
||||
|
||||
## Mods involved besides Cobblemon
|
||||
(Does your suggestion require any other mods besides Cobblemon? If so, please list them here)
|
||||
|
||||
## Sketches, screenshots and/or videos
|
||||
(Feel free to add any sketches, screenshots or videos that might help the Design team understand your suggestion)
|
||||
|
||||
## Additional Information
|
||||
(Is there anything else you would like to add?)
|
||||
|
||||
/label ~feature ~suggestion ~needs-design
|
||||
+214
-59
@@ -1,68 +1,189 @@
|
||||
# Changelog
|
||||
## [1.4.1](#1-4-1)
|
||||
## [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 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.
|
||||
- Added Ancient Poké Balls, which are aesthetic variants crafted from Tumblestones.
|
||||
- Added the Ancient Feather, Wing, and Jet Balls, which fly further than regular Poké Balls.
|
||||
- Added the Ancient Heavy, Leaden, and Gigaton Balls, which are heavier and don't fly as far as regular Poké Balls. These will receive more functionality in a future update.
|
||||
- Added Original Trainer functionality. To edit the OT through commands, you must specify originaltrainertype=<Player/NPC>, and originaltrainer=<Username or UUID/NPC Name>
|
||||
- Added support for planting Apricorn trees, berries, and mints in [Botany Pots](https://modrinth.com/mod/botany-pots)
|
||||
- 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 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.
|
||||
- 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 Gilded Chests, available in all Apricorn colors.
|
||||
- Added Relic Coins, Relic Coin Pouches, and Relic Coin Sacks.
|
||||
- Added 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?
|
||||
|
||||
### Changes
|
||||
- Slightly lowered the volume of all cries
|
||||
- Updated Pokeball animations and model.
|
||||
- Turtwig can now be put on shoulder.
|
||||
- Updated Zubat line model, texture, and animations.
|
||||
- Added animations for Hitmontop, Tyrogue, and Mightyena.
|
||||
- Tweaked animations for Dusknoir, Ratatta, Bewear, Exeggutor, and Alolan Exeggutor.
|
||||
- Sized Kantonian Exeggutor down. Still big but not TOO BIG.
|
||||
- Tweaked cries for Pikachu, Raichu and Alolan Raichu.
|
||||
- Pasture blocks will now also connect their bottom left and right sides to walls, iron bars, glass panes and any other modded block that follows the same connection rules.
|
||||
- The config option `consumeHeldItems` has been removed, please see the Datapack & Resourcepack Creators for instructions on the updated method.
|
||||
- Using Potions, Status Heals, Ethers, and Antidotes will now return a glass bottle
|
||||
- Using a Remedy, Fine Remedy, or Superb Remedy will no longer lower friendship with a Pokémon
|
||||
- The Healing Machine now has a more difficult recipe, placing it later game.
|
||||
- Heal Powder can now be composted with a 75% chance of adding a layer
|
||||
- Mental, Power, White, and Mirror Herbs can now be composted with a 100% chance of adding a layer.
|
||||
- Added emissive to Hoothoot.
|
||||
- Mining Evolution Stone Ores with a Fortune pickaxe will now increase the amount of items recieved
|
||||
- Black Augurite can now be used to craft stone axes and obsidian.
|
||||
- Using Experience Candies brings up the Party Pokémon Select screen when not targeting a Pokémon.
|
||||
- Added tab completion for statuses to commands
|
||||
|
||||
### Additions
|
||||
- Added battle spectating, can disable in config
|
||||
- Cobblemon now has compatibility with [Adorn](https://modrinth.com/mod/adorn) allowing you to craft Apricorn wood furniture.
|
||||
- Berries can now be used in recipes from [Farmer's Delight](https://modrinth.com/mod/farmers-delight) and [Farmer's Delight (Fabric)](https://modrinth.com/mod/farmers-delight-fabric), as well as any other mods using the same berry tags.
|
||||
- The nature of cobblemon will now be displayed italicized when a mint has been applied. Hovering over the nature will display the mint that was applied. This is the intended behaviour, because the original nature and taste of the Cobblemon does not change when a mint is applied.
|
||||
- Giving Pokémon items now plays a sound
|
||||
- A boat, sign and hanging sign is now craftable with Apricorn wood. The recipes are the same shape as Minecraft's equivalent with Apricorn planks as replacements.
|
||||
- Added the Cleanse Tag held item.
|
||||
- Added the Inferno, Void, and Forsaken patterns for Vivillon. These can be obtained by evolving a Spewpa in the Nether, End, or Deep Dark respectively.
|
||||
- Added the Litwick line.
|
||||
- Bees can now be fed using Pep-Up Flowers.
|
||||
- Mooshtank can now be milked with a bowl for Mushroom Stew.
|
||||
- Added cries to Beldum, Metang and Metagross.
|
||||
- Pokémon now transition more smoothly between different poses.
|
||||
- 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.
|
||||
- You can now punch grown apricorns to harvest them.
|
||||
- Renamed the "Vivillionaire" advancement to "Aspiring Vivillionaire"
|
||||
- Removed the Inferno, Forsaken, Poké Ball, and Void patterns from the Aspiring Vivillionaire advancement.
|
||||
- Updated movesets to add Gen 9 DLC moves.
|
||||
- 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.
|
||||
- Using the run button in battle will now actually flee the battle.
|
||||
|
||||
### Fixes
|
||||
- Fixed various stone related blocks not being valid for Big Roots to spread on the Fabric version.
|
||||
- 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 battle lang for Poison Touch Ability
|
||||
- Fixed Cubone not being able to evolve into Alolan Marowak.
|
||||
- Fixed Squawkabilly forms not being recognized.
|
||||
- Fixed the bounce animation for Poké Balls being delayed by like, a full second.
|
||||
- Note blocks now play the correct sound on the Apricorn Plank based blocks.
|
||||
- Fixed an issue with transformed parts in posers causing whacky positional issues.
|
||||
- Fixed Poké Balls freezing in an open state if you look away when it's meant to close.
|
||||
- Adds a translation string name to the Empty Pokeball entity.
|
||||
- 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 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.
|
||||
|
||||
### Developer
|
||||
- Significantly changed the way properties in PokemonEntity work. This could break some plugins (not in a big way, but changes will be needed).
|
||||
- Rebuilt the scheduling API to more clearly force side choices and temporal frames of reference for tasks.
|
||||
- Added dialogue API and data registry.
|
||||
- Opened up the ItemDropEntry class to allow for it to be extended.
|
||||
- Added a new "advancement" evolution variant that takes an advancement identifier and succeeds if the player has the advancement.
|
||||
- Made spawning API capable of non-entity spawning
|
||||
- Made PokemonProperties.parse more interoperable with Java.
|
||||
- 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.
|
||||
|
||||
### Datapack & Resourcepack Creators
|
||||
- The maximum amount of fossils that can fit in the Fossil Analyzer can be adjusted in the config.
|
||||
- Custom fossils can be defined using a list of items and the resulting Pokémon. An example of `aerodactyl.json`:
|
||||
```JSON
|
||||
{
|
||||
"result": "aerodactyl",
|
||||
"fossils": [
|
||||
"cobblemon:old_amber_fossil"
|
||||
]
|
||||
}
|
||||
```
|
||||
- Fetus models can be defined in `bedrock/fossils`.
|
||||
- Fetus textures can be defined in `textures/fossils`.
|
||||
- Fuel for the Restoration Machine is registered inside the `natural_materials` folder. To register more fuels, create a JSON file containing an array of objects. Each object supports the following fields:
|
||||
- `content`: Integer containing the amount of fuel to add.
|
||||
- `item` OR `tag`: Identifier of the item or item tag to be inserted.
|
||||
- `returnItem`: Identifier of an item to return to the player after consumption.
|
||||
- Added 3 new item tags: `ancient_poke_balls`, `fossils`, and `tumblestones`.
|
||||
- Added a spawn rules system to modify general spawning behaviour, see the [wiki](https://wiki.cobblemon.com/index.php/Spawn_Rules) for more information.
|
||||
- Added dialogue datapack folder and /opendialogue command.
|
||||
- Added the item tag ``cobblemon:held/leaves_leftovers`` this can be used to flag apple-like items that can create leftovers when eaten.
|
||||
- You can now add support for dynamic lighting implementations, Cobblemon ships with a default implementation for [LambDynamicLights](https://modrinth.com/mod/lambdynamiclights) and the [Dynamic Lights Reforged](https://www.curseforge.com/minecraft/mc-mods/dynamiclights-reforged), add the following to any species or form:
|
||||
```JSON
|
||||
{
|
||||
"lightingData": {
|
||||
"lightLevel": 14,
|
||||
"_lightLevelCommentRemoveMe": "Above supports 0 to 15",
|
||||
"liquidGlowMode": "LAND",
|
||||
"_liquidGlowModeCommentRemoveMe": "Above supports LAND, UNDERWATER or BOTH"
|
||||
}
|
||||
}
|
||||
```
|
||||
- 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.
|
||||
|
||||
## [1.4.1 (December 23rd, 2023)](#1-4-1)
|
||||
|
||||
### Additions
|
||||
- Added battle spectating. Press R on a player in a battle and you can spectate and bully them for their tactics.
|
||||
- Added the Litwick and Drifloon lines.
|
||||
- Cobblemon now has compatibility with [Adorn](https://modrinth.com/mod/adorn), allowing you to craft Apricorn wood furniture.
|
||||
- Berries can now be used in recipes from [Farmer's Delight](https://modrinth.com/mod/farmers-delight) and [Farmer's Delight (Fabric)](https://modrinth.com/mod/farmers-delight-fabric), as well as any other mods using the same berry tags.
|
||||
- Boats, signs and hanging signs are now craftable with Apricorn wood.
|
||||
- Added the Fairy Feather, Iron Ball, Cleanse Tag, Flame Orb, Life Orb, Smoke Ball, and Toxic Orb held items.
|
||||
- Added the Inferno, Void, and Forsaken patterns for Vivillon. These can be obtained by evolving a Spewpa in the Nether, End, or Deep Dark respectively.
|
||||
- Bees can now be fed using Pep-Up Flowers.
|
||||
- Mooshtank can now be milked with a bowl for Mushroom Stew.
|
||||
- Updated Showdown version to use generation 9 battle data.
|
||||
- Added cries to Beldum, Metang and Metagross.
|
||||
- Added a /bedrockparticle command to run Snowstorm-format particle effects.
|
||||
- Added data for Dipplin, Fezandipiti, Munkidori, Ogerpon, Okidogi, Poltchageist and Sinistcha.
|
||||
- Added additional nickname trigger "Grumm" for Inkay's evolution.
|
||||
|
||||
### Changes
|
||||
- Using Potions, Status Heals, Ethers, and Antidotes will now return a glass bottle
|
||||
- Using a Remedy, Fine Remedy, or Superb Remedy will no longer lower friendship with a Pokémon.
|
||||
- The Healing Machine now has a [much more difficult recipe](https://wiki.cobblemon.com/index.php/Healing_Machine), placing it later game.
|
||||
- Made the EXP. Share recipe cheaper.
|
||||
- Turtwig can now be put on your shoulder.
|
||||
- Updated Zubat line model, texture, and animations.
|
||||
- Updated Geodude line models and textures.
|
||||
- Added animations for Hitmontop, Tyrogue, and Mightyena.
|
||||
- Tweaked animations for Dusknoir, Ratatta, Bewear, Exeggutor, and Alolan Exeggutor.
|
||||
- Sized Kantonian Exeggutor down. Still big, but not TOO big.
|
||||
- Tweaked cries for Pikachu, Raichu and Alolan Raichu.
|
||||
- Fixed Swimming behaviors for Wimpod line, Oshawott line, Quaxly line, and Clodsire
|
||||
- Changed the way level scaling works in spawning. By default, anything with a spawn range of up to 5 either side of the party highest level and everything else will spawn per its specified ranges.
|
||||
- The nature of Pokémon will now be displayed italicized when a mint has been applied. Hovering over the nature will display the mint that was applied.
|
||||
- Slightly lowered the volume of all cries.
|
||||
- Giving Pokémon items now plays a sound
|
||||
- Updated the Poké Ball model and animations.
|
||||
- Pasture blocks will now also connect their bottom left and right sides to walls, iron bars, glass panes, and any other modded block that follows the same connection rules.
|
||||
- The config option `consumeHeldItems` has been removed, please see the Datapack & Resourcepack Creators section for instructions on the updated method.
|
||||
- Heal Powder can now be composted with a 75% chance of adding a layer
|
||||
- Mental, Power, White, and Mirror Herbs can now be composted with a 100% chance of adding a layer.
|
||||
- Added glowing eyes to Hoothoot and Noctowl.
|
||||
- Mining Evolution Stone Ores with a Fortune pickaxe will now increase the amount of items received.
|
||||
- Black Augurite can now be used to craft stone axes and obsidian.
|
||||
- Using Experience Candies brings up the Party Pokémon Select screen when not targeting a Pokémon.
|
||||
- Added tab completion for statuses to commands.
|
||||
- Remedies can now be cooked in a Smoker and on a Campfire.
|
||||
- Vertically flipped the Destiny Knot recipe.
|
||||
|
||||
### Fixes
|
||||
- Fixed Raticate, Onix, Unfezant, Bergmite, Avalugg, Boltund and Revavroom cries not playing.
|
||||
- Fixed Alolan Ratticate animations causing a crash.
|
||||
- Fixed Quaxwell not doing its cry.
|
||||
- Fixed Shroomish not using its idle.
|
||||
- Fixed how Weight and Height is calculated for Pokémon, fixing the damage from moves like Low Kick.
|
||||
- Fixed a staggering number of battle messages.
|
||||
- Fixed various stone related blocks not being valid for Big Roots to spread onto on the Fabric version.
|
||||
- Updated the registration of compostable items to improve compatibility with Fabric forks such as Quilt. Please note this does not mean we officially support Quilt, this change was only done since it was possible by correcting the registration to use the new intended way in the Fabric API.
|
||||
- Fixed Dispensers being unable to shear grown Apricorns.
|
||||
- Fixed Bowl not being given back to player after using Berry Juice
|
||||
- Added context for -fail and -block handlers for battle text and added 16 related battle texts for them
|
||||
- Fixed Battle text for Disable, Laser Focus, Foresight, Fire Spin, Telekinesis, Curse, Recharge and Encore
|
||||
- Fixed missing text for snowy weather in battles
|
||||
- Fixed missing text for attempting to catch an uncatchable Pokémon
|
||||
- Fixed Moonphases for Clefairy line
|
||||
- Fixed issue where Potions, Super Potions, and Hyper Potions did not work during battle
|
||||
- Fixed the compatibility patch with the Forge version of [Carry On](https://modrinth.com/mod/carry-on) due to a bug on the mod, the Fabric version was unchanged and is still compatible.
|
||||
- Added the ability to place Berries on modded Farmland blocks.
|
||||
- Shouldered Pokémon now hop off when selected in team and r is pressed. This also is in effect in battles leading to shouldered Pokémon jumping of the shoulder of the trainer when it is their turn.
|
||||
- Shouldered Pokémon now hop off when selected in team and R is pressed. This also is in effect in battles leading to shouldered Pokémon jumping of the shoulder of the trainer when it is their turn.
|
||||
- Made more items compostable and changed the process for making items compostable.
|
||||
- Added the ability for Hoppers to fill Brewing Stands with Medicinal Brews and Potions.
|
||||
- Apricorn blocks are now flammable.
|
||||
- Apricorn blocks are now flammable. Probably should have started that way, but we got there.
|
||||
- The default pose for Pokémon being passengers is now "standing".
|
||||
- Fixed issue where some IVs were changing every player relog.
|
||||
- Fixed cursed battle message
|
||||
- Fixed mistakes in pokemon spawning JSONs
|
||||
- Fixed issue where some IVs were changing every time a player logged back in.
|
||||
- Fixed advancement crash from bad datapack evolution data.
|
||||
- Fixed global influences being applied to TickingSpawners twice.
|
||||
- Reverted the default SpawningSelector back to FlatContextWeightedSelector. This fixes multiple weight related issues, including weights with SpawningInfluences.
|
||||
- Apricorn Planting advancement should work again.
|
||||
- Advancement "Patterned Wings" should now allow High Plains and Icy Snow Vivillon to register.
|
||||
- Advancement "Vivillonaire" should now allow High Plains and Icy Snow Vivillon to register.
|
||||
- Fixed the last battle critical hits evolution requirement not working.
|
||||
- Fixed the damage taken evolution requirement not saving progress.
|
||||
- Fixed the defeated Pokémon evolution requirement not saving progress.
|
||||
@@ -70,20 +191,54 @@
|
||||
- Fixed an exploit that could convert a single piece of Blaze Powder into an extra Medicinal Brew on the Forge version.
|
||||
- Fixed an issue where health percentages would show incorrectly after healing
|
||||
- Fixed the move Revival Blessing not allowing you to select from fainted party members.
|
||||
- Fixed villagers not being able to pick up and plant mint seeds, vivichoke seeds, and revival herbs.
|
||||
- Fixed Exeggcute faint.
|
||||
- Fixed Raticate, Onix, Unfezant, Bergmite, Avalugg, Boltund and Revavroom cries not playing.
|
||||
- Fixed Alolan Ratticate animations causing a crash.
|
||||
- Fixed Quaxwell not doing its cry.
|
||||
- Fixed Shroomish not using its idle.
|
||||
- Fixed various spawn configuration issues across the board.
|
||||
- Fixed a possible visual duplication of sent out Pokémon.
|
||||
- Fixed battle text for Trace, Receiver, and Power of Alchemy.
|
||||
- Fixed tooltips being appended too late in items.
|
||||
- Fixed battles ending background music when battle music is not present.
|
||||
- Fixed battles ending background music, instead of pausing, when battle music is played.
|
||||
- Fixed a bunch of regionals to actually be obtainable, namely the unmodelled ones
|
||||
- Fixed battle text for moves that were missing.
|
||||
- Fixed a formatting error that affected Pokémon nicknames when the storage type is JSON.
|
||||
- Fixed a crash that could occur on some servers relating to chunk loading and teleporting.
|
||||
- Fixed an issue with Inkay's evolution requirement.
|
||||
- Fixed conflicting evolution requirements that would cause the Ocean, River, Sun, and Tundra variants of Vivillon to be unobtainable through evolution.
|
||||
- Fixed the Modern variant of Vivillon not being obtainable through evolution.
|
||||
- Fixed Pokémon pathing through berry bushes, harming themselves in the process.
|
||||
|
||||
### Developer
|
||||
- Fixed the `SpawnEvent` not respecting usage of `Cancelable#cancel`.
|
||||
- Added the `EvolutionTestedEvent`, this allows listening and overriding the final result of evolution requirement tests.
|
||||
- Rebuilt the scheduling API to more clearly force side choices and allow more local temporal frames of reference for tasks.
|
||||
- Added utility script that can be used to generate all Spawn JSONS for all pokemon from the spawning spreadsheet in 1 click ([cobblemon_spawn_csv_to_json.py](utilityscripts%2Fcobblemon_spawn_csv_to_json.py)).
|
||||
- The `HeldItemManager` has a new method `shouldConsumeItem`, this will return false by default to prevent breaking changes, see the documentation and update your implementations as needed.
|
||||
- Added and implemented minSkyLight and maxSkyLight as config options for SpawnConditions
|
||||
- Player specific battle themes can now be assigned to `PlayerData#battleTheme`.
|
||||
- Changed design of `BattleStartedPreEvent`. Will now expose the `PokemonBattle`.
|
||||
|
||||
### Datapack & Resourcepack Creators
|
||||
- Added 3 new item tags: `cobblemon:held/consumed_in_npc_battle`, `cobblemon:held/consumed_in_pvp_battle` & `cobblemon:held/consumed_in_wild_battle` these will determine which items get consumed in the implied battle types by Cobblemon, keep in mind the controller for this behaviour can be overriden by 3rd party.
|
||||
- Unique wild encounter themes can now be associated with a specific species (or form) by assigning a SoundEvent identifier to the `battleTheme` field in the species' data configuration.
|
||||
- Added a `structure` evolution condition, used to check if a Pokémon is in a given structure.
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
- French and Canadian French
|
||||
- Simplified and Traditional Chinese
|
||||
- Spanish and Mexican Spanish
|
||||
- Pirate English
|
||||
- German
|
||||
- Thai
|
||||
- Portuguese and Brazilian Portuguese
|
||||
- Polish
|
||||
- Italian
|
||||
- Dutch
|
||||
- Ukrainian
|
||||
- Russian
|
||||
|
||||
Thank you so much to all of our community translators that bring the mod to the rest of the world!
|
||||
|
||||
## [1.4.0 - The Friends and Farms Update (October 13th, 2023)](#1-4-0)
|
||||
### Additions
|
||||
@@ -872,17 +1027,17 @@
|
||||
- Fixed spawning in several biome tag categories.
|
||||
- Fixed resource pack support for Pokémon models and textures.
|
||||
- **Model Fixes**
|
||||
- Fixed Paras and Nidoqueen looking very weird.
|
||||
- Fixed Hitmonchan asserting dominance with a T-pose as well as Grimer and Muk pointing their hands to the sky.
|
||||
- Fixed specific Pokémon suddenly pausing their animation after staying still for a long time.
|
||||
- Fixed Mankey's feet being buried in the ground.
|
||||
- Updated the Substitute model and updated its shiny texture to be better for the red-green colorblind.
|
||||
- Improved Horsea, Seadra, and Kingdra animations, especially on land.
|
||||
- Fixed Paras and Nidoqueen looking very weird.
|
||||
- Fixed Hitmonchan asserting dominance with a T-pose as well as Grimer and Muk pointing their hands to the sky.
|
||||
- Fixed specific Pokémon suddenly pausing their animation after staying still for a long time.
|
||||
- Fixed Mankey's feet being buried in the ground.
|
||||
- Updated the Substitute model and updated its shiny texture to be better for the red-green colorblind.
|
||||
- Improved Horsea, Seadra, and Kingdra animations, especially on land.
|
||||
- **Battle Fixes**
|
||||
- Fixed an issue with battles where Pokémon had a different max HP causing some desync issues with the health bars.
|
||||
- Fixed Magnitude battle messages.
|
||||
- Moves that are disabled or out of PP now show transparently in the battle GUI instead of being hidden completely.
|
||||
- Statuses like sleep and frozen no longer last forever if it was carried over from a previous battle.
|
||||
- Fixed an issue with battles where Pokémon had a different max HP causing some desync issues with the health bars.
|
||||
- Fixed Magnitude battle messages.
|
||||
- Moves that are disabled or out of PP now show transparently in the battle GUI instead of being hidden completely.
|
||||
- Statuses like sleep and frozen no longer last forever if it was carried over from a previous battle.
|
||||
|
||||
### Localization
|
||||
- Added species, ability, and move translations for `ko_ko`, `jp_jp`, `fr_fr`, `es_es`, `it_it`, and `zh_cn`.
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
plugins {
|
||||
base
|
||||
id("cobblemon.root-conventions")
|
||||
id ("net.nemerosa.versioning") version "2.8.2"
|
||||
}
|
||||
|
||||
group = "com.cobblemon.mod"
|
||||
@@ -8,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"
|
||||
version = "$version-SNAPSHOT-${versioning.info.branch}-${versioning.info.build}"
|
||||
}
|
||||
@@ -33,6 +33,7 @@ dependencies {
|
||||
modApi(libs.molang)
|
||||
compileOnlyApi(libs.jeiApi)
|
||||
modCompileOnly(libs.adornFabric)
|
||||
modCompileOnly(libs.lambDynamicLights) { isTransitive = false }
|
||||
|
||||
// For Showdown
|
||||
modCompileOnly(libs.graal)
|
||||
|
||||
-3
@@ -8,12 +8,9 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pose;
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityModel;
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.RenderContext;
|
||||
import net.minecraft.client.render.VertexConsumer;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.entity.Entity;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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.compat;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonEntities;
|
||||
import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokemon.FormData;
|
||||
import com.cobblemon.mod.common.pokemon.lighthing.LightingData;
|
||||
import dev.lambdaurora.lambdynlights.api.DynamicLightHandler;
|
||||
import dev.lambdaurora.lambdynlights.api.DynamicLightHandlers;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.util.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
// Java class due to relying on entrypoint on Fabric side
|
||||
public class LambDynamicLightsCompat {
|
||||
|
||||
// This is all called on client side
|
||||
// These things are checked every tick so try to keep it as free as possible
|
||||
// That being said it's unlikely school Toshiba person is running dynamic lighting and shaders to enjoy this
|
||||
// Make sure not to call anything Fabric specific :)
|
||||
public static void hookCompat() {
|
||||
// Pokémon entities
|
||||
DynamicLightHandlers.registerDynamicLightHandler(
|
||||
CobblemonEntities.POKEMON,
|
||||
DynamicLightHandler.makeHandler(
|
||||
pokemon -> resolvedPokemonLightLevel(pokemon, false),
|
||||
pokemon -> true
|
||||
)
|
||||
);
|
||||
DynamicLightHandlers.registerDynamicLightHandler(
|
||||
CobblemonEntities.POKEMON,
|
||||
DynamicLightHandler.makeHandler(
|
||||
pokemon -> resolvedPokemonLightLevel(pokemon, true),
|
||||
pokemon -> false
|
||||
)
|
||||
);
|
||||
|
||||
// Shouldered Pokémon
|
||||
DynamicLightHandlers.registerDynamicLightHandler(
|
||||
EntityType.PLAYER,
|
||||
DynamicLightHandler.makeHandler(
|
||||
player -> resolvedShoulderLightLevel(player, false),
|
||||
player -> true
|
||||
)
|
||||
);
|
||||
DynamicLightHandlers.registerDynamicLightHandler(
|
||||
EntityType.PLAYER,
|
||||
DynamicLightHandler.makeHandler(
|
||||
player -> resolvedShoulderLightLevel(player, true),
|
||||
player -> false
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private static int resolvedPokemonLightLevel(PokemonEntity pokemon, boolean underwater) {
|
||||
return extractFormLightLevel(pokemon.getForm(), underwater).orElse(0);
|
||||
}
|
||||
|
||||
private static int resolvedShoulderLightLevel(PlayerEntity player, boolean underwater) {
|
||||
final Pair<PokemonOnShoulderRenderer.ShoulderData, PokemonOnShoulderRenderer.ShoulderData> shoulderDataPair = PokemonOnShoulderRenderer.shoulderDataOf(player);
|
||||
final Optional<Integer> leftLightLevel = extractShoulderLightLevel(shoulderDataPair.getLeft(), underwater);
|
||||
final Optional<Integer> rightLightLevel = extractShoulderLightLevel(shoulderDataPair.getRight(), underwater);
|
||||
return Math.max(leftLightLevel.orElse(0), rightLightLevel.orElse(0));
|
||||
}
|
||||
|
||||
private static Optional<Integer> extractFormLightLevel(@NotNull FormData form, boolean underwater) {
|
||||
if (form.getLightingData() == null || !liquidGlowModeSupport(form.getLightingData().getLiquidGlowMode(), underwater)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(form.getLightingData().getLightLevel());
|
||||
}
|
||||
|
||||
private static Optional<Integer> extractShoulderLightLevel(@Nullable PokemonOnShoulderRenderer.ShoulderData shoulderData, boolean underwater) {
|
||||
if (shoulderData == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return extractFormLightLevel(shoulderData.getForm(), underwater);
|
||||
}
|
||||
|
||||
private static boolean liquidGlowModeSupport(@NotNull LightingData.LiquidGlowMode liquidGlowMode, boolean underwater) {
|
||||
return underwater ? liquidGlowMode.getGlowsUnderwater() : liquidGlowMode.getGlowsInLand();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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.duck;
|
||||
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
import net.minecraft.util.Identifier;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface SoundManagerDuck {
|
||||
|
||||
void pauseSounds(@Nullable Identifier id, @Nullable SoundCategory category);
|
||||
|
||||
void resumeSounds(@Nullable Identifier id, @Nullable SoundCategory category);
|
||||
}
|
||||
@@ -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.duck;
|
||||
|
||||
import net.minecraft.client.sound.SoundInstance;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
import net.minecraft.util.Identifier;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface SoundSystemDuck {
|
||||
|
||||
void pauseSounds(@Nullable Identifier id, @Nullable SoundCategory category);
|
||||
|
||||
void resumeSounds(@Nullable Identifier id, @Nullable SoundCategory category);
|
||||
|
||||
Collection<SoundInstance> getSounds(@Nullable SoundCategory category);
|
||||
}
|
||||
@@ -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.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.sherds.CobblemonSherds;
|
||||
import net.minecraft.block.DecoratedPotPatterns;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.registry.RegistryKey;
|
||||
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.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(DecoratedPotPatterns.class)
|
||||
public abstract class DecoratedPotPatternsMixin {
|
||||
@Inject(method = "fromSherd", at=@At("HEAD"), cancellable = true)
|
||||
private static void cobblemon$getCobblemonSherdTexture(Item sherd,
|
||||
CallbackInfoReturnable<RegistryKey<String>> cir) {
|
||||
if (CobblemonSherds.INSTANCE.getSherdToPattern().containsKey(sherd)) {
|
||||
cir.setReturnValue(CobblemonSherds.INSTANCE.getSherdToPattern().get(sherd));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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 net.minecraft.entity.passive.VillagerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.village.VillagerProfession;
|
||||
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.CallbackInfoReturnable;
|
||||
import com.cobblemon.mod.common.villager.VillagerGatherableItems;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@Mixin(VillagerEntity.class)
|
||||
public abstract class EntityVillagerMixin {
|
||||
|
||||
@Inject(method = "canGather", at = @At(value = "RETURN"), cancellable = true)
|
||||
private void cobblemon$canGather(ItemStack stack, CallbackInfoReturnable<Boolean> ci) {
|
||||
final VillagerEntity villager = (VillagerEntity) (Object) this;
|
||||
if(ci.getReturnValue() == false && Objects.equals(villager.getVillagerData().getProfession(), VillagerProfession.FARMER) && villager.getInventory().canInsert(stack)) {
|
||||
if(VillagerGatherableItems.INSTANCE.getVillagerGatherableItems().contains(stack.getItem()))
|
||||
ci.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,20 +8,37 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.api.scheduling.ScheduledTaskTracker;
|
||||
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.render.GameRenderer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(GameRenderer.class)
|
||||
public class GameRendererMixin {
|
||||
@Unique
|
||||
long lastTime = -1;
|
||||
|
||||
@Inject(
|
||||
method = "render",
|
||||
at = @At(value = "TAIL")
|
||||
)
|
||||
public void render(float tickDelta, long startTime, boolean tick, CallbackInfo ci) {
|
||||
ScheduledTaskTracker.INSTANCE.update();
|
||||
MinecraftClient client = MinecraftClient.getInstance();
|
||||
long newTime = System.currentTimeMillis();
|
||||
// Don't play scheduled animations when the game is paused
|
||||
if (client.isPaused()) {
|
||||
lastTime = newTime;
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastTime != -1) {
|
||||
ClientTaskTracker.INSTANCE.update((newTime - lastTime) / 1000F);
|
||||
}
|
||||
lastTime = newTime;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.client.CobblemonBakingOverrides;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import net.minecraft.client.color.block.BlockColors;
|
||||
import net.minecraft.client.render.model.ModelLoader;
|
||||
import net.minecraft.client.render.model.UnbakedModel;
|
||||
import net.minecraft.client.render.model.json.JsonUnbakedModel;
|
||||
import net.minecraft.client.util.ModelIdentifier;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.profiler.Profiler;
|
||||
import org.slf4j.Logger;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
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.InjectionPoint;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.points.BeforeStringInvoke;
|
||||
|
||||
@Mixin(ModelLoader.class)
|
||||
public abstract class ModelLoaderMixin {
|
||||
|
||||
@Shadow protected abstract void addModel(ModelIdentifier modelId);
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private Map<Identifier, UnbakedModel> unbakedModels;
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private static Logger LOGGER;
|
||||
|
||||
@Inject(
|
||||
method = "<init>",
|
||||
at = @At("TAIL")
|
||||
)
|
||||
public void init(BlockColors blockColors,
|
||||
Profiler profiler,
|
||||
Map jsonUnbakedModels,
|
||||
Map blockStates,
|
||||
CallbackInfo ci) {
|
||||
CobblemonBakingOverrides.INSTANCE.getModels().forEach(bakingOverride -> {
|
||||
try {
|
||||
this.unbakedModels.put(bakingOverride.getModelIdentifier(), this.loadModelFromJson(bakingOverride.getModelLocation()));
|
||||
this.addModel(bakingOverride.getModelIdentifier());
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Error loading a Cobblemon BakedModel:", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Shadow
|
||||
private JsonUnbakedModel loadModelFromJson(Identifier id) throws IOException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -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.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.client.sound.battle.BattleMusicController;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.sound.MusicTracker;
|
||||
import net.minecraft.client.sound.SoundInstance;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
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.callback.CallbackInfo;
|
||||
|
||||
@Mixin(MusicTracker.class)
|
||||
public class MusicTrackerMixin {
|
||||
|
||||
@Shadow @Final
|
||||
private MinecraftClient client;
|
||||
|
||||
@Shadow @Nullable
|
||||
private SoundInstance current;
|
||||
|
||||
/** Freezes the tracker while a BattleMusicInstance is in progress. Current SoundInstance being tracked will be paused by BattleMusicHandler. */
|
||||
@Inject(method = "tick()V", at = @At("HEAD"), cancellable = true)
|
||||
public void tick(CallbackInfo cb) {
|
||||
if (this.client.getSoundManager().isPlaying(BattleMusicController.INSTANCE.getMusic())) cb.cancel();
|
||||
}
|
||||
}
|
||||
@@ -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.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.api.snowstorm.ParticleMaterials;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import net.minecraft.client.particle.ParticleManager;
|
||||
import net.minecraft.client.particle.ParticleTextureSheet;
|
||||
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.callback.CallbackInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(ParticleManager.class)
|
||||
final class ParticleManagerMixin {
|
||||
@Mutable
|
||||
@Final
|
||||
@Shadow
|
||||
private static List<ParticleTextureSheet> PARTICLE_TEXTURE_SHEETS;
|
||||
|
||||
@Inject(at = @At("RETURN"), method = "<clinit>")
|
||||
private static void lodestone$addTypes(CallbackInfo ci) {
|
||||
PARTICLE_TEXTURE_SHEETS = ImmutableList.<ParticleTextureSheet>builder().addAll(PARTICLE_TEXTURE_SHEETS)
|
||||
.add(ParticleMaterials.INSTANCE.getADD(), ParticleMaterials.INSTANCE.getALPHA(), ParticleMaterials.INSTANCE.getBLEND(), ParticleMaterials.INSTANCE.getOPAQUE()).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.CobblemonItems;
|
||||
import net.minecraft.entity.mob.PiglinBrain;
|
||||
import net.minecraft.item.ItemStack;
|
||||
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.CallbackInfoReturnable;
|
||||
|
||||
|
||||
@Mixin(PiglinBrain.class)
|
||||
public class PiglinBarterMixin {
|
||||
|
||||
@Inject(method = "acceptsForBarter", at = @At(value = "RETURN"), cancellable = true)
|
||||
private static void cobblemon$acceptsForBarter(ItemStack stack, CallbackInfoReturnable<Boolean> ci) {
|
||||
if(!ci.getReturnValue()) {
|
||||
//TODO: Make a tag?
|
||||
if(stack.isOf(CobblemonItems.RELIC_COIN_POUCH))
|
||||
ci.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.CobblemonItems;
|
||||
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;
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.api.events.CobblemonEvents;
|
||||
import com.cobblemon.mod.common.api.events.item.LeftoversCreatedEvent;
|
||||
import com.cobblemon.mod.common.api.storage.NoPokemonStoreException;
|
||||
import com.cobblemon.mod.common.api.storage.party.PartyStore;
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags;
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon;
|
||||
import com.cobblemon.mod.common.util.CompoundTagExtensionsKt;
|
||||
import com.cobblemon.mod.common.util.DataKeys;
|
||||
@@ -22,11 +23,8 @@ import net.minecraft.entity.ItemEntity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.sound.SoundEvent;
|
||||
import net.minecraft.sound.SoundEvents;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.world.World;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
@@ -40,8 +38,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.cobblemon.mod.common.util.LocalizationUtilsKt.lang;
|
||||
|
||||
@Mixin(PlayerEntity.class)
|
||||
public abstract class PlayerMixin extends LivingEntity {
|
||||
|
||||
@@ -144,7 +140,7 @@ public abstract class PlayerMixin extends LivingEntity {
|
||||
)
|
||||
public void onEatFood(World world, ItemStack stack, CallbackInfoReturnable<ItemStack> cir) {
|
||||
if (!getWorld().isClient) {
|
||||
if (stack.getItem() == Items.APPLE && getWorld().random.nextDouble() < Cobblemon.config.getAppleLeftoversChance()) {
|
||||
if (stack.isIn(CobblemonItemTags.LEAVES_LEFTOVERS) && getWorld().random.nextDouble() < Cobblemon.config.getAppleLeftoversChance()) {
|
||||
ItemStack leftovers = new ItemStack(CobblemonItems.LEFTOVERS);
|
||||
ServerPlayerEntity player = Objects.requireNonNull(getServer()).getPlayerManager().getPlayer(uuid);
|
||||
assert player != null;
|
||||
|
||||
@@ -8,36 +8,77 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.access.SoundManagerDuck;
|
||||
import net.minecraft.client.sound.SoundInstance;
|
||||
import net.minecraft.client.sound.SoundManager;
|
||||
import com.cobblemon.mod.common.client.sound.battle.BattleMusicController;
|
||||
import com.cobblemon.mod.common.duck.SoundManagerDuck;
|
||||
import com.cobblemon.mod.common.duck.SoundSystemDuck;
|
||||
import net.minecraft.client.sound.*;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
import net.minecraft.util.Identifier;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
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.callback.CallbackInfo;
|
||||
|
||||
@Mixin(SoundManager.class)
|
||||
public class SoundManagerMixin implements SoundManagerDuck {
|
||||
public abstract class SoundManagerMixin implements SoundManagerDuck {
|
||||
|
||||
private boolean[] blockedCategories = new boolean[SoundCategory.values().length];
|
||||
@Shadow
|
||||
public abstract boolean isPlaying(SoundInstance sound);
|
||||
|
||||
@Override
|
||||
public void toggleCategories(SoundCategory... categories) {
|
||||
for (SoundCategory category : categories) {
|
||||
int index = category.ordinal();
|
||||
boolean blocked = blockedCategories[index];
|
||||
blockedCategories[index] = !blocked;
|
||||
}
|
||||
@Shadow @Final
|
||||
private SoundSystem soundSystem;
|
||||
|
||||
// Never-ending ambient loops are a special exception (they are only initiated once) and should always be paused if filtered.
|
||||
private boolean isAmbientLoop(SoundInstance sound) {
|
||||
return sound instanceof BiomeEffectSoundPlayer.MusicLoop || sound instanceof AmbientSoundLoops.Underwater;
|
||||
}
|
||||
|
||||
private boolean filterCondition(SoundInstance sound) {
|
||||
return !isAmbientLoop(sound) &&
|
||||
this.isPlaying(BattleMusicController.INSTANCE.getMusic()) &&
|
||||
BattleMusicController.INSTANCE.getFilteredCategories().contains(sound.getCategory());
|
||||
}
|
||||
|
||||
private boolean ambientLoopCondition(SoundInstance sound) {
|
||||
return isAmbientLoop(sound) &&
|
||||
this.isPlaying(BattleMusicController.INSTANCE.getMusic()) &&
|
||||
BattleMusicController.INSTANCE.getFilteredCategories().contains(sound.getCategory());
|
||||
}
|
||||
|
||||
/** Pauses the queried SoundInstance(s). If id is null, will pause all sounds belonging to the SoundCategory. */
|
||||
@Override
|
||||
public void pauseSounds(@Nullable Identifier id, @Nullable SoundCategory category) {
|
||||
((SoundSystemDuck)soundSystem).pauseSounds(id, category);
|
||||
}
|
||||
|
||||
/** Resumes the queried SoundInstance(s). If id is null, will resume all sounds belonging to the SoundCategory. */
|
||||
@Override
|
||||
public void resumeSounds(@Nullable Identifier id, @Nullable SoundCategory category) {
|
||||
((SoundSystemDuck)soundSystem).resumeSounds(id, category);
|
||||
}
|
||||
|
||||
/** Blocks filtered sounds from being played while a BattleMusicInstance is in progress. */
|
||||
@Inject(method = "play(Lnet/minecraft/client/sound/SoundInstance;)V", at = @At("HEAD"), cancellable = true)
|
||||
public void play(SoundInstance sound, CallbackInfo cb) {
|
||||
if (blockedCategories[sound.getCategory().ordinal()]) cb.cancel();
|
||||
public void playStart(SoundInstance sound, CallbackInfo cb) {
|
||||
if (filterCondition(sound)) cb.cancel();
|
||||
}
|
||||
|
||||
@Inject(method = "play(Lnet/minecraft/client/sound/SoundInstance;I)V", at = @At("HEAD"), cancellable = true)
|
||||
public void play(SoundInstance sound, int delay, CallbackInfo cb) {
|
||||
if (blockedCategories[sound.getCategory().ordinal()]) cb.cancel();
|
||||
public void playStart(SoundInstance sound, int delay, CallbackInfo cb) {
|
||||
if (filterCondition(sound)) cb.cancel();
|
||||
}
|
||||
|
||||
/** Pauses ambient loops while a BattleMusicInstance is in progress. */
|
||||
@Inject(method = "play(Lnet/minecraft/client/sound/SoundInstance;)V", at = @At("TAIL"))
|
||||
public void playEnd(SoundInstance sound, CallbackInfo cb) {
|
||||
if (ambientLoopCondition(sound)) this.pauseSounds(sound.getId(), SoundCategory.AMBIENT);
|
||||
}
|
||||
|
||||
@Inject(method = "play(Lnet/minecraft/client/sound/SoundInstance;I)V", at = @At("TAIL"))
|
||||
public void playEnd(SoundInstance sound, int delay, CallbackInfo cb) {
|
||||
if (ambientLoopCondition(sound)) this.pauseSounds(sound.getId(), SoundCategory.AMBIENT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,31 +8,102 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.client.sound.battle.BattleMusicController;
|
||||
import com.cobblemon.mod.common.duck.SoundSystemDuck;
|
||||
import com.google.common.collect.Multimap;
|
||||
import net.minecraft.client.sound.SoundInstance;
|
||||
import net.minecraft.client.sound.SoundSystem;
|
||||
import net.minecraft.client.sound.*;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
import net.minecraft.util.Identifier;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
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.callback.CallbackInfo;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(SoundSystem.class)
|
||||
public abstract class SoundSystemMixin {
|
||||
public abstract class SoundSystemMixin implements SoundSystemDuck {
|
||||
|
||||
@Shadow
|
||||
private boolean started;
|
||||
|
||||
@Shadow
|
||||
private Multimap<SoundCategory, SoundInstance> sounds;
|
||||
|
||||
@Shadow @Final
|
||||
private Map<SoundInstance, Channel.SourceManager> sources;
|
||||
|
||||
@Shadow
|
||||
protected abstract void stop(SoundInstance sound);
|
||||
|
||||
@Shadow
|
||||
public abstract boolean isPlaying(SoundInstance sound);
|
||||
|
||||
/** Resumes the Source belonging to the queried SoundInstance. */
|
||||
private void resume(SoundInstance sound) {
|
||||
Channel.SourceManager sourceManager = this.sources.get(sound);
|
||||
if (this.started && sourceManager != null) sourceManager.run(Source::resume);
|
||||
}
|
||||
|
||||
/** Pauses the Source belonging to the queried SoundInstance. */
|
||||
private void pause(SoundInstance sound) {
|
||||
Channel.SourceManager sourceManager = this.sources.get(sound);
|
||||
if (this.started && sourceManager != null) sourceManager.run(Source::pause);
|
||||
}
|
||||
|
||||
/** Resumes the SoundInstance(s) queried by id and/or category. */
|
||||
@Override
|
||||
public void resumeSounds(@Nullable Identifier id, @Nullable SoundCategory category) {
|
||||
if (category != null) {
|
||||
this.sounds.get(category).forEach((sound) -> {
|
||||
if (id == null || sound.getId().equals(id)) resume(sound);
|
||||
});
|
||||
} else if (id == null) {
|
||||
this.sources.keySet().forEach(this::resume);
|
||||
} else {
|
||||
this.sources.keySet().forEach(sound -> {
|
||||
if (sound.getId().equals(id)) resume(sound);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Pauses the SoundInstances queried by id and/or category. */
|
||||
@Override
|
||||
public void pauseSounds(@Nullable Identifier id, @Nullable SoundCategory category) {
|
||||
if (category != null) {
|
||||
this.sounds.get(category).forEach((sound) -> {
|
||||
if (id == null || sound.getId().equals(id)) pause(sound);
|
||||
});
|
||||
} else if (id == null) {
|
||||
this.sources.keySet().forEach(this::pause);
|
||||
} else {
|
||||
this.sources.keySet().forEach(sound -> {
|
||||
if (sound.getId().equals(id)) pause(sound);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Allows stopping all SoundInstances that belong to a queried category. */
|
||||
@Inject(method = "stopSounds(Lnet/minecraft/util/Identifier;Lnet/minecraft/sound/SoundCategory;)V", at = @At("HEAD"), cancellable = true)
|
||||
public void stopSounds(@Nullable Identifier id, @Nullable SoundCategory category, CallbackInfo cb) {
|
||||
if (id == null && category != null) {
|
||||
sounds.get(category).forEach(this::stop);
|
||||
this.sounds.get(category).forEach(this::stop);
|
||||
cb.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
/** Different behavior for resuming SoundInstances while a BattleMusicInstance is being played. We do not want to resume filtered sounds. */
|
||||
@Inject(method = "resumeAll()V", at = @At("HEAD"), cancellable = true)
|
||||
public void resumeAll(CallbackInfo cb) {
|
||||
if (this.isPlaying(BattleMusicController.INSTANCE.getMusic())) {
|
||||
this.sounds.values().forEach(sound -> {
|
||||
if (sound == BattleMusicController.INSTANCE.getMusic() || !BattleMusicController.INSTANCE.getFilteredCategories().contains(sound.getCategory())) {
|
||||
resume(sound);
|
||||
}
|
||||
});
|
||||
cb.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
-22
@@ -1,22 +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.mixin.accessor;
|
||||
|
||||
import net.minecraft.client.sound.MusicTracker;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(MusicTracker.class)
|
||||
public interface MusicTrackerAccessor {
|
||||
@Accessor("timeUntilNextSong")
|
||||
int timeUntilNextSong();
|
||||
|
||||
@Accessor("timeUntilNextSong")
|
||||
void setTimeUntilNextSong(int timeUntilNextSong);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.render.model.BakedModel
|
||||
import net.minecraft.client.util.ModelIdentifier
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* Contains information for forcing a model to be baked
|
||||
*
|
||||
* @param modelLocation The location of the model
|
||||
* @param modelIdentifier The identifier that the BakedModel will be registered to
|
||||
*/
|
||||
data class BakingOverride(
|
||||
val modelLocation: Identifier,
|
||||
val modelIdentifier: ModelIdentifier
|
||||
) {
|
||||
fun getModel(): BakedModel {
|
||||
return MinecraftClient.getInstance().bakedModelManager.getModel(modelIdentifier)
|
||||
}
|
||||
}
|
||||
@@ -19,9 +19,11 @@ import com.cobblemon.mod.common.api.drop.ItemDropEntry
|
||||
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
|
||||
import com.cobblemon.mod.common.api.net.serializers.IdentifierDataSerializer
|
||||
import com.cobblemon.mod.common.api.net.serializers.PoseTypeDataSerializer
|
||||
import com.cobblemon.mod.common.api.net.serializers.StringSetDataSerializer
|
||||
import com.cobblemon.mod.common.api.net.serializers.Vec3DataSerializer
|
||||
@@ -33,15 +35,14 @@ 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.ChoiceSpeciesFeatureProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.FlagSpeciesFeatureProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.SpeciesFeatures
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.*
|
||||
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
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.StatProvider
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
|
||||
import com.cobblemon.mod.common.api.scheduling.ScheduledTaskTracker
|
||||
import com.cobblemon.mod.common.api.scheduling.ServerRealTimeTaskTracker
|
||||
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
|
||||
import com.cobblemon.mod.common.api.spawning.BestSpawner
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawningProspector
|
||||
import com.cobblemon.mod.common.api.spawning.context.AreaContextResolver
|
||||
@@ -54,6 +55,7 @@ import com.cobblemon.mod.common.api.storage.adapter.flatfile.FileStoreAdapter
|
||||
import com.cobblemon.mod.common.api.storage.adapter.flatfile.JSONStoreAdapter
|
||||
import com.cobblemon.mod.common.api.storage.adapter.flatfile.NBTStoreAdapter
|
||||
import com.cobblemon.mod.common.api.storage.factory.FileBackedPokemonStoreFactory
|
||||
import com.cobblemon.mod.common.api.storage.molang.NbtMoLangDataStoreFactory
|
||||
import com.cobblemon.mod.common.api.storage.pc.PCStore
|
||||
import com.cobblemon.mod.common.api.storage.pc.link.PCLinkManager
|
||||
import com.cobblemon.mod.common.api.storage.player.PlayerDataStoreManager
|
||||
@@ -67,6 +69,7 @@ import com.cobblemon.mod.common.battles.BattleSide
|
||||
import com.cobblemon.mod.common.battles.ShowdownThread
|
||||
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.command.argument.DialogueArgumentType
|
||||
import com.cobblemon.mod.common.command.argument.MoveArgumentType
|
||||
import com.cobblemon.mod.common.command.argument.PartySlotArgumentType
|
||||
import com.cobblemon.mod.common.command.argument.PokemonArgumentType
|
||||
@@ -90,10 +93,12 @@ 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
|
||||
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
|
||||
import com.cobblemon.mod.common.sherds.CobblemonSherds
|
||||
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
|
||||
import com.cobblemon.mod.common.trade.TradeManager
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
@@ -125,6 +130,7 @@ 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
|
||||
@@ -153,6 +159,7 @@ object Cobblemon {
|
||||
val bestSpawner = BestSpawner
|
||||
val battleRegistry = BattleRegistry
|
||||
var storage = PokemonStoreManager()
|
||||
var molangData = NbtMoLangDataStoreFactory
|
||||
lateinit var playerData: PlayerDataStoreManager
|
||||
lateinit var starterConfig: StarterConfig
|
||||
val dataProvider: DataProvider = CobblemonDataProvider
|
||||
@@ -231,6 +238,7 @@ object Cobblemon {
|
||||
TrackedDataHandlerRegistry.register(Vec3DataSerializer)
|
||||
TrackedDataHandlerRegistry.register(StringSetDataSerializer)
|
||||
TrackedDataHandlerRegistry.register(PoseTypeDataSerializer)
|
||||
TrackedDataHandlerRegistry.register(IdentifierDataSerializer)
|
||||
|
||||
HeldItemProvider.register(CobblemonHeldItemManager, Priority.LOWEST)
|
||||
}
|
||||
@@ -246,6 +254,7 @@ object Cobblemon {
|
||||
|
||||
SpeciesFeatures.types["choice"] = ChoiceSpeciesFeatureProvider::class.java
|
||||
SpeciesFeatures.types["flag"] = FlagSpeciesFeatureProvider::class.java
|
||||
SpeciesFeatures.types["integer"] = IntSpeciesFeatureProvider::class.java
|
||||
|
||||
SpeciesFeatures.register(
|
||||
DataKeys.CAN_BE_MILKED,
|
||||
@@ -260,9 +269,15 @@ object Cobblemon {
|
||||
|
||||
ifDedicatedServer {
|
||||
isDedicatedServer = true
|
||||
PlatformEvents.SERVER_TICK_POST.subscribe { ScheduledTaskTracker.update() }
|
||||
}
|
||||
|
||||
PlatformEvents.SERVER_TICK_POST.subscribe {
|
||||
ServerTaskTracker.update(1/20F)
|
||||
ServerRealTimeTaskTracker.update()
|
||||
}
|
||||
PlatformEvents.SERVER_TICK_PRE.subscribe {
|
||||
ServerRealTimeTaskTracker.update()
|
||||
}
|
||||
PlatformEvents.SERVER_STARTING.subscribe { event ->
|
||||
val server = event.server
|
||||
playerData = PlayerDataStoreManager().also { it.setup(server) }
|
||||
@@ -371,9 +386,12 @@ object Cobblemon {
|
||||
battleRegistry.startBattle(
|
||||
BattleFormat.GEN_9_SINGLES,
|
||||
BattleSide(PokemonBattleActor(UUID.randomUUID(), BattlePokemon(Pokemon().initialize()), -1F)),
|
||||
BattleSide(PokemonBattleActor(UUID.randomUUID(), BattlePokemon(Pokemon().initialize()), -1F))
|
||||
).apply { mute = true }
|
||||
BattleSide(PokemonBattleActor(UUID.randomUUID(), BattlePokemon(Pokemon().initialize()), -1F)),
|
||||
true
|
||||
).ifSuccessful { it.mute = true }
|
||||
}
|
||||
|
||||
CobblemonSherds.registerSherds()
|
||||
}
|
||||
|
||||
fun getLevel(dimension: RegistryKey<World>): World? {
|
||||
@@ -477,6 +495,7 @@ object Cobblemon {
|
||||
this.implementation.registerCommandArgument(cobblemonResource("move"), MoveArgumentType::class, ConstantArgumentSerializer.of(MoveArgumentType::move))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("party_slot"), PartySlotArgumentType::class, ConstantArgumentSerializer.of(PartySlotArgumentType::partySlot))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("pokemon_store"), PokemonStoreArgumentType::class, ConstantArgumentSerializer.of(PokemonStoreArgumentType::pokemonStore))
|
||||
this.implementation.registerCommandArgument(cobblemonResource("dialogue"), DialogueArgumentType::class, ConstantArgumentSerializer.of(DialogueArgumentType::dialogue))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import net.minecraft.entity.ai.brain.Activity
|
||||
|
||||
object CobblemonActivities {
|
||||
val activities = mutableListOf<Activity>()
|
||||
val BATTLING_ACTIVITY = Activity("pokemon_battling")
|
||||
|
||||
fun register(activity: Activity): Activity {
|
||||
activities.add(activity)
|
||||
return activity
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,14 @@
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.block.entity.BerryBlockEntity
|
||||
import com.cobblemon.mod.common.block.entity.HealingMachineBlockEntity
|
||||
import com.cobblemon.mod.common.block.entity.PCBlockEntity
|
||||
import com.cobblemon.mod.common.block.entity.PokemonPastureBlockEntity
|
||||
import com.cobblemon.mod.common.block.entity.FossilAnalyzerBlockEntity
|
||||
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.platform.PlatformRegistry
|
||||
import net.minecraft.block.entity.BlockEntityType
|
||||
@@ -23,9 +31,13 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
|
||||
|
||||
@JvmField
|
||||
val HEALING_MACHINE: BlockEntityType<HealingMachineBlockEntity> = this.create("healing_machine", BlockEntityType.Builder.create(::HealingMachineBlockEntity, CobblemonBlocks.HEALING_MACHINE).build(null))
|
||||
|
||||
@JvmField
|
||||
val PC: BlockEntityType<PCBlockEntity> = this.create("pc", BlockEntityType.Builder.create(::PCBlockEntity, CobblemonBlocks.PC).build(null))
|
||||
|
||||
@JvmField
|
||||
val BERRY = this.create("berry", BlockEntityType.Builder.create(::BerryBlockEntity, *CobblemonBlocks.berries().values.toTypedArray()).build(null))
|
||||
|
||||
@JvmField
|
||||
val PASTURE: BlockEntityType<PokemonPastureBlockEntity> = this.create("pasture", BlockEntityType.Builder.create(::PokemonPastureBlockEntity, CobblemonBlocks.PASTURE).build(null))
|
||||
@JvmField
|
||||
@@ -33,4 +45,36 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
|
||||
@JvmField
|
||||
val HANGING_SIGN: BlockEntityType<CobblemonHangingSignBlockEntity> = this.create("hanging_sign", BlockEntityType.Builder.create(::CobblemonHangingSignBlockEntity, CobblemonBlocks.APRICORN_HANGING_SIGN, CobblemonBlocks.APRICORN_WALL_HANGING_SIGN).build(null))
|
||||
|
||||
}
|
||||
@JvmField
|
||||
val GILDED_CHEST: BlockEntityType<GildedChestBlockEntity> = this.create("chest", BlockEntityType.Builder.create(::GildedChestBlockEntity,
|
||||
CobblemonBlocks.GILDED_CHEST,
|
||||
CobblemonBlocks.BLUE_GILDED_CHEST,
|
||||
CobblemonBlocks.YELLOW_GILDED_CHEST,
|
||||
CobblemonBlocks.PINK_GILDED_CHEST,
|
||||
CobblemonBlocks.BLACK_GILDED_CHEST,
|
||||
CobblemonBlocks.WHITE_GILDED_CHEST,
|
||||
CobblemonBlocks.GREEN_GILDED_CHEST,
|
||||
CobblemonBlocks.GIMMIGHOUL_CHEST
|
||||
).build(null))
|
||||
|
||||
@JvmField
|
||||
val FOSSIL_MULTIBLOCK: BlockEntityType<FossilMultiblockEntity> = this.create("fossil_multiblock",
|
||||
BlockEntityType.Builder.create({ pos, state -> FossilMultiblockEntity(pos, state, FossilMultiblockBuilder(pos)) },
|
||||
CobblemonBlocks.MONITOR
|
||||
).build(null)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val RESTORATION_TANK: BlockEntityType<RestorationTankBlockEntity> = this.create("restoration_tank",
|
||||
BlockEntityType.Builder.create({ pos, state -> RestorationTankBlockEntity(pos, state, FossilMultiblockBuilder(pos)) },
|
||||
CobblemonBlocks.RESTORATION_TANK
|
||||
).build(null)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val FOSSIL_ANALYZER: BlockEntityType<FossilAnalyzerBlockEntity> = this.create("fossil_analyzer",
|
||||
BlockEntityType.Builder.create({ pos, state -> FossilAnalyzerBlockEntity(pos, state, FossilMultiblockBuilder(pos)) },
|
||||
CobblemonBlocks.FOSSIL_ANALYZER
|
||||
).build(null)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@ package com.cobblemon.mod.common
|
||||
import com.cobblemon.mod.common.api.apricorn.Apricorn
|
||||
import com.cobblemon.mod.common.block.*
|
||||
import com.cobblemon.mod.common.block.MintBlock.MintType
|
||||
import com.cobblemon.mod.common.block.FossilAnalyzerBlock
|
||||
import com.cobblemon.mod.common.block.MonitorBlock
|
||||
import com.cobblemon.mod.common.block.RestorationTankBlock
|
||||
import com.cobblemon.mod.common.mixin.invoker.DoorBlockInvoker
|
||||
import com.cobblemon.mod.common.mixin.invoker.PressurePlateBlockInvoker
|
||||
import com.cobblemon.mod.common.mixin.invoker.StairsBlockInvoker
|
||||
@@ -19,11 +22,13 @@ import com.cobblemon.mod.common.mixin.invoker.*
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.block.BerryBlock
|
||||
import com.cobblemon.mod.common.block.chest.GildedChestBlock
|
||||
import com.cobblemon.mod.common.block.sign.CobblemonHangingSignBlock
|
||||
import com.cobblemon.mod.common.block.sign.CobblemonSignBlock
|
||||
import com.cobblemon.mod.common.block.sign.CobblemonWallHangingSignBlock
|
||||
import com.cobblemon.mod.common.block.sign.CobblemonWallSignBlock
|
||||
import net.minecraft.block.*
|
||||
import net.minecraft.block.enums.Instrument
|
||||
import net.minecraft.block.piston.PistonBehavior
|
||||
import net.minecraft.entity.effect.StatusEffects
|
||||
import net.minecraft.registry.Registries
|
||||
@@ -53,6 +58,8 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
@JvmField
|
||||
val FIRE_STONE_ORE = evolutionStoneOre("fire_stone_ore")
|
||||
@JvmField
|
||||
val NETHER_FIRE_STONE_ORE = evolutionStoneOre("nether_fire_stone_ore")
|
||||
@JvmField
|
||||
val ICE_STONE_ORE = evolutionStoneOre("ice_stone_ore")
|
||||
@JvmField
|
||||
val LEAF_STONE_ORE = evolutionStoneOre("leaf_stone_ore")
|
||||
@@ -100,17 +107,17 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
@JvmField
|
||||
val STRIPPED_APRICORN_WOOD = log("stripped_apricorn_wood")
|
||||
@JvmField
|
||||
val APRICORN_PLANKS = this.create("apricorn_planks", Block(AbstractBlock.Settings.create().mapColor(MapColor.DIRT_BROWN).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
|
||||
val APRICORN_PLANKS = this.create("apricorn_planks", Block(AbstractBlock.Settings.create().mapColor(MapColor.DIRT_BROWN).instrument(Instrument.BASS).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
|
||||
@JvmField
|
||||
val APRICORN_LEAVES = leaves("apricorn_leaves")
|
||||
@JvmField
|
||||
val APRICORN_FENCE = this.create("apricorn_fence", FenceBlock(AbstractBlock.Settings.create().mapColor(APRICORN_PLANKS.defaultMapColor).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
|
||||
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).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD), APRICORN_WOOD_TYPE))
|
||||
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))
|
||||
@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).noCollision().strength(0.5f).sounds(BlockSoundGroup.WOOD), APRICORN_BLOCK_SET_TYPE))
|
||||
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))
|
||||
@JvmField
|
||||
val APRICORN_SIGN = this.create("apricorn_sign", CobblemonSignBlock(AbstractBlock.Settings.copy(Blocks.OAK_SIGN), APRICORN_WOOD_TYPE))
|
||||
@JvmField
|
||||
@@ -120,13 +127,13 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
@JvmField
|
||||
val APRICORN_WALL_HANGING_SIGN = this.create("apricorn_wall_hanging_sign", CobblemonWallHangingSignBlock(AbstractBlock.Settings.copy(Blocks.OAK_HANGING_SIGN), APRICORN_WOOD_TYPE))
|
||||
@JvmField
|
||||
val APRICORN_SLAB = this.create("apricorn_slab", SlabBlock(AbstractBlock.Settings.create().mapColor(MapColor.OAK_TAN).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
|
||||
val APRICORN_SLAB = this.create("apricorn_slab", SlabBlock(AbstractBlock.Settings.create().mapColor(MapColor.OAK_TAN).instrument(Instrument.BASS).strength(2.0f, 3.0f).sounds(BlockSoundGroup.WOOD)))
|
||||
@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).strength(3.0F).sounds(BlockSoundGroup.WOOD).nonOpaque(), APRICORN_BLOCK_SET_TYPE))
|
||||
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))
|
||||
@JvmField
|
||||
val APRICORN_TRAPDOOR = this.create("apricorn_trapdoor", TrapdoorBlockInvoker.`cobblemon$create`(AbstractBlock.Settings.create().mapColor(MapColor.OAK_TAN).strength(3.0F).sounds(BlockSoundGroup.WOOD).nonOpaque().allowsSpawning { _, _, _, _ -> false }, APRICORN_BLOCK_SET_TYPE))
|
||||
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))
|
||||
|
||||
private val PLANT_PROPERTIES = AbstractBlock.Settings.create().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.GRASS).pistonBehavior(PistonBehavior.DESTROY)
|
||||
@JvmField
|
||||
@@ -145,14 +152,66 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
val YELLOW_APRICORN_SAPLING = this.create("yellow_apricorn_sapling", ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.YELLOW))
|
||||
|
||||
@JvmField
|
||||
val MEDICINAL_LEEK = this.create("medicinal_leek", MedicinalLeekBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DULL_RED).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
||||
val MEDICINAL_LEEK = this.create("medicinal_leek", MedicinalLeekBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DULL_RED).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MEDICINAL_LEEK_SOUNDS)))
|
||||
@JvmField
|
||||
val ENERGY_ROOT = this.create("energy_root", EnergyRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DIRT_BROWN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.ROOTS)))
|
||||
val ENERGY_ROOT = this.create("energy_root", EnergyRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DIRT_BROWN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.ENERGY_ROOT_SOUNDS)))
|
||||
@JvmField
|
||||
val BIG_ROOT = this.create("big_root", BigRootBlock(AbstractBlock.Settings.create().pistonBehavior(PistonBehavior.DESTROY).burnable().mapColor(MapColor.DARK_GREEN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.ROOTS)))
|
||||
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)))
|
||||
|
||||
@JvmField
|
||||
val TUMBLESTONE_CLUSTER = tumblestoneBlock("tumblestone_cluster", GrowableStoneBlock.STAGE_3, 7, 3, null)
|
||||
@JvmField
|
||||
val LARGE_BUDDING_TUMBLESTONE = tumblestoneBlock("large_budding_tumblestone", GrowableStoneBlock.STAGE_2, 5, 3, TUMBLESTONE_CLUSTER)
|
||||
@JvmField
|
||||
val MEDIUM_BUDDING_TUMBLESTONE = tumblestoneBlock("medium_budding_tumblestone", GrowableStoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_TUMBLESTONE)
|
||||
@JvmField
|
||||
val SMALL_BUDDING_TUMBLESTONE = tumblestoneBlock("small_budding_tumblestone", GrowableStoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_TUMBLESTONE)
|
||||
|
||||
@JvmField
|
||||
val SKY_TUMBLESTONE_CLUSTER = tumblestoneBlock("sky_tumblestone_cluster", GrowableStoneBlock.STAGE_3, 7, 3, null)
|
||||
@JvmField
|
||||
val LARGE_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("large_budding_sky_tumblestone", GrowableStoneBlock.STAGE_2, 5, 3, SKY_TUMBLESTONE_CLUSTER)
|
||||
@JvmField
|
||||
val MEDIUM_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("medium_budding_sky_tumblestone", GrowableStoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_SKY_TUMBLESTONE)
|
||||
@JvmField
|
||||
val SMALL_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("small_budding_sky_tumblestone", GrowableStoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_SKY_TUMBLESTONE)
|
||||
|
||||
@JvmField
|
||||
val BLACK_TUMBLESTONE_CLUSTER = tumblestoneBlock("black_tumblestone_cluster", GrowableStoneBlock.STAGE_3, 7, 3, null)
|
||||
@JvmField
|
||||
val LARGE_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("large_budding_black_tumblestone", GrowableStoneBlock.STAGE_2, 5, 3, BLACK_TUMBLESTONE_CLUSTER)
|
||||
@JvmField
|
||||
val MEDIUM_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("medium_budding_black_tumblestone", GrowableStoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_BLACK_TUMBLESTONE)
|
||||
@JvmField
|
||||
val SMALL_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("small_budding_black_tumblestone", GrowableStoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_BLACK_TUMBLESTONE)
|
||||
|
||||
@JvmField
|
||||
val TUMBLESTONE_BLOCK = this.create("tumblestone_block", Block(AbstractBlock.Settings.create()
|
||||
.mapColor(MapColor.TERRACOTTA_ORANGE)
|
||||
.strength(1.0F)
|
||||
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
|
||||
.requiresTool()
|
||||
.instrument(Instrument.BASEDRUM)
|
||||
))
|
||||
@JvmField
|
||||
val SKY_TUMBLESTONE_BLOCK = this.create("sky_tumblestone_block", Block(AbstractBlock.Settings.create()
|
||||
.mapColor(MapColor.LIGHT_BLUE)
|
||||
.strength(1.0F)
|
||||
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
|
||||
.requiresTool()
|
||||
.instrument(Instrument.BASEDRUM)
|
||||
))
|
||||
@JvmField
|
||||
val BLACK_TUMBLESTONE_BLOCK = this.create("black_tumblestone_block", Block(AbstractBlock.Settings.create()
|
||||
.mapColor(MapColor.TERRACOTTA_BLACK)
|
||||
.strength(1.0F)
|
||||
.sounds(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS)
|
||||
.requiresTool()
|
||||
.instrument(Instrument.BASEDRUM)
|
||||
))
|
||||
|
||||
@JvmField
|
||||
val BLACK_APRICORN = apricornBlock("black_apricorn", Apricorn.BLACK)
|
||||
@JvmField
|
||||
@@ -168,6 +227,138 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
@JvmField
|
||||
val YELLOW_APRICORN = apricornBlock("yellow_apricorn", Apricorn.YELLOW)
|
||||
|
||||
@JvmField
|
||||
val RELIC_COIN_POUCH = create(
|
||||
"relic_coin_pouch",
|
||||
CoinPouchBlock(
|
||||
AbstractBlock.Settings.create()
|
||||
.sounds(CobblemonSounds.COIN_POUCH_SOUNDS)
|
||||
.pistonBehavior(PistonBehavior.DESTROY)
|
||||
.strength(0.4f)
|
||||
.nonOpaque(), true
|
||||
)
|
||||
)
|
||||
@JvmField
|
||||
val RELIC_COIN_SACK = create(
|
||||
"relic_coin_sack",
|
||||
CoinPouchBlock(
|
||||
AbstractBlock.Settings.create()
|
||||
.sounds(CobblemonSounds.COIN_POUCH_SOUNDS)
|
||||
.pistonBehavior(PistonBehavior.DESTROY)
|
||||
.strength(0.4f), false
|
||||
))
|
||||
|
||||
@JvmField
|
||||
val GILDED_CHEST = create(
|
||||
"gilded_chest",
|
||||
GildedChestBlock(
|
||||
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
|
||||
GildedChestBlock.Type.RED
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val BLUE_GILDED_CHEST = create(
|
||||
"blue_gilded_chest",
|
||||
GildedChestBlock(
|
||||
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
|
||||
GildedChestBlock.Type.BLUE
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val BLACK_GILDED_CHEST = create(
|
||||
"black_gilded_chest",
|
||||
GildedChestBlock(
|
||||
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
|
||||
GildedChestBlock.Type.BLACK
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val YELLOW_GILDED_CHEST = create(
|
||||
"yellow_gilded_chest",
|
||||
GildedChestBlock(
|
||||
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
|
||||
GildedChestBlock.Type.YELLOW
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val WHITE_GILDED_CHEST = create(
|
||||
"white_gilded_chest",
|
||||
GildedChestBlock(
|
||||
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
|
||||
GildedChestBlock.Type.WHITE
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val GREEN_GILDED_CHEST = create(
|
||||
"green_gilded_chest",
|
||||
GildedChestBlock(
|
||||
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
|
||||
GildedChestBlock.Type.GREEN
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val PINK_GILDED_CHEST = create(
|
||||
"pink_gilded_chest",
|
||||
GildedChestBlock(
|
||||
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
|
||||
GildedChestBlock.Type.PINK
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val GIMMIGHOUL_CHEST = create(
|
||||
"gimmighoul_chest",
|
||||
GildedChestBlock(
|
||||
AbstractBlock.Settings.copy(Blocks.CHEST).nonOpaque().sounds(CobblemonSounds.GILDED_CHEST_SOUNDS),
|
||||
GildedChestBlock.Type.FAKE
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val MONITOR = create(
|
||||
"monitor",
|
||||
MonitorBlock(
|
||||
AbstractBlock.Settings.create()
|
||||
.mapColor(MapColor.IRON_GRAY)
|
||||
.sounds(BlockSoundGroup.METAL)
|
||||
.pistonBehavior(PistonBehavior.BLOCK)
|
||||
.requiresTool()
|
||||
.strength(5.0F, 6.0F)
|
||||
.luminance { if (it.get(MonitorBlock.SCREEN) != MonitorBlock.MonitorScreen.OFF) 15 else 0 }
|
||||
)
|
||||
)
|
||||
@JvmField
|
||||
val FOSSIL_ANALYZER = create(
|
||||
"fossil_analyzer",
|
||||
FossilAnalyzerBlock(
|
||||
AbstractBlock.Settings.create()
|
||||
.mapColor(MapColor.IRON_GRAY)
|
||||
.sounds(BlockSoundGroup.METAL)
|
||||
.pistonBehavior(PistonBehavior.BLOCK)
|
||||
.requiresTool()
|
||||
.strength(5.0F, 6.0F)
|
||||
.nonOpaque()
|
||||
)
|
||||
)
|
||||
@JvmField
|
||||
val RESTORATION_TANK = create(
|
||||
"restoration_tank",
|
||||
RestorationTankBlock(
|
||||
AbstractBlock.Settings.create()
|
||||
.mapColor(MapColor.IRON_GRAY)
|
||||
.sounds(BlockSoundGroup.GLASS)
|
||||
.pistonBehavior(PistonBehavior.BLOCK)
|
||||
.requiresTool()
|
||||
.strength(5.0F, 6.0F)
|
||||
.nonOpaque()
|
||||
)
|
||||
)
|
||||
@JvmField
|
||||
val HEALING_MACHINE = create(
|
||||
"healing_machine",
|
||||
@@ -196,17 +387,17 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val RED_MINT = create("red_mint", MintBlock(MintType.RED, AbstractBlock.Settings.create().mapColor(MapColor.RED).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
||||
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(BlockSoundGroup.CROP)))
|
||||
val BLUE_MINT = create("blue_mint", MintBlock(MintType.BLUE, AbstractBlock.Settings.create().mapColor(MapColor.BLUE).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
|
||||
@JvmField
|
||||
val CYAN_MINT = create("cyan_mint", MintBlock(MintType.CYAN, AbstractBlock.Settings.create().mapColor(MapColor.CYAN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
||||
val CYAN_MINT = create("cyan_mint", MintBlock(MintType.CYAN, AbstractBlock.Settings.create().mapColor(MapColor.CYAN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
|
||||
@JvmField
|
||||
val PINK_MINT = create("pink_mint", MintBlock(MintType.PINK, AbstractBlock.Settings.create().mapColor(MapColor.PINK).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
||||
val PINK_MINT = create("pink_mint", MintBlock(MintType.PINK, AbstractBlock.Settings.create().mapColor(MapColor.PINK).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
|
||||
@JvmField
|
||||
val GREEN_MINT = create("green_mint", MintBlock(MintType.GREEN, AbstractBlock.Settings.create().mapColor(MapColor.GREEN).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
||||
val GREEN_MINT = create("green_mint", MintBlock(MintType.GREEN, AbstractBlock.Settings.create().mapColor(MapColor.GREEN).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
|
||||
@JvmField
|
||||
val WHITE_MINT = create("white_mint", MintBlock(MintType.WHITE, AbstractBlock.Settings.create().mapColor(MapColor.WHITE).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP)))
|
||||
val WHITE_MINT = create("white_mint", MintBlock(MintType.WHITE, AbstractBlock.Settings.create().mapColor(MapColor.WHITE).noCollision().ticksRandomly().breakInstantly().sounds(CobblemonSounds.MINT_SOUNDS)))
|
||||
|
||||
@JvmField
|
||||
val PASTURE = create(
|
||||
@@ -243,6 +434,15 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
|
||||
private fun apricornBlock(name: String, apricorn: Apricorn): ApricornBlock = this.create(name, ApricornBlock(AbstractBlock.Settings.create().mapColor(apricorn.mapColor()).ticksRandomly().strength(Blocks.OAK_LOG.hardness, Blocks.OAK_LOG.blastResistance).sounds(BlockSoundGroup.WOOD).nonOpaque(), apricorn))
|
||||
|
||||
private fun tumblestoneBlock(name: String, stage: Int, height: Int, xzOffset: Int, nextStage: Block?) : Block {
|
||||
return this.create(name, TumblestoneBlock(AbstractBlock.Settings.create()
|
||||
.pistonBehavior(PistonBehavior.DESTROY)
|
||||
.nonOpaque()
|
||||
.strength(1.5F)
|
||||
.sounds(CobblemonSounds.TUMBLESTONE_SOUNDS),
|
||||
stage, height, xzOffset, nextStage))
|
||||
}
|
||||
|
||||
private val berries = mutableMapOf<Identifier, BerryBlock>()
|
||||
|
||||
val AGUAV_BERRY = this.berryBlock("aguav")
|
||||
@@ -338,7 +538,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
|
||||
private fun berryBlock(name: String): BerryBlock {
|
||||
val identifier = cobblemonResource("${name}_berry")
|
||||
val block = this.create(identifier.path, BerryBlock(identifier, AbstractBlock.Settings.copy(Blocks.WHEAT).dynamicBounds().sounds(BlockSoundGroup.CROP).strength(0.2F)))
|
||||
val block = this.create(identifier.path, BerryBlock(identifier, AbstractBlock.Settings.copy(Blocks.WHEAT).dynamicBounds().sounds(CobblemonSounds.BERRY_BUSH_SOUNDS).strength(0.2F)))
|
||||
this.berries[identifier] = block
|
||||
return block
|
||||
}
|
||||
|
||||
@@ -46,5 +46,7 @@ object CobblemonCommands {
|
||||
ClearPartyCommand.register(dispatcher)
|
||||
ClearPCCommand.register(dispatcher)
|
||||
PokemonRestartCommand.register(dispatcher)
|
||||
BedrockParticleCommand.register(dispatcher)
|
||||
OpenDialogueCommand.register(dispatcher)
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.entity.boat.CobblemonBoatEntity
|
||||
import com.cobblemon.mod.common.entity.boat.CobblemonChestBoatEntity
|
||||
import com.cobblemon.mod.common.entity.generic.GenericBedrockEntity
|
||||
import com.cobblemon.mod.common.entity.pokeball.EmptyPokeBallEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
@@ -65,6 +66,15 @@ object CobblemonEntities : PlatformRegistry<Registry<EntityType<*>>, RegistryKey
|
||||
.build(CHEST_BOAT_KEY.toString())
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val GENERIC_BEDROCK_ENTITY_KEY = cobblemonResource("generic_bedrock")
|
||||
@JvmField
|
||||
val GENERIC_BEDROCK_ENTITY: EntityType<GenericBedrockEntity> = this.create(
|
||||
GENERIC_BEDROCK_ENTITY_KEY.path,
|
||||
EntityType.Builder.create({ _, world -> GenericBedrockEntity(world) }, SpawnGroup.MISC)
|
||||
.build(GENERIC_BEDROCK_ENTITY_KEY.toString())
|
||||
)
|
||||
|
||||
fun registerAttributes(consumer: (EntityType<out LivingEntity>, DefaultAttributeContainer.Builder) -> Unit) {
|
||||
consumer(POKEMON, PokemonEntity.createAttributes())
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.cobblemon.mod.common.block.MintBlock
|
||||
import com.cobblemon.mod.common.block.MintBlock.MintType
|
||||
import com.cobblemon.mod.common.entity.boat.CobblemonBoatType
|
||||
import com.cobblemon.mod.common.item.*
|
||||
import com.cobblemon.mod.common.item.armor.CobblemonArmorTrims
|
||||
import com.cobblemon.mod.common.item.battle.DireHitItem
|
||||
import com.cobblemon.mod.common.item.battle.GuardSpecItem
|
||||
import com.cobblemon.mod.common.item.battle.XStatItem
|
||||
@@ -28,7 +29,6 @@ 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.platform.PlatformRegistry
|
||||
import com.cobblemon.mod.common.pokeball.PokeBall
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
@@ -37,7 +37,14 @@ 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.*
|
||||
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.registry.Registries
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.RegistryKey
|
||||
@@ -116,6 +123,38 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
val MASTER_BALL = pokeBallItem(PokeBalls.MASTER_BALL)
|
||||
@JvmField
|
||||
val CHERISH_BALL = pokeBallItem(PokeBalls.CHERISH_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_POKE_BALL = pokeBallItem(PokeBalls.ANCIENT_POKE_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_CITRINE_BALL = pokeBallItem(PokeBalls.ANCIENT_CITRINE_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_VERDANT_BALL = pokeBallItem(PokeBalls.ANCIENT_VERDANT_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_AZURE_BALL = pokeBallItem(PokeBalls.ANCIENT_AZURE_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_ROSEATE_BALL = pokeBallItem(PokeBalls.ANCIENT_ROSEATE_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_SLATE_BALL = pokeBallItem(PokeBalls.ANCIENT_SLATE_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_IVORY_BALL = pokeBallItem(PokeBalls.ANCIENT_IVORY_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_GREAT_BALL = pokeBallItem(PokeBalls.ANCIENT_GREAT_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_ULTRA_BALL = pokeBallItem(PokeBalls.ANCIENT_ULTRA_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_FEATHER_BALL = pokeBallItem(PokeBalls.ANCIENT_FEATHER_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_WING_BALL = pokeBallItem(PokeBalls.ANCIENT_WING_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_JET_BALL = pokeBallItem(PokeBalls.ANCIENT_JET_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_HEAVY_BALL = pokeBallItem(PokeBalls.ANCIENT_HEAVY_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_LEADEN_BALL = pokeBallItem(PokeBalls.ANCIENT_LEADEN_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_GIGATON_BALL = pokeBallItem(PokeBalls.ANCIENT_GIGATON_BALL)
|
||||
@JvmField
|
||||
val ANCIENT_ORIGIN_BALL = pokeBallItem(PokeBalls.ANCIENT_ORIGIN_BALL)
|
||||
|
||||
@JvmField
|
||||
val VIVICHOKE = compostableItem("vivichoke")
|
||||
@@ -139,19 +178,19 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
val WHITE_APRICORN = apricornItem("white", ApricornItem(CobblemonBlocks.WHITE_APRICORN))
|
||||
|
||||
@JvmField
|
||||
val RED_APRICORN_SEED = apricornSeedItem("red", ApricornSeedItem(CobblemonBlocks.RED_APRICORN_SAPLING))
|
||||
val RED_APRICORN_SEED = apricornSeedItem("red", ApricornSeedItem(CobblemonBlocks.RED_APRICORN_SAPLING, CobblemonBlocks.RED_APRICORN))
|
||||
@JvmField
|
||||
val YELLOW_APRICORN_SEED = apricornSeedItem("yellow", ApricornSeedItem(CobblemonBlocks.YELLOW_APRICORN_SAPLING))
|
||||
val YELLOW_APRICORN_SEED = apricornSeedItem("yellow", ApricornSeedItem(CobblemonBlocks.YELLOW_APRICORN_SAPLING, CobblemonBlocks.YELLOW_APRICORN))
|
||||
@JvmField
|
||||
val GREEN_APRICORN_SEED = apricornSeedItem("green", ApricornSeedItem(CobblemonBlocks.GREEN_APRICORN_SAPLING))
|
||||
val GREEN_APRICORN_SEED = apricornSeedItem("green", ApricornSeedItem(CobblemonBlocks.GREEN_APRICORN_SAPLING, CobblemonBlocks.GREEN_APRICORN))
|
||||
@JvmField
|
||||
val BLUE_APRICORN_SEED = apricornSeedItem("blue", ApricornSeedItem(CobblemonBlocks.BLUE_APRICORN_SAPLING))
|
||||
val BLUE_APRICORN_SEED = apricornSeedItem("blue", ApricornSeedItem(CobblemonBlocks.BLUE_APRICORN_SAPLING, CobblemonBlocks.BLUE_APRICORN))
|
||||
@JvmField
|
||||
val PINK_APRICORN_SEED = apricornSeedItem("pink", ApricornSeedItem(CobblemonBlocks.PINK_APRICORN_SAPLING))
|
||||
val PINK_APRICORN_SEED = apricornSeedItem("pink", ApricornSeedItem(CobblemonBlocks.PINK_APRICORN_SAPLING, CobblemonBlocks.PINK_APRICORN))
|
||||
@JvmField
|
||||
val BLACK_APRICORN_SEED = apricornSeedItem("black", ApricornSeedItem(CobblemonBlocks.BLACK_APRICORN_SAPLING))
|
||||
val BLACK_APRICORN_SEED = apricornSeedItem("black", ApricornSeedItem(CobblemonBlocks.BLACK_APRICORN_SAPLING, CobblemonBlocks.BLACK_APRICORN))
|
||||
@JvmField
|
||||
val WHITE_APRICORN_SEED = apricornSeedItem("white", ApricornSeedItem(CobblemonBlocks.WHITE_APRICORN_SAPLING))
|
||||
val WHITE_APRICORN_SEED = apricornSeedItem("white", ApricornSeedItem(CobblemonBlocks.WHITE_APRICORN_SAPLING, CobblemonBlocks.WHITE_APRICORN))
|
||||
|
||||
@JvmField
|
||||
val APRICORN_LOG = blockItem("apricorn_log", CobblemonBlocks.APRICORN_LOG)
|
||||
@@ -190,7 +229,29 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
val APRICORN_SIGN = this.create("apricorn_sign", SignItem(Item.Settings().maxCount(16), CobblemonBlocks.APRICORN_SIGN, CobblemonBlocks.APRICORN_WALL_SIGN))
|
||||
@JvmField
|
||||
val APRICORN_HANGING_SIGN = this.create("apricorn_hanging_sign", HangingSignItem(CobblemonBlocks.APRICORN_HANGING_SIGN, CobblemonBlocks.APRICORN_WALL_HANGING_SIGN, Item.Settings().maxCount(16)))
|
||||
@JvmField
|
||||
val GILDED_CHEST = this.create("gilded_chest", BlockItem(CobblemonBlocks.GILDED_CHEST, Item.Settings()))
|
||||
@JvmField
|
||||
val BLUE_GILDED_CHEST = this.create("blue_gilded_chest", BlockItem(CobblemonBlocks.BLUE_GILDED_CHEST, Item.Settings()))
|
||||
@JvmField
|
||||
val YELLOW_GILDED_CHEST = this.create("yellow_gilded_chest", BlockItem(CobblemonBlocks.YELLOW_GILDED_CHEST, Item.Settings()))
|
||||
@JvmField
|
||||
val PINK_GILDED_CHEST = this.create("pink_gilded_chest", BlockItem(CobblemonBlocks.PINK_GILDED_CHEST, Item.Settings()))
|
||||
@JvmField
|
||||
val BLACK_GILDED_CHEST = this.create("black_gilded_chest", BlockItem(CobblemonBlocks.BLACK_GILDED_CHEST, Item.Settings()))
|
||||
@JvmField
|
||||
val WHITE_GILDED_CHEST = this.create("white_gilded_chest", BlockItem(CobblemonBlocks.WHITE_GILDED_CHEST, Item.Settings()))
|
||||
@JvmField
|
||||
val GREEN_GILDED_CHEST = this.create("green_gilded_chest", BlockItem(CobblemonBlocks.GREEN_GILDED_CHEST, Item.Settings()))
|
||||
@JvmField
|
||||
val GIMMIGHOUL_CHEST = this.create("gimmighoul_chest", BlockItem(CobblemonBlocks.GIMMIGHOUL_CHEST, Item.Settings()))
|
||||
|
||||
@JvmField
|
||||
val RESTORATION_TANK = blockItem("restoration_tank", CobblemonBlocks.RESTORATION_TANK)
|
||||
@JvmField
|
||||
val FOSSIL_ANALYZER = blockItem("fossil_analyzer", CobblemonBlocks.FOSSIL_ANALYZER)
|
||||
@JvmField
|
||||
val MONITOR = blockItem("monitor", CobblemonBlocks.MONITOR)
|
||||
@JvmField
|
||||
val HEALING_MACHINE = blockItem("healing_machine", CobblemonBlocks.HEALING_MACHINE)
|
||||
@JvmField
|
||||
@@ -335,6 +396,18 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
@JvmField
|
||||
val ZINC = create("zinc", VitaminItem(Stats.SPECIAL_DEFENCE))
|
||||
@JvmField
|
||||
val GENIUS_FEATHER = create("genius_feather", FeatherItem(Stats.SPECIAL_ATTACK))
|
||||
@JvmField
|
||||
val SWIFT_FEATHER = create("swift_feather", FeatherItem(Stats.SPEED))
|
||||
@JvmField
|
||||
val HEALTH_FEATHER = create("health_feather", FeatherItem(Stats.HP))
|
||||
@JvmField
|
||||
val RESIST_FEATHER = create("resist_feather", FeatherItem(Stats.DEFENCE))
|
||||
@JvmField
|
||||
val MUSCLE_FEATHER = create("muscle_feather", FeatherItem(Stats.ATTACK))
|
||||
@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())))
|
||||
@JvmField
|
||||
val ROASTED_LEEK = create("roasted_leek", Item(Item.Settings().food(FoodComponent.Builder().snack().hunger(3).saturationModifier(0.3f).build())))
|
||||
@@ -530,6 +603,9 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
val DEEPSLATE_WATER_STONE_ORE = blockItem("deepslate_water_stone_ore", CobblemonBlocks.DEEPSLATE_WATER_STONE_ORE)
|
||||
@JvmField
|
||||
val DRIPSTONE_MOON_STONE_ORE = blockItem("dripstone_moon_stone_ore", CobblemonBlocks.DRIPSTONE_MOON_STONE_ORE)
|
||||
@JvmField
|
||||
val NETHER_FIRE_STONE_ORE = blockItem("nether_fire_stone_ore", CobblemonBlocks.NETHER_FIRE_STONE_ORE)
|
||||
|
||||
@JvmField
|
||||
val DAWN_STONE = noSettingsItem("dawn_stone")
|
||||
@JvmField
|
||||
@@ -652,6 +728,14 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
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")
|
||||
|
||||
// Mulch
|
||||
@JvmField
|
||||
@@ -673,9 +757,145 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
@JvmField
|
||||
val SURPRISE_MULCH = mulchItem("surprise_mulch", MulchVariant.SURPRISE)
|
||||
|
||||
// Archaeology
|
||||
@JvmField
|
||||
val ARMOR_FOSSIL = noSettingsItem("armor_fossil")
|
||||
@JvmField
|
||||
val FOSSILIZED_BIRD = noSettingsItem("fossilized_bird")
|
||||
@JvmField
|
||||
val CLAW_FOSSIL = noSettingsItem("claw_fossil")
|
||||
@JvmField
|
||||
val COVER_FOSSIL = noSettingsItem("cover_fossil")
|
||||
@JvmField
|
||||
val FOSSILIZED_DINO = noSettingsItem("fossilized_dino")
|
||||
@JvmField
|
||||
val DOME_FOSSIL = noSettingsItem("dome_fossil")
|
||||
@JvmField
|
||||
val FOSSILIZED_DRAKE = noSettingsItem("fossilized_drake")
|
||||
@JvmField
|
||||
val FOSSILIZED_FISH = noSettingsItem("fossilized_fish")
|
||||
@JvmField
|
||||
val HELIX_FOSSIL = noSettingsItem("helix_fossil")
|
||||
@JvmField
|
||||
val JAW_FOSSIL = noSettingsItem("jaw_fossil")
|
||||
@JvmField
|
||||
val OLD_AMBER_FOSSIL = noSettingsItem("old_amber_fossil")
|
||||
@JvmField
|
||||
val PLUME_FOSSIL = noSettingsItem("plume_fossil")
|
||||
@JvmField
|
||||
val ROOT_FOSSIL = noSettingsItem("root_fossil")
|
||||
@JvmField
|
||||
val SAIL_FOSSIL = noSettingsItem("sail_fossil")
|
||||
@JvmField
|
||||
val SKULL_FOSSIL = noSettingsItem("skull_fossil")
|
||||
|
||||
@JvmField
|
||||
val BYGONE_SHERD = noSettingsItem("bygone_sherd")
|
||||
@JvmField
|
||||
val CAPTURE_SHERD = noSettingsItem("capture_sherd")
|
||||
@JvmField
|
||||
val DOME_SHERD = noSettingsItem("dome_sherd")
|
||||
@JvmField
|
||||
val HELIX_SHERD = noSettingsItem("helix_sherd")
|
||||
@JvmField
|
||||
val NOSTALGIC_SHERD = noSettingsItem("nostalgic_sherd")
|
||||
@JvmField
|
||||
val SUSPICIOUS_SHERD = noSettingsItem("suspicious_sherd")
|
||||
|
||||
@JvmField
|
||||
val TUMBLESTONE = this.create("tumblestone", TumblestoneItem(Item.Settings(), CobblemonBlocks.SMALL_BUDDING_TUMBLESTONE))
|
||||
@JvmField
|
||||
val BLACK_TUMBLESTONE = this.create("black_tumblestone", TumblestoneItem(Item.Settings(), CobblemonBlocks.SMALL_BUDDING_BLACK_TUMBLESTONE))
|
||||
@JvmField
|
||||
val SKY_TUMBLESTONE = this.create("sky_tumblestone", TumblestoneItem(Item.Settings(), CobblemonBlocks.SMALL_BUDDING_SKY_TUMBLESTONE))
|
||||
|
||||
@JvmField
|
||||
val SMALL_BUDDING_TUMBLESTONE = blockItem("small_budding_tumblestone", CobblemonBlocks.SMALL_BUDDING_TUMBLESTONE)
|
||||
@JvmField
|
||||
val MEDIUM_BUDDING_TUMBLESTONE = blockItem("medium_budding_tumblestone", CobblemonBlocks.MEDIUM_BUDDING_TUMBLESTONE)
|
||||
@JvmField
|
||||
val LARGE_BUDDING_TUMBLESTONE = blockItem("large_budding_tumblestone", CobblemonBlocks.LARGE_BUDDING_TUMBLESTONE)
|
||||
@JvmField
|
||||
val TUMBLESTONE_CLUSTER = blockItem("tumblestone_cluster", CobblemonBlocks.TUMBLESTONE_CLUSTER)
|
||||
|
||||
@JvmField
|
||||
val SMALL_BUDDING_SKY_TUMBLESTONE = blockItem("small_budding_sky_tumblestone", CobblemonBlocks.SMALL_BUDDING_SKY_TUMBLESTONE)
|
||||
@JvmField
|
||||
val MEDIUM_BUDDING_SKY_TUMBLESTONE = blockItem("medium_budding_sky_tumblestone", CobblemonBlocks.MEDIUM_BUDDING_SKY_TUMBLESTONE)
|
||||
@JvmField
|
||||
val LARGE_BUDDING_SKY_TUMBLESTONE = blockItem("large_budding_sky_tumblestone", CobblemonBlocks.LARGE_BUDDING_SKY_TUMBLESTONE)
|
||||
@JvmField
|
||||
val SKY_TUMBLESTONE_CLUSTER = blockItem("sky_tumblestone_cluster", CobblemonBlocks.SKY_TUMBLESTONE_CLUSTER)
|
||||
|
||||
@JvmField
|
||||
val SMALL_BUDDING_BLACK_TUMBLESTONE = blockItem("small_budding_black_tumblestone", CobblemonBlocks.SMALL_BUDDING_BLACK_TUMBLESTONE)
|
||||
@JvmField
|
||||
val MEDIUM_BUDDING_BLACK_TUMBLESTONE = blockItem("medium_budding_black_tumblestone", CobblemonBlocks.MEDIUM_BUDDING_BLACK_TUMBLESTONE)
|
||||
@JvmField
|
||||
val LARGE_BUDDING_BLACK_TUMBLESTONE = blockItem("large_budding_black_tumblestone", CobblemonBlocks.LARGE_BUDDING_BLACK_TUMBLESTONE)
|
||||
@JvmField
|
||||
val BLACK_TUMBLESTONE_CLUSTER = blockItem("black_tumblestone_cluster", CobblemonBlocks.BLACK_TUMBLESTONE_CLUSTER)
|
||||
|
||||
@JvmField
|
||||
val TUMBLESTONE_BLOCK = blockItem("tumblestone_block", CobblemonBlocks.TUMBLESTONE_BLOCK)
|
||||
@JvmField
|
||||
val SKY_TUMBLESTONE_BLOCK = blockItem("sky_tumblestone_block", CobblemonBlocks.SKY_TUMBLESTONE_BLOCK)
|
||||
@JvmField
|
||||
val BLACK_TUMBLESTONE_BLOCK = blockItem("black_tumblestone_block", CobblemonBlocks.BLACK_TUMBLESTONE_BLOCK)
|
||||
|
||||
@JvmField
|
||||
val AUTOMATON_ARMOR_TRIM_SMITHING_TEMPLATE: SmithingTemplateItem = this.create(
|
||||
"automaton_armor_trim_smithing_template",
|
||||
SmithingTemplateItem.of(CobblemonArmorTrims.AUTOMATON)
|
||||
)
|
||||
|
||||
// Misc
|
||||
@JvmField
|
||||
val POKEMON_MODEL = this.create("pokemon_model", PokemonItem())
|
||||
@JvmField
|
||||
val RELIC_COIN = noSettingsItem("relic_coin")
|
||||
@JvmField
|
||||
val RELIC_COIN_POUCH = blockItem("relic_coin_pouch", CobblemonBlocks.RELIC_COIN_POUCH)
|
||||
@JvmField
|
||||
val RELIC_COIN_SACK = blockItem("relic_coin_sack", CobblemonBlocks.RELIC_COIN_SACK)
|
||||
|
||||
// Type Gems
|
||||
@JvmField
|
||||
val NORMAL_GEM = noSettingsItem("normal_gem")
|
||||
@JvmField
|
||||
val FIRE_GEM = noSettingsItem("fire_gem")
|
||||
@JvmField
|
||||
val WATER_GEM = noSettingsItem("water_gem")
|
||||
@JvmField
|
||||
val GRASS_GEM = noSettingsItem("grass_gem")
|
||||
@JvmField
|
||||
val ELECTRIC_GEM = noSettingsItem("electric_gem")
|
||||
@JvmField
|
||||
val ICE_GEM = noSettingsItem("ice_gem")
|
||||
@JvmField
|
||||
val FIGHTING_GEM = noSettingsItem("fighting_gem")
|
||||
@JvmField
|
||||
val POISON_GEM = noSettingsItem("poison_gem")
|
||||
@JvmField
|
||||
val GROUND_GEM = noSettingsItem("ground_gem")
|
||||
@JvmField
|
||||
val FLYING_GEM = noSettingsItem("flying_gem")
|
||||
@JvmField
|
||||
val PSYCHIC_GEM = noSettingsItem("psychic_gem")
|
||||
@JvmField
|
||||
val BUG_GEM = noSettingsItem("bug_gem")
|
||||
@JvmField
|
||||
val ROCK_GEM = noSettingsItem("rock_gem")
|
||||
@JvmField
|
||||
val GHOST_GEM = noSettingsItem("ghost_gem")
|
||||
@JvmField
|
||||
val DRAGON_GEM = noSettingsItem("dragon_gem")
|
||||
@JvmField
|
||||
val DARK_GEM = noSettingsItem("dark_gem")
|
||||
@JvmField
|
||||
val STEEL_GEM = noSettingsItem("steel_gem")
|
||||
@JvmField
|
||||
val FAIRY_GEM = noSettingsItem("fairy_gem")
|
||||
|
||||
private fun blockItem(name: String, block: Block): BlockItem = this.create(name, BlockItem(block, Item.Settings()))
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
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
|
||||
@@ -37,6 +38,10 @@ import com.cobblemon.mod.common.client.net.callback.party.OpenPartyCallbackHandl
|
||||
import com.cobblemon.mod.common.client.net.callback.partymove.OpenPartyMoveCallbackHandler
|
||||
import com.cobblemon.mod.common.client.net.data.DataRegistrySyncPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.data.UnlockReloadPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.RunPosableMoLangHandler
|
||||
import com.cobblemon.mod.common.client.net.dialogue.DialogueClosedHandler
|
||||
import com.cobblemon.mod.common.client.net.dialogue.DialogueOpenedHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormEntityParticleHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormParticleHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.InteractPokemonUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.SummaryUIPacketHandler
|
||||
@@ -46,7 +51,6 @@ import com.cobblemon.mod.common.client.net.pasture.PokemonPasturedHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.PokemonUnpasturedHandler
|
||||
import com.cobblemon.mod.common.client.net.pokemon.update.PokemonUpdatePacketHandler
|
||||
import com.cobblemon.mod.common.client.net.settings.ServerSettingsPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.sound.PokemonCryHandler
|
||||
import com.cobblemon.mod.common.client.net.sound.UnvalidatedPlaySoundS2CPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.spawn.SpawnExtraDataEntityHandler
|
||||
import com.cobblemon.mod.common.client.net.starter.StarterUIPacketHandler
|
||||
@@ -71,17 +75,27 @@ import com.cobblemon.mod.common.client.net.trade.TradeOfferNotificationHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeStartedHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeUpdatedHandler
|
||||
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.animation.PlayPoseableAnimationPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.*
|
||||
import com.cobblemon.mod.common.net.messages.client.callback.OpenMoveCallbackPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyCallbackPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyMoveCallbackPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.AbilityRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.BerryRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.GlobalSpeciesFeatureSyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.MovesRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.PropertiesCompletionRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.SpeciesFeatureAssignmentSyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.SpeciesRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.StandardSpeciesFeatureSyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.UnlockReloadPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueClosedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.fossil.FossilRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.fossil.NaturalMaterialRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.ClosePasturePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.OpenPasturePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pasture.PokemonPasturedPacket
|
||||
@@ -91,8 +105,8 @@ import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.Add
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.ClearEvolutionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.evolution.RemoveEvolutionPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.sound.PokemonCryPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.sound.UnvalidatedPlaySoundS2CPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnGenericBedrockPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnPokeballPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.spawn.SpawnPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.starter.OpenStarterUIPacket
|
||||
@@ -121,6 +135,7 @@ import com.cobblemon.mod.common.net.messages.client.ui.InteractPokemonUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.SummaryUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.*
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.BattleSelectActionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.FleeBattlePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.RemoveSpectatorPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.SpectateBattlePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectCancelledPacket
|
||||
@@ -129,6 +144,8 @@ import com.cobblemon.mod.common.net.messages.server.callback.party.PartyPokemonS
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.party.PartySelectCancelledPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.partymove.PartyMoveSelectCancelledPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.partymove.PartyPokemonMoveSelectedPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.dialogue.EscapeDialoguePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.dialogue.InputToDialoguePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.PasturePokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.UnpastureAllPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.pasture.UnpasturePokemonPacket
|
||||
@@ -154,6 +171,7 @@ import com.cobblemon.mod.common.net.messages.server.trade.UpdateTradeOfferPacket
|
||||
import com.cobblemon.mod.common.net.serverhandling.ChallengeHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.RequestInteractionsHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.BattleSelectActionsHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.FleeBattlePacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.RemoveSpectatorHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.SpectateBattleHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.move.MoveSelectCancelledHandler
|
||||
@@ -162,6 +180,8 @@ import com.cobblemon.mod.common.net.serverhandling.callback.party.PartyPokemonSe
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.party.PartySelectCancelledHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.partymove.PartyMoveSelectCancelledHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.partymove.PartyPokemonMoveSelectedHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.dialogue.EscapeDialogueHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.dialogue.InputToDialogueHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.evolution.AcceptEvolutionHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pasture.PasturePokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pasture.UnpastureAllPokemonHandler
|
||||
@@ -233,6 +253,8 @@ object CobblemonNetwork : NetworkManager {
|
||||
this.createClientBound(PokemonStateUpdatePacket.ID, PokemonStateUpdatePacket::decode, PokemonUpdatePacketHandler())
|
||||
this.createClientBound(TetheringUpdatePacket.ID, TetheringUpdatePacket::decode, PokemonUpdatePacketHandler())
|
||||
this.createClientBound(TradeableUpdatePacket.ID, TradeableUpdatePacket::decode, PokemonUpdatePacketHandler())
|
||||
this.createClientBound(SpeciesFeatureUpdatePacket.ID, SpeciesFeatureUpdatePacket::decode, PokemonUpdatePacketHandler())
|
||||
this.createClientBound(OriginalTrainerUpdatePacket.ID, OriginalTrainerUpdatePacket::decode, PokemonUpdatePacketHandler())
|
||||
|
||||
// Evolution start
|
||||
this.createClientBound(AddEvolutionPacket.ID, AddEvolutionPacket::decode, PokemonUpdatePacketHandler())
|
||||
@@ -298,15 +320,23 @@ object CobblemonNetwork : NetworkManager {
|
||||
this.createClientBound(PropertiesCompletionRegistrySyncPacket.ID, PropertiesCompletionRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(UnlockReloadPacket.ID, UnlockReloadPacket::decode, UnlockReloadPacketHandler)
|
||||
this.createClientBound(BerryRegistrySyncPacket.ID, BerryRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(StandardSpeciesFeatureSyncPacket.ID, StandardSpeciesFeatureSyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(GlobalSpeciesFeatureSyncPacket.ID, GlobalSpeciesFeatureSyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(SpeciesFeatureAssignmentSyncPacket.ID, SpeciesFeatureAssignmentSyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(NaturalMaterialRegistrySyncPacket.ID, NaturalMaterialRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
this.createClientBound(FossilRegistrySyncPacket.ID, FossilRegistrySyncPacket::decode, DataRegistrySyncPacketHandler())
|
||||
|
||||
// Effects
|
||||
this.createClientBound(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler)
|
||||
this.createClientBound(SpawnSnowstormEntityParticlePacket.ID, SpawnSnowstormEntityParticlePacket::decode, SpawnSnowstormEntityParticleHandler)
|
||||
this.createClientBound(RunPosableMoLangPacket.ID, RunPosableMoLangPacket::decode, RunPosableMoLangHandler)
|
||||
|
||||
// Hax
|
||||
this.createClientBound(UnvalidatedPlaySoundS2CPacket.ID, UnvalidatedPlaySoundS2CPacket::decode, UnvalidatedPlaySoundS2CPacketHandler)
|
||||
this.createClientBound(SpawnPokemonPacket.ID, SpawnPokemonPacket::decode, SpawnExtraDataEntityHandler())
|
||||
this.createClientBound(SpawnPokeballPacket.ID, SpawnPokeballPacket::decode, SpawnExtraDataEntityHandler())
|
||||
this.createClientBound(ToastPacket.ID, ToastPacket::decode, ToastPacketHandler)
|
||||
this.createClientBound(SpawnGenericBedrockPacket.ID, SpawnGenericBedrockPacket::decode, SpawnExtraDataEntityHandler())
|
||||
|
||||
// Trade packets
|
||||
this.createClientBound(TradeAcceptanceChangedPacket.ID, TradeAcceptanceChangedPacket::decode, TradeAcceptanceChangedHandler)
|
||||
@@ -324,7 +354,7 @@ object CobblemonNetwork : NetworkManager {
|
||||
this.createClientBound(PokemonUnpasturedPacket.ID, PokemonUnpasturedPacket::decode, PokemonUnpasturedHandler)
|
||||
|
||||
// Behaviours
|
||||
this.createClientBound(PokemonCryPacket.ID, PokemonCryPacket::decode, PokemonCryHandler)
|
||||
this.createClientBound(PlayPoseableAnimationPacket.ID, PlayPoseableAnimationPacket::decode, PlayPoseableAnimationHandler)
|
||||
|
||||
// Move select packets
|
||||
this.createClientBound(OpenMoveCallbackPacket.ID, OpenMoveCallbackPacket::decode, OpenMoveCallbackHandler)
|
||||
@@ -334,6 +364,10 @@ object CobblemonNetwork : NetworkManager {
|
||||
|
||||
// Party move select packets
|
||||
this.createClientBound(OpenPartyMoveCallbackPacket.ID, OpenPartyMoveCallbackPacket::decode, OpenPartyMoveCallbackHandler)
|
||||
|
||||
// Dialogue packets
|
||||
this.createClientBound(DialogueClosedPacket.ID, DialogueClosedPacket::decode, DialogueClosedHandler)
|
||||
this.createClientBound(DialogueOpenedPacket.ID, DialogueOpenedPacket::decode, DialogueOpenedHandler)
|
||||
}
|
||||
|
||||
override fun registerServerBound() {
|
||||
@@ -375,6 +409,7 @@ object CobblemonNetwork : NetworkManager {
|
||||
this.createServerBound(BattleSelectActionsPacket.ID, BattleSelectActionsPacket::decode, BattleSelectActionsHandler)
|
||||
this.createServerBound(SpectateBattlePacket.ID, SpectateBattlePacket::decode, SpectateBattleHandler)
|
||||
this.createServerBound(RemoveSpectatorPacket.ID, RemoveSpectatorPacket::decode, RemoveSpectatorHandler)
|
||||
this.createServerBound(FleeBattlePacket.ID, FleeBattlePacket::decode, FleeBattlePacketHandler)
|
||||
|
||||
// Trade
|
||||
this.createServerBound(AcceptTradeRequestPacket.ID, AcceptTradeRequestPacket::decode, AcceptTradeRequestHandler)
|
||||
@@ -399,6 +434,10 @@ object CobblemonNetwork : NetworkManager {
|
||||
// Party move select packets
|
||||
this.createServerBound(PartyPokemonMoveSelectedPacket.ID, PartyPokemonMoveSelectedPacket::decode, PartyPokemonMoveSelectedHandler)
|
||||
this.createServerBound(PartyMoveSelectCancelledPacket.ID, PartyMoveSelectCancelledPacket::decode, PartyMoveSelectCancelledHandler)
|
||||
|
||||
// Dialogue packets
|
||||
this.createServerBound(EscapeDialoguePacket.ID, EscapeDialoguePacket::decode, EscapeDialogueHandler)
|
||||
this.createServerBound(InputToDialoguePacket.ID, InputToDialoguePacket::decode, InputToDialogueHandler)
|
||||
}
|
||||
|
||||
private inline fun <reified T : NetworkPacket<T>> createClientBound(identifier: Identifier, noinline decoder: (PacketByteBuf) -> T, handler: ClientNetworkPacketHandler<T>) {
|
||||
|
||||
@@ -14,7 +14,9 @@ import net.minecraft.registry.Registries
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.RegistryKey
|
||||
import net.minecraft.registry.RegistryKeys
|
||||
import net.minecraft.sound.BlockSoundGroup
|
||||
import net.minecraft.sound.SoundEvent
|
||||
import net.minecraft.sound.SoundEvents
|
||||
|
||||
object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Registry<SoundEvent>>, SoundEvent>() {
|
||||
|
||||
@@ -54,6 +56,10 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
||||
val POKE_BALL_SEND_OUT = this.create("poke_ball.send_out")
|
||||
@JvmField
|
||||
val POKE_BALL_RECALL = this.create("poke_ball.recall")
|
||||
@JvmField
|
||||
val POKE_BALL_THROW = this.create("poke_ball.throw")
|
||||
@JvmField
|
||||
val POKE_BALL_TRAIL = this.create("poke_ball.trail")
|
||||
|
||||
@JvmField
|
||||
val ITEM_USE = this.create("item.use")
|
||||
@@ -61,6 +67,8 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
||||
val CAN_EVOLVE = this.create("pokemon.can_evolve")
|
||||
@JvmField
|
||||
val EVOLVING = this.create("pokemon.evolving")
|
||||
@JvmField
|
||||
val EVOLVE = this.create("evolution.evolve")
|
||||
|
||||
@JvmField
|
||||
val PVN_BATTLE = this.create("battle.pvn.default")
|
||||
@@ -77,6 +85,8 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
||||
val MEDICINE_PILLS_USE = this.create("medicine_pills.use")
|
||||
@JvmField
|
||||
val MEDICINE_SPRAY_USE = this.create("medicine_spray.use")
|
||||
@JvmField
|
||||
val MEDICINE_FEATHER_USE = this.create("medicine_feather.use")
|
||||
|
||||
@JvmField
|
||||
val BERRY_HARVEST = this.create("berry.harvest")
|
||||
@@ -88,6 +98,202 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
||||
@JvmField
|
||||
val MULCH_REMOVE = this.create("mulch.remove")
|
||||
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_ACTIVATE = this.create("fossilmachine.activate")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_ACTIVE_LOOP = this.create("fossilmachine.active_loop")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_ASSEMBLE = this.create("fossilmachine.assemble")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_DNA_FULL = this.create("fossilmachine.dna_full")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_FINISHED = this.create("fossilmachine.finished")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_INSERT_DNA = this.create("fossilmachine.insert_dna")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_INSERT_DNA_SMALL = this.create("fossilmachine.insert_dna_small")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_INSERT_FOSSIL = this.create("fossilmachine.insert_fossil")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_RETRIEVE_FOSSIL = this.create("fossilmachine.retrieve_fossil")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_RETRIEVE_POKEMON = this.create("fossilmachine.retrieve_pokemon")
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_UNPROTECTED = this.create("fossilmachine.unprotected")
|
||||
|
||||
@JvmField
|
||||
val COIN_POUCH_BREAK = this.create("coin_pouch.break")
|
||||
@JvmField
|
||||
val COIN_POUCH_HIT = this.create("coin_pouch.hit")
|
||||
@JvmField
|
||||
val COIN_POUCH_STEP = this.create("coin_pouch.step")
|
||||
@JvmField
|
||||
val COIN_POUCH_PLACE = this.create("coin_pouch.place")
|
||||
@JvmField
|
||||
val TUMBLESTONE_BREAK = this.create("tumblestone.break")
|
||||
@JvmField
|
||||
val TUMBLESTONE_BLOCK_BREAK = this.create("tumblestone.block_break")
|
||||
@JvmField
|
||||
val TUMBLESTONE_HIT = this.create("tumblestone.hit")
|
||||
@JvmField
|
||||
val TUMBLESTONE_PLACE = this.create("tumblestone.place")
|
||||
@JvmField
|
||||
val TUMBLESTONE_STEP = this.create("tumblestone.step")
|
||||
|
||||
@JvmField
|
||||
val GIMMIGHOUL_GIVE_ITEM_SMALL = this.create("gimmighoul.give_item_small")
|
||||
@JvmField
|
||||
val GIMMIGHOUL_REVEAL = this.create("gimmighoul.reveal")
|
||||
|
||||
@JvmField
|
||||
val BERRY_BUSH_BREAK = this.create("berry_bush.break")
|
||||
@JvmField
|
||||
val BERRY_BUSH_PLACE = this.create("berry_bush.place")
|
||||
|
||||
@JvmField
|
||||
val BIG_ROOT_BREAK = this.create("big_root.break")
|
||||
@JvmField
|
||||
val ENERGY_ROOT_PLACE = this.create("energy_root.place")
|
||||
|
||||
@JvmField
|
||||
val MINT_BREAK = this.create("mint.break")
|
||||
@JvmField
|
||||
val MINT_PLACE = this.create("mint.place")
|
||||
|
||||
@JvmField
|
||||
val MEDICINAL_LEEK_BREAK = this.create("medicinal_leek.break")
|
||||
@JvmField
|
||||
val MEDICINAL_LEEK_PLACE = this.create("medicinal_leek.plant")
|
||||
|
||||
@JvmField
|
||||
val GILDED_CHEST_OPEN = this.create("gilded_chest.open")
|
||||
@JvmField
|
||||
val GILDED_CHEST_CLOSE = this.create("gilded_chest.close")
|
||||
@JvmField
|
||||
val GILDED_CHEST_STEP = this.create("gilded_chest.step")
|
||||
@JvmField
|
||||
val GILDED_CHEST_HIT = this.create("gilded_chest.hit")
|
||||
@JvmField
|
||||
val GILDED_CHEST_BREAK = this.create("gilded_chest.break")
|
||||
@JvmField
|
||||
val GILDED_CHEST_PLACE = this.create("gilded_chest.place")
|
||||
|
||||
@JvmField
|
||||
val COIN_POUCH_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
COIN_POUCH_BREAK,
|
||||
COIN_POUCH_STEP,
|
||||
COIN_POUCH_PLACE,
|
||||
COIN_POUCH_HIT,
|
||||
COIN_POUCH_STEP
|
||||
)
|
||||
@JvmField
|
||||
val IMPACT_NORMAL = this.create("impact.normal")
|
||||
@JvmField
|
||||
val IMPACT_BUG = this.create("impact.bug")
|
||||
@JvmField
|
||||
val IMPACT_DARK = this.create("impact.dark")
|
||||
@JvmField
|
||||
val IMPACT_DRAGON = this.create("impact.dragon")
|
||||
@JvmField
|
||||
val IMPACT_ELECTRIC = this.create("impact.electric")
|
||||
@JvmField
|
||||
val IMPACT_FAIRY = this.create("impact.fairy")
|
||||
@JvmField
|
||||
val IMPACT_FIGHTING = this.create("impact.fighting")
|
||||
@JvmField
|
||||
val IMPACT_FIRE = this.create("impact.fire")
|
||||
@JvmField
|
||||
val IMPACT_FLYING = this.create("impact.flying")
|
||||
@JvmField
|
||||
val IMPACT_GHOST = this.create("impact.ghost")
|
||||
@JvmField
|
||||
val IMPACT_GRASS = this.create("impact.grass")
|
||||
@JvmField
|
||||
val IMPACT_GROUND = this.create("impact.ground")
|
||||
@JvmField
|
||||
val IMPACT_ICE = this.create("impact.ice")
|
||||
@JvmField
|
||||
val IMPACT_POISON = this.create("impact.poison")
|
||||
@JvmField
|
||||
val IMPACT_PSYCHIC = this.create("impact.psychic")
|
||||
@JvmField
|
||||
val IMPACT_ROCK = this.create("impact.rock")
|
||||
@JvmField
|
||||
val IMPACT_STEEL = this.create("impact.steel")
|
||||
@JvmField
|
||||
val IMPACT_WATER = this.create("impact.water")
|
||||
|
||||
@JvmField
|
||||
val TUMBLESTONE_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
TUMBLESTONE_BREAK,
|
||||
TUMBLESTONE_STEP,
|
||||
TUMBLESTONE_PLACE,
|
||||
TUMBLESTONE_HIT,
|
||||
TUMBLESTONE_STEP
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val TUMBLESTONE_BLOCK_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
TUMBLESTONE_BLOCK_BREAK,
|
||||
TUMBLESTONE_STEP,
|
||||
TUMBLESTONE_PLACE,
|
||||
TUMBLESTONE_HIT,
|
||||
TUMBLESTONE_STEP
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val BERRY_BUSH_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
BERRY_BUSH_BREAK,
|
||||
SoundEvents.BLOCK_GRASS_STEP,
|
||||
BERRY_BUSH_PLACE,
|
||||
SoundEvents.BLOCK_GRASS_HIT,
|
||||
SoundEvents.BLOCK_GRASS_STEP
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val BIG_ROOT_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
BIG_ROOT_BREAK,
|
||||
SoundEvents.BLOCK_ROOTS_STEP,
|
||||
SoundEvents.BLOCK_ROOTS_PLACE,
|
||||
SoundEvents.BLOCK_ROOTS_HIT,
|
||||
SoundEvents.BLOCK_ROOTS_FALL
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val ENERGY_ROOT_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
SoundEvents.BLOCK_ROOTS_BREAK,
|
||||
SoundEvents.BLOCK_ROOTS_STEP,
|
||||
ENERGY_ROOT_PLACE,
|
||||
SoundEvents.BLOCK_ROOTS_HIT,
|
||||
SoundEvents.BLOCK_ROOTS_FALL
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val MEDICINAL_LEEK_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
MEDICINAL_LEEK_BREAK,
|
||||
SoundEvents.BLOCK_GRASS_STEP,
|
||||
MEDICINAL_LEEK_PLACE,
|
||||
SoundEvents.BLOCK_GRASS_HIT,
|
||||
SoundEvents.BLOCK_GRASS_FALL
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val MINT_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
MINT_BREAK,
|
||||
SoundEvents.BLOCK_GRASS_STEP,
|
||||
MINT_PLACE,
|
||||
SoundEvents.BLOCK_GRASS_HIT,
|
||||
SoundEvents.BLOCK_GRASS_FALL
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val GILDED_CHEST_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
GILDED_CHEST_BREAK,
|
||||
GILDED_CHEST_STEP,
|
||||
GILDED_CHEST_PLACE,
|
||||
GILDED_CHEST_HIT,
|
||||
GILDED_CHEST_STEP
|
||||
)
|
||||
|
||||
private fun create(name: String): SoundEvent = this.create(name, SoundEvent.of(cobblemonResource(name)))
|
||||
}
|
||||
@@ -99,6 +99,13 @@ object CobblemonCriteria {
|
||||
)
|
||||
)
|
||||
|
||||
val RESURRECT_POKEMON = this.create(
|
||||
SimpleCriterionTrigger(
|
||||
cobblemonResource("resurrect_pokemon"),
|
||||
PickStarterCriterionCondition::class.java
|
||||
)
|
||||
)
|
||||
|
||||
val TRADE_POKEMON = this.create(
|
||||
SimpleCriterionTrigger(
|
||||
cobblemonResource("trade_pokemon"),
|
||||
|
||||
@@ -8,9 +8,13 @@
|
||||
|
||||
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
|
||||
@@ -18,6 +22,8 @@ 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
|
||||
@@ -46,9 +52,9 @@ import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.getPlayer
|
||||
import java.io.File
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.text.Text
|
||||
import java.util.concurrent.ConcurrentLinkedDeque
|
||||
|
||||
/**
|
||||
* Individual battle instance
|
||||
@@ -69,6 +75,7 @@ open class PokemonBattle(
|
||||
side1.battle = this
|
||||
side2.battle = this
|
||||
this.actors.forEach { actor ->
|
||||
actor.battle = this
|
||||
actor.pokemonList.forEach { battlePokemon ->
|
||||
battlePokemon.effectedPokemon.evolutionProxy.current().progress()
|
||||
.filterIsInstance<LastBattleCriticalHitsEvolutionProgress>()
|
||||
@@ -102,7 +109,7 @@ open class PokemonBattle(
|
||||
|
||||
|
||||
var dispatchResult = GO
|
||||
val dispatches = ConcurrentLinkedQueue<BattleDispatch>()
|
||||
val dispatches = ConcurrentLinkedDeque<BattleDispatch>()
|
||||
val afterDispatches = mutableListOf<() -> Unit>()
|
||||
|
||||
val captureActions = mutableListOf<BattleCaptureAction>()
|
||||
@@ -252,7 +259,6 @@ open class PokemonBattle(
|
||||
}
|
||||
}
|
||||
sendUpdate(BattleEndPacket())
|
||||
sendUpdate(BattleMusicPacket(null))
|
||||
BattleRegistry.closeBattle(this)
|
||||
}
|
||||
|
||||
@@ -319,6 +325,12 @@ open class PokemonBattle(
|
||||
|
||||
fun dispatch(dispatcher: () -> DispatchResult) {
|
||||
dispatches.add(BattleDispatch { dispatcher() })
|
||||
|
||||
}
|
||||
|
||||
fun dispatchToFront(dispatcher: () -> DispatchResult) {
|
||||
dispatches.addFirst(BattleDispatch { dispatcher() })
|
||||
|
||||
}
|
||||
|
||||
fun dispatchGo(dispatcher: () -> Unit) {
|
||||
@@ -350,6 +362,10 @@ open class PokemonBattle(
|
||||
dispatches.add(dispatcher)
|
||||
}
|
||||
|
||||
fun dispatchToFront(dispatcher: BattleDispatch) {
|
||||
dispatches.addFirst(dispatcher)
|
||||
}
|
||||
|
||||
fun doWhenClear(action: () -> Unit) {
|
||||
afterDispatches.add(action)
|
||||
}
|
||||
@@ -454,4 +470,13 @@ open class PokemonBattle(
|
||||
LOGGER.error("Missing interpretation on '{}' action: \nPublic » {}\nPrivate » {}", publicMessage.id, publicMessage.rawMessage, privateMessage.rawMessage)
|
||||
return Text.literal("Missing interpretation on '${publicMessage.id}' action please report to the developers").red()
|
||||
}
|
||||
|
||||
fun addQueryFunctions(queryStruct: QueryStruct): QueryStruct {
|
||||
queryStruct.addFunction("pvp") { DoubleValue(isPvP) }
|
||||
queryStruct.addFunction("pvn") { DoubleValue(isPvN) }
|
||||
queryStruct.addFunction("pvw") { DoubleValue(isPvW) }
|
||||
queryStruct.addFunction("has_rule") { params -> DoubleValue(params.getString(0) in format.ruleSet) }
|
||||
|
||||
return queryStruct
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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.dialogue
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.struct.MoStruct
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
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.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.api.dialogue.input.ActiveInput
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.scheduling.ServerRealTimeTaskTracker
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
|
||||
import java.util.UUID
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
|
||||
/**
|
||||
* An active instance of [Dialogue]. Bound to a player. These all need to be created through DialogueManager
|
||||
* or things will go to shit.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 27th, 2023
|
||||
*/
|
||||
class ActiveDialogue(var playerEntity: ServerPlayerEntity, var dialogueReference: Dialogue) {
|
||||
val dialogueId = UUID.randomUUID()
|
||||
val runtime = MoLangRuntime().setup()
|
||||
var currentPage = dialogueReference.pages[0]
|
||||
val playerStruct = playerEntity.asMoLangValue()
|
||||
var activeInput = ActiveInput(this, currentPage.input)
|
||||
|
||||
init {
|
||||
runtime.environment.getQueryStruct().addFunctions(
|
||||
mapOf(
|
||||
"dialogue" to java.util.function.Function { _ -> toMoLangStruct() },
|
||||
"player" to java.util.function.Function { _ -> playerStruct }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val currentPageIndex
|
||||
get() = dialogueReference.pages.indexOf(currentPage)
|
||||
|
||||
fun setPage(value: MoValue) {
|
||||
val page = if (value is StringValue) {
|
||||
dialogueReference.pages.find { it.id == value.value }
|
||||
?: return Cobblemon.LOGGER.error("Dialogue requested page ${value.value} but it doesn't exist")
|
||||
} else {
|
||||
val pageNum = value.asDouble().toInt()
|
||||
if (pageNum < 0 || pageNum >= dialogueReference.pages.size) {
|
||||
return Cobblemon.LOGGER.error("Dialogue requested page $pageNum but it doesn't exist")
|
||||
} else {
|
||||
dialogueReference.pages[pageNum]
|
||||
}
|
||||
}
|
||||
setPage(page)
|
||||
}
|
||||
|
||||
fun isActive() = DialogueManager.activeDialogues[playerEntity.uuid] == this
|
||||
|
||||
fun incrementPage() {
|
||||
setPage(currentPageIndex + 1)
|
||||
}
|
||||
|
||||
fun setPage(page: DialoguePage) {
|
||||
currentPage = page
|
||||
activeInput = ActiveInput(this, currentPage.input)
|
||||
val deadline = currentPage.input.timeout?.duration
|
||||
val inputId = activeInput.inputId
|
||||
if (deadline != null && deadline > 0) {
|
||||
ServerRealTimeTaskTracker.after(seconds = deadline) {
|
||||
if (inputId == activeInput.inputId && isActive()) {
|
||||
activeInput.dialogueInput.timeout?.action?.invoke(this, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
playerEntity.sendPacket(DialogueOpenedPacket(this, false))
|
||||
}
|
||||
|
||||
fun setPage(index: Int) {
|
||||
if (index == dialogueReference.pages.size) {
|
||||
return close()
|
||||
}
|
||||
|
||||
if (index < 0 || index > dialogueReference.pages.size) {
|
||||
return Cobblemon.LOGGER.error("Dialogue requested page $index but it doesn't exist")
|
||||
}
|
||||
|
||||
setPage(dialogueReference.pages[index])
|
||||
}
|
||||
|
||||
fun toMoLangStruct(): MoStruct {
|
||||
return QueryStruct(
|
||||
hashMapOf(
|
||||
"current_page" to java.util.function.Function { _ -> currentPage.toMoLangStruct(this) },
|
||||
"current_page_number" to java.util.function.Function { _ -> DoubleValue(currentPageIndex) },
|
||||
"next_page" to java.util.function.Function { _ -> incrementPage() },
|
||||
"set_page" to java.util.function.Function { args -> setPage(args[0]) },
|
||||
"close" to java.util.function.Function { _ -> close() },
|
||||
"input" to java.util.function.Function { params -> activeInput.handle(if (params.params.size > 0) params.get<MoValue>(0).asString() else "") },
|
||||
)
|
||||
).addStandardFunctions()
|
||||
}
|
||||
|
||||
fun close() {
|
||||
DialogueManager.stopDialogue(playerEntity)
|
||||
}
|
||||
|
||||
fun escape() {
|
||||
val action = currentPage.escapeAction ?: dialogueReference.escapeAction
|
||||
action(this, null)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.dialogue
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
|
||||
/**
|
||||
* A dialogue that could be sent to players.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 27th, 2023
|
||||
*/
|
||||
class Dialogue(
|
||||
val pages: List<DialoguePage> = mutableListOf(),
|
||||
val escapeAction: DialogueAction = FunctionDialogueAction { dialogue, _ -> dialogue.close() },
|
||||
val speakers: Map<String, DialogueSpeaker> = emptyMap()
|
||||
) {
|
||||
companion object {
|
||||
fun of(
|
||||
pages: Iterable<DialoguePage>,
|
||||
escapeAction: ExpressionLike,
|
||||
speakers: Map<String, DialogueSpeaker>
|
||||
): Dialogue {
|
||||
return Dialogue(
|
||||
pages = pages.toList(),
|
||||
escapeAction = ExpressionLikeDialogueAction(escapeAction),
|
||||
speakers = speakers
|
||||
)
|
||||
}
|
||||
|
||||
fun of(
|
||||
pages: Iterable<DialoguePage>,
|
||||
escapeAction: (ActiveDialogue) -> Unit,
|
||||
speakers: Map<String, DialogueSpeaker>
|
||||
): Dialogue {
|
||||
val dialogue = Dialogue(
|
||||
pages = pages.toList(),
|
||||
escapeAction = FunctionDialogueAction { activeDialogue, _ -> escapeAction(activeDialogue) },
|
||||
speakers = speakers
|
||||
)
|
||||
return dialogue
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.dialogue
|
||||
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolve
|
||||
|
||||
/**
|
||||
* Something that can happen in the context of an [ActiveDialogue]. The input field is nullable because I'm reusing
|
||||
* this for dialogue input timeouts which don't have an input. It'll be fine.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 29th, 2023
|
||||
*/
|
||||
interface DialogueAction {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
val types = mutableMapOf<String, Class<out DialogueAction>>()
|
||||
}
|
||||
|
||||
operator fun invoke(dialogue: ActiveDialogue, input: String? = null)
|
||||
}
|
||||
|
||||
class FunctionDialogueAction(val consumer: (ActiveDialogue, String?) -> Unit) : DialogueAction {
|
||||
override fun invoke(dialogue: ActiveDialogue, input: String?) {
|
||||
consumer(dialogue, input)
|
||||
}
|
||||
}
|
||||
|
||||
class ExpressionLikeDialogueAction(val expression: ExpressionLike) : DialogueAction {
|
||||
override fun invoke(dialogue: ActiveDialogue, input: String?) {
|
||||
if (input != null) {
|
||||
dialogue.runtime.environment.setSimpleVariable("selected_option", StringValue(input))
|
||||
}
|
||||
dialogue.runtime.resolve(expression)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.dialogue
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import java.util.UUID
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* Something that produces a dialogue's renderable face. This is sealed because the client has very particular handling for this.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since January 1st, 2024
|
||||
*/
|
||||
sealed interface DialogueFaceProvider {
|
||||
companion object {
|
||||
val types = mutableMapOf(
|
||||
"player" to PlayerDialogueFaceProvider::class.java,
|
||||
"standard" to ArtificialDialogueFaceProvider::class.java,
|
||||
"expression" to ExpressionLikeDialogueFaceProvider::class.java
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class ArtificialDialogueFaceProvider(
|
||||
val modelType: String = "",
|
||||
val identifier: Identifier = cobblemonResource("bulbasaur"),
|
||||
val aspects: Set<String> = setOf()
|
||||
) : DialogueFaceProvider
|
||||
|
||||
class ReferenceDialogueFaceProvider(
|
||||
val entityId: Int
|
||||
): DialogueFaceProvider
|
||||
|
||||
class PlayerDialogueFaceProvider(val playerId: UUID) : DialogueFaceProvider
|
||||
|
||||
class ExpressionLikeDialogueFaceProvider(
|
||||
val providerExpression: ExpressionLike
|
||||
): DialogueFaceProvider
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.dialogue
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueClosedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
|
||||
import com.cobblemon.mod.common.util.activeDialogue
|
||||
import java.util.UUID
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
|
||||
/**
|
||||
* Manages the active dialogues for players. Map is indexed by player UUID.
|
||||
* You really need to make sure any dialogues you start with a player go through this otherwise
|
||||
* the player won't be able to close the dialogue.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 27th, 2023
|
||||
*/
|
||||
object DialogueManager {
|
||||
val activeDialogues = mutableMapOf<UUID, ActiveDialogue>()
|
||||
|
||||
fun startDialogue(playerEntity: ServerPlayerEntity, dialogue: Dialogue) {
|
||||
val activeDialogue = ActiveDialogue(playerEntity, dialogue)
|
||||
activeDialogues[playerEntity.uuid] = activeDialogue
|
||||
val packet = DialogueOpenedPacket(activeDialogue, includeFaces = true)
|
||||
playerEntity.sendPacket(packet)
|
||||
}
|
||||
|
||||
fun stopDialogue(playerEntity: ServerPlayerEntity) {
|
||||
val activeDialogue = playerEntity.activeDialogue ?: return
|
||||
DialogueClosedPacket(activeDialogue.dialogueId).sendToPlayer(playerEntity)
|
||||
activeDialogues.remove(activeDialogue.dialogueId)
|
||||
}
|
||||
}
|
||||
@@ -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.api.dialogue
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.struct.MoStruct
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.dialogue.input.DialogueInput
|
||||
import com.cobblemon.mod.common.api.dialogue.input.DialogueNoInput
|
||||
import com.google.gson.JsonArray
|
||||
import net.minecraft.text.MutableText
|
||||
|
||||
/**
|
||||
* A page of a dialogue. This has lines of text and also some kind of input expected from the player.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 27th, 2023
|
||||
*/
|
||||
class DialoguePage(
|
||||
var id: String = "",
|
||||
var speaker: String? = null,
|
||||
var lines: MutableList<DialogueText> = mutableListOf(),
|
||||
var input: DialogueInput = DialogueNoInput(),
|
||||
var clientActions: MutableList<Expression> = mutableListOf(),
|
||||
var escapeAction: DialogueAction? = null,
|
||||
) {
|
||||
companion object {
|
||||
@JvmOverloads
|
||||
fun of(
|
||||
/** The ID is optional, but if you want to be able to jump to this page from other pages then you probably want to set this. */
|
||||
id: String = "",
|
||||
speaker: String? = null,
|
||||
lines: Iterable<MutableText>,
|
||||
input: DialogueInput = DialogueNoInput(),
|
||||
clientActions: Iterable<Expression> = emptyList(),
|
||||
/** The thing to do when the player presses ESC while on this page. If null, falls back to the same property on [Dialogue]. */
|
||||
escapeAction: ((ActiveDialogue) -> Unit)? = null,
|
||||
): DialoguePage {
|
||||
return DialoguePage(
|
||||
id = id,
|
||||
speaker = speaker,
|
||||
lines = lines.map { WrappedDialogueText(it) }.toMutableList(),
|
||||
input = input,
|
||||
clientActions = clientActions.toMutableList(),
|
||||
escapeAction = escapeAction?.let { func -> FunctionDialogueAction { activeDialogue, _ -> func(activeDialogue) } }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun toMoLangStruct(activeDialogue: ActiveDialogue): MoStruct {
|
||||
return QueryStruct(
|
||||
hashMapOf(
|
||||
"id" to java.util.function.Function { _ -> StringValue(id) },
|
||||
"input" to java.util.function.Function { _ -> activeDialogue.activeInput.struct },
|
||||
"lines" to java.util.function.Function { _ ->
|
||||
val array = JsonArray()
|
||||
lines.forEach { array.add(it(activeDialogue).string) }
|
||||
MoValue.of(array)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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.api.dialogue
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
|
||||
/**
|
||||
* A predicate loaded for a particular dialogue. Tests arbitrary conditions about the dialogue context.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 29th, 2023
|
||||
*/
|
||||
interface DialoguePredicate {
|
||||
companion object {
|
||||
val types = mutableMapOf<String, Class<out DialoguePredicate>>()
|
||||
}
|
||||
|
||||
operator fun invoke(dialogue: ActiveDialogue): Boolean
|
||||
}
|
||||
|
||||
class ExpressionLikeDialoguePredicate(val expression: ExpressionLike = "true".asExpressionLike()) : DialoguePredicate {
|
||||
override fun invoke(dialogue: ActiveDialogue) = dialogue.runtime.resolveBoolean(expression)
|
||||
}
|
||||
|
||||
class FunctionDialoguePredicate(val predicate: (ActiveDialogue) -> Boolean = { true }) : DialoguePredicate {
|
||||
override fun invoke(dialogue: ActiveDialogue) = predicate(dialogue)
|
||||
}
|
||||
@@ -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.dialogue
|
||||
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import net.minecraft.text.MutableText
|
||||
|
||||
/**
|
||||
* A kind of speaker in a dialogue. They include a name and a face, each optional.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since January 1st, 2024
|
||||
*/
|
||||
class DialogueSpeaker(
|
||||
val name: DialogueText? = null,
|
||||
val face: DialogueFaceProvider? = null
|
||||
) {
|
||||
fun of(name: MutableText = "".text(), face: DialogueFaceProvider? = null) = DialogueSpeaker(WrappedDialogueText(name), face)
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.dialogue
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveString
|
||||
import net.minecraft.text.MutableText
|
||||
|
||||
/**
|
||||
* Some kind of text-resolving property. This is to hide where sometimes we want literals,
|
||||
* sometimes we want the text to come from a function, and sometimes we want it to be the
|
||||
* product of a MoLang script.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 29th, 2023
|
||||
*/
|
||||
interface DialogueText {
|
||||
companion object {
|
||||
val types = mutableMapOf<String, Class<out DialogueText>>(
|
||||
"expression" to ExpressionLikeDialogueText::class.java,
|
||||
)
|
||||
}
|
||||
|
||||
operator fun invoke(activeDialogue: ActiveDialogue): MutableText
|
||||
}
|
||||
|
||||
class FunctionDialogueText(val function: (ActiveDialogue) -> MutableText = { "".text() }) : DialogueText {
|
||||
override fun invoke(activeDialogue: ActiveDialogue) = function(activeDialogue)
|
||||
}
|
||||
|
||||
class WrappedDialogueText(val text: MutableText = "".text()) : DialogueText {
|
||||
override fun invoke(activeDialogue: ActiveDialogue) = text.copy()
|
||||
}
|
||||
|
||||
class ExpressionLikeDialogueText(val expression: ExpressionLike = "''".asExpressionLike()) : DialogueText {
|
||||
override fun invoke(activeDialogue: ActiveDialogue): MutableText {
|
||||
return activeDialogue.runtime.resolveString(expression).text()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.dialogue
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.dialogue.input.DialogueInput
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.util.adapters.DialogueActionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.DialogueFaceProviderAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.DialogueInputAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.DialoguePredicateAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.DialogueTextAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.TextAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.resource.ResourceType
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.text.MutableText
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* Registry for dialogue data.
|
||||
*
|
||||
* @see Dialogue
|
||||
* @since December 29th, 2023
|
||||
* @author Hiroku
|
||||
*/
|
||||
object Dialogues : JsonDataRegistry<Dialogue> {
|
||||
override val id = cobblemonResource("dialogues")
|
||||
override val type = ResourceType.SERVER_DATA
|
||||
override val observable = SimpleObservable<Dialogues>()
|
||||
|
||||
val dialogues = mutableMapOf<Identifier, Dialogue>()
|
||||
/** If you need custom adapters registered, subscribe to this and register them. */
|
||||
val gsonObservable: SimpleObservable<GsonBuilder> = SimpleObservable()
|
||||
|
||||
override fun sync(player: ServerPlayerEntity) {}
|
||||
|
||||
override val gson = GsonBuilder()
|
||||
.registerTypeAdapter(DialogueAction::class.java, DialogueActionAdapter)
|
||||
.registerTypeAdapter(DialoguePredicate::class.java, DialoguePredicateAdapter)
|
||||
.registerTypeAdapter(DialogueInput::class.java, DialogueInputAdapter)
|
||||
.registerTypeAdapter(DialogueFaceProvider::class.java, DialogueFaceProviderAdapter)
|
||||
.registerTypeAdapter(DialogueText::class.java, DialogueTextAdapter)
|
||||
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
|
||||
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
|
||||
.registerTypeAdapter(MutableText::class.java, TextAdapter)
|
||||
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
|
||||
.also { gsonObservable.emit(it) }
|
||||
.create()
|
||||
|
||||
override val typeToken = TypeToken.get(Dialogue::class.java)
|
||||
override val resourcePath = "dialogues"
|
||||
|
||||
override fun reload(data: Map<Identifier, Dialogue>) {
|
||||
dialogues.putAll(data)
|
||||
observable.emit(this)
|
||||
}
|
||||
}
|
||||
@@ -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.api.dialogue.input
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.api.dialogue.ActiveDialogue
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import java.util.UUID
|
||||
|
||||
/**
|
||||
* An active input waiting for the player as part of an [ActiveDialogue]. The purpose of this is to
|
||||
* maintain some data integrity and track how long it's taken to choose an action.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 27th, 2023
|
||||
*/
|
||||
class ActiveInput(
|
||||
val activeDialogue: ActiveDialogue,
|
||||
val dialogueInput: DialogueInput
|
||||
) {
|
||||
val inputId = UUID.randomUUID()
|
||||
val startTime = server()!!.overworld.time
|
||||
|
||||
val struct = toMoLangStruct()
|
||||
|
||||
fun handle(input: String) {
|
||||
val secondsToChoose = (server()!!.overworld.time - startTime) / 20F
|
||||
activeDialogue.runtime.environment.setSimpleVariable("seconds_taken_to_input", DoubleValue(secondsToChoose))
|
||||
dialogueInput.handle(this, input)
|
||||
}
|
||||
|
||||
fun toMoLangStruct(): MoValue {
|
||||
return dialogueInput.toMoLangStruct(this)
|
||||
}
|
||||
}
|
||||
+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.api.dialogue.input
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.dialogue.DialogueAction
|
||||
import com.cobblemon.mod.common.api.dialogue.FunctionDialogueAction
|
||||
|
||||
/**
|
||||
* Input that has no input but has an action that will run after a delay.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 27th, 2023
|
||||
*/
|
||||
class DialogueAutoContinueInput : DialogueInput {
|
||||
val delay = 5F
|
||||
/** Whether the player can click to move on in a hurry or if they must wait. */
|
||||
var allowSkip = true
|
||||
var showTimer = false
|
||||
val action: DialogueAction = FunctionDialogueAction { dialogue, _ -> dialogue.incrementPage() }
|
||||
|
||||
override var timeout: DialogueTimeout?
|
||||
get() = DialogueTimeout(duration = delay, showTimer = showTimer, action)
|
||||
set(_) {}
|
||||
|
||||
override fun toMoLangStruct(activeInput: ActiveInput) = QueryStruct(hashMapOf())
|
||||
|
||||
|
||||
override fun handle(activeInput: ActiveInput, value: String) {
|
||||
if (!allowSkip) {
|
||||
return Cobblemon.LOGGER.warn("A no-skip dialogue received input from ${activeInput.activeDialogue.playerEntity.gameProfile.name}, is this person a hacker or something")
|
||||
}
|
||||
|
||||
action.invoke(activeInput.activeDialogue)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.dialogue.input
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.MoStruct
|
||||
import com.cobblemon.mod.common.api.dialogue.DialoguePage
|
||||
|
||||
/**
|
||||
* A type of input to [DialoguePage]s. This is sealed because the client needs to know about it. Sorry.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 27th, 2023
|
||||
*/
|
||||
sealed interface DialogueInput {
|
||||
var timeout: DialogueTimeout?
|
||||
fun toMoLangStruct(activeInput: ActiveInput): MoStruct
|
||||
fun handle(activeInput: ActiveInput, value: String)
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.dialogue.input
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.VariableStruct
|
||||
import com.cobblemon.mod.common.api.dialogue.DialogueAction
|
||||
import com.cobblemon.mod.common.api.dialogue.FunctionDialogueAction
|
||||
|
||||
/**
|
||||
* An input type that's really just waiting for the player to click or something.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 27th, 2023
|
||||
|
||||
*/
|
||||
class DialogueNoInput(
|
||||
var action: DialogueAction = FunctionDialogueAction { dialogue, _ -> dialogue.incrementPage() }
|
||||
) : DialogueInput {
|
||||
override var timeout: DialogueTimeout?
|
||||
get() = null
|
||||
set(_) {}
|
||||
|
||||
override fun toMoLangStruct(activeInput: ActiveInput) = VariableStruct()
|
||||
override fun handle(activeInput: ActiveInput, value: String) {
|
||||
action(activeInput.activeDialogue)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.dialogue.input
|
||||
|
||||
import com.cobblemon.mod.common.api.dialogue.DialogueAction
|
||||
import com.cobblemon.mod.common.api.dialogue.DialoguePredicate
|
||||
import com.cobblemon.mod.common.api.dialogue.DialogueText
|
||||
import com.cobblemon.mod.common.api.dialogue.FunctionDialogueAction
|
||||
import com.cobblemon.mod.common.api.dialogue.FunctionDialoguePredicate
|
||||
import com.cobblemon.mod.common.api.dialogue.WrappedDialogueText
|
||||
|
||||
/**
|
||||
* A choosable option as part of a [DialogueOptionSetInput].
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 27th, 2023
|
||||
*/
|
||||
class DialogueOption(
|
||||
var text: DialogueText = WrappedDialogueText(),
|
||||
/** The value is a unique identifier so the client can tell the server what they selected. Don't forget this. */
|
||||
var value: String = "",
|
||||
/** The action to run when they click it. */
|
||||
var action: DialogueAction = FunctionDialogueAction { _, _ -> },
|
||||
val isVisible: DialoguePredicate = FunctionDialoguePredicate(),
|
||||
val isSelectable: DialoguePredicate = FunctionDialoguePredicate()
|
||||
)
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.dialogue.input
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.dialogue.ActiveDialogue
|
||||
|
||||
/**
|
||||
* A type of [DialogueInput] that has the player choose from a list of options.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 27th, 2023
|
||||
*/
|
||||
class DialogueOptionSetInput(
|
||||
var options: MutableList<DialogueOption>,
|
||||
override var timeout: DialogueTimeout? = null,
|
||||
/** Whether the buttons should be stacked vertically. */
|
||||
var vertical: Boolean = false,
|
||||
) : DialogueInput {
|
||||
|
||||
// JSON uses this. Basically so that the main constructor can force people to specify options
|
||||
constructor() : this(mutableListOf(), null, false)
|
||||
|
||||
fun getVisibleOptions(activeDialogue: ActiveDialogue) = options.filter { it.isVisible(activeDialogue) }
|
||||
override fun toMoLangStruct(activeInput: ActiveInput) = QueryStruct(hashMapOf())
|
||||
override fun handle(activeInput: ActiveInput, value: String) {
|
||||
val option = options.firstOrNull { it.value == value }
|
||||
if (option != null) {
|
||||
if (!option.isSelectable(activeInput.activeDialogue)) {
|
||||
Cobblemon.LOGGER.warn("Dialogue option $value is not selectable but ${activeInput.activeDialogue.playerEntity.gameProfile.name} selected it anyway")
|
||||
activeInput.activeDialogue.close()
|
||||
} else if (!option.isVisible(activeInput.activeDialogue)) {
|
||||
Cobblemon.LOGGER.warn("Dialogue option $value is not visible but ${activeInput.activeDialogue.playerEntity.gameProfile.name} selected it anyway")
|
||||
activeInput.activeDialogue.close()
|
||||
}
|
||||
|
||||
option.action(activeInput.activeDialogue, value)
|
||||
} else {
|
||||
Cobblemon.LOGGER.warn("No option with value $value found in dialogue option set")
|
||||
}
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.dialogue.input
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.dialogue.DialogueAction
|
||||
import com.cobblemon.mod.common.api.dialogue.FunctionDialogueAction
|
||||
|
||||
/**
|
||||
* A text input for dialogues where the player can enter free text.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 27th, 2023
|
||||
*/
|
||||
class DialogueTextInput : DialogueInput {
|
||||
override var timeout: DialogueTimeout? = null
|
||||
val action: DialogueAction = FunctionDialogueAction { dialogue, _ -> dialogue.setPage(dialogue.currentPageIndex + 1) }
|
||||
override fun toMoLangStruct(activeInput: ActiveInput) = QueryStruct(hashMapOf())
|
||||
|
||||
override fun handle(activeInput: ActiveInput, value: String) {
|
||||
action.invoke(activeInput.activeDialogue, value)
|
||||
}
|
||||
}
|
||||
@@ -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.dialogue.input
|
||||
|
||||
import com.cobblemon.mod.common.api.dialogue.DialogueAction
|
||||
import com.cobblemon.mod.common.api.dialogue.FunctionDialogueAction
|
||||
|
||||
/**
|
||||
* A deadline for dialogue input. This is used to have something occur if the player spends
|
||||
* too long on one page of dialogue.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since December 27th, 2023
|
||||
*/
|
||||
class DialogueTimeout(
|
||||
var duration: Float = 10F,
|
||||
var showTimer: Boolean = true,
|
||||
var action: DialogueAction = FunctionDialogueAction { dialogue, _ -> dialogue.close() }
|
||||
)
|
||||
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.api.drop
|
||||
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.LOOT_DROPPED
|
||||
import com.cobblemon.mod.common.api.events.drops.LootDroppedEvent
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.entity.LivingEntity
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
@@ -88,6 +89,8 @@ class DropTable {
|
||||
amount: IntRange = this.amount
|
||||
) {
|
||||
val drops = getDrops(amount).toMutableList()
|
||||
val heldItem = (entity as PokemonEntity).pokemon.heldItemNoCopy()
|
||||
if (!heldItem.isEmpty) entity.dropItem(heldItem.item)
|
||||
LOOT_DROPPED.postThen(
|
||||
event = LootDroppedEvent(this, player, entity, drops),
|
||||
ifSucceeded = { it.drops.forEach { it.drop(entity, world, pos, player) } }
|
||||
|
||||
@@ -31,14 +31,14 @@ import net.minecraft.util.math.Vec3d
|
||||
* @author Hiroku
|
||||
* @since July 24th, 2022
|
||||
*/
|
||||
class ItemDropEntry : DropEntry {
|
||||
open class ItemDropEntry : DropEntry {
|
||||
override val percentage = 100F
|
||||
override val quantity = 1
|
||||
val quantityRange: IntRange? = null
|
||||
open val quantityRange: IntRange? = null
|
||||
override val maxSelectableTimes = 1
|
||||
val dropMethod: ItemDropMethod? = null
|
||||
val item = Identifier("minecraft:fish")
|
||||
val nbt: NbtCompound? = null
|
||||
open val dropMethod: ItemDropMethod? = null
|
||||
open val item = Identifier("minecraft:fish")
|
||||
open val nbt: NbtCompound? = null
|
||||
|
||||
override fun drop(entity: LivingEntity?, world: ServerWorld, pos: Vec3d, player: ServerPlayerEntity?) {
|
||||
val item = world.registryManager.get(RegistryKeys.ITEM).get(item) ?: return LOGGER.error("Unable to load drop item: $item")
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.api.entity
|
||||
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.entity.data.TrackedData
|
||||
|
||||
/**
|
||||
* Represents a delegation of a portion of an entity's logic to a particular side.
|
||||
@@ -16,4 +17,5 @@ import net.minecraft.entity.Entity
|
||||
interface EntitySideDelegate<T : Entity> {
|
||||
fun initialize(entity: T) {}
|
||||
fun tick(entity: T) {}
|
||||
fun onTrackedDataSet(data: TrackedData<*>) {}
|
||||
}
|
||||
@@ -33,6 +33,8 @@ import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionCompleteEv
|
||||
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionDisplayEvent
|
||||
import com.cobblemon.mod.common.api.events.pokemon.evolution.EvolutionTestedEvent
|
||||
import com.cobblemon.mod.common.api.events.pokemon.interaction.ExperienceCandyUseEvent
|
||||
import com.cobblemon.mod.common.api.events.pokemon.interaction.HeldItemUpdatedEvent
|
||||
import com.cobblemon.mod.common.api.events.pokemon.interaction.PokemonInteractionGUICreationEvent
|
||||
import com.cobblemon.mod.common.api.events.starter.StarterChosenEvent
|
||||
import com.cobblemon.mod.common.api.events.storage.ReleasePokemonEvent
|
||||
import com.cobblemon.mod.common.api.events.world.BigRootPropagatedEvent
|
||||
@@ -65,6 +67,8 @@ object CobblemonEvents {
|
||||
val EVOLUTION_COMPLETE = EventObservable<EvolutionCompleteEvent>()
|
||||
@JvmField
|
||||
val POKEMON_NICKNAMED = CancelableObservable<PokemonNicknamedEvent>()
|
||||
@JvmField
|
||||
val HELD_ITEM_UPDATED = CancelableObservable<HeldItemUpdatedEvent>()
|
||||
|
||||
@JvmField
|
||||
val THROWN_POKEBALL_HIT = CancelableObservable<ThrownPokeballHitEvent>()
|
||||
@@ -100,6 +104,9 @@ object CobblemonEvents {
|
||||
@JvmField
|
||||
val LEVEL_UP_EVENT = EventObservable<LevelUpEvent>()
|
||||
|
||||
@JvmField
|
||||
/** CLIENT ONLY! */
|
||||
val POKEMON_INTERACTION_GUI_CREATION = EventObservable<PokemonInteractionGUICreationEvent>()
|
||||
@JvmField
|
||||
val POKEMON_ENTITY_SAVE = EventObservable<PokemonEntitySaveEvent>()
|
||||
@JvmField
|
||||
@@ -153,4 +160,8 @@ object CobblemonEvents {
|
||||
val LEFTOVERS_CREATED = CancelableObservable<LeftoversCreatedEvent>()
|
||||
@JvmField
|
||||
val BIG_ROOT_PROPAGATED = CancelableObservable<BigRootPropagatedEvent>()
|
||||
@JvmField
|
||||
val HELD_ITEM_PRE = CancelableObservable<HeldItemEvent.Pre>()
|
||||
@JvmField
|
||||
val HELD_ITEM_POST = EventObservable<HeldItemEvent.Post>()
|
||||
}
|
||||
+5
-16
@@ -9,26 +9,19 @@
|
||||
package com.cobblemon.mod.common.api.events.battles
|
||||
|
||||
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.events.Cancelable
|
||||
import com.cobblemon.mod.common.battles.BattleFormat
|
||||
import net.minecraft.text.MutableText
|
||||
|
||||
/**
|
||||
* Event fired before a [PokemonBattle] is started. Canceling this event prevents the battle from being
|
||||
* created and launched.
|
||||
*
|
||||
* @property reason The text used to inform the participants why the battle was canceled. Keep null for a default error.
|
||||
*
|
||||
* @author Segfault Guy
|
||||
* @since March 26th 2023
|
||||
*/
|
||||
data class BattleStartedPreEvent (
|
||||
|
||||
val participants: Collection<BattleActor>,
|
||||
val format: BattleFormat,
|
||||
val isPvP: Boolean,
|
||||
val isPvN: Boolean,
|
||||
val isPvW: Boolean
|
||||
|
||||
) : Cancelable()
|
||||
data class BattleStartedPreEvent (override val battle: PokemonBattle, var reason: MutableText? = null) : BattleEvent, Cancelable()
|
||||
|
||||
/**
|
||||
* Event fired after a [PokemonBattle] starts.
|
||||
@@ -36,8 +29,4 @@ data class BattleStartedPreEvent (
|
||||
* @author Segfault Guy
|
||||
* @since March 26th 2023
|
||||
*/
|
||||
data class BattleStartedPostEvent (
|
||||
|
||||
override val battle: PokemonBattle
|
||||
|
||||
) : BattleEvent
|
||||
data class BattleStartedPostEvent (override val battle: PokemonBattle) : BattleEvent
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.events.pokemon
|
||||
|
||||
import com.cobblemon.mod.common.api.events.Cancelable
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import net.minecraft.item.ItemStack
|
||||
|
||||
/**
|
||||
* The base for all the events related to held items.
|
||||
*
|
||||
* @see [Pre]
|
||||
* @see [Post]
|
||||
*/
|
||||
interface HeldItemEvent {
|
||||
|
||||
/**
|
||||
* The [Pokemon] triggering this event.
|
||||
*/
|
||||
val pokemon: Pokemon
|
||||
|
||||
/**
|
||||
* Fired at the start of [Pokemon.swapHeldItem].
|
||||
*
|
||||
* This event should be used to mutate the results of this transaction.
|
||||
*
|
||||
* Canceling this event will prevent the operation and causes the return to be item attempted to be given originally.
|
||||
*
|
||||
* @property pokemon The [Pokemon] triggering this event.
|
||||
* @property receiving The [ItemStack] being sent received from the transaction. By default, this is the item that triggered the interaction.
|
||||
* @property returning The [ItemStack] being sent back from the transaction. By default, this is the currently held item.
|
||||
* @property decrement If the operation should decrement the [receiving] [ItemStack.count], this is handled in the implementation.
|
||||
*
|
||||
* @see [Post]
|
||||
*/
|
||||
data class Pre(override val pokemon: Pokemon, var receiving: ItemStack, var returning: ItemStack, var decrement: Boolean) : HeldItemEvent, Cancelable()
|
||||
|
||||
/**
|
||||
* Fired at the end of [Pokemon.swapHeldItem].
|
||||
*
|
||||
* @property pokemon The [Pokemon] triggering this event.
|
||||
* @property received The [ItemStack] considered as received and set to the [pokemon]. This is a copy and mutation will not be taken into account.
|
||||
* @property returned The [ItemStack] returned by the method call. This is a copy and mutation will not be taken into account.
|
||||
* @property decremented If the [received] [ItemStack] got decremented.
|
||||
*
|
||||
* @see [Pre]
|
||||
*/
|
||||
data class Post(override val pokemon: Pokemon, val received: ItemStack, val returned: ItemStack, val decremented: Boolean) : HeldItemEvent
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.events.pokemon.interaction
|
||||
|
||||
import com.cobblemon.mod.common.api.events.Cancelable
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import net.minecraft.entity.LivingEntity
|
||||
import net.minecraft.item.ItemStack
|
||||
|
||||
/**
|
||||
* Event published when a held item is being updated on a [Pokemon].
|
||||
* Cancelling the event will prevent any action from being taken on
|
||||
* the Pokémon.
|
||||
*
|
||||
* [newItem] differs from [originalStack] in that the former is a
|
||||
* one-sized version of the original (Pokémon cannot hold stacks) and
|
||||
* changing it in any way will not affect the original item held by
|
||||
* the player.
|
||||
*
|
||||
* @author Whatsy, Hiroku
|
||||
* @since November 13th, 2023
|
||||
*/
|
||||
data class HeldItemUpdatedEvent(
|
||||
val cause: LivingEntity?,
|
||||
val pokemon: Pokemon,
|
||||
val originalStack: ItemStack,
|
||||
val decrement: Boolean,
|
||||
val oldItem: ItemStack,
|
||||
val newItem: ItemStack
|
||||
) : Cancelable()
|
||||
+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.api.events.pokemon.interaction
|
||||
|
||||
import com.cobblemon.mod.common.client.gui.interact.wheel.InteractWheelOption
|
||||
import com.cobblemon.mod.common.client.gui.interact.wheel.Orientation
|
||||
import com.google.common.collect.Multimap
|
||||
import java.util.UUID
|
||||
|
||||
data class PokemonInteractionGUICreationEvent(
|
||||
val pokemonID: UUID,
|
||||
val mountShoulder: Boolean,
|
||||
val options: Multimap<Orientation, InteractWheelOption>
|
||||
) {
|
||||
fun addFillingOption(option: InteractWheelOption) {
|
||||
options.put(getNextFreeOrientation(), option)
|
||||
}
|
||||
|
||||
fun addOption(orientation: Orientation, option: InteractWheelOption) {
|
||||
options.put(orientation, option)
|
||||
}
|
||||
|
||||
private fun getNextFreeOrientation(): Orientation {
|
||||
var largest = Orientation.TOP_LEFT
|
||||
for(orientation in Orientation.values()) {
|
||||
if(!options.containsKey(orientation)) {
|
||||
return orientation
|
||||
} else {
|
||||
if(options.get(orientation).size < options.get(largest).size) {
|
||||
largest = orientation
|
||||
}
|
||||
}
|
||||
}
|
||||
return largest
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.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
|
||||
import net.minecraft.util.StringIdentifiable
|
||||
|
||||
class Fossil(
|
||||
identifier: Identifier,
|
||||
val result: PokemonProperties,
|
||||
val fossils: List<NbtItemPredicate>
|
||||
): StringIdentifiable {
|
||||
|
||||
@Transient
|
||||
var identifier: Identifier = identifier
|
||||
internal set
|
||||
|
||||
override fun asString(): String {
|
||||
return identifier.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the fossil.
|
||||
* @return The name of the fossil.
|
||||
*/
|
||||
fun getName(): MutableText = Text.translatable("${identifier.namespace}.fossil.${identifier.path}.name")
|
||||
|
||||
/**
|
||||
* Whether the fossil ingredients match this fossil.
|
||||
* @param ingredients The ingredients to check.
|
||||
* @return True if the ingredients match, false otherwise.
|
||||
*/
|
||||
fun matchesIngredients(ingredients: List<ItemStack>): Boolean {
|
||||
if (this.fossils.size != ingredients.size) {
|
||||
return false
|
||||
}
|
||||
|
||||
return this.fossils.all { fossil ->
|
||||
ingredients.any { fossil.item.fits(it.item, Registries.ITEM) && fossil.nbt.test(it) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the fossil ingredients match a subset of this fossil.
|
||||
* @param ingredients The ingredients to check.
|
||||
* @return True if the ingredients are a subset, false otherwise.
|
||||
*/
|
||||
fun matchesIngredientsSubSet(ingredients: List<ItemStack>): Boolean {
|
||||
if (this.fossils.size < ingredients.size) {
|
||||
return false
|
||||
}
|
||||
|
||||
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) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the [ItemStack] is an ingredient for this fossil.
|
||||
* @param itemStack The [ItemStack] to check.
|
||||
* @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) }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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.fossil
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.net.messages.client.fossil.FossilRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.pokemon.evolution.adapters.NbtItemPredicateAdapter
|
||||
import com.cobblemon.mod.common.pokemon.evolution.predicate.NbtItemPredicate
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ItemLikeConditionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.pokemonPropertiesShortAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.resource.ResourceType
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
object Fossils: JsonDataRegistry<Fossil> {
|
||||
|
||||
override val id: Identifier = cobblemonResource("fossils")
|
||||
override val type: ResourceType = ResourceType.SERVER_DATA
|
||||
override val observable = SimpleObservable<Fossils>()
|
||||
|
||||
override val gson = GsonBuilder()
|
||||
.disableHtmlEscaping()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
|
||||
.registerTypeAdapter(PokemonProperties::class.java, pokemonPropertiesShortAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Item::class.java).type, ItemLikeConditionAdapter)
|
||||
.registerTypeAdapter(NbtItemPredicate::class.java, NbtItemPredicateAdapter)
|
||||
.create()
|
||||
|
||||
override val typeToken: TypeToken<Fossil> = TypeToken.get(Fossil::class.java)
|
||||
override val resourcePath: String = "fossils"
|
||||
|
||||
private val fossils = hashMapOf<Identifier, Fossil>()
|
||||
|
||||
override fun reload(data: Map<Identifier, Fossil>) {
|
||||
this.fossils.clear()
|
||||
data.forEach { (identifier, fossil) ->
|
||||
try {
|
||||
fossil.identifier = identifier
|
||||
this.fossils[identifier] = fossil
|
||||
} catch (e: Exception) {
|
||||
Cobblemon.LOGGER.error("Skipped loading the {} fossil", identifier, e)
|
||||
}
|
||||
}
|
||||
Cobblemon.LOGGER.info("Loaded {} fossils", this.fossils.size)
|
||||
this.observable.emit(this)
|
||||
}
|
||||
|
||||
override fun sync(player: ServerPlayerEntity) {
|
||||
FossilRegistrySyncPacket(this.all()).sendToPlayer(player)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all loaded [Fossil]s.
|
||||
*/
|
||||
fun all() = this.fossils.values.toList()
|
||||
|
||||
/**
|
||||
* Gets a [Fossil] by its [Identifier].
|
||||
* @param identifier The identifier of the fossil.
|
||||
* @return The [Fossil] if loaded, otherwise null.
|
||||
*/
|
||||
fun getByIdentifier(identifier: Identifier): Fossil? = this.fossils[identifier]
|
||||
|
||||
/**
|
||||
* Looks for a [Fossil] that matches a [ItemStack].
|
||||
* @param fossilStacks The fossil [ItemStack]'s.
|
||||
* @return The [Fossil] if found, otherwise null.
|
||||
*/
|
||||
fun getFossilByItemStacks(fossilStacks: List<ItemStack>): Fossil? {
|
||||
return this.all().firstOrNull { it.matchesIngredients(fossilStacks) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for a [Fossil] that is a superset of [ItemStack].
|
||||
* @param fossilStacks The fossil [ItemStack]'s.
|
||||
* @return The [Fossil] if found to be a superset, otherwise null.
|
||||
*/
|
||||
fun getSubFossilByItemStacks(fossilStacks: List<ItemStack>): Fossil? {
|
||||
return this.all().firstOrNull { it.matchesIngredientsSubSet(fossilStacks) }
|
||||
}
|
||||
/**
|
||||
* Checks if a [ItemStack] is a fossil ingredient.
|
||||
* @param itemStack The ingredient [ItemStack].
|
||||
* @return true if it's a fossil ingredient, otherwise false.
|
||||
*/
|
||||
fun isFossilIngredient(itemStack: ItemStack): Boolean {
|
||||
return this.all().any { it.isIngredient(itemStack) }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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.fossil
|
||||
|
||||
import com.cobblemon.mod.common.registry.ItemTagCondition
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
data class NaturalMaterial(
|
||||
val content: Int = 0,
|
||||
val item: Identifier?,
|
||||
val tag: ItemTagCondition? = null,
|
||||
val returnItem: Identifier? = null
|
||||
)
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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.fossil
|
||||
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.net.messages.client.fossil.NaturalMaterialRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.registry.ItemTagCondition
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ItemLikeConditionAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.registry.Registries
|
||||
import net.minecraft.resource.ResourceType
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
object NaturalMaterials : JsonDataRegistry<List<NaturalMaterial>>{
|
||||
override val id = cobblemonResource("natural_materials")
|
||||
override val type = ResourceType.SERVER_DATA
|
||||
override val observable = SimpleObservable<NaturalMaterials>()
|
||||
override val typeToken: TypeToken<List<NaturalMaterial>> =
|
||||
TypeToken.getParameterized(List::class.java, NaturalMaterial::class.java) as TypeToken<List<NaturalMaterial>>
|
||||
override val resourcePath = "natural_materials"
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
|
||||
.registerTypeAdapter(ItemTagCondition::class.java, ItemLikeConditionAdapter)
|
||||
.create()
|
||||
|
||||
private val itemMap = mutableMapOf<Identifier, NaturalMaterial>()
|
||||
private val tagMap = mutableMapOf<ItemTagCondition, NaturalMaterial>()
|
||||
override fun sync(player: ServerPlayerEntity) {
|
||||
NaturalMaterialRegistrySyncPacket(this.itemMap.values.toList() + this.tagMap.values.toList()).sendToPlayer(player)
|
||||
}
|
||||
|
||||
override fun reload(data: Map<Identifier, List<NaturalMaterial>>) {
|
||||
data.forEach { entry ->
|
||||
entry.value.forEach {
|
||||
itemMap.remove(it.item)
|
||||
if (it.item != null) {
|
||||
itemMap[it.item] = it
|
||||
}
|
||||
if (it.tag != null) {
|
||||
tagMap[it.tag] = it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun isNaturalMaterial(item: ItemStack): Boolean {
|
||||
val itemId = Registries.ITEM.getId(item.item)
|
||||
return itemId in itemMap.keys || tagMap.keys.any {
|
||||
it.fits(item.item, Registries.ITEM)
|
||||
}
|
||||
}
|
||||
|
||||
fun getContent(item: ItemStack): Int? {
|
||||
val itemId = Registries.ITEM.getId(item.item)
|
||||
if (itemId in itemMap.keys) {
|
||||
return itemMap[itemId]?.content
|
||||
}
|
||||
val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
|
||||
if (tag != null) {
|
||||
return tagMap[tag]?.content
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun getReturnItem(item: ItemStack): Identifier? {
|
||||
val itemId = Registries.ITEM.getId(item.item)
|
||||
if (itemId in itemMap.keys) {
|
||||
return itemMap[itemId]?.returnItem
|
||||
}
|
||||
val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
|
||||
if (tag != null) {
|
||||
return tagMap[tag]?.returnItem
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -196,6 +196,8 @@ fun drawPortraitPokemon(
|
||||
val context = RenderContext()
|
||||
PokemonModelRepository.getTextureNoSubstitute(species.resourceIdentifier, aspects, 0f).let { it -> context.put(RenderContext.TEXTURE, it) }
|
||||
context.put(RenderContext.SCALE, species.getForm(aspects).baseScale)
|
||||
context.put(RenderContext.SPECIES, species.resourceIdentifier)
|
||||
context.put(RenderContext.ASPECTS, aspects)
|
||||
|
||||
val renderType = model.getLayer(texture)
|
||||
|
||||
@@ -206,10 +208,12 @@ fun drawPortraitPokemon(
|
||||
if (state == null) {
|
||||
model.setupAnimStateless(setOf(PoseType.PORTRAIT, PoseType.PROFILE))
|
||||
} else {
|
||||
val originalPose = state.currentPose
|
||||
model.getPose(PoseType.PORTRAIT)?.let { state.setPose(it.poseName) }
|
||||
state.timeEnteredPose = 0F
|
||||
state.updatePartialTicks(partialTicks)
|
||||
model.setupAnimStateful(null, state, 0F, 0F, 0F, 0F, 0F)
|
||||
originalPose?.let { state.setPose(it) }
|
||||
}
|
||||
|
||||
matrixStack.push()
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.molang
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
|
||||
/**
|
||||
* An object that can be given a [MoLangRuntime] to produce a single [MoValue]. This abstracts
|
||||
* the use of simple and complex [Expression]s as MoLang can be a single line or multiple.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 22nd, 2023
|
||||
*/
|
||||
interface ExpressionLike {
|
||||
/** Produces a [MoValue] for a [MoLangRuntime] to supply an environment. */
|
||||
fun resolve(runtime: MoLangRuntime): MoValue
|
||||
|
||||
fun resolveDouble(runtime: MoLangRuntime) = resolve(runtime).asDouble()
|
||||
fun resolveFloat(runtime: MoLangRuntime) = resolveDouble(runtime).toFloat()
|
||||
fun resolveString(runtime: MoLangRuntime) = resolve(runtime).asString()
|
||||
fun resolveInt(runtime: MoLangRuntime) = resolveDouble(runtime).toInt()
|
||||
fun resolveBoolean(runtime: MoLangRuntime) = resolveDouble(runtime) == 1.0
|
||||
fun resolveObject(runtime: MoLangRuntime) = resolve(runtime) as ObjectValue<*>
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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.molang
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.util.resolve
|
||||
|
||||
/**
|
||||
* An [ExpressionLike] that produces MoValues by evaluating a series of [Expression]s.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 22nd, 2023
|
||||
*/
|
||||
class ListExpression(val exprs: List<Expression>): ExpressionLike {
|
||||
override fun resolve(runtime: MoLangRuntime) = exprs.resolve(runtime)
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* 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.molang
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangEnvironment
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.MoParams
|
||||
import com.bedrockk.molang.runtime.struct.ArrayStruct
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.struct.VariableStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
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.isInt
|
||||
import com.cobblemon.mod.common.util.itemRegistry
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.nbt.NbtDouble
|
||||
import net.minecraft.nbt.NbtElement
|
||||
import net.minecraft.nbt.NbtList
|
||||
import net.minecraft.nbt.NbtString
|
||||
import net.minecraft.registry.Registry
|
||||
import net.minecraft.registry.RegistryKey
|
||||
import net.minecraft.registry.RegistryKeys
|
||||
import net.minecraft.registry.entry.RegistryEntry
|
||||
import net.minecraft.registry.tag.TagKey
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.world.World
|
||||
import net.minecraft.world.biome.Biome
|
||||
import net.minecraft.world.dimension.DimensionType
|
||||
|
||||
/**
|
||||
* Holds a bunch of useful MoLang trickery that can be used or extended in API
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 2nd, 2023
|
||||
*/
|
||||
object MoLangFunctions {
|
||||
val generalFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>(
|
||||
"is_int" to java.util.function.Function { params -> DoubleValue(params.get<MoValue>(0).asString().isInt()) },
|
||||
"is_number" to java.util.function.Function { params -> DoubleValue(params.get<MoValue>(0).asString().toDoubleOrNull() != null) },
|
||||
"to_number" to java.util.function.Function { params -> DoubleValue(params.get<MoValue>(0).asString().toDoubleOrNull() ?: 0.0) },
|
||||
"to_int" to java.util.function.Function { params -> DoubleValue(params.get<MoValue>(0).asString().toIntOrNull() ?: 0) },
|
||||
"to_string" to java.util.function.Function { params -> StringValue(params.get<MoValue>(0).asString()) },
|
||||
"do_effect_walks" to java.util.function.Function { _ ->
|
||||
DoubleValue(Cobblemon.config.walkingInBattleAnimations)
|
||||
},
|
||||
"random" to java.util.function.Function { params ->
|
||||
val options = mutableListOf<MoValue>()
|
||||
var index = 0
|
||||
while (params.contains(index)) {
|
||||
options.add(params.get(index))
|
||||
index++
|
||||
}
|
||||
return@Function options.random() // Can throw an exception if they specified no args. They'd be idiots though.
|
||||
},
|
||||
"curve" to java.util.function.Function { params ->
|
||||
val curveName = params.getString(0)
|
||||
val curve = WaveFunctions.functions[curveName] ?: throw IllegalArgumentException("Unknown curve: $curveName")
|
||||
return@Function ObjectValue(curve)
|
||||
},
|
||||
"array" to java.util.function.Function { params ->
|
||||
val values = params.params
|
||||
val array = ArrayStruct(hashMapOf())
|
||||
values.forEachIndexed { index, moValue -> array.setDirectly("$index", moValue) }
|
||||
return@Function array
|
||||
}
|
||||
)
|
||||
val biomeFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
val worldFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
val dimensionTypeFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
val blockFunctions = hashMapOf<String, java.util.function.Function<MoParams, Any>>()
|
||||
val playerFunctions = mutableListOf<(ServerPlayerEntity) -> HashMap<String, java.util.function.Function<MoParams, Any>>>(
|
||||
{ player ->
|
||||
hashMapOf(
|
||||
"username" to java.util.function.Function { _ -> StringValue(player.gameProfile.name) },
|
||||
"uuid" to java.util.function.Function { _ -> StringValue(player.gameProfile.id.toString()) },
|
||||
"data" to java.util.function.Function { _ -> return@Function Cobblemon.molangData.load(player.uuid) },
|
||||
"save_data" to java.util.function.Function { _ -> Cobblemon.molangData.save(player.uuid) },
|
||||
"main_held_item" to java.util.function.Function { _ -> player.world.itemRegistry.getEntry(player.mainHandStack.item).asMoLangValue(RegistryKeys.ITEM) },
|
||||
"off_held_item" to java.util.function.Function { _ -> player.world.itemRegistry.getEntry(player.offHandStack.item).asMoLangValue(RegistryKeys.ITEM) },
|
||||
"face" to java.util.function.Function { _ -> ObjectValue(PlayerDialogueFaceProvider(player.uuid)) }
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
fun RegistryEntry<Biome>.asBiomeMoLangValue() = asMoLangValue(RegistryKeys.BIOME).addFunctions(biomeFunctions)
|
||||
fun RegistryEntry<World>.asWorldMoLangValue() = asMoLangValue(RegistryKeys.WORLD).addFunctions(worldFunctions)
|
||||
fun RegistryEntry<Block>.asBlockMoLangValue() = asMoLangValue(RegistryKeys.BLOCK).addFunctions(blockFunctions)
|
||||
fun RegistryEntry<DimensionType>.asDimensionTypeMoLangValue() = asMoLangValue(RegistryKeys.DIMENSION_TYPE).addFunctions(dimensionTypeFunctions)
|
||||
fun ServerPlayerEntity.asMoLangValue(): ObjectValue<ServerPlayerEntity> {
|
||||
val value = ObjectValue(
|
||||
obj = this,
|
||||
stringify = { it.entityName }
|
||||
)
|
||||
value.addFunctions(playerFunctions.flatMap { it(this).entries.map { it.key to it.value } }.toMap())
|
||||
return value
|
||||
}
|
||||
|
||||
fun <T> RegistryEntry<T>.asMoLangValue(key: RegistryKey<Registry<T>>): ObjectValue<RegistryEntry<T>> {
|
||||
val value = ObjectValue(
|
||||
obj = this,
|
||||
stringify = { it.key.get().value.toString() }
|
||||
)
|
||||
value.functions.put("is_in") {
|
||||
val tag = TagKey.of(key, Identifier(it.getString(0).replace("#", "")))
|
||||
return@put DoubleValue(if (value.obj.isIn(tag)) 1.0 else 0.0)
|
||||
}
|
||||
value.functions.put("is_of") {
|
||||
val identifier = Identifier(it.getString(0))
|
||||
return@put DoubleValue(if (value.obj.matchesId(identifier)) 1.0 else 0.0)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
fun QueryStruct.addStandardFunctions(): QueryStruct {
|
||||
functions.putAll(generalFunctions)
|
||||
return this
|
||||
}
|
||||
|
||||
fun <T : QueryStruct> T.addFunctions(functions: Map<String, java.util.function.Function<MoParams, Any>>): T {
|
||||
this.functions.putAll(functions)
|
||||
return this
|
||||
}
|
||||
|
||||
fun <T : QueryStruct> T.addFunction(name: String, function: java.util.function.Function<MoParams, Any>): T {
|
||||
this.functions[name] = function
|
||||
return this
|
||||
}
|
||||
|
||||
fun MoLangEnvironment.getQueryStruct(name: String = "query") = structs.getOrPut(name) { QueryStruct(hashMapOf()) } as QueryStruct
|
||||
|
||||
fun MoLangRuntime.setup(): MoLangRuntime {
|
||||
environment.getQueryStruct().addStandardFunctions()
|
||||
return this
|
||||
}
|
||||
|
||||
fun writeMoValueToNBT(value: MoValue): NbtElement? {
|
||||
return when (value) {
|
||||
is DoubleValue -> NbtDouble.of(value.value)
|
||||
is StringValue -> NbtString.of(value.value)
|
||||
is ArrayStruct -> {
|
||||
val list = value.map.values
|
||||
val nbtList = NbtList()
|
||||
list.mapNotNull(::writeMoValueToNBT).forEach(nbtList::add)
|
||||
nbtList
|
||||
}
|
||||
is VariableStruct -> {
|
||||
val nbt = NbtCompound()
|
||||
value.map.forEach { (key, value) ->
|
||||
val element = writeMoValueToNBT(value) ?: return@forEach
|
||||
nbt.put(key, element)
|
||||
}
|
||||
nbt
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun readMoValueFromNBT(nbt: NbtElement): MoValue {
|
||||
return when (nbt) {
|
||||
is NbtDouble -> DoubleValue(nbt.doubleValue())
|
||||
is NbtString -> StringValue(nbt.asString())
|
||||
is NbtList -> {
|
||||
val array = ArrayStruct(hashMapOf())
|
||||
var index = 0
|
||||
nbt.forEach { element ->
|
||||
val value = readMoValueFromNBT(element)
|
||||
array.setDirectly("$index", value)
|
||||
index++
|
||||
}
|
||||
array
|
||||
}
|
||||
is NbtCompound -> {
|
||||
val variable = VariableStruct(hashMapOf())
|
||||
nbt.keys.toList().forEach { key ->
|
||||
val value = readMoValueFromNBT(nbt[key]!!)
|
||||
variable.map[key] = value
|
||||
}
|
||||
variable
|
||||
}
|
||||
else -> null
|
||||
} ?: throw IllegalArgumentException("Invalid NBT element type: ${nbt.type}")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.molang
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
|
||||
/**
|
||||
* A [MoValue] that just wraps around some other object value. It's for good and valid reasons.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 2nd, 2023
|
||||
*/
|
||||
class ObjectValue<T>(
|
||||
var obj: T,
|
||||
val stringify: (T) -> String = { it.toString() },
|
||||
val doublify: (T) -> Double = { throw NotImplementedError("Doublify not implemented for this object value, are you doing weird molang") }
|
||||
) : QueryStruct(hashMapOf()) {
|
||||
override fun value() = this
|
||||
override fun asDouble() = doublify(obj)
|
||||
override fun asString() = stringify(obj)
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.molang
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.util.resolve
|
||||
|
||||
/**
|
||||
* A simple implementation of [ExpressionLike] that is just a single [Expression]. This
|
||||
* is as opposed to [ListExpression]s.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 22nd, 2023
|
||||
*/
|
||||
class SingleExpression(val expr: Expression) : ExpressionLike {
|
||||
override fun resolve(runtime: MoLangRuntime) = runtime.resolve(expr)
|
||||
}
|
||||
@@ -8,6 +8,12 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.moves
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.MoStruct
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunction
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategories
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategory
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
@@ -45,8 +51,22 @@ open class MoveTemplate(
|
||||
val pp: Int,
|
||||
val priority: Int,
|
||||
val critRatio: Double,
|
||||
val effectChances: Array<Double>
|
||||
val effectChances: Array<Double>,
|
||||
val actionEffect: ActionEffectTimeline?
|
||||
) {
|
||||
val struct: MoStruct by lazy {
|
||||
QueryStruct(hashMapOf())
|
||||
.addFunction("name") { StringValue(name) }
|
||||
.addFunction("type") { StringValue(elementalType.name) }
|
||||
.addFunction("damage_category") { StringValue(damageCategory.name) }
|
||||
.addFunction("power") { DoubleValue(power) }
|
||||
.addFunction("target") { StringValue(target.name) }
|
||||
.addFunction("accuracy") { DoubleValue(accuracy) }
|
||||
.addFunction("pp") { DoubleValue(pp) }
|
||||
.addFunction("priority") { DoubleValue(priority) }
|
||||
.addFunction("crit_ratio") { DoubleValue(critRatio) }
|
||||
}
|
||||
|
||||
|
||||
val displayName: MutableText
|
||||
get() = lang("move.$name")
|
||||
@@ -65,7 +85,8 @@ open class MoveTemplate(
|
||||
pp = 5,
|
||||
priority = 0,
|
||||
critRatio = 0.0,
|
||||
effectChances = emptyArray()
|
||||
effectChances = emptyArray(),
|
||||
actionEffect = null
|
||||
)
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -10,12 +10,15 @@ package com.cobblemon.mod.common.api.moves
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.data.DataRegistry
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategories
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.battles.MoveTarget
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||
import com.cobblemon.mod.common.net.messages.client.data.MovesRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
@@ -72,7 +75,18 @@ object Moves : DataRegistry {
|
||||
effectChances += secondaryMember.get("chance").asDouble
|
||||
}
|
||||
}
|
||||
val move = MoveTemplate(id, num, elementalType, damageCategory, power, target, accuracy, pp, priority, critRatio, effectChances.toTypedArray())
|
||||
val actionEffect = ActionEffects.actionEffects[id.asIdentifierDefaultingNamespace()]
|
||||
?: run {
|
||||
ActionEffects.actionEffects["generic_move".asIdentifierDefaultingNamespace()]
|
||||
// if (damageCategory == DamageCategories.STATUS) {
|
||||
// ActionEffects.actionEffects[cobblemonResource("status")]
|
||||
// } else {
|
||||
// val type = elementalType.name.lowercase()
|
||||
// val category = damageCategory.name.lowercase()
|
||||
// ActionEffects.actionEffects["${category}_$type".asIdentifierDefaultingNamespace()]
|
||||
// }
|
||||
}
|
||||
val move = MoveTemplate(id, num, elementalType, damageCategory, power, target, accuracy, pp, priority, critRatio, effectChances.toTypedArray(), actionEffect)
|
||||
this.register(move)
|
||||
} catch (e: Exception) {
|
||||
Cobblemon.LOGGER.error("Caught exception trying to resolve the move '{}'", id, e)
|
||||
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.moves.animations
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.struct.VariableStruct
|
||||
import com.cobblemon.mod.common.api.moves.animations.keyframes.ActionEffectKeyframe
|
||||
import com.cobblemon.mod.common.api.scheduling.ScheduledTask
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import net.minecraft.entity.Entity
|
||||
|
||||
/**
|
||||
* An action effect will run and execute a series of 'keyframes', with each running once
|
||||
* the previous has completed. The entire effect is considered complete for the given context
|
||||
* once all the 'holds' provided in the context have been cleared or once every keyframe
|
||||
* has finished.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 20th, 2023
|
||||
*/
|
||||
class ActionEffectTimeline(
|
||||
val timeline: List<ActionEffectKeyframe> = mutableListOf(),
|
||||
val condition: Expression = "true".asExpression()
|
||||
) {
|
||||
companion object {
|
||||
val NONE = ActionEffectTimeline()
|
||||
}
|
||||
|
||||
fun run(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
return if (timeline.isEmpty() || !context.runtime.resolveBoolean(condition)) {
|
||||
CompletableFuture.completedFuture(Unit)
|
||||
} else {
|
||||
val finalFuture = CompletableFuture<Unit>()
|
||||
// .toList copy because I'm paranoid about iterators being trying to share between identical effects playing
|
||||
chainKeyframes(context, timeline.toList().iterator(), finalFuture)
|
||||
finalFuture
|
||||
}
|
||||
}
|
||||
|
||||
fun chainKeyframes(context: ActionEffectContext, iterator: Iterator<ActionEffectKeyframe>, finalFuture: CompletableFuture<Unit>) {
|
||||
if (!iterator.hasNext()) {
|
||||
finalFuture.complete(Unit)
|
||||
} else {
|
||||
val keyframe = iterator.next()
|
||||
context.currentKeyframes.add(keyframe)
|
||||
keyframe.play(context)
|
||||
.thenRun { context.currentKeyframes.remove(keyframe) }
|
||||
.thenApply { chainKeyframes(context, iterator, finalFuture) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ActionEffectContext(
|
||||
val actionEffect: ActionEffectTimeline,
|
||||
val holds: MutableSet<String> = mutableSetOf(),
|
||||
val providers: MutableList<Any> = mutableListOf(),
|
||||
val runtime: MoLangRuntime,
|
||||
var canBeInterrupted: Boolean = false,
|
||||
var interrupted: Boolean = false,
|
||||
var currentKeyframes: MutableList<ActionEffectKeyframe> = mutableListOf()
|
||||
) {
|
||||
inline fun <reified T> findOneProvider() = providers.filterIsInstance<T>().firstOrNull()
|
||||
|
||||
|
||||
}
|
||||
|
||||
class UsersProvider(users: List<Entity>): EntityProvider {
|
||||
override val entities = users
|
||||
constructor(vararg users: Entity): this(users.toList())
|
||||
}
|
||||
|
||||
class TargetsProvider(targets: List<Entity>): EntityProvider {
|
||||
override val entities = targets
|
||||
constructor(vararg targets: Entity): this(targets.toList())
|
||||
}
|
||||
|
||||
interface EntityProvider {
|
||||
val entities: List<Entity>
|
||||
}
|
||||
|
||||
//class MoveAnimationKeyframe(
|
||||
// val sound: Identifier? = null,
|
||||
// val animation: List<AnimationWithMoments> = listOf(),
|
||||
// val effects: List<ActionEffect> = listOf()
|
||||
//)
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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.moves.animations
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.moves.animations.keyframes.*
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stat
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.pokemon.adapters.CobblemonStatTypeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.*
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import java.awt.Color
|
||||
import net.minecraft.predicate.NumberRange
|
||||
import net.minecraft.resource.ResourceType
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.Box
|
||||
import net.minecraft.util.math.Vec3d
|
||||
|
||||
/**
|
||||
* Data registry containing all of the [ActionEffectTimeline]s that can be triggered from various actions.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 21st, 2023
|
||||
*/
|
||||
object ActionEffects : JsonDataRegistry<ActionEffectTimeline> {
|
||||
override val id: Identifier = cobblemonResource("action_effects")
|
||||
override val type: ResourceType = ResourceType.SERVER_DATA
|
||||
override val observable = SimpleObservable<ActionEffects>()
|
||||
|
||||
init {
|
||||
ActionEffectKeyframe.register<AnimationActionEffectKeyframe>("animation")
|
||||
ActionEffectKeyframe.register<EntityMoLangActionEffectKeyframe>("entity_molang")
|
||||
ActionEffectKeyframe.register<MoLangActionEffectKeyframe>("molang")
|
||||
ActionEffectKeyframe.register<ParallelActionEffectKeyframe>("parallel")
|
||||
ActionEffectKeyframe.register<CanInterruptActionEffectKeyframe>("can_interrupt")
|
||||
ActionEffectKeyframe.register<CannotInterruptActionEffectKeyframe>("cannot_interrupt")
|
||||
ActionEffectKeyframe.register<RemoveHoldsActionEffectKeyframe>("remove_holds")
|
||||
ActionEffectKeyframe.register<AddHoldsActionEffectKeyframe>("add_holds")
|
||||
ActionEffectKeyframe.register<MoveToTargetActionEffectKeyframe>("move_to_target")
|
||||
ActionEffectKeyframe.register<ReturnToPositionActionEffectKeyframe>("return_to_position")
|
||||
ActionEffectKeyframe.register<PauseActionEffectKeyframe>("pause")
|
||||
ActionEffectKeyframe.register<SavePositionActionEffectKeyframe>("save_position")
|
||||
ActionEffectKeyframe.register<ForkActionEffectKeyframe>("fork")
|
||||
ActionEffectKeyframe.register<SequenceActionEffectKeyframe>("sequence")
|
||||
ActionEffectKeyframe.register<RunActionEffectKeyframe>("run_action_effect")
|
||||
ActionEffectKeyframe.register<EntityParticlesActionEffectKeyframe>("entity_particles")
|
||||
ActionEffectKeyframe.register<EntitySoundActionEffectKeyframe>("entity_sound")
|
||||
}
|
||||
|
||||
override val gson = GsonBuilder()
|
||||
.disableHtmlEscaping()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(ActionEffectKeyframe::class.java, ActionEffectKeyframeAdapter)
|
||||
.registerTypeAdapter(NumberRange.FloatRange::class.java, FloatNumberRangeAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(Collection::class.java, Box::class.java).type, BoxCollectionAdapter)
|
||||
.registerTypeAdapter(Box::class.java, BoxAdapter)
|
||||
.registerTypeAdapter(Vec3d::class.java, VerboseVec3dAdapter)
|
||||
.registerTypeAdapter(Identifier::class.java, IdentifierAdapter)
|
||||
.registerTypeAdapter(IntRange::class.java, VerboseIntRangeAdapter)
|
||||
.registerTypeAdapter(Color::class.java, LiteralHexColorAdapter)
|
||||
.registerTypeAdapter(Stat::class.java, CobblemonStatTypeAdapter)
|
||||
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
|
||||
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
|
||||
.registerTypeAdapter(
|
||||
TypeToken.getParameterized(
|
||||
TypeToken.get(List::class.java).type,
|
||||
TypeToken.get(ActionEffectKeyframe::class.java).type
|
||||
).type,
|
||||
SingleToPluralAdapter(ActionEffectKeyframe::class.java) { it }
|
||||
)
|
||||
.create()
|
||||
|
||||
override val typeToken: TypeToken<ActionEffectTimeline> = TypeToken.get(ActionEffectTimeline::class.java)
|
||||
override val resourcePath = "action_effects"
|
||||
|
||||
val actionEffects = mutableMapOf<Identifier, ActionEffectTimeline>()
|
||||
override fun reload(data: Map<Identifier, ActionEffectTimeline>) {
|
||||
actionEffects.clear()
|
||||
actionEffects.putAll(data)
|
||||
observable.emit(this)
|
||||
}
|
||||
|
||||
override fun sync(player: ServerPlayerEntity) {}
|
||||
}
|
||||
+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.api.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* A single component of an action effect. When played it must return a completable future that completes
|
||||
* when the action this keyframe represents is finished. [interrupt] is provided for when something successfully
|
||||
* interrupts the effect so that if any cancellation logic is necessary, it can be provided.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 26th, 2023
|
||||
*/
|
||||
interface ActionEffectKeyframe {
|
||||
companion object {
|
||||
val types = mutableMapOf<String, Class<out ActionEffectKeyframe>>()
|
||||
|
||||
inline fun <reified T : ActionEffectKeyframe> register(type: String) {
|
||||
types[type] = T::class.java
|
||||
}
|
||||
}
|
||||
|
||||
fun play(context: ActionEffectContext): CompletableFuture<Unit>
|
||||
fun interrupt(context: ActionEffectContext) {}
|
||||
fun skip(): CompletableFuture<Unit> = CompletableFuture.completedFuture(Unit)
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* An [ActionEffectKeyframe] that adds some holds from the context for future code to recognize as blocking some
|
||||
* functionality from proceeding.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 27th, 2023
|
||||
*/
|
||||
class AddHoldsActionEffectKeyframe : ActionEffectKeyframe {
|
||||
val holds = mutableSetOf<String>()
|
||||
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
context.holds.addAll(holds)
|
||||
return CompletableFuture.completedFuture(Unit)
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.moves.animations.keyframes
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.EntityProvider
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.api.scheduling.delayedFuture
|
||||
import com.cobblemon.mod.common.net.messages.client.animation.PlayPoseableAnimationPacket
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
|
||||
class AnimationActionEffectKeyframe : ConditionalActionEffectKeyframe(), EntityConditionalActionEffectKeyframe {
|
||||
var delay = "0".asExpressionLike()
|
||||
var visibilityRange = 200
|
||||
var animation: Set<String> = setOf("physical")
|
||||
var variables: List<Expression> = listOf()
|
||||
override val entityCondition = "q.entity.is_user".asExpressionLike()
|
||||
|
||||
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
val entities = context.providers
|
||||
.filterIsInstance<EntityProvider>()
|
||||
.flatMap { prov -> prov.entities.filter { test(context, it, isUser = prov is UsersProvider) } }
|
||||
|
||||
val expressions = variables.map { it.originalString }.toSet()
|
||||
|
||||
// Treat them as expressions if possible but otherwise yeah just send them as strings
|
||||
val animation = animation.map {
|
||||
try {
|
||||
it.asExpressionLike().resolveString(context.runtime).takeIf { it != "0.0" } ?: it
|
||||
} catch (e: Exception) {
|
||||
it
|
||||
}
|
||||
}.toSet()
|
||||
|
||||
for (entity in entities) {
|
||||
val world = entity.world as ServerWorld
|
||||
val players = world.getPlayers { it.distanceTo(entity) <= visibilityRange }
|
||||
val pkt = PlayPoseableAnimationPacket(entity.id, animation = animation, expressions = expressions)
|
||||
players.forEach { it.sendPacket(pkt) }
|
||||
}
|
||||
|
||||
return delayedFuture(seconds = delay.resolveFloat(context.runtime), serverThread = true)
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class CanInterruptActionEffectKeyframe : ConditionalActionEffectKeyframe() {
|
||||
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
context.canBeInterrupted = true
|
||||
return CompletableFuture.completedFuture(Unit)
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class CannotInterruptActionEffectKeyframe : ConditionalActionEffectKeyframe() {
|
||||
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
context.canBeInterrupted = true
|
||||
return CompletableFuture.completedFuture(Unit)
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
abstract class ConditionalActionEffectKeyframe : ActionEffectKeyframe {
|
||||
var condition: ExpressionLike = "true".asExpressionLike()
|
||||
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
return if (condition.resolveBoolean(context.runtime)) {
|
||||
playWhenTrue(context)
|
||||
} else {
|
||||
skip()
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit>
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.moves.animations.keyframes
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import net.minecraft.entity.Entity
|
||||
|
||||
/**
|
||||
* An action effect keyframe that plays for all entities for which the condition is true.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since January 21st, 2024
|
||||
*/
|
||||
interface EntityConditionalActionEffectKeyframe {
|
||||
val entityCondition: ExpressionLike
|
||||
fun test(context: ActionEffectContext, entity: Entity, isUser: Boolean): Boolean {
|
||||
// TODO this should use the entity's own query struct
|
||||
context.runtime.environment.getQueryStruct().addFunction("entity") {
|
||||
QueryStruct(hashMapOf())
|
||||
.addFunction("uuid") { StringValue(entity.uuidAsString) }
|
||||
.addFunction("is_user") { DoubleValue(isUser) }
|
||||
}
|
||||
return entityCondition.resolveBoolean(context.runtime)
|
||||
}
|
||||
}
|
||||
+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.api.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.EntityProvider
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.api.scheduling.delayedFuture
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
|
||||
/**
|
||||
* An action effect keyframe that will run client-side MoLang for all entities that fit the entity condition.
|
||||
*
|
||||
* This MoLang executes within that entity's runtime, meaning you can trigger animations or locational particles
|
||||
* or sounds.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 30th, 2023
|
||||
*/
|
||||
class EntityMoLangActionEffectKeyframe : ConditionalActionEffectKeyframe(), EntityConditionalActionEffectKeyframe {
|
||||
var delay = "0".asExpressionLike()
|
||||
val expressions = mutableSetOf<String>()
|
||||
val visibilityRange = 200
|
||||
override val entityCondition: ExpressionLike = "q.entity.is_user".asExpressionLike()
|
||||
|
||||
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
val entities = context.providers
|
||||
.filterIsInstance<EntityProvider>()
|
||||
.flatMap { prov -> prov.entities.filter { test(context, it, isUser = prov is UsersProvider) } }
|
||||
|
||||
for (entity in entities) {
|
||||
val world = entity.world as ServerWorld
|
||||
val players = world.getPlayers { it.distanceTo(entity) <= visibilityRange }
|
||||
val pkt = RunPosableMoLangPacket(entityId = entity.id, expressions = expressions)
|
||||
players.forEach { it.sendPacket(pkt) }
|
||||
}
|
||||
|
||||
return delayedFuture(seconds = delay.resolveFloat(context.runtime), serverThread = true)
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.EntityProvider
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.api.scheduling.delayedFuture
|
||||
import com.cobblemon.mod.common.entity.Poseable
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
|
||||
/**
|
||||
* Spawns particles on the entity based on the given particle effect and locator.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since January 21st, 2024
|
||||
*/
|
||||
class EntityParticlesActionEffectKeyframe : ConditionalActionEffectKeyframe(), EntityConditionalActionEffectKeyframe {
|
||||
override val entityCondition = "q.entity.is_user".asExpressionLike()
|
||||
var effect: String? = null
|
||||
var locator: String = "root"
|
||||
val delay: ExpressionLike = "0".asExpressionLike()
|
||||
val visibilityRange = 200
|
||||
|
||||
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
val entities = context.providers
|
||||
.filterIsInstance<EntityProvider>()
|
||||
.flatMap { prov -> prov.entities.filter { test(context, it, isUser = prov is UsersProvider) } }
|
||||
|
||||
val effectIdentifier = try {
|
||||
effect?.asExpressionLike()?.resolveString(context.runtime)
|
||||
} catch (e: Exception) {
|
||||
effect
|
||||
}?.asIdentifierDefaultingNamespace() ?: return skip()
|
||||
|
||||
entities.filter { it is Poseable }.forEach { entity ->
|
||||
val packet = SpawnSnowstormEntityParticlePacket(effectIdentifier, entity.id, locator)
|
||||
val players = (entity.world as ServerWorld).getPlayers { it.distanceTo(entity) <= visibilityRange }
|
||||
packet.sendToPlayers(players)
|
||||
}
|
||||
|
||||
return delayedFuture(seconds = delay.resolveFloat(context.runtime), serverThread = true)
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.EntityProvider
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.api.scheduling.delayedFuture
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import net.minecraft.registry.RegistryKeys
|
||||
|
||||
/**
|
||||
* An action effect keyframe that plays a positioned sound for all matching entities.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since January 21st, 2024
|
||||
*/
|
||||
class EntitySoundActionEffectKeyframe : ConditionalActionEffectKeyframe(), EntityConditionalActionEffectKeyframe {
|
||||
override val entityCondition = "q.entity.is_user".asExpressionLike()
|
||||
var sound: String? = null
|
||||
val delay: ExpressionLike = "0".asExpressionLike()
|
||||
|
||||
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
val entities = context.providers
|
||||
.filterIsInstance<EntityProvider>()
|
||||
.flatMap { prov -> prov.entities.filter { test(context, it, isUser = prov is UsersProvider) } }
|
||||
|
||||
val soundIdentifier = try {
|
||||
sound?.asExpressionLike()?.resolveString(context.runtime)?.takeIf { it != "0.0" } ?: sound
|
||||
} catch (e: Exception) {
|
||||
sound
|
||||
}?.asIdentifierDefaultingNamespace() ?: return skip()
|
||||
|
||||
entities.forEach { entity ->
|
||||
val soundEvent = entity.world.registryManager.get(RegistryKeys.SOUND_EVENT).get(soundIdentifier) ?: return skip()
|
||||
entity.playSound(soundEvent, 1f, 1f)
|
||||
}
|
||||
|
||||
return delayedFuture(seconds = delay.resolveFloat(context.runtime), serverThread = true)
|
||||
}
|
||||
}
|
||||
+35
@@ -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.api.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class ForkActionEffectKeyframe(
|
||||
val condition: ExpressionLike = "true".asExpressionLike(),
|
||||
val ifTrue: List<ActionEffectKeyframe> = listOf(),
|
||||
val ifFalse: List<ActionEffectKeyframe> = listOf()
|
||||
) : ActionEffectKeyframe {
|
||||
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
val future = CompletableFuture<Unit>()
|
||||
/*
|
||||
* Using .toList() before running chainKeyframes because iterators can be weird about sharing,
|
||||
* .toList() creates a copy of the list and then grabs its iterator so much safer (three parachutes)
|
||||
*/
|
||||
if (!condition.resolveBoolean(context.runtime)) {
|
||||
context.actionEffect.chainKeyframes(context, ifFalse.toList().iterator(), future)
|
||||
} else {
|
||||
context.actionEffect.chainKeyframes(context, ifTrue.toList().iterator(), future)
|
||||
}
|
||||
|
||||
return future
|
||||
}
|
||||
}
|
||||
+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.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.scheduling.delayedFuture
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* An action effect keyframe that simply executes some MoLang on the effect context's runtime.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since January 21st, 2024
|
||||
*/
|
||||
class MoLangActionEffectKeyframe : ActionEffectKeyframe {
|
||||
val expressions: ExpressionLike = "0".asExpressionLike()
|
||||
val delay: ExpressionLike = "0".asExpressionLike()
|
||||
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
expressions.resolve(context.runtime)
|
||||
return delayedFuture(seconds = delay.resolveFloat(context.runtime), serverThread = true)
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||
import com.cobblemon.mod.common.api.moves.animations.TargetsProvider
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.api.scheduling.afterOnServer
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.PokemonNavigation
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sqrt
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
class MoveToTargetActionEffectKeyframe : ActionEffectKeyframe {
|
||||
val speed = 1F
|
||||
val timeout = "4".asExpressionLike()
|
||||
var proximity = -1F
|
||||
val timeoutActionEffect: Identifier? = null
|
||||
|
||||
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
val user = context.findOneProvider<UsersProvider>()?.entities?.firstOrNull() as? PokemonEntity ?: return CompletableFuture.completedFuture(Unit)
|
||||
val target = context.findOneProvider<TargetsProvider>()?.entities?.firstOrNull() ?: return CompletableFuture.completedFuture(Unit)
|
||||
|
||||
val future = CompletableFuture<Unit>()
|
||||
|
||||
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()
|
||||
|
||||
if (target.distanceTo(user) !in proximity..20F) {
|
||||
future.complete(Unit)
|
||||
return future
|
||||
}
|
||||
|
||||
val timeoutEffect = timeoutActionEffect?.let { ActionEffects.actionEffects[it] } ?: ActionEffectTimeline.NONE
|
||||
|
||||
val nav = user.navigation
|
||||
val navContext = PokemonNavigation.NavigationContext(
|
||||
destinationProximity = proximity,
|
||||
onArrival = {
|
||||
if (!future.isDone && !timedOut) {
|
||||
future.complete(Unit)
|
||||
}
|
||||
},
|
||||
onCannotReach = {
|
||||
if (!future.isDone && !timedOut) {
|
||||
timedOut = true
|
||||
timeoutEffect.run(context).thenApply { future.complete(Unit) }
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
afterOnServer(seconds = timeout.resolveFloat(context.runtime)) {
|
||||
if (!future.isDone && !timedOut) {
|
||||
timedOut = true
|
||||
timeoutEffect.run(context).thenApply { future.complete(Unit) }
|
||||
nav.stop()
|
||||
}
|
||||
}
|
||||
|
||||
nav.startMovingTo(target.x, target.y, target.z, speed.toDouble(), navContext)
|
||||
return future
|
||||
}
|
||||
}
|
||||
+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.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class ParallelActionEffectKeyframe : ConditionalActionEffectKeyframe() {
|
||||
var keyframes: MutableList<ActionEffectKeyframe> = mutableListOf()
|
||||
|
||||
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
return CompletableFuture.allOf(
|
||||
*keyframes.map {
|
||||
context.currentKeyframes.add(it)
|
||||
it.play(context).thenRun { context.currentKeyframes.remove(it) }
|
||||
}.toTypedArray()
|
||||
).thenApply {} // Map Void -> Unit at the end
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.scheduling.delayedFuture
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
|
||||
class PauseActionEffectKeyframe : ConditionalActionEffectKeyframe() {
|
||||
val pause = "1".asExpressionLike()
|
||||
override fun playWhenTrue(context: ActionEffectContext) = delayedFuture(seconds = pause.resolveFloat(context.runtime), serverThread = true)
|
||||
}
|
||||
+35
@@ -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.api.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.scheduling.delayedFuture
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* An [ActionEffectKeyframe] that clears some holds from the context, potentially marking the effect as
|
||||
* complete as far as any blocked actions are concerned. If no holds are specified, then all holds are
|
||||
* removed.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 27th, 2023
|
||||
*/
|
||||
class RemoveHoldsActionEffectKeyframe : ActionEffectKeyframe {
|
||||
val delay = 0F
|
||||
val holds = mutableSetOf<String>()
|
||||
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
return delayedFuture(seconds = delay, serverThread = true).thenApply {
|
||||
if (holds.isEmpty()) {
|
||||
context.holds.clear()
|
||||
} else {
|
||||
context.holds.removeAll(holds)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.api.scheduling.after
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.PokemonNavigation
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import net.minecraft.util.Identifier
|
||||
import net.minecraft.util.math.Vec3d
|
||||
|
||||
class ReturnToPositionActionEffectKeyframe : ActionEffectKeyframe {
|
||||
val speed = 1F
|
||||
val timeout = "4".asExpressionLike()
|
||||
val timeoutActionEffect: Identifier? = null
|
||||
|
||||
override fun play(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
val user = context.findOneProvider<UsersProvider>()?.entities?.firstOrNull() as? PokemonEntity ?: return skip()
|
||||
val future = CompletableFuture<Unit>()
|
||||
|
||||
val pos = (context.runtime.environment.getValue(setOf("${user.uuidAsString}-pos").iterator())?.value() as? ObjectValue<*>)?.obj as? Vec3d ?: return skip()
|
||||
|
||||
var timedOut = false
|
||||
|
||||
if (pos.distanceTo(user.pos) > 20) {
|
||||
future.complete(Unit)
|
||||
return future
|
||||
}
|
||||
|
||||
val timeoutEffect = timeoutActionEffect?.let { ActionEffects.actionEffects[it] } ?: ActionEffectTimeline.NONE
|
||||
|
||||
val nav = user.navigation
|
||||
val navContext = PokemonNavigation.NavigationContext(
|
||||
onArrival = {
|
||||
if (!future.isDone && !timedOut) {
|
||||
future.complete(Unit)
|
||||
}
|
||||
},
|
||||
onCannotReach = {
|
||||
if (!future.isDone && !timedOut) {
|
||||
timedOut = true
|
||||
timeoutEffect.run(context).thenApply { future.complete(Unit) }
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
after(seconds = timeout.resolveFloat(context.runtime), serverThread = true) {
|
||||
if (!future.isDone && !timedOut) {
|
||||
timedOut = true
|
||||
timeoutEffect.run(context).thenApply { future.complete(Unit) }
|
||||
nav.stop()
|
||||
}
|
||||
}
|
||||
|
||||
nav.startMovingTo(pos.x, pos.y, pos.z, speed.toDouble(), navContext)
|
||||
return future
|
||||
}
|
||||
}
|
||||
+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.api.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* An action effect keyframe that simply runs another action effect based on an identifier. This action
|
||||
* effect is marked complete only when the action effect it runs is complete unless [waitForActionEffect] is
|
||||
* false.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since January 21st, 2024
|
||||
*/
|
||||
class RunActionEffectKeyframe : ConditionalActionEffectKeyframe() {
|
||||
val actionEffect: Identifier? = null
|
||||
val waitForActionEffect = true
|
||||
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
return if (actionEffect != null) {
|
||||
ActionEffects.actionEffects[actionEffect]?.run(context)?.takeIf { waitForActionEffect } ?: skip()
|
||||
} else {
|
||||
skip()
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
class SavePositionActionEffectKeyframe: ConditionalActionEffectKeyframe() {
|
||||
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
val user = context.findOneProvider<UsersProvider>()?.entities?.firstOrNull() ?: return skip()
|
||||
context.runtime.environment.setSimpleVariable("${user.uuidAsString}-pos", ObjectValue(user.pos))
|
||||
return skip()
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* A sequence of action effects that are dependent on a condition.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 29th, 2023
|
||||
*/
|
||||
class SequenceActionEffectKeyframe(val keyframes: List<ActionEffectKeyframe> = listOf()) : ConditionalActionEffectKeyframe() {
|
||||
override fun playWhenTrue(context: ActionEffectContext): CompletableFuture<Unit> {
|
||||
val future = CompletableFuture<Unit>()
|
||||
context.actionEffect.chainKeyframes(context, keyframes.toList().iterator(), future)
|
||||
return future
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.multiblock
|
||||
|
||||
import com.cobblemon.mod.common.block.entity.FossilMultiblockEntity
|
||||
import net.minecraft.block.*
|
||||
import net.minecraft.block.entity.BlockEntity
|
||||
import net.minecraft.entity.LivingEntity
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
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
|
||||
|
||||
/**
|
||||
* A block that can be part of a [MultiblockStructure]
|
||||
*/
|
||||
abstract class MultiblockBlock(properties: Settings) : BlockWithEntity(properties) {
|
||||
|
||||
override fun onPlaced(
|
||||
world: World,
|
||||
pos: BlockPos,
|
||||
state: BlockState,
|
||||
placer: LivingEntity?,
|
||||
itemStack: ItemStack?
|
||||
) {
|
||||
if (world is ServerWorld) {
|
||||
val multiblockEntity = world.getBlockEntity(pos) as MultiblockEntity
|
||||
multiblockEntity.multiblockBuilder?.validate(world)
|
||||
}
|
||||
super.onPlaced(world, pos, state, placer, itemStack)
|
||||
}
|
||||
|
||||
override fun onUse(
|
||||
state: BlockState,
|
||||
world: World,
|
||||
pos: BlockPos,
|
||||
player: PlayerEntity,
|
||||
hand: Hand,
|
||||
hit: BlockHitResult
|
||||
): ActionResult {
|
||||
if(hand == Hand.OFF_HAND) {
|
||||
return ActionResult.SUCCESS
|
||||
}
|
||||
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)
|
||||
if (!world.isClient) {
|
||||
val entity = world.getBlockEntity(pos)
|
||||
if (entity is MultiblockEntity && entity.multiblockStructure != null) {
|
||||
entity.multiblockStructure!!.onBreak(world, pos, state, player)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun createBlockEntity(pos: BlockPos, state: BlockState): BlockEntity? {
|
||||
return createMultiBlockEntity(pos, state)
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun getRenderType(state: BlockState?): BlockRenderType {
|
||||
return BlockRenderType.MODEL
|
||||
}
|
||||
|
||||
override fun getPickStack(world: BlockView, 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
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.multiblock
|
||||
|
||||
import com.cobblemon.mod.common.api.multiblock.MultiblockStructure
|
||||
import com.cobblemon.mod.common.api.multiblock.builder.MultiblockStructureBuilder
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.block.entity.BlockEntity
|
||||
import net.minecraft.block.entity.BlockEntityType
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.nbt.NbtHelper
|
||||
import net.minecraft.network.listener.ClientPlayPacketListener
|
||||
import net.minecraft.network.packet.Packet
|
||||
import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket
|
||||
import net.minecraft.util.math.BlockPos
|
||||
|
||||
/**
|
||||
* Multiblock entities are kind of complicated. Basically every multiblock entity should have a MultiBlockStructureBuilder
|
||||
* that is checked when this block entity is created. The multiblock entity also contains a reference to a MultiblockStructure
|
||||
* which is shared between all MultiblockEntities in the structure. Finally, every Multiblock contains the location of the
|
||||
* block that controls this blockentities associated structure
|
||||
*/
|
||||
abstract class MultiblockEntity(
|
||||
type: BlockEntityType<*>,
|
||||
pos: BlockPos,
|
||||
state: BlockState,
|
||||
var multiblockBuilder: MultiblockStructureBuilder?
|
||||
) : BlockEntity(type, pos, state) {
|
||||
|
||||
abstract var multiblockStructure: MultiblockStructure?
|
||||
abstract var masterBlockPos: BlockPos?
|
||||
|
||||
override fun toUpdatePacket(): Packet<ClientPlayPacketListener>? {
|
||||
return BlockEntityUpdateS2CPacket.create(this)
|
||||
}
|
||||
|
||||
override fun toInitialChunkDataNbt(): NbtCompound {
|
||||
val result = NbtCompound()
|
||||
writeNbt(result)
|
||||
return result
|
||||
}
|
||||
|
||||
override fun writeNbt(nbt: NbtCompound) {
|
||||
super.writeNbt(nbt)
|
||||
//Used for checking build conditions in multiblocks (Dont count a block if it has the FORMED flag)
|
||||
nbt.putBoolean(DataKeys.FORMED, masterBlockPos != null)
|
||||
if (multiblockStructure != null && multiblockStructure!!.controllerBlockPos == pos) {
|
||||
nbt.put(DataKeys.MULTIBLOCK_STORAGE, multiblockStructure!!.writeToNbt())
|
||||
}
|
||||
else if (masterBlockPos != null) {
|
||||
nbt.put(DataKeys.CONTROLLER_BLOCK, NbtHelper.fromBlockPos(masterBlockPos))
|
||||
}
|
||||
}
|
||||
|
||||
abstract override fun readNbt(nbt: NbtCompound)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.multiblock
|
||||
|
||||
import net.minecraft.block.BlockState
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
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.util.math.random.Random
|
||||
import net.minecraft.world.World
|
||||
|
||||
interface MultiblockStructure {
|
||||
val controllerBlockPos: BlockPos
|
||||
|
||||
fun onUse(
|
||||
blockState: BlockState,
|
||||
world: World,
|
||||
blockPos: BlockPos,
|
||||
player: PlayerEntity,
|
||||
interactionHand: Hand,
|
||||
blockHitResult: BlockHitResult
|
||||
): ActionResult
|
||||
|
||||
fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity?)
|
||||
|
||||
fun tick(world: World)
|
||||
|
||||
fun syncToClient(world: World)
|
||||
|
||||
fun markDirty(world: World)
|
||||
fun writeToNbt(): NbtCompound
|
||||
fun getComparatorOutput(state: BlockState, world: World?, pos: BlockPos?): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
fun markRemoved(world: World):Unit
|
||||
fun onTriggerEvent(state: BlockState?, world: ServerWorld?, pos: BlockPos?, random: Random?)
|
||||
}
|
||||
+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.api.multiblock.builder
|
||||
|
||||
import com.cobblemon.mod.common.api.multiblock.condition.MultiblockCondition
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.math.Box
|
||||
import net.minecraft.util.shape.VoxelShape
|
||||
|
||||
/**
|
||||
* Represents an area that has a potential to form a MultiBlockStructure
|
||||
* @property boundingBox The box that each condition checks in
|
||||
* @property conditions The [MultiblockCondition]s that must be met for the multiblock to form. All must be true.
|
||||
*
|
||||
* @author Apion
|
||||
* @since August 24, 2023
|
||||
*/
|
||||
interface MultiblockStructureBuilder {
|
||||
val boundingBox: VoxelShape
|
||||
val conditions: List<MultiblockCondition>
|
||||
|
||||
fun validate(world: ServerWorld): Boolean {
|
||||
conditions.forEach {
|
||||
if (!it.test(world, boundingBox)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
form(world)
|
||||
return true
|
||||
}
|
||||
|
||||
fun form(world: ServerWorld)
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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.multiblock.condition
|
||||
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.math.Box
|
||||
import net.minecraft.util.shape.VoxelShape
|
||||
|
||||
class AndCondition(val conditionOne: MultiblockCondition, val conditionTwo: MultiblockCondition) :
|
||||
MultiblockCondition {
|
||||
override fun test(world: ServerWorld, box: VoxelShape): Boolean {
|
||||
return conditionOne.test(world, box) and conditionTwo.test(world, box)
|
||||
}
|
||||
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.multiblock.condition
|
||||
|
||||
import com.cobblemon.mod.common.util.blockPositionsAsList
|
||||
import net.minecraft.predicate.BlockPredicate
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.util.math.Direction
|
||||
import net.minecraft.util.shape.VoxelShape
|
||||
|
||||
/**
|
||||
* Checks that a block adjacent to another block matches a predicate. Basically we find a block that
|
||||
* matched relToBlock, then we look in each direction to see if there is an adjacent block that matches
|
||||
* target block.
|
||||
*
|
||||
* @param relToBlock The [BlockPredicate] for the main block. The block that matches this predicate is the block whose adjacent blocks we check
|
||||
* @param targetBlock The [BlockPredicate] that is checked for blocks adjacent to relToBlock
|
||||
* @param directionsToCheck The [Direction]s that we check from the target relToBlock
|
||||
*
|
||||
* @author Apion
|
||||
* @since August 24th, 2023
|
||||
*/
|
||||
class BlockRelativeCondition(
|
||||
val relToBlock: BlockPredicate,
|
||||
val targetBlock: BlockPredicate,
|
||||
val directionsToCheck: Array<Direction> = Direction.values()
|
||||
) : MultiblockCondition {
|
||||
override fun test(world: ServerWorld, box: VoxelShape): Boolean {
|
||||
val relToBlockBlockPositions = box.blockPositionsAsList().filter { relToBlock.test(world, it) }
|
||||
relToBlockBlockPositions.forEach { pos ->
|
||||
directionsToCheck.forEach {
|
||||
if (targetBlock.test(world, pos.offset(it))) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user