mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-21 14:46:25 -04:00
Compare commits
649
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58cdf2e756 | ||
|
|
d4b6e36aab | ||
|
|
0fb721702d | ||
|
|
0e5053b787 | ||
|
|
f3867e0b1d | ||
|
|
a4fcd1ae7b | ||
|
|
ed9aff2448 | ||
|
|
8497a2a083 | ||
|
|
b389a95b5e | ||
|
|
c310027ce1 | ||
|
|
5ddb01df36 | ||
|
|
5a6f49aad5 | ||
|
|
793efcfa3d | ||
|
|
d671c5a8b8 | ||
|
|
69b31dd9b9 | ||
|
|
fc94bbac4c | ||
|
|
f7d315fa33 | ||
|
|
7c30fd81f3 | ||
|
|
7f1704d573 | ||
|
|
0c2ec3ca81 | ||
|
|
33d3e156cc | ||
|
|
415642a8ba | ||
|
|
dd12081cd1 | ||
|
|
b7de84acfd | ||
|
|
8efda8c47b | ||
|
|
6baf96f83b | ||
|
|
009a9c3f15 | ||
|
|
fc0a6c0c8b | ||
|
|
041e080cd4 | ||
|
|
65bbadcfa8 | ||
|
|
a70d5e200a | ||
|
|
4d0ee751a3 | ||
|
|
d87438e53d | ||
|
|
3efef07afa | ||
|
|
9ff227fbef | ||
|
|
55ef5fd537 | ||
|
|
b3cdfb579c | ||
|
|
29588f1fde | ||
|
|
24c10d1a4f | ||
|
|
ac0d9d4d74 | ||
|
|
d33974b19e | ||
|
|
1dcdfe309e | ||
|
|
6ce1990145 | ||
|
|
1203721889 | ||
|
|
333672f993 | ||
|
|
f0f9a9596f | ||
|
|
80b8aa2b8c | ||
|
|
b919e447d8 | ||
|
|
3075b7fd73 | ||
|
|
412e3fcb8a | ||
|
|
32253fd462 | ||
|
|
4de018a209 | ||
|
|
2204a4b700 | ||
|
|
22a27cbbd7 | ||
|
|
e202e7bf2f | ||
|
|
03104b3a3d | ||
|
|
280e1ae820 | ||
|
|
ee5653bfba | ||
|
|
a9c3c14367 | ||
|
|
9cdc979067 | ||
|
|
4b45fdde3f | ||
|
|
5bf7cc6aef | ||
|
|
7cf1f5a4e5 | ||
|
|
0fe2b0f60c | ||
|
|
667376226b | ||
|
|
5506e076f6 | ||
|
|
f8799efd9d | ||
|
|
bb642fbf29 | ||
|
|
e19aa02283 | ||
|
|
e65010e289 | ||
|
|
4b4a715868 | ||
|
|
26ec5717f1 | ||
|
|
446d4771d8 | ||
|
|
9d817b3f77 | ||
|
|
21213c4fce | ||
|
|
cebf105dd5 | ||
|
|
123d3291c6 | ||
|
|
935a39c578 | ||
|
|
d53e67b55c | ||
|
|
ec0766ddcd | ||
|
|
917577f7a8 | ||
|
|
01de2f71af | ||
|
|
0779251581 | ||
|
|
14d4c6c2e4 | ||
|
|
de82d36da3 | ||
|
|
ae2704e218 | ||
|
|
a235c1286c | ||
|
|
ce584bd403 | ||
|
|
1c25861e04 | ||
|
|
006cc21ebb | ||
|
|
5ab9072f94 | ||
|
|
f7023b9737 | ||
|
|
987a7d0ccc | ||
|
|
d49c0a0ec6 | ||
|
|
d4a910bf26 | ||
|
|
25b75231ad | ||
|
|
0db1f372e3 | ||
|
|
1ddffc1c0d | ||
|
|
5fe04aad83 | ||
|
|
03b74d4b72 | ||
|
|
a5f150af9a | ||
|
|
b3b5e47cc9 | ||
|
|
1d0aa06dc4 | ||
|
|
1e5c0f5137 | ||
|
|
7bafd53f58 | ||
|
|
bdbdf238f5 | ||
|
|
6cd71050df | ||
|
|
2047f4f461 | ||
|
|
0aaed4bb84 | ||
|
|
3779b4c0b3 | ||
|
|
74aaa16a0d | ||
|
|
332ef2fddd | ||
|
|
f29c5c5f6d | ||
|
|
c46375aafb | ||
|
|
a5e16ccf65 | ||
|
|
4cc83560e8 | ||
|
|
a7f4ef8449 | ||
|
|
edaafa2263 | ||
|
|
0162bdae5f | ||
|
|
da82eb8d61 | ||
|
|
34fc434883 | ||
|
|
74949a02de | ||
|
|
1617c1b087 | ||
|
|
4b1c180538 | ||
|
|
cba6f51706 | ||
|
|
9b9fbedaf7 | ||
|
|
8c3acd9a0e | ||
|
|
4ab52cac0e | ||
|
|
68805a5dd1 | ||
|
|
5a0b4e8f99 | ||
|
|
3e9d3a307f | ||
|
|
7c4d3ecb71 | ||
|
|
e91fd5596a | ||
|
|
f9d218adf8 | ||
|
|
05d70b28e7 | ||
|
|
6755462eb0 | ||
|
|
7ef3facac8 | ||
|
|
2dc93f3336 | ||
|
|
b7c16324bd | ||
|
|
e8864418d4 | ||
|
|
7ccd0bbe11 | ||
|
|
e1cc9c7aba | ||
|
|
79e821a438 | ||
|
|
d289880cc8 | ||
|
|
19dd57feed | ||
|
|
6609c7d038 | ||
|
|
88afe05c16 | ||
|
|
e739b57a08 | ||
|
|
99aa25e1bf | ||
|
|
76faa50035 | ||
|
|
8ce989cb6b | ||
|
|
02030950aa | ||
|
|
82b418d54d | ||
|
|
6148b58fdc | ||
|
|
2044762b72 | ||
|
|
77117e83c7 | ||
|
|
55f4e6e738 | ||
|
|
1e4936aeac | ||
|
|
15ea72e777 | ||
|
|
3c3d4e4552 | ||
|
|
796e416578 | ||
|
|
7608dfde94 | ||
|
|
b2b871617a | ||
|
|
bc4c8d13b7 | ||
|
|
0f9c51f7dd | ||
|
|
2c2623e0f9 | ||
|
|
8ec85e7d2f | ||
|
|
d5a08314eb | ||
|
|
062c32be2a | ||
|
|
09590b49cd | ||
|
|
420cbd2c99 | ||
|
|
0380013f37 | ||
|
|
6c1fcc103a | ||
|
|
59b01c3988 | ||
|
|
678fa2d0ce | ||
|
|
94abd79923 | ||
|
|
0a1931aaae | ||
|
|
85d76dcc29 | ||
|
|
bd0a9ef654 | ||
|
|
7a702e276c | ||
|
|
3f9a2825cb | ||
|
|
d1462bc27b | ||
|
|
211b14dbd0 | ||
|
|
47e83003c3 | ||
|
|
59134c4212 | ||
|
|
44b434562c | ||
|
|
7af9b0854a | ||
|
|
344b0750f9 | ||
|
|
10d9d97c11 | ||
|
|
94bcfba076 | ||
|
|
69a75ffcd4 | ||
|
|
cc1317dd06 | ||
|
|
e15ac73b1b | ||
|
|
6c6576c117 | ||
|
|
ebdfa7edc0 | ||
|
|
297e8eae77 | ||
|
|
ea8179018d | ||
|
|
14fccfae1d | ||
|
|
26386638ad | ||
|
|
5d1d99b64a | ||
|
|
a3c5a6c377 | ||
|
|
eb2a5837eb | ||
|
|
93298d9a87 | ||
|
|
abb5346305 | ||
|
|
9466f66721 | ||
|
|
716ea55bc7 | ||
|
|
4d1f46c37c | ||
|
|
15f0ad1821 | ||
|
|
a2101b5759 | ||
|
|
187a190ec6 | ||
|
|
0d433ff394 | ||
|
|
a16975c750 | ||
|
|
c0e6d87c40 | ||
|
|
91078b917e | ||
|
|
b7e27fa52a | ||
|
|
dc87ffd2a8 | ||
|
|
d873399d05 | ||
|
|
a7aab51e0d | ||
|
|
e8e2057558 | ||
|
|
56b5dba911 | ||
|
|
f0a66458e5 | ||
|
|
dba6a38f9e | ||
|
|
342c0041e9 | ||
|
|
cbeda361d4 | ||
|
|
a811b3347c | ||
|
|
80e593f5c6 | ||
|
|
ff617348fe | ||
|
|
1adecbf5f6 | ||
|
|
29dbb13a0e | ||
|
|
67e03ecebd | ||
|
|
215f48bdc7 | ||
|
|
d4beab1bfb | ||
|
|
f2c21ec902 | ||
|
|
c9f3912677 | ||
|
|
c21b7d1a7d | ||
|
|
26068694ad | ||
|
|
c86d8f0696 | ||
|
|
16468059e4 | ||
|
|
54dbe4769e | ||
|
|
82019c3722 | ||
|
|
079a2fb50d | ||
|
|
78f0951345 | ||
|
|
96aaab29e2 | ||
|
|
b1def44953 | ||
|
|
e2e38add1d | ||
|
|
1db0b0709a | ||
|
|
c3ce3db387 | ||
|
|
b5e6fd3816 | ||
|
|
5b5dcddb25 | ||
|
|
0158524bff | ||
|
|
2611e311a7 | ||
|
|
17061691a1 | ||
|
|
9c6d7ddfef | ||
|
|
e8119198c1 | ||
|
|
55c0e3e8a0 | ||
|
|
70443bc7b0 | ||
|
|
acb166b5b9 | ||
|
|
462c361998 | ||
|
|
76c90fb1ae | ||
|
|
27e11dee87 | ||
|
|
d7c8b8dd62 | ||
|
|
eb12ccf6d0 | ||
|
|
e7b58edcd1 | ||
|
|
ca5c2ba381 | ||
|
|
8aa538d8e7 | ||
|
|
1bd33a0635 | ||
|
|
ff9ca4ee09 | ||
|
|
1def8fcd1a | ||
|
|
d53603ec49 | ||
|
|
5362995fbb | ||
|
|
e2d0b12f94 | ||
|
|
b32c2cb81c | ||
|
|
98a7240191 | ||
|
|
84adc0e1cb | ||
|
|
3ab2dfa0b3 | ||
|
|
d67669a278 | ||
|
|
2a85dee373 | ||
|
|
86e8238230 | ||
|
|
bdc7b5a504 | ||
|
|
f3c165d282 | ||
|
|
9caf8376bc | ||
|
|
8661f7a01e | ||
|
|
e933a03e92 | ||
|
|
982fc054a9 | ||
|
|
cb73bfb31b | ||
|
|
5b84c2c8a0 | ||
|
|
9f998d92e6 | ||
|
|
b835bfe596 | ||
|
|
757e3d48cb | ||
|
|
2fbf77dd65 | ||
|
|
bd451bf951 | ||
|
|
d88a9dda92 | ||
|
|
86c2282cf8 | ||
|
|
ac85cddeb6 | ||
|
|
a9c2373979 | ||
|
|
6ac8523cf5 | ||
|
|
acb0aa854e | ||
|
|
d5cff3ba06 | ||
|
|
8e22538707 | ||
|
|
f161699b6a | ||
|
|
fdafb1e64a | ||
|
|
b0119e32c5 | ||
|
|
58bab4b94b | ||
|
|
a91bf60ff8 | ||
|
|
2d4c419216 | ||
|
|
981f7307e6 | ||
|
|
c04345a789 | ||
|
|
93e84e6ffd | ||
|
|
cc6305bfec | ||
|
|
7d38efaa50 | ||
|
|
9a3f5a605a | ||
|
|
bd525c8740 | ||
|
|
b9922057ce | ||
|
|
d9c765ca53 | ||
|
|
96c3f7764e | ||
|
|
255930751a | ||
|
|
d3f32ee645 | ||
|
|
e444206a55 | ||
|
|
209dee1d25 | ||
|
|
e58acd646f | ||
|
|
bdcc05aa78 | ||
|
|
bb899118ef | ||
|
|
71585174c0 | ||
|
|
1eedc4862a | ||
|
|
b1fbf9ca02 | ||
|
|
3449c98b56 | ||
|
|
5fda445274 | ||
|
|
60aa991d55 | ||
|
|
8da0fc34c6 | ||
|
|
41c55d80a8 | ||
|
|
09dfbccb8e | ||
|
|
ce0265e954 | ||
|
|
a66d263dd8 | ||
|
|
5a929e3901 | ||
|
|
da1654d9aa | ||
|
|
27132031cd | ||
|
|
cdc4a571b6 | ||
|
|
e8bc138e5d | ||
|
|
038d239f95 | ||
|
|
d95db24426 | ||
|
|
a64cbb7e8a | ||
|
|
9b2a1dc065 | ||
|
|
3c222a3349 | ||
|
|
e2ba1dc575 | ||
|
|
f7e381924e | ||
|
|
a1035608c9 | ||
|
|
2345565e38 | ||
|
|
f4c2a5197c | ||
|
|
620002c165 | ||
|
|
361a8fcbe1 | ||
|
|
e179e044ef | ||
|
|
d89224a684 | ||
|
|
f55d8737ba | ||
|
|
336180656e | ||
|
|
856eb2a1bd | ||
|
|
620589681d | ||
|
|
8359b1ade1 | ||
|
|
136d7c08b8 | ||
|
|
ddc03766bb | ||
|
|
81dccf9c07 | ||
|
|
ea93b8c1d8 | ||
|
|
8018c1142a | ||
|
|
cfca238573 | ||
|
|
e3cf367e45 | ||
|
|
b9b01af451 | ||
|
|
1abe39db3c | ||
|
|
4e7cdb6266 | ||
|
|
79b13acdc6 | ||
|
|
c68f637b70 | ||
|
|
d44126179a | ||
|
|
432b350d98 | ||
|
|
26677420dd | ||
|
|
a1487e4ee5 | ||
|
|
78b2a7d721 | ||
|
|
d4a3dfdb07 | ||
|
|
0f3dcb760e | ||
|
|
0ffd6fad90 | ||
|
|
3c9661dfd3 | ||
|
|
520f522f3c | ||
|
|
113ae1f749 | ||
|
|
61bf5ffab1 | ||
|
|
0e1b59fb25 | ||
|
|
3565015039 | ||
|
|
218b90860b | ||
|
|
a59573073f | ||
|
|
6475d7d732 | ||
|
|
c467e98345 | ||
|
|
6b206cfaaf | ||
|
|
8aac4c294f | ||
|
|
2e330076b8 | ||
|
|
e1cd217290 | ||
|
|
87da3e83a0 | ||
|
|
c325d0215a | ||
|
|
8afb4e6d16 | ||
|
|
60f00ca34d | ||
|
|
416a2ac390 | ||
|
|
0ffff6f4af | ||
|
|
690ada8271 | ||
|
|
b1b06f19b2 | ||
|
|
5bc41245ad | ||
|
|
490fa91ce7 | ||
|
|
8606d6928d | ||
|
|
5897b43564 | ||
|
|
9fd8d32215 | ||
|
|
03c278229b | ||
|
|
8ce3322105 | ||
|
|
364d084584 | ||
|
|
916e6de1d2 | ||
|
|
0b9e706a36 | ||
|
|
6d4f529fc0 | ||
|
|
015de548d3 | ||
|
|
04ca03b3a5 | ||
|
|
c7c145ab78 | ||
|
|
a376863953 | ||
|
|
2e68c3fc44 | ||
|
|
36f2eee7f9 | ||
|
|
71ac29ba8b | ||
|
|
781c82230e | ||
|
|
c58d49ebab | ||
|
|
fd8d5630f4 | ||
|
|
a86b11fdd5 | ||
|
|
829dca9d99 | ||
|
|
0f0368f3bd | ||
|
|
6533030d36 | ||
|
|
0efb0d9767 | ||
|
|
8151f9b3e6 | ||
|
|
4e8ffd3558 | ||
|
|
b88873fbc3 | ||
|
|
dba1ab26a5 | ||
|
|
cc2295d629 | ||
|
|
4d3d8d1607 | ||
|
|
1d09360844 | ||
|
|
079e75d828 | ||
|
|
a3567ead04 | ||
|
|
f4fef2855b | ||
|
|
6f614eb02e | ||
|
|
72b82858b3 | ||
|
|
361047c309 | ||
|
|
18f43f72ad | ||
|
|
cbb409b057 | ||
|
|
f8cec09f70 | ||
|
|
5579975b46 | ||
|
|
5a57f41fbb | ||
|
|
1845faf9ad | ||
|
|
0e93682457 | ||
|
|
cef69f478d | ||
|
|
5ea7bc9c48 | ||
|
|
bfc8ace83a | ||
|
|
e0f93fd797 | ||
|
|
ba13414ada | ||
|
|
66c63d54db | ||
|
|
9e836bcc3b | ||
|
|
27fb1f6c66 | ||
|
|
7f60885f92 | ||
|
|
cb7f6d7bba | ||
|
|
a3498fe03b | ||
|
|
af4af3395c | ||
|
|
3ab07ecbca | ||
|
|
b96eccbf2f | ||
|
|
afa7426116 | ||
|
|
a5ace52cb5 | ||
|
|
9f3940bb31 | ||
|
|
8a8c131a44 | ||
|
|
8b0fba4201 | ||
|
|
e1e04b19bf | ||
|
|
a04beb1ce8 | ||
|
|
bd9aea7c59 | ||
|
|
757e3a7ff7 | ||
|
|
66d03651f9 | ||
|
|
3c1577d58f | ||
|
|
dd7d562228 | ||
|
|
a01ac32e54 | ||
|
|
5c0ae854bf | ||
|
|
55c189b749 | ||
|
|
b5b81fa1aa | ||
|
|
eda58859ce | ||
|
|
3888a48cb0 | ||
|
|
c9b609a3f8 | ||
|
|
70fb7c87ad | ||
|
|
a24189b816 | ||
|
|
c0d80634a4 | ||
|
|
b52e4de85c | ||
|
|
7d37a98a58 | ||
|
|
a424796aa8 | ||
|
|
8518be0d44 | ||
|
|
24760270bd | ||
|
|
19f9490274 | ||
|
|
93a94f04a1 | ||
|
|
97eac48cd7 | ||
|
|
2c31f002b2 | ||
|
|
4f0eb16ab0 | ||
|
|
5004b61967 | ||
|
|
cf137efa02 | ||
|
|
862c0bda89 | ||
|
|
868874b06d | ||
|
|
068e4a1c92 | ||
|
|
267f2aa5a8 | ||
|
|
333d8fa732 | ||
|
|
e8d4e406d5 | ||
|
|
9e5c296309 | ||
|
|
69dc89b04f | ||
|
|
dd31fb1a51 | ||
|
|
9b3a729b3c | ||
|
|
ed732429b9 | ||
|
|
8d27394665 | ||
|
|
943c421b1d | ||
|
|
cc9541c146 | ||
|
|
538f72c474 | ||
|
|
c72ab20cfa | ||
|
|
3cfc915b1a | ||
|
|
b8541486d4 | ||
|
|
c69b38454e | ||
|
|
0e5787b8ab | ||
|
|
082be6f2d0 | ||
|
|
398f14efd5 | ||
|
|
4ba33c2a80 | ||
|
|
e8ace8ba05 | ||
|
|
1a78625111 | ||
|
|
596c2b95b4 | ||
|
|
38648111a6 | ||
|
|
149b8f27e6 | ||
|
|
dc78e40941 | ||
|
|
ca7e2054fe | ||
|
|
14ea73332f | ||
|
|
91433d7e13 | ||
|
|
85aadbabe9 | ||
|
|
8fed14e706 | ||
|
|
e64c1487cf | ||
|
|
2c16e5c20d | ||
|
|
21505bc5de | ||
|
|
a365aca9ca | ||
|
|
19b70e1fbb | ||
|
|
e1ec69f4cf | ||
|
|
c23e506570 | ||
|
|
28a4805cd3 | ||
|
|
8d3a895591 | ||
|
|
e8089d6a5d | ||
|
|
88988c21f1 | ||
|
|
cf4409e61d | ||
|
|
516343406c | ||
|
|
5ecbf33a6b | ||
|
|
4d866f6207 | ||
|
|
e81418836e | ||
|
|
03786a9845 | ||
|
|
d199e372ca | ||
|
|
3d779e637b | ||
|
|
bd0ad89971 | ||
|
|
586ced7bfb | ||
|
|
218f2c67d3 | ||
|
|
59b0397ea4 | ||
|
|
aadb78149c | ||
|
|
3305874dd4 | ||
|
|
2f688291dc | ||
|
|
1f099b231c | ||
|
|
c1ccc718cc | ||
|
|
74df81006b | ||
|
|
e7a87e299c | ||
|
|
c688e9f80c | ||
|
|
ac1897b41a | ||
|
|
40e8f4efa5 | ||
|
|
e00165aafb | ||
|
|
b2015c9cd8 | ||
|
|
d0b796f777 | ||
|
|
83488ec728 | ||
|
|
b3d387d8da | ||
|
|
902c6751c5 | ||
|
|
4088f144e4 | ||
|
|
3e592b21f1 | ||
|
|
b1186c8033 | ||
|
|
d038f63024 | ||
|
|
7a3088eb59 | ||
|
|
de51d2b1b2 | ||
|
|
3c3aa3d4a3 | ||
|
|
50e4829b79 | ||
|
|
ebdd06a4a9 | ||
|
|
82fd4bae08 | ||
|
|
277a7dc32b | ||
|
|
f00d578f64 | ||
|
|
ea9fba72ec | ||
|
|
4654c3c2b8 | ||
|
|
b4496b30a9 | ||
|
|
431662b237 | ||
|
|
1299214d61 | ||
|
|
c5c2c3a059 | ||
|
|
64b7970cb5 | ||
|
|
ce6c777c4e | ||
|
|
284b032dd8 | ||
|
|
23d70ab1fe | ||
|
|
3340239440 | ||
|
|
e513d52c3d | ||
|
|
9660e64dff | ||
|
|
f992a9cf0f | ||
|
|
edd4d18150 | ||
|
|
8b5bc78b5a | ||
|
|
1cfa1ce9fd | ||
|
|
4e821962e3 | ||
|
|
962720a12c | ||
|
|
a1b6bd79d2 | ||
|
|
83eb483f0b | ||
|
|
d8498d7a37 | ||
|
|
3693e7eec0 | ||
|
|
60c9f5d054 | ||
|
|
e1541a3512 | ||
|
|
1c1c3f51bb | ||
|
|
500f1f53a4 | ||
|
|
9ed10bb217 | ||
|
|
2f6d4313e7 | ||
|
|
d640a04fa6 | ||
|
|
7749f346b5 | ||
|
|
a29bc68663 | ||
|
|
1358380905 | ||
|
|
2679885fb4 | ||
|
|
278c5d8e81 | ||
|
|
a55916998b | ||
|
|
cca2d54682 | ||
|
|
f5bd6a4054 | ||
|
|
13466815e5 | ||
|
|
e871047cf1 | ||
|
|
a1de8c95f6 | ||
|
|
eb94bdb9c2 | ||
|
|
509c2365bb | ||
|
|
6271476ed3 | ||
|
|
f5cec10e3e | ||
|
|
b6f20c1d75 | ||
|
|
750d583770 | ||
|
|
05f0b439a8 | ||
|
|
1cb4ffd02f | ||
|
|
8600d026c3 | ||
|
|
4e24c764de | ||
|
|
192d40a475 | ||
|
|
8c86bb636d | ||
|
|
5dc43a8d58 | ||
|
|
68a3d7e3b1 | ||
|
|
8f4b2c3c0a | ||
|
|
6645cb68f7 | ||
|
|
4c5f330f2a | ||
|
|
00d445b793 | ||
|
|
cd236c2dea | ||
|
|
aebf40f78c | ||
|
|
52b28fb73f | ||
|
|
9b75f20fff | ||
|
|
56b1fc1149 | ||
|
|
662ca83a60 | ||
|
|
d80ff055f5 | ||
|
|
898f48cf8f | ||
|
|
1688dd42b3 | ||
|
|
c4e8fe9c74 | ||
|
|
3ecaf2dd13 | ||
|
|
281afd74e6 |
@@ -24,6 +24,7 @@ eclipse
|
||||
run
|
||||
runClient
|
||||
runServer
|
||||
utilityscripts/implementation/*.txt
|
||||
|
||||
# Files from Forge MDK
|
||||
forge*changelog.txt
|
||||
|
||||
+6
-2
@@ -16,6 +16,7 @@ check_assets_cache:
|
||||
stage: preprocessing
|
||||
script:
|
||||
- echo "Checking if cached hash matches current hash"
|
||||
- yum install -y findutils
|
||||
|
||||
# Calculate the current hash
|
||||
- find common/src/main/resources/assets common/src/main/resources/data -type f -exec sha256sum {} + | sort -k 2 | sha256sum > current_hash.txt
|
||||
@@ -71,8 +72,8 @@ setup_packsquash:
|
||||
- echo "Installing wget & unzip"
|
||||
- yum install -y wget unzip
|
||||
- echo "Downloading PackSquash"
|
||||
- wget https://github.com/ComunidadAylas/PackSquash/releases/download/v0.4.0/PackSquash.CLI.executable.x86_64-unknown-linux-musl.zip
|
||||
- unzip PackSquash.CLI.executable.x86_64-unknown-linux-musl.zip -d ./packsquash_bin
|
||||
- wget https://github.com/ComunidadAylas/PackSquash/releases/download/v0.4.1/packsquash-x86_64-unknown-linux-musl.zip
|
||||
- unzip packsquash-x86_64-unknown-linux-musl.zip -d ./packsquash_bin
|
||||
- echo "Creating PackSquash options.toml"
|
||||
- |
|
||||
cat <<EOF > ./options.toml
|
||||
@@ -148,6 +149,7 @@ build:
|
||||
dependencies:
|
||||
- replace_resources
|
||||
script:
|
||||
- yum install -y findutils
|
||||
- export GRADLE_OPTS="-Xmx4G -Xms4G"
|
||||
- chmod +x ./gradlew
|
||||
- ./gradlew build
|
||||
@@ -163,6 +165,7 @@ publish:
|
||||
rules:
|
||||
- if: '$CI_PROJECT_PATH == "cable-mc/cobblemon" && $CI_COMMIT_BRANCH == "main"'
|
||||
script:
|
||||
- yum install -y findutils
|
||||
- export GRADLE_OPTS="-Xmx4G -Xms4G"
|
||||
- chmod +x ./gradlew
|
||||
- ./gradlew publish
|
||||
@@ -176,6 +179,7 @@ deploy_artifacts:
|
||||
dependencies:
|
||||
- build
|
||||
script:
|
||||
- yum install -y findutils
|
||||
- echo "Collecting artifacts..."
|
||||
- find neoforge/build/libs/ -type f -name "*.jar" | grep -vE "dev-shadow|sources|javadoc" | xargs -I {} mv {} ./
|
||||
- find fabric/build/libs/ -type f -name "*.jar" | grep -vE "dev-shadow|sources|javadoc" | xargs -I {} mv {} ./
|
||||
|
||||
+309
-38
@@ -21,7 +21,7 @@
|
||||
- Added Move Dex to Pokédex
|
||||
- Added the Habitat Block, a spawner block for servers and adventure maps that controls spawning in an area.
|
||||
- Added Disk Rack for storing disks and being an audio sequencer for Noteblocks
|
||||
- Added intrinsic scaling to all mons (+-5%). Some rendering cases, such as shoulder mounting, revert to 1.0 scaling to preserve animation accuracy.
|
||||
- Added intrinsic scaling to all Pokémon (+-5%). Some rendering cases, such as shoulder mounting, revert to 1.0 scaling to preserve animation accuracy.
|
||||
- Added scaling to "baby" Pokémon (smaller (-20%) at level 1 → normally sized at level 10)
|
||||
- Added conditional seats for riding. Seats can be gated by molang such as "is_alpha".
|
||||
- Added Alpha Pokémon
|
||||
@@ -42,9 +42,8 @@
|
||||
- All ruin structures gilded chest loot tables have been updated to include a guaranteed TM not learned naturally by any Pokémon through their level-up moveset. Each ruin gets its own specific TM, so you can now go hunting ruins to complete your move dex!
|
||||
- All fossil structures have been transferred over to biome features, allowing for better placement in generation.
|
||||
- The prehistoric_underwater_fissure & prehistoric_submerged_impact fossil structures now use the biome tag `#cobblemon:is_temperate_ocean`.
|
||||
- A new Biome tag called `#cobblemon:is_stony_beach` has been added.
|
||||
- Gimmighoul towers now generate at ground level rather than sinking one block into the ground.
|
||||
- 1 New shipwreck cove structure called the "magma_shipwreck_cove" has been added.
|
||||
- A new shipwreck cove structure called the "magma_shipwreck_cove" has been added.
|
||||
- Shipwreck coves now generate slightly more frequently.
|
||||
- Added equipment loot tables for shipwreck cove enemies.
|
||||
- Maps from abandoned fishing boats leading to shipwreck coves now will skip explored chunks, allowing the player to find more shipwreck coves easier.
|
||||
@@ -53,80 +52,198 @@
|
||||
- All shipwreck coves' spawners have been adjusted to give compatible mobs enchanted iron or diamond armour and weapons while in its ominous state. The armour given to the mobs will also use the automaton trim. We upped the difficulty because it was too easy now that your Pokémon can fight for you.
|
||||
- One TM of the elemental hyper beams has been added as guaranteed loot to the main treasure chest in every shipwreck cove. (Magma cove gets blast burn, lush cove gets frenzy plant, and submerged cove gets hydro cannon)
|
||||
- Added 7 new advancements
|
||||
- Pressing the inventory key now closes the Pokémon interact wheel GUI
|
||||
- Pokémon cries now play when clicking Pokémon in the summary screen.
|
||||
- Pressing the Summary key while either the starter selection or summary screen are open now closes those screens
|
||||
- Ice type Pokémon are now immune to Packed Snow
|
||||
- Held item visibility can now be controlled by the held_item_visible command argument.
|
||||
|
||||
### New rideable Pokémon
|
||||
- Drampa
|
||||
- Crobat
|
||||
- Skarmory
|
||||
- Milotic
|
||||
- Archeops
|
||||
- Goodra
|
||||
- Goodra (Hisuian Form)
|
||||
- Drampa
|
||||
- Duraludon
|
||||
- Archaludon
|
||||
|
||||
### Pokémon Added
|
||||
- Pancham (+ Cosmetic with Black Glasses)
|
||||
- Pangoro (+ Cosmetic with Black Glasses)
|
||||
- Skitty
|
||||
- Delcatty
|
||||
#### Generation 3
|
||||
- Wurmple
|
||||
- Silcoon
|
||||
- Beautifly
|
||||
- Cascoon
|
||||
- Dustox
|
||||
- Skitty
|
||||
- Delcatty
|
||||
- Seviper
|
||||
- Zangoose
|
||||
|
||||
#### Generation 4
|
||||
- Cherubi
|
||||
- Cherrim
|
||||
- Stunky
|
||||
- Skuntank
|
||||
|
||||
#### Generation 5
|
||||
- Audino
|
||||
- Pawniard
|
||||
- Bisharp
|
||||
|
||||
#### Generation 6
|
||||
- Pancham (+ Cosmetic with Black Glasses)
|
||||
- Pangoro (+ Cosmetic with Black Glasses)
|
||||
|
||||
#### Generation 7
|
||||
- Rockruff
|
||||
- Lycanroc
|
||||
|
||||
#### Generation 8
|
||||
- Rolycoly
|
||||
- Carkol
|
||||
- Coalossal
|
||||
- Runerigus
|
||||
- Snom
|
||||
- Frosmoth
|
||||
- Indeedee
|
||||
- Duraludon
|
||||
- Applin
|
||||
- Flapple
|
||||
- Appletun
|
||||
- Dipplin
|
||||
- Hydrapple
|
||||
- Sandshrew (Alolan)
|
||||
- Sandslash (Alolan)
|
||||
- Seviper
|
||||
- Zangoose
|
||||
- Stunky
|
||||
- Skuntank
|
||||
- Pawniard
|
||||
- Bisharp
|
||||
|
||||
#### Generation 9
|
||||
|
||||
- Nymble
|
||||
- Lokix
|
||||
- Kingambit
|
||||
- Dipplin
|
||||
- Archaludon
|
||||
- Hydrapple
|
||||
|
||||
#### Regional Forms
|
||||
- Sandshrew (Alolan Form)
|
||||
- Sandslash (Alolan Form)
|
||||
- Yamask (Galarian Form)
|
||||
- Avalugg (Hisuian Form)
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
- Goomy
|
||||
- Sliggoo
|
||||
- Goodra
|
||||
- Porygon
|
||||
- Porygon2
|
||||
- Porygon-Z
|
||||
|
||||
- Sandshrew
|
||||
- Sandslash
|
||||
- Nidoking
|
||||
- Zubat
|
||||
- Golbat
|
||||
- Crobat
|
||||
- Pidgey
|
||||
- Pidgeotto
|
||||
- Pidgeot
|
||||
- Sandslash
|
||||
- Nidoking
|
||||
- Ditto
|
||||
- Porygon
|
||||
- Porygon2
|
||||
- Porygon-Z
|
||||
- Skarmory
|
||||
- Smoochum
|
||||
- Jynx
|
||||
- Popplio
|
||||
- Brionne
|
||||
- Primarina
|
||||
- Fletchling
|
||||
- Fletchinder
|
||||
- Talonflame
|
||||
- Sableye
|
||||
- Mawile
|
||||
- Goomy
|
||||
- Sliggoo
|
||||
- Goodra
|
||||
- Nacli
|
||||
- Naclestack
|
||||
- Naclstack
|
||||
- Garganacl
|
||||
- Skarmory
|
||||
- Bidoof
|
||||
- Cranidos
|
||||
- Chatot
|
||||
- Yamask
|
||||
- Cofagrigus
|
||||
- Tyranitar
|
||||
- Turtonator
|
||||
- Golett
|
||||
- Corsola
|
||||
- Arbok (New Patterns: Angry, Cartoon, Clown, Comedic, Crow, Grin, Ink, Modern, Rain, Scribble, Silence, Sloth, Suspicious, Will)
|
||||
- ... and Substitute
|
||||
|
||||
#### Model changes to the regional bias resource pack:
|
||||
|
||||
- Added Mime Jr. (Galar Bias)
|
||||
- Added Bergmite (Hisui Bias)
|
||||
- Changed models for every existing regional bias
|
||||
|
||||
### Animation updates for the following Pokémon
|
||||
- Drampa
|
||||
- Archeops
|
||||
|
||||
- Kakuna
|
||||
- Grimer
|
||||
- Nidoran♀ (+ New shoulder mount)
|
||||
- Nidorina
|
||||
- Nidoran♂ (+ New shoulder mount)
|
||||
- Sandshrew
|
||||
- Diglett
|
||||
- Dugtrio
|
||||
- Graveler
|
||||
- Happiny
|
||||
- Chansey
|
||||
- Blissey
|
||||
- Poliwhirl
|
||||
- Poliwrath
|
||||
- Zubat
|
||||
- Vulpix
|
||||
- Drowzee
|
||||
- Hypno
|
||||
- Noctowl
|
||||
- Skarmory
|
||||
- Skitty
|
||||
- Flygon
|
||||
- Shellos
|
||||
- Riolu
|
||||
- Lucario
|
||||
- Shellos
|
||||
- Skitty
|
||||
- Joltik
|
||||
- Purrloin
|
||||
- Liepard
|
||||
- Flygon
|
||||
- Joltik
|
||||
- Galvantula
|
||||
- Nidoking
|
||||
- Fletchling
|
||||
- Fletchinder
|
||||
- Talonflame
|
||||
- Archeops
|
||||
- Drampa
|
||||
- Sewaddle
|
||||
- Swadloon
|
||||
- Leavanny
|
||||
- Goomy
|
||||
- Sliggoo
|
||||
- Goodra
|
||||
- Shedinja
|
||||
- Skwovet
|
||||
- Greedent
|
||||
- Bidoof
|
||||
- Cranidos
|
||||
- Chatot
|
||||
- Yamask
|
||||
- Cofagrigus
|
||||
- Luvdisc
|
||||
- Staryu
|
||||
- Starmie
|
||||
- Togetic
|
||||
- Rellor
|
||||
- Rabsca
|
||||
- Yungoos
|
||||
- Gumshoos
|
||||
- Cottonee
|
||||
- Whimsicott
|
||||
- Corsola
|
||||
|
||||
#### Added sounds to the following moves
|
||||
|
||||
- Absorb
|
||||
- Aurora Beam
|
||||
- Double Team
|
||||
- Draco Meteor
|
||||
- Fire Punch
|
||||
- Fire Spin
|
||||
- Flame Charge
|
||||
@@ -146,10 +263,14 @@
|
||||
- Tail Whip
|
||||
|
||||
### Changes
|
||||
- Stat increase and decrease particles have been changed, with the addition of alpha boost particles.
|
||||
- Dragonite's mailbag cosmetic can now also be obtained with a chest in the cosmetic slot
|
||||
- Adjusted Croagunk's walkspeed
|
||||
- Adjusted Aerodactyl's walkspeed
|
||||
- Sharp Beak can now be crafted
|
||||
- Metal Alloy can now be crafted
|
||||
- Ability Capsules can now be brewed
|
||||
- Using an Ability Capsule will now return an Empty Bottle
|
||||
- The following items can now be obtained by brushing the following Pokémon:
|
||||
- Pink Wool - Wigglytuff
|
||||
- White Wool - Swablu, Altaria
|
||||
@@ -173,17 +294,50 @@
|
||||
- Cleaned up seat data. Removed all now unused fields from seats in all species files. Also made locator seat names explicit in the species files (however, this doesn't break the legacy format)
|
||||
- Marks can now provide aspects.
|
||||
- Added new shiny and Alpha chance configs
|
||||
- Apricorns now make a new sound when harvested
|
||||
- Lowered the volume of harvesting berries
|
||||
- Added alternate versions of the basic PC Wallpapers based on the original design of Cobblemon's PC, before public release
|
||||
- Improved compatibility with various mods
|
||||
- Farmer's Delight's cutting board can now be used to strip Apricorn and Saccharine's logs, or salvage their planks from various blocks. It can also separate their boats from chests
|
||||
- Farmer's Delight's cutting board can be used to get two white dye from Pep-Up Flowers and two magenta dye from Medicinal Leeks
|
||||
- Farmer's Delight's cutting board can separate Tumblestone Blocks back into Tumblestones
|
||||
- Farmer's Delight's cutting board can salvage Type Gems from their Gem Blocks
|
||||
- Farmer's Delight's Onions, Tomatoes, and Cabbages can be used to cook Open-Faced Sandwiches. Nature's Spirit's Olives also can be used
|
||||
- Farmer's Delight's cutting board can be used on Hearty Grains to obtain rice and straw, similarly to Farmer's Delight's Rice Panicles
|
||||
- Farmer's Delight's Apple Pies and Apple Ciders can now be made using Applin Apples, alongside the Vanilla counterpart
|
||||
- Amendments allows for cooking Leek and Potato Stew in a Cauldron
|
||||
- Any mods that utilise Moonlight's Soft Fluid system can store Leek and Potato Stew, Medicinal Brew, Antidote, Awakening, Burn Heal, Ice Heal, Paralyze Heal, Full Heal, Potion, Super Potion, Hyper Potion, Max Potion, Full Restore, Ability Capsules, Moomoo Milk, and Berry Juice in liquid form (such as Suplementaries' Jar or Goblet, or Cauldrons while using Amendments)
|
||||
- Supplementaries' Hourglass can now use Bright Powder, Quick Powder, Metal Powder, Heal Powder, Silver Powder, and Remedy
|
||||
- Berry Trees are now compatible with the Planter properly
|
||||
- Saccharine Way Signs (added by Supplementaries automagically) now use a premade texture to prevent odd visual issues
|
||||
- Supplementaries' Jar can now store various Cobblemon cookies, candies, and similar items
|
||||
- Some of Supplementaries' items have been added to the `#cobblemon:held/container_held_items` item tag, including sacks, safes, and lunch baskets
|
||||
- Experience Nuggets can be used in place of Sculk for making the EXP Candies if using Create
|
||||
- Rage Candy Bar has a Create Mixing recipe
|
||||
- All Cobblemon ores can now be crushed in Create's Crushing Wheels
|
||||
- All Gem and Tumblestone Clusters can be crushed for automatic, low return, gems
|
||||
- Hearty Grains can be milled like Farmer's Delight Rice Panicles if both Farmer's Delight and Create are installed
|
||||
- Big Roots and Revival Herbs can be milled to their respective powders
|
||||
- Pep-Up Flowers, Medicinal Leeks, and all 70 berries can be milled in Create's Millstone for additional dye drops
|
||||
- Auspicious Armour and Upgrades can be Haunted using Create's crafting systems
|
||||
- Applin Apples can be used to make Honeyed Apples in Create
|
||||
- Golden Apples can now be crafted using the Applin Apples
|
||||
- Prismarine Crystals and Amethyst Shards can now be used to craft Pokedexes
|
||||
- Updated Pokédex Screens item tag to support tagged variants of Redstone and Glowstone Dust
|
||||
- Sounds for interacting with various Cobblemon blocks now play from the centre of the block, rather than the corner
|
||||
- The `/pc` command no longer plays PC activation sounds
|
||||
|
||||
### Fixes
|
||||
- Fixed Croagunk's walkspeed
|
||||
- Fixed Blitzle's base scale being `1` rather than the intended `0.8`
|
||||
- Fixed Magnezone's emissive layer for the shiny having the wrong name, thus displaying wrongly
|
||||
- Fixed Litleo not blinking
|
||||
- Fixed Omanyte and Omastar incorrectly using water animations on land.
|
||||
- Fixed Pokédex layout for genderless variations
|
||||
- Fixed odd stacking behaviour with the poke_bait item.
|
||||
- Fixed a compatibility issue with World Game Rules which caused some log spam in specific cases.
|
||||
- Fixed improper validation of Pokémon when performing a trade.
|
||||
- Fixed an issue where particle like beam can disappear when you don't see the beginning of the beam, or you look away
|
||||
- Fixed Bedrock particle materials (alpha/opaque/blend/add) sharing one render batch, which caused incorrect culling on mixed batches; each material now batches and draws with its own blend and cull state, and the alpha material renders as a true cutout
|
||||
- Fixed an occasional crash on retrieving revived fossils
|
||||
- Fixed brushing not working on Neoforge
|
||||
- Fixed braking not working for submarines (whoops).
|
||||
@@ -210,6 +364,39 @@
|
||||
- Fixed Galarian Ponyta missing its cry.
|
||||
- Fixed various log warnings caused by redundant files and sound events.
|
||||
- Traded Pokémon will now retain the original friendship level when traded back to its OT
|
||||
- Clusters now display correctly on maps
|
||||
- Fixed removing mulch from berry trees with a shovel not working.
|
||||
- Fixed collecting honey from Saccharine Leaf blocks deleting Honey Bottles when the inventory was full
|
||||
- Fixed Stripped Saccharine Wood recipe being missing
|
||||
- Fixed CancelableSoundInstance causing lag by attempting to create sounds every tick when out of range of hearing
|
||||
- Fixed Stat Reducing Aprijuice not being possible to apply on a max out Pokémon, and the possibility of going into negatives
|
||||
- Fixed Exploit where you could take out the bait or drop your Pokérod with bait to avoid consuming bait, now the bobber will just disappear if you do so
|
||||
- Fixed Apricorn and Saccharine boats incorrectly using chest boat models
|
||||
- Fixed wild and trainer battle AI refusing to select moves with the `adjacentAlly` target type, even when it's their only option
|
||||
- Fixed gilded chests being more accessible than intended
|
||||
- Fixed fished up Pokémon not being added as "seen" to the Pokedex
|
||||
- Fixed surprised Gimmighoul encounters not being added as "seen" to the Pokedex
|
||||
- Fixed a crash involving berry trees that have been world edited.
|
||||
- Fixed visual desync in multiplayer for players mounting Pokémon outside other players' loaded chunks
|
||||
- Fixed Pokémon entities leveled by rare candy not getting stronger as Minecraft entities unless recalled.
|
||||
- Fixed a freeze during game load that occurred when multiple mods tried to load Cobblemon API classes at the same time.
|
||||
- Fixed random tick crashes from berry trees
|
||||
- Lowered the volume of Blitzle and Zebstrika's cry
|
||||
- Regional Foods will now prioritise being eaten instead of used for healing Pokémon, shift clicking will use it as healing
|
||||
- Resolved Z-Fighting on Pokédex Models
|
||||
- Restored Ninjask's ability to do barrel rolls
|
||||
- Fixed Raichu (male) and Alolan Raichu (both genders) not displaying the correct Partner Cap when Pewter Crunchies are in the cosmetic slot.
|
||||
- Fixed a crash caused by adding enchanted items to the Resurrection Machine
|
||||
- Fixed a crash that could occur when starting a PvN battle with only fainted Pokémon.
|
||||
- Fixed the Remember Riding Camera config not being respected when dismounting and resolved the incompatibility with the Auto Third Person mod
|
||||
- Fixed Full Heal block not dropping Full Heals
|
||||
- Fixed status cure items not returning an empty bottle when used
|
||||
- Fixed Panpour consuming its held item when evolving with a Water Stone
|
||||
- Fixed Smoked Tail Curry returning a Wooden Bowl when consumed despite it not being included in the recipe
|
||||
- Fixed `/giveallpokemon` not respecting the min and max parameters
|
||||
- Fixed the choose starter toast not disappearing when capturing a Pokémon instead of opening the starter selection screen
|
||||
- Fixed an issue where certain Sinister Tea seasonings were only applying as instant effects and would not apply over time
|
||||
- Long config option labels now scroll instead of overflowing
|
||||
|
||||
### Developer
|
||||
- Added `PokeSnackSpawnerFactory` which allows influence registration on PokeSnack encounters
|
||||
@@ -218,6 +405,11 @@
|
||||
- Tweaked the spawning selector interface to take a bucket function rather than a bucket directly.
|
||||
- Added a new `cobblemon:height_range` processor type to allow developers to restrict structure-spawning ranges.
|
||||
- Separated all the functions of MoLangFunctions.kt into their own files.
|
||||
- Spawn buckets and their base weights are now provided by the spawner, with different base weights for world, fishing, snack, and habitat spawn buckets.
|
||||
- Removed "SpawnBucket" class in favour of just storing maps of bucket names to weights.
|
||||
- Fixed nicknames not being applied to Pokémon spawned from `spawn_pool_world` files.
|
||||
- Added support for `profilePokedexScale`, `profilePokedexTranslation`, `profileSummaryScale`, and `profileSummaryTranslation` in poser files for finer control over profile displays.
|
||||
- Fixed riding camera offsets defined on Pokémon forms not being applied
|
||||
|
||||
### Molang & Datapacks
|
||||
- Added `moveset_builders` datapack folder for different styles of movesets.
|
||||
@@ -228,6 +420,7 @@
|
||||
- Added `q.item.is_enchanted()`
|
||||
- Added `q.item.has_enchantment(minecraft:sharpness, 3)`
|
||||
- Added `has_chosen_starter` & `get_starter_uuid` as available Molang functions
|
||||
- Added `has_tm_move_unlocked`, `unlock_tm_move`, & `lock_tm_move` as available Molang functions for Players
|
||||
- Added `marks`, `has_mark`, & `remove_marks` as available Molang functions for Pokémon
|
||||
- Added Data Component support for species drops, eg `"components": {"minecraft:custom_model_data": 123}`
|
||||
- Added the new `sortOrder` field to mark entries, (defaults to 0 if not specified) which controls the order in which marks are rendered on the HUD, with higher numbers being rendered on top of lower numbers
|
||||
@@ -240,8 +433,86 @@
|
||||
- Ride sounds can now be set as exclusive to passengers
|
||||
- Ride sounds no longer play when submerged unless specified with a new setting
|
||||
- NPC Trainers can now call a `command` animation when issuing a command in battle.
|
||||
- Added a q.failed function to move action effects.
|
||||
- Herd spawned Pokémon have their levels controlled differently. The `levelRange` property now acts as a clamp instead of a filter, with a new `herdLevelRange` property to do the filter behaviour.
|
||||
- `q.sound` now accepts three parameters (sound event, volume and pitch) instead of just the sound event and pitch.
|
||||
|
||||
### Particles
|
||||
|
||||
#### New Move Animations
|
||||
- Blizzard
|
||||
- Disarming Voice
|
||||
- Draco Meteor
|
||||
- Dragon Breath
|
||||
- Dragon Rage
|
||||
- Drain Punch
|
||||
- Fairy Wind
|
||||
- Fire Fang
|
||||
- Gust
|
||||
- Horn Drill
|
||||
- Hydro Pump
|
||||
- Ice Fang
|
||||
- Leafage
|
||||
- Leaf Storm
|
||||
- Light Screen
|
||||
- Night Shade
|
||||
- Play Rough
|
||||
- Pyro Ball
|
||||
- Reflect
|
||||
- Rock Slide
|
||||
- Sonic Boom
|
||||
- Sucker Punch
|
||||
- Supersonic
|
||||
- Thunder Fang
|
||||
|
||||
#### Tweaks and Fixes (Moves)
|
||||
|
||||
- Confusion
|
||||
- Dragon Claw
|
||||
- Eruption
|
||||
- Fire Punch
|
||||
- Flame Burst
|
||||
- Flame Charge
|
||||
- Flamethrower
|
||||
- Frost Breath
|
||||
- Hypnosis
|
||||
- Ice Punch
|
||||
- Icy Wind
|
||||
- Mud Sport
|
||||
- Poison Fang
|
||||
- Protect
|
||||
- Psychic
|
||||
- Quick Attack
|
||||
- Rage Powder
|
||||
- Razor Leaf
|
||||
- Sand Attack
|
||||
- Scratch
|
||||
- Shadow Claw
|
||||
- Sing
|
||||
- Spore
|
||||
- String Shot
|
||||
- Tackle
|
||||
- Tail Whip
|
||||
- Thunder
|
||||
- Thunder Punch
|
||||
- Thunder Wave
|
||||
- Water Gun
|
||||
- Water Pulse
|
||||
- Water Sport
|
||||
|
||||
#### Miscellaneous Particles
|
||||
|
||||
+ Added Wild Might particles for Alpha Pokémon
|
||||
+ Updated stat increase and decrease particles
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
- Japanese
|
||||
- German
|
||||
- Spanish
|
||||
- Ecuadorian Spanish
|
||||
- Portuguese
|
||||
- Brazilian Portuguese
|
||||
- Simplified Chinese
|
||||
- Traditional Chinese
|
||||
- Korean
|
||||
@@ -72,6 +72,10 @@ tasks.withType<Test> {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.processResources {
|
||||
exclude("data/**/README.md")
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
blossom {
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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.mixin.accessor.SinglePoolElementAccessor;
|
||||
import com.cobblemon.mod.common.world.structureprocessors.HeightRangeStructureProcessor;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||
import net.minecraft.world.level.levelgen.structure.pools.*;
|
||||
import net.minecraft.world.level.levelgen.structure.pools.alias.PoolAliasLookup;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.LiquidSettings;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessor;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorList;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
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.CallbackInfoReturnable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Mixin(JigsawPlacement.class)
|
||||
public class JigsawPlacementMixin {
|
||||
|
||||
@Unique
|
||||
private static final Logger cobblemon$LOGGER = LoggerFactory.getLogger("Cobblemon/HeightRangeVeto");
|
||||
|
||||
@Inject(
|
||||
method = "addPieces(Lnet/minecraft/world/level/levelgen/structure/Structure$GenerationContext;Lnet/minecraft/core/Holder;Ljava/util/Optional;ILnet/minecraft/core/BlockPos;ZLjava/util/Optional;ILnet/minecraft/world/level/levelgen/structure/pools/alias/PoolAliasLookup;Lnet/minecraft/world/level/levelgen/structure/pools/DimensionPadding;Lnet/minecraft/world/level/levelgen/structure/templatesystem/LiquidSettings;)Ljava/util/Optional;",
|
||||
at = @At("RETURN"),
|
||||
cancellable = true
|
||||
)
|
||||
private static void onAddPieces(
|
||||
Structure.GenerationContext context,
|
||||
Holder<StructureTemplatePool> startPool,
|
||||
Optional<ResourceLocation> startJigsawName,
|
||||
int maxDepth,
|
||||
BlockPos pos,
|
||||
boolean useExpansionHack,
|
||||
Optional<Heightmap.Types> projectStartToHeightmap,
|
||||
int maxDistanceFromCenter,
|
||||
PoolAliasLookup aliasLookup,
|
||||
DimensionPadding dimensionPadding,
|
||||
LiquidSettings liquidSettings,
|
||||
CallbackInfoReturnable<Optional<Structure.GenerationStub>> cir
|
||||
) {
|
||||
Optional<Structure.GenerationStub> result = cir.getReturnValue();
|
||||
if (result.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
BlockPos spawnPos = result.get().position();
|
||||
String poolId = startPool.unwrapKey().map(key -> key.location().toString()).orElse("unknown");
|
||||
boolean canPlace = cobblemon$canStructurePlace(context, startPool, spawnPos);
|
||||
|
||||
cobblemon$LOGGER.info(
|
||||
"[HeightRangeVeto] addPieces evaluated requestedPos={} spawnPos={} startPool={} -> canPlace={}",
|
||||
pos, spawnPos, poolId, canPlace
|
||||
);
|
||||
|
||||
if (canPlace) {
|
||||
return;
|
||||
}
|
||||
|
||||
cobblemon$LOGGER.info(
|
||||
"[HeightRangeVeto] Vetoing structure start at {} (startPool={})",
|
||||
spawnPos, poolId
|
||||
);
|
||||
|
||||
cir.setReturnValue(Optional.empty());
|
||||
}
|
||||
|
||||
@Unique
|
||||
private static boolean cobblemon$canStructurePlace(
|
||||
Structure.GenerationContext generationContext,
|
||||
Holder<StructureTemplatePool> startPool,
|
||||
BlockPos startPos
|
||||
) {
|
||||
for (StructurePoolElement element : startPool.value().templates) {
|
||||
Optional<HeightRangeStructureProcessor> heightRangeProcessor = cobblemon$getHeightRangeProcessor(element);
|
||||
|
||||
if (heightRangeProcessor.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
HeightRangeStructureProcessor processor = heightRangeProcessor.get();
|
||||
boolean valid = processor.isValidPlacement(
|
||||
generationContext.chunkGenerator(),
|
||||
generationContext.heightAccessor(),
|
||||
generationContext.randomState(),
|
||||
startPos
|
||||
);
|
||||
|
||||
cobblemon$LOGGER.info(
|
||||
"[HeightRangeVeto] template={} pos={} valid={}",
|
||||
element, startPos, valid
|
||||
);
|
||||
|
||||
if (!valid) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Unique
|
||||
private static Optional<HeightRangeStructureProcessor> cobblemon$getHeightRangeProcessor(StructurePoolElement element) {
|
||||
if (!(element instanceof SinglePoolElement)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
StructureProcessorList processorList = ((SinglePoolElementAccessor) element).getProcessors().value();
|
||||
for (StructureProcessor processor : processorList.list()) {
|
||||
if (processor instanceof HeightRangeStructureProcessor heightRangeStructureProcessor) {
|
||||
return Optional.of(heightRangeStructureProcessor);
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
@@ -139,23 +139,4 @@ public abstract class ServerEntityMixin {
|
||||
CobblemonNetwork.INSTANCE.sendPacketToPlayer(player, packet);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "sendPairingData", at = @At("TAIL"))
|
||||
private void cobblemon$sendPairingSeatAssignments(
|
||||
ServerPlayer player,
|
||||
Consumer<Packet<ClientGamePacketListener>> consumer,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
if (!(entity instanceof PokemonEntity pokemon)) return;
|
||||
if (pokemon.getOccupiedSeats().isEmpty()) return;
|
||||
|
||||
pokemon.getOccupiedSeats().forEach((seat, passenger) -> {
|
||||
if (seat.getLocator() == null) return;
|
||||
CobblemonNetwork.INSTANCE.sendPacketToPlayer(
|
||||
player,
|
||||
new ClientboundSeatAssignmentPacket(passenger.getId(), pokemon.getId(), seat.getLocator())
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+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.mixin.accessor;
|
||||
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.world.level.levelgen.structure.pools.SinglePoolElement;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorList;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(SinglePoolElement.class)
|
||||
public interface SinglePoolElementAccessor {
|
||||
@Accessor("processors")
|
||||
Holder<StructureProcessorList> getProcessors();
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.duck.ChannelDuck;
|
||||
import com.mojang.blaze3d.audio.Channel;
|
||||
@@ -108,6 +108,7 @@ import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
import com.cobblemon.mod.common.pokemon.properties.AspectPropertyType
|
||||
import com.cobblemon.mod.common.pokemon.properties.BattleCloneProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.FreezeFrameProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.HeldItemVisibleProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.HiddenAbilityPropertyType
|
||||
import com.cobblemon.mod.common.pokemon.properties.LabelProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.NoAIProperty
|
||||
@@ -308,7 +309,9 @@ object Cobblemon {
|
||||
this.config.maxPokemonLevel,
|
||||
this.config.maxPokemonFriendship,
|
||||
this.config.maxDynamaxLevel,
|
||||
this.config.unlockAllMoveDexMovesByDefault
|
||||
this.config.unlockAllMoveDexMovesByDefault,
|
||||
this.config.pokemonIntrinsicSizeMin,
|
||||
this.config.pokemonIntrinsicSizeMax
|
||||
).sendToPlayer(player)
|
||||
}
|
||||
|
||||
@@ -348,6 +351,7 @@ object Cobblemon {
|
||||
CustomPokemonProperty.register(UnaspectPropertyType)
|
||||
CustomPokemonProperty.register(FreezeFrameProperty)
|
||||
CustomPokemonProperty.register(NoAIProperty)
|
||||
CustomPokemonProperty.register(HeldItemVisibleProperty)
|
||||
|
||||
CobblemonEvents.POKEMON_PROPERTY_INITIALISED.emit(Unit)
|
||||
|
||||
|
||||
@@ -255,31 +255,31 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
val POKE_SNACK = this.create("poke_snack", PokeSnackBlock(BlockBehaviour.Properties.of().forceSolidOn().strength(0.5F).sound(SoundType.WOOL).pushReaction(PushReaction.DESTROY).lightLevel { if (it.getValue(BlockStateProperties.LIT)) 3 else 0 }, true))
|
||||
|
||||
@JvmField
|
||||
val TUMBLESTONE_CLUSTER = tumblestoneBlock("tumblestone_cluster", TumblestoneBlock.STAGE_3, 7, 3, null)
|
||||
val TUMBLESTONE_CLUSTER = tumblestoneBlock("tumblestone_cluster", TumblestoneBlock.STAGE_3, 7, 3, null, MapColor.TERRACOTTA_ORANGE)
|
||||
@JvmField
|
||||
val LARGE_BUDDING_TUMBLESTONE = tumblestoneBlock("large_budding_tumblestone", TumblestoneBlock.STAGE_2, 5, 3, TUMBLESTONE_CLUSTER)
|
||||
val LARGE_BUDDING_TUMBLESTONE = tumblestoneBlock("large_budding_tumblestone", TumblestoneBlock.STAGE_2, 5, 3, TUMBLESTONE_CLUSTER, MapColor.TERRACOTTA_ORANGE)
|
||||
@JvmField
|
||||
val MEDIUM_BUDDING_TUMBLESTONE = tumblestoneBlock("medium_budding_tumblestone", TumblestoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_TUMBLESTONE)
|
||||
val MEDIUM_BUDDING_TUMBLESTONE = tumblestoneBlock("medium_budding_tumblestone", TumblestoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_TUMBLESTONE, MapColor.TERRACOTTA_ORANGE)
|
||||
@JvmField
|
||||
val SMALL_BUDDING_TUMBLESTONE = tumblestoneBlock("small_budding_tumblestone", TumblestoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_TUMBLESTONE)
|
||||
val SMALL_BUDDING_TUMBLESTONE = tumblestoneBlock("small_budding_tumblestone", TumblestoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_TUMBLESTONE, MapColor.TERRACOTTA_ORANGE)
|
||||
|
||||
@JvmField
|
||||
val SKY_TUMBLESTONE_CLUSTER = tumblestoneBlock("sky_tumblestone_cluster", TumblestoneBlock.STAGE_3, 7, 3, null)
|
||||
val SKY_TUMBLESTONE_CLUSTER = tumblestoneBlock("sky_tumblestone_cluster", TumblestoneBlock.STAGE_3, 7, 3, null, MapColor.COLOR_LIGHT_BLUE)
|
||||
@JvmField
|
||||
val LARGE_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("large_budding_sky_tumblestone", TumblestoneBlock.STAGE_2, 5, 3, SKY_TUMBLESTONE_CLUSTER)
|
||||
val LARGE_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("large_budding_sky_tumblestone", TumblestoneBlock.STAGE_2, 5, 3, SKY_TUMBLESTONE_CLUSTER, MapColor.COLOR_LIGHT_BLUE)
|
||||
@JvmField
|
||||
val MEDIUM_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("medium_budding_sky_tumblestone", TumblestoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_SKY_TUMBLESTONE)
|
||||
val MEDIUM_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("medium_budding_sky_tumblestone", TumblestoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_SKY_TUMBLESTONE, MapColor.COLOR_LIGHT_BLUE)
|
||||
@JvmField
|
||||
val SMALL_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("small_budding_sky_tumblestone", TumblestoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_SKY_TUMBLESTONE)
|
||||
val SMALL_BUDDING_SKY_TUMBLESTONE = tumblestoneBlock("small_budding_sky_tumblestone", TumblestoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_SKY_TUMBLESTONE, MapColor.COLOR_LIGHT_BLUE)
|
||||
|
||||
@JvmField
|
||||
val BLACK_TUMBLESTONE_CLUSTER = tumblestoneBlock("black_tumblestone_cluster", TumblestoneBlock.STAGE_3, 7, 3, null)
|
||||
val BLACK_TUMBLESTONE_CLUSTER = tumblestoneBlock("black_tumblestone_cluster", TumblestoneBlock.STAGE_3, 7, 3, null, MapColor.TERRACOTTA_BLACK)
|
||||
@JvmField
|
||||
val LARGE_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("large_budding_black_tumblestone", TumblestoneBlock.STAGE_2, 5, 3, BLACK_TUMBLESTONE_CLUSTER)
|
||||
val LARGE_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("large_budding_black_tumblestone", TumblestoneBlock.STAGE_2, 5, 3, BLACK_TUMBLESTONE_CLUSTER, MapColor.TERRACOTTA_BLACK)
|
||||
@JvmField
|
||||
val MEDIUM_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("medium_budding_black_tumblestone", TumblestoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_BLACK_TUMBLESTONE)
|
||||
val MEDIUM_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("medium_budding_black_tumblestone", TumblestoneBlock.STAGE_1, 4, 3, LARGE_BUDDING_BLACK_TUMBLESTONE, MapColor.TERRACOTTA_BLACK)
|
||||
@JvmField
|
||||
val SMALL_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("small_budding_black_tumblestone", TumblestoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_BLACK_TUMBLESTONE)
|
||||
val SMALL_BUDDING_BLACK_TUMBLESTONE = tumblestoneBlock("small_budding_black_tumblestone", TumblestoneBlock.STAGE_0, 3, 4, MEDIUM_BUDDING_BLACK_TUMBLESTONE, MapColor.TERRACOTTA_BLACK)
|
||||
|
||||
@JvmField
|
||||
val TUMBLESTONE_BLOCK = this.create("tumblestone_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_ORANGE).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@@ -289,85 +289,85 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
val BLACK_TUMBLESTONE_BLOCK = this.create("black_tumblestone_block", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BLACK).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
|
||||
@JvmField
|
||||
val TYPE_GEM_CORE = this.create("deepslate_crystal_core", TypeGemCoreBlock(BlockBehaviour.Properties.of().strength(4.0F, 10.0F).requiresCorrectToolForDrops()))
|
||||
val TYPE_GEM_CORE = this.create("deepslate_crystal_core", TypeGemCoreBlock(BlockBehaviour.Properties.of().strength(4.0F, 10.0F).requiresCorrectToolForDrops().mapColor(MapColor.DEEPSLATE)))
|
||||
|
||||
private val typeGemBlocks = mutableMapOf<ResourceLocation, Block>()
|
||||
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_NORMAL = typeGemBlock("normal_gem_block")
|
||||
val TYPE_GEM_BLOCK_NORMAL = typeGemBlock("normal_gem_block", MapColor.QUARTZ)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_FIRE = typeGemBlock("fire_gem_block")
|
||||
val TYPE_GEM_BLOCK_FIRE = typeGemBlock("fire_gem_block", MapColor.FIRE)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_WATER = typeGemBlock("water_gem_block")
|
||||
val TYPE_GEM_BLOCK_WATER = typeGemBlock("water_gem_block", MapColor.WATER)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_ELECTRIC = typeGemBlock("electric_gem_block")
|
||||
val TYPE_GEM_BLOCK_GRASS = typeGemBlock("grass_gem_block", MapColor.COLOR_LIGHT_GREEN)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_GRASS = typeGemBlock("grass_gem_block")
|
||||
val TYPE_GEM_BLOCK_ELECTRIC = typeGemBlock("electric_gem_block", MapColor.GOLD)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_ICE = typeGemBlock("ice_gem_block")
|
||||
val TYPE_GEM_BLOCK_ICE = typeGemBlock("ice_gem_block", MapColor.ICE)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_FIGHTING = typeGemBlock("fighting_gem_block")
|
||||
val TYPE_GEM_BLOCK_FIGHTING = typeGemBlock("fighting_gem_block", MapColor.COLOR_RED)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_POISON = typeGemBlock("poison_gem_block")
|
||||
val TYPE_GEM_BLOCK_POISON = typeGemBlock("poison_gem_block", MapColor.COLOR_PURPLE)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_GROUND = typeGemBlock("ground_gem_block")
|
||||
val TYPE_GEM_BLOCK_GROUND = typeGemBlock("ground_gem_block", MapColor.PODZOL)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_FLYING = typeGemBlock("flying_gem_block")
|
||||
val TYPE_GEM_BLOCK_FLYING = typeGemBlock("flying_gem_block", MapColor.COLOR_LIGHT_BLUE)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_PSYCHIC = typeGemBlock("psychic_gem_block")
|
||||
val TYPE_GEM_BLOCK_PSYCHIC = typeGemBlock("psychic_gem_block", MapColor.COLOR_MAGENTA)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_BUG = typeGemBlock("bug_gem_block")
|
||||
val TYPE_GEM_BLOCK_BUG = typeGemBlock("bug_gem_block", MapColor.TERRACOTTA_LIGHT_GREEN)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_ROCK = typeGemBlock("rock_gem_block")
|
||||
val TYPE_GEM_BLOCK_ROCK = typeGemBlock("rock_gem_block", MapColor.TERRACOTTA_LIGHT_GRAY)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_GHOST = typeGemBlock("ghost_gem_block")
|
||||
val TYPE_GEM_BLOCK_GHOST = typeGemBlock("ghost_gem_block", MapColor.TERRACOTTA_MAGENTA)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_DRAGON = typeGemBlock("dragon_gem_block")
|
||||
val TYPE_GEM_BLOCK_DRAGON = typeGemBlock("dragon_gem_block", MapColor.COLOR_BLUE)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_DARK = typeGemBlock("dark_gem_block")
|
||||
val TYPE_GEM_BLOCK_DARK = typeGemBlock("dark_gem_block", MapColor.TERRACOTTA_BLACK)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_STEEL = typeGemBlock("steel_gem_block")
|
||||
val TYPE_GEM_BLOCK_STEEL = typeGemBlock("steel_gem_block", MapColor.METAL)
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_FAIRY = typeGemBlock("fairy_gem_block")
|
||||
val TYPE_GEM_BLOCK_FAIRY = typeGemBlock("fairy_gem_block", MapColor.COLOR_PINK)
|
||||
|
||||
private val typeGemClusters = mutableMapOf<ResourceLocation, TypeGemClusterBlock>()
|
||||
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_NORMAL = typeGemCluster("normal_gem_cluster", TYPE_GEM_BLOCK_NORMAL, cobblemonResource("normal_gem"))
|
||||
val TYPE_GEM_CLUSTER_NORMAL = typeGemCluster("normal_gem_cluster", TYPE_GEM_BLOCK_NORMAL, cobblemonResource("normal_gem"), MapColor.QUARTZ)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_FIRE = typeGemCluster("fire_gem_cluster", TYPE_GEM_BLOCK_FIRE, cobblemonResource("fire_gem"))
|
||||
val TYPE_GEM_CLUSTER_FIRE = typeGemCluster("fire_gem_cluster", TYPE_GEM_BLOCK_FIRE, cobblemonResource("fire_gem"), MapColor.FIRE)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_WATER = typeGemCluster("water_gem_cluster", TYPE_GEM_BLOCK_WATER, cobblemonResource("water_gem"))
|
||||
val TYPE_GEM_CLUSTER_WATER = typeGemCluster("water_gem_cluster", TYPE_GEM_BLOCK_WATER, cobblemonResource("water_gem"), MapColor.WATER)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_ELECTRIC = typeGemCluster("electric_gem_cluster", TYPE_GEM_BLOCK_ELECTRIC, cobblemonResource("electric_gem"))
|
||||
val TYPE_GEM_CLUSTER_GRASS = typeGemCluster("grass_gem_cluster", TYPE_GEM_BLOCK_GRASS, cobblemonResource("grass_gem"), MapColor.COLOR_LIGHT_GREEN)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_GRASS = typeGemCluster("grass_gem_cluster", TYPE_GEM_BLOCK_GRASS, cobblemonResource("grass_gem"))
|
||||
val TYPE_GEM_CLUSTER_ELECTRIC = typeGemCluster("electric_gem_cluster", TYPE_GEM_BLOCK_ELECTRIC, cobblemonResource("electric_gem"), MapColor.GOLD)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_ICE = typeGemCluster("ice_gem_cluster", TYPE_GEM_BLOCK_ICE, cobblemonResource("ice_gem"))
|
||||
val TYPE_GEM_CLUSTER_ICE = typeGemCluster("ice_gem_cluster", TYPE_GEM_BLOCK_ICE, cobblemonResource("ice_gem"), MapColor.ICE)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_FIGHTING = typeGemCluster("fighting_gem_cluster", TYPE_GEM_BLOCK_FIGHTING, cobblemonResource("fighting_gem"))
|
||||
val TYPE_GEM_CLUSTER_FIGHTING = typeGemCluster("fighting_gem_cluster", TYPE_GEM_BLOCK_FIGHTING, cobblemonResource("fighting_gem"), MapColor.COLOR_RED)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_POISON = typeGemCluster("poison_gem_cluster", TYPE_GEM_BLOCK_POISON, cobblemonResource("poison_gem"))
|
||||
val TYPE_GEM_CLUSTER_POISON = typeGemCluster("poison_gem_cluster", TYPE_GEM_BLOCK_POISON, cobblemonResource("poison_gem"), MapColor.COLOR_PURPLE)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_GROUND = typeGemCluster("ground_gem_cluster", TYPE_GEM_BLOCK_GROUND, cobblemonResource("ground_gem"))
|
||||
val TYPE_GEM_CLUSTER_GROUND = typeGemCluster("ground_gem_cluster", TYPE_GEM_BLOCK_GROUND, cobblemonResource("ground_gem"), MapColor.PODZOL)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_FLYING = typeGemCluster("flying_gem_cluster", TYPE_GEM_BLOCK_FLYING, cobblemonResource("flying_gem"))
|
||||
val TYPE_GEM_CLUSTER_FLYING = typeGemCluster("flying_gem_cluster", TYPE_GEM_BLOCK_FLYING, cobblemonResource("flying_gem"), MapColor.COLOR_LIGHT_BLUE)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_PSYCHIC = typeGemCluster("psychic_gem_cluster", TYPE_GEM_BLOCK_PSYCHIC, cobblemonResource("psychic_gem"))
|
||||
val TYPE_GEM_CLUSTER_PSYCHIC = typeGemCluster("psychic_gem_cluster", TYPE_GEM_BLOCK_PSYCHIC, cobblemonResource("psychic_gem"), MapColor.COLOR_MAGENTA)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_BUG = typeGemCluster("bug_gem_cluster", TYPE_GEM_BLOCK_BUG, cobblemonResource("bug_gem"))
|
||||
val TYPE_GEM_CLUSTER_BUG = typeGemCluster("bug_gem_cluster", TYPE_GEM_BLOCK_BUG, cobblemonResource("bug_gem"), MapColor.TERRACOTTA_LIGHT_GREEN)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_ROCK = typeGemCluster("rock_gem_cluster", TYPE_GEM_BLOCK_ROCK, cobblemonResource("rock_gem"))
|
||||
val TYPE_GEM_CLUSTER_ROCK = typeGemCluster("rock_gem_cluster", TYPE_GEM_BLOCK_ROCK, cobblemonResource("rock_gem"), MapColor.TERRACOTTA_LIGHT_GRAY)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_GHOST = typeGemCluster("ghost_gem_cluster", TYPE_GEM_BLOCK_GHOST, cobblemonResource("ghost_gem"))
|
||||
val TYPE_GEM_CLUSTER_GHOST = typeGemCluster("ghost_gem_cluster", TYPE_GEM_BLOCK_GHOST, cobblemonResource("ghost_gem"), MapColor.TERRACOTTA_MAGENTA)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_DRAGON = typeGemCluster("dragon_gem_cluster", TYPE_GEM_BLOCK_DRAGON, cobblemonResource("dragon_gem"))
|
||||
val TYPE_GEM_CLUSTER_DRAGON = typeGemCluster("dragon_gem_cluster", TYPE_GEM_BLOCK_DRAGON, cobblemonResource("dragon_gem"), MapColor.COLOR_BLUE)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_DARK = typeGemCluster("dark_gem_cluster", TYPE_GEM_BLOCK_DARK, cobblemonResource("dark_gem"))
|
||||
val TYPE_GEM_CLUSTER_DARK = typeGemCluster("dark_gem_cluster", TYPE_GEM_BLOCK_DARK, cobblemonResource("dark_gem"), MapColor.TERRACOTTA_BLACK)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_STEEL = typeGemCluster("steel_gem_cluster", TYPE_GEM_BLOCK_STEEL, cobblemonResource("steel_gem"))
|
||||
val TYPE_GEM_CLUSTER_STEEL = typeGemCluster("steel_gem_cluster", TYPE_GEM_BLOCK_STEEL, cobblemonResource("steel_gem"), MapColor.METAL)
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_FAIRY = typeGemCluster("fairy_gem_cluster", TYPE_GEM_BLOCK_FAIRY, cobblemonResource("fairy_gem"))
|
||||
val TYPE_GEM_CLUSTER_FAIRY = typeGemCluster("fairy_gem_cluster", TYPE_GEM_BLOCK_FAIRY, cobblemonResource("fairy_gem"), MapColor.COLOR_PINK)
|
||||
|
||||
@JvmField
|
||||
val POLISHED_TUMBLESTONE = this.create("polished_tumblestone", Block(BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_ORANGE).strength(1.0F).sound(CobblemonSounds.TUMBLESTONE_BLOCK_SOUNDS).requiresCorrectToolForDrops().instrument(NoteBlockInstrument.BASEDRUM)))
|
||||
@@ -558,7 +558,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
@JvmField
|
||||
val RELIC_COIN_POUCH = create("relic_coin_pouch", CoinPouchBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.RELIC_COIN_POUCH_SOUNDS).pushReaction(PushReaction.DESTROY).noOcclusion(), true))
|
||||
@JvmField
|
||||
val RELIC_COIN_SACK = create("relic_coin_sack", CoinPouchBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.RELIC_COIN_SACK_SOUNDS).pushReaction(PushReaction.DESTROY).strength(0.4F), false))
|
||||
val RELIC_COIN_SACK = create("relic_coin_sack", CoinPouchBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.RELIC_COIN_SACK_SOUNDS).pushReaction(PushReaction.DESTROY).strength(0.4F).mapColor(MapColor.GOLD), false))
|
||||
|
||||
@JvmField
|
||||
val GILDED_CHEST = create("gilded_chest", GildedChestBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.CHEST).noOcclusion().sound(CobblemonSounds.GILDED_CHEST_SOUNDS), GildedChestBlock.Type.RED))
|
||||
@@ -777,8 +777,9 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
|
||||
private fun apricornBlock(name: String, apricorn: Apricorn): ApricornBlock = this.create(name, ApricornBlock(BlockBehaviour.Properties.of().mapColor(apricorn.mapColor()).randomTicks().strength(Blocks.OAK_LOG.defaultDestroyTime(), Blocks.OAK_LOG.explosionResistance).sound(SoundType.WOOD).noOcclusion(), apricorn))
|
||||
|
||||
private fun tumblestoneBlock(name: String, stage: Int, height: Int, xzOffset: Int, nextStage: Block?) : Block {
|
||||
private fun tumblestoneBlock(name: String, stage: Int, height: Int, xzOffset: Int, nextStage: Block?, mapColor: MapColor) : Block {
|
||||
return this.create(name, TumblestoneBlock(BlockBehaviour.Properties.of()
|
||||
.mapColor(mapColor)
|
||||
.pushReaction(PushReaction.DESTROY)
|
||||
.noOcclusion()
|
||||
.strength(1.5F)
|
||||
@@ -1008,8 +1009,8 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
return this.create(name, block)
|
||||
}
|
||||
|
||||
private fun typeGemBlock(name: String): Block {
|
||||
val typeGemBlock = this.create(name, Block(BlockBehaviour.Properties.of().strength(3.0F, 6.0F).sound(CobblemonSounds.TYPE_GEM_BLOCK_SOUNDS)))
|
||||
private fun typeGemBlock(name: String, mapColor: MapColor): Block {
|
||||
val typeGemBlock = this.create(name, Block(BlockBehaviour.Properties.of().mapColor(mapColor).strength(3.0F, 6.0F).sound(CobblemonSounds.TYPE_GEM_BLOCK_SOUNDS)))
|
||||
|
||||
val identifier = cobblemonResource(name)
|
||||
typeGemBlocks[identifier] = typeGemBlock
|
||||
@@ -1019,8 +1020,8 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
|
||||
fun typeGemBlocks() = typeGemBlocks.toMap()
|
||||
|
||||
private fun typeGemCluster(name: String, gemBlock: Block, dropItemId: ResourceLocation): Block {
|
||||
val gemClusterBlock = this.create(name, TypeGemClusterBlock(BlockBehaviour.Properties.of().strength(2.0F, 3.0F).sound(CobblemonSounds.TYPE_GEM_CLUSTER_SOUNDS).pushReaction(PushReaction.DESTROY), gemBlock, dropItemId))
|
||||
private fun typeGemCluster(name: String, gemBlock: Block, dropItemId: ResourceLocation, mapColor: MapColor): Block {
|
||||
val gemClusterBlock = this.create(name, TypeGemClusterBlock(BlockBehaviour.Properties.of().mapColor(mapColor).strength(2.0F, 3.0F).sound(CobblemonSounds.TYPE_GEM_CLUSTER_SOUNDS).pushReaction(PushReaction.DESTROY), gemBlock, dropItemId))
|
||||
|
||||
TypeGemClusterBlock.gemToClusterMap[gemBlock] = gemClusterBlock
|
||||
|
||||
@@ -1031,4 +1032,4 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
}
|
||||
|
||||
fun typeGemClusters() = typeGemClusters.toMap()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -405,7 +405,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val BIG_MALASADA = regionalFoodItem("big_malasada", 64, 7, 0.3f, false)
|
||||
@JvmField
|
||||
val SMOKED_TAIL_CURRY = regionalFoodItem("smoked_tail_curry", 64, 10, 0.6f, false, ItemStack(Items.BOWL, 1))
|
||||
val SMOKED_TAIL_CURRY = regionalFoodItem("smoked_tail_curry", 64, 10, 0.6f, false)
|
||||
@JvmField
|
||||
val JUBILIFE_MUFFIN = regionalFoodItem("jubilife_muffin", 64, 7, 0.3f, false)
|
||||
@JvmField
|
||||
|
||||
@@ -35,6 +35,7 @@ import com.cobblemon.mod.common.client.net.gui.PokedexUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.SetActiveTMPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.SetTMMachineContainerDataPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.SummaryUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.SynchronizeActiveTMHandler
|
||||
import com.cobblemon.mod.common.client.net.habitat.OpenHabitatBlockEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.npc.CloseNPCEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.npc.OpenNPCEditorHandler
|
||||
@@ -131,6 +132,7 @@ import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.ChangeP
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.RequestPCBoxWallpapersPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.SetPCBoxWallpapersPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.storage.pc.wallpaper.UnlockPCBoxWallpaperPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.tms.TechnicalMachineRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.toast.ToastPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeAcceptanceChangedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeCancelledPacket
|
||||
@@ -146,6 +148,7 @@ import com.cobblemon.mod.common.net.messages.client.ui.PokedexUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.SetActiveTMPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.SetTMMachineContainerDataPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.SummaryUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.SynchronizeActiveTMPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.BattleChallengePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.BattleChallengeResponsePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.BenchMovePacket
|
||||
@@ -374,6 +377,7 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(PlayerInteractOptionsPacket.ID, PlayerInteractOptionsPacket::decode, PlayerInteractOptionsHandler))
|
||||
list.add(PacketRegisterInfo(PokedexUIPacket.ID, PokedexUIPacket::decode, PokedexUIPacketHandler))
|
||||
list.add(PacketRegisterInfo(ExpGainedDataPacket.ID, ExpGainedDataPacket::decode, ExpGainedDataPacketHandler))
|
||||
list.add(PacketRegisterInfo(SynchronizeActiveTMPacket.ID, SynchronizeActiveTMPacket::decode, SynchronizeActiveTMHandler))
|
||||
|
||||
// Starter packets
|
||||
list.add(PacketRegisterInfo(OpenStarterUIPacket.ID, OpenStarterUIPacket::decode, StarterUIPacketHandler))
|
||||
@@ -439,6 +443,7 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(BehaviourSyncPacket.ID, BehaviourSyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarkRegistrySyncPacket.ID, MarkRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(RideSettingsSyncPacket.ID, RideSettingsSyncPacket::decode, RideSettingsSyncHandler))
|
||||
list.add(PacketRegisterInfo(TechnicalMachineRegistrySyncPacket.ID, TechnicalMachineRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
|
||||
// Effects
|
||||
list.add(PacketRegisterInfo(SpawnSnowstormParticlePacket.ID, SpawnSnowstormParticlePacket::decode, SpawnSnowstormParticleHandler))
|
||||
|
||||
@@ -108,6 +108,9 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
@JvmField
|
||||
val LEVELUP = this.create("gui.levelup")
|
||||
|
||||
@JvmField
|
||||
val MOVE_LEARN = this.create("gui.move_learn")
|
||||
|
||||
@JvmField
|
||||
val PVN_BATTLE = this.create("battle.pvn.default")
|
||||
@JvmField
|
||||
@@ -142,6 +145,8 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
val MONITOR_INSERT = this.create("block.monitor.insert")
|
||||
@JvmField
|
||||
val MONITOR_LOADING = this.create("block.monitor.loading")
|
||||
@JvmField
|
||||
val MONITOR_GLITCHING = this.create("block.monitor.glitching")
|
||||
|
||||
@JvmField
|
||||
val FOSSIL_MACHINE_ACTIVATE = this.create("block.fossil_machine.activate")
|
||||
@@ -210,17 +215,23 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
@JvmField
|
||||
val TM_USE = this.create("item.tm.use")
|
||||
@JvmField
|
||||
val TM_MACHINE_BURN_LOOP = this.create("block.tm_machine.burn_loop")
|
||||
@JvmField
|
||||
val TM_MACHINE_CRAFT = this.create("block.tm_machine.craft")
|
||||
@JvmField
|
||||
val TM_MACHINE_OFF = this.create("block.tm_machine.off")
|
||||
@JvmField
|
||||
val TM_MACHINE_ON = this.create("block.tm_machine.on")
|
||||
val TM_MACHINE_START = this.create("block.tm_machine.start")
|
||||
@JvmField
|
||||
val TM_MACHINE_OPEN = this.create("block.tm_machine.open")
|
||||
@JvmField
|
||||
val TM_MACHINE_CLOSE = this.create("block.tm_machine.close")
|
||||
@JvmField
|
||||
val TM_MACHINE_PLACE_DISC = this.create("block.tm_machine.place_disc")
|
||||
val TM_MACHINE_TM_INSERT = this.create("block.tm_machine.tm_insert")
|
||||
@JvmField
|
||||
val TM_MACHINE_TM_RETRIEVE = this.create("block.tm_machine.tm_retrieve")
|
||||
@JvmField
|
||||
val TM_MACHINE_ITEM_INSERT = this.create("block.tm_machine.item_insert")
|
||||
@JvmField
|
||||
val TM_MACHINE_ITEM_RETRIEVE = this.create("block.tm_machine.item_retrieve")
|
||||
|
||||
|
||||
@JvmField
|
||||
@@ -261,6 +272,9 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
@JvmField
|
||||
val BERRY_EAT_FULL = this.create("item.berry.eat.full")
|
||||
|
||||
@JvmField
|
||||
val APRICORN_HARVEST = this.create("block.apricorn.harvest")
|
||||
|
||||
@JvmField
|
||||
val BIG_ROOT_BREAK = this.create("block.big_root.break")
|
||||
@JvmField
|
||||
@@ -408,9 +422,9 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_BREAK = this.create("block.type_gem_cluster.break")
|
||||
val TYPE_GEM_BLOCK_BREAK = this.create("block.type_gem_block.break")
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_BREAK = this.create("block.type_gem_block.break")
|
||||
val TYPE_GEM_CLUSTER_BREAK = this.create("block.type_gem_cluster.break")
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_HIT = this.create("block.type_gem_block.hit")
|
||||
@JvmField
|
||||
@@ -419,7 +433,7 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
val TYPE_GEM_BLOCK_STEP = this.create("block.type_gem_block.step")
|
||||
|
||||
@JvmField
|
||||
val TYPE_GEM_CLUSTER_SOUNDS = SoundType(1f, 1.2f,
|
||||
val TYPE_GEM_CLUSTER_SOUNDS = SoundType(1f, 1.1f,
|
||||
TYPE_GEM_CLUSTER_BREAK,
|
||||
TYPE_GEM_BLOCK_STEP,
|
||||
TYPE_GEM_BLOCK_PLACE,
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ class RidingStatBoostCriterion(
|
||||
val max = context.pokemon.pokemon.getMaxRideBoost(rideStat).toDouble()
|
||||
val min = context.pokemon.pokemon.getBaseRideStat(rideStat).toDouble()
|
||||
val value = context.pokemon.getRideStat(rideStat, ridingStyle, min, max)
|
||||
val isSufficient = (value >= this.statValue && this.statValue > 0.0) || !context.pokemon.pokemon.canAddRideBoost(rideStat)
|
||||
val isSufficient = (value >= this.statValue && this.statValue > 0.0) || !context.pokemon.pokemon.canApplyRideBoost(rideStat)
|
||||
if (isSufficient && this.rideStat == "any") {
|
||||
return true
|
||||
} else if (!isSufficient && this.rideStat == "all") {
|
||||
|
||||
+10
-1
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.cooking.effects
|
||||
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.effect.MobEffect
|
||||
import net.minecraft.world.effect.MobEffectCategory
|
||||
import net.minecraft.world.entity.Entity
|
||||
@@ -18,5 +19,13 @@ class CleanseAllEffect : MobEffect(MobEffectCategory.BENEFICIAL, 0xFFFFFF) {
|
||||
override fun applyInstantenousEffect(source: Entity?, indirect: Entity?, target: LivingEntity, amplifier: Int, proximity: Double) {
|
||||
target.removeAllEffects()
|
||||
}
|
||||
override fun shouldApplyEffectTickThisTick(duration: Int, amplifier: Int) = false
|
||||
|
||||
override fun applyEffectTick(livingEntity: LivingEntity, amplifier: Int): Boolean {
|
||||
if (livingEntity is ServerPlayer){
|
||||
livingEntity.removeAllEffects()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun shouldApplyEffectTickThisTick(duration: Int, amplifier: Int) = true
|
||||
}
|
||||
+15
-1
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.cooking.effects
|
||||
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.effect.MobEffect
|
||||
import net.minecraft.world.effect.MobEffectCategory
|
||||
import net.minecraft.world.entity.Entity
|
||||
@@ -23,5 +24,18 @@ class CleanseNegativeEffect : MobEffect(MobEffectCategory.BENEFICIAL, 0xFFFFFF)
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun shouldApplyEffectTickThisTick(duration: Int, amplifier: Int) = false
|
||||
|
||||
override fun applyEffectTick(livingEntity: LivingEntity, amplifier: Int): Boolean {
|
||||
if (livingEntity is ServerPlayer){
|
||||
val snapshot = livingEntity.activeEffects.toList()
|
||||
for (ei in snapshot) {
|
||||
if (ei.effect.value().category == MobEffectCategory.HARMFUL) {
|
||||
livingEntity.removeEffect(ei.effect)
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun shouldApplyEffectTickThisTick(duration: Int, amplifier: Int) = true
|
||||
}
|
||||
@@ -1,33 +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.api.data
|
||||
|
||||
import com.cobblemon.mod.common.api.net.Decodable
|
||||
import com.cobblemon.mod.common.api.net.Encodable
|
||||
|
||||
// TODO this is implemented in multiple places but unused. Can we scratch this?
|
||||
/**
|
||||
* Represents an object that will possibly be synchronized to the client during datapack synchronization.
|
||||
*
|
||||
* @param T The type of the object being synchronized.
|
||||
*
|
||||
* @author Licious
|
||||
* @since October 14th, 2022
|
||||
*/
|
||||
interface ClientDataSynchronizer<T> : Decodable, Encodable {
|
||||
|
||||
/**
|
||||
* Compares an object of type [T] with this instance to see if synchronization is necessary.
|
||||
*
|
||||
* @param other The other instance of type [T].
|
||||
* @return If synchronization is necessary.
|
||||
*/
|
||||
fun shouldSynchronize(other: T): Boolean
|
||||
|
||||
}
|
||||
+2
-3
@@ -8,7 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.events.entity
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnCause
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
|
||||
|
||||
@@ -21,7 +20,7 @@ class SpawnBucketChosenEvent(
|
||||
/** The cause of the spawn. */
|
||||
val spawnCause: SpawnCause,
|
||||
/** The bucket that was chosen. You can alter this. */
|
||||
var bucket: SpawnBucket,
|
||||
var bucket: String,
|
||||
/** The final weights that were used to make the choice. */
|
||||
val bucketWeights: Map<SpawnBucket, Float>
|
||||
val bucketWeights: Map<String, Float>
|
||||
)
|
||||
+3
-4
@@ -9,7 +9,6 @@
|
||||
package com.cobblemon.mod.common.api.events.fishing
|
||||
|
||||
import com.cobblemon.mod.common.api.events.Cancelable
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.entity.fishing.PokeRodFishingBobberEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.world.item.ItemStack
|
||||
@@ -27,7 +26,7 @@ interface BaitSpawnPokemonEvent {
|
||||
*/
|
||||
data class Pre(
|
||||
val bobber: PokeRodFishingBobberEntity, // todo replace this with the bait entity
|
||||
val chosenBucket: SpawnBucket,
|
||||
val chosenBucket: String,
|
||||
val rod: ItemStack
|
||||
) : Cancelable(), BobberSpawnPokemonEvent
|
||||
|
||||
@@ -38,7 +37,7 @@ interface BaitSpawnPokemonEvent {
|
||||
* @param pokemon The Pokemon that is modified.
|
||||
*/
|
||||
data class Modify(
|
||||
val chosenBucket: SpawnBucket,
|
||||
val chosenBucket: String,
|
||||
val rod: ItemStack,
|
||||
val pokemon: PokemonEntity
|
||||
) : BobberSpawnPokemonEvent
|
||||
@@ -52,7 +51,7 @@ interface BaitSpawnPokemonEvent {
|
||||
*/
|
||||
data class Post(
|
||||
val bobber: PokeRodFishingBobberEntity,
|
||||
val chosenBucket: SpawnBucket,
|
||||
val chosenBucket: String,
|
||||
val bait: ItemStack,
|
||||
val pokemon: PokemonEntity
|
||||
) : BobberSpawnPokemonEvent
|
||||
|
||||
+1
-3
@@ -8,12 +8,10 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.events.fishing
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
|
||||
/**
|
||||
* Event that is fired when a bucket is chosen by the bobber.
|
||||
* @param chosenBucket The bucket that is chosen.
|
||||
* @param buckets The list of buckets that the bobber can choose from.
|
||||
* @param luckOfTheSeaLevel The level of the Luck of the Sea enchantment on the rod.
|
||||
*/
|
||||
class BobberBucketChosenEvent(var chosenBucket: SpawnBucket, val buckets: MutableList<SpawnBucket>, val luckOfTheSeaLevel: Int)
|
||||
class BobberBucketChosenEvent(var chosenBucket: String, val buckets: MutableList<String>, val luckOfTheSeaLevel: Int)
|
||||
+2
-5
@@ -12,10 +12,7 @@ import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.events.Cancelable
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
|
||||
import com.cobblemon.mod.common.entity.fishing.PokeRodFishingBobberEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
@@ -73,8 +70,8 @@ interface BobberSpawnPokemonEvent {
|
||||
val bait: ItemStack,
|
||||
val pokemon: PokemonEntity
|
||||
) : BobberSpawnPokemonEvent {
|
||||
val context = mutableMapOf<String, MoValue>(
|
||||
"chosen_bucket" to ObjectValue(spawnAction.bucket, { it.name }),
|
||||
val context = mutableMapOf(
|
||||
"chosen_bucket" to StringValue(spawnAction.bucket),
|
||||
"bait" to pokemon.level().itemRegistry.wrapAsHolder(bait.item).asMoLangValue(Registries.ITEM),
|
||||
"pokemon_entity" to pokemon.asMoLangValue()
|
||||
)
|
||||
|
||||
@@ -1,37 +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.api.habitats
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
/**
|
||||
* A [HabitatPool] of [ActivatedHabitatSpawn]s. Mainly just to help with deserialization and ensuring
|
||||
* a single type for everything that's applied to a habitat block.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since February 13th, 2026
|
||||
*/
|
||||
class ActivatedHabitatPool : HabitatPool<ActivatedHabitatSpawn>() {
|
||||
override val type: ResourceLocation = ActivatedHabitatSpawn.TYPE
|
||||
override var spawns: List<ActivatedHabitatSpawn> = listOf()
|
||||
|
||||
companion object {
|
||||
fun default() = ActivatedHabitatPool().apply {
|
||||
id = ResourceLocation("cobblemon", "custom__default_activated_pool")
|
||||
name = "Custom"
|
||||
}
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf, buckets: List<SpawnBucket>) {
|
||||
super.decode(buffer, buckets)
|
||||
spawns = buffer.readList { ActivatedHabitatSpawn().apply { decode(buffer, buckets) } }
|
||||
}
|
||||
}
|
||||
@@ -1,23 +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.api.habitats
|
||||
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
|
||||
/**
|
||||
* A basic [HabitatSpawn] that will be triggered via activated spawning in a habitat. Nothing to it, really.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since February 13th, 2026
|
||||
*/
|
||||
class ActivatedHabitatSpawn : HabitatSpawn() {
|
||||
companion object {
|
||||
val TYPE = cobblemonResource("activated")
|
||||
}
|
||||
}
|
||||
@@ -8,39 +8,81 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.habitats
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
import com.cobblemon.mod.common.block.habitat.HabitatBlockEntity
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.nbt.Tag
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
/**
|
||||
* A pool of [HabitatSpawn]s. This is either filled with [NaturalHabitatSpawn]s or [ActivatedHabitatSpawn]s depending
|
||||
* on whether the pool is a [NaturalHabitatPool] or an [ActivatedHabitatPool]. The pool is responsible for converting
|
||||
* A pool of [HabitatSpawn]s. This is filled with [HabitatSpawn]s. The pool is responsible for converting
|
||||
* its spawns into [PokemonSpawnDetail]s.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since February 13th, 2026
|
||||
*/
|
||||
abstract class HabitatPool<T : HabitatSpawn> {
|
||||
class HabitatPool {
|
||||
companion object {
|
||||
val types = mutableMapOf(
|
||||
ActivatedHabitatSpawn.TYPE to ActivatedHabitatPool::class.java,
|
||||
NaturalHabitatSpawn.TYPE to NaturalHabitatPool::class.java
|
||||
)
|
||||
fun default() = HabitatPool().apply {
|
||||
id = ResourceLocation("cobblemon", "custom__default_pool")
|
||||
name = "Custom"
|
||||
}
|
||||
|
||||
fun writePoolToNBT(pool: HabitatPool, nbt: CompoundTag) {
|
||||
nbt.putString(DataKeys.HABITAT_POOL_ID, pool.id.toString())
|
||||
if (pool.id.path.startsWith("custom__")) {
|
||||
nbt.putString(DataKeys.HABITAT_POOL_NAME, pool.name)
|
||||
val spawnsListNBT = ListTag()
|
||||
for (spawn in pool.spawns) {
|
||||
val spawnTag = CompoundTag()
|
||||
spawn.writeToNBT(spawnTag)
|
||||
spawnsListNBT.add(spawnTag)
|
||||
}
|
||||
nbt.put(DataKeys.HABITAT_POOL_SPAWNS, spawnsListNBT)
|
||||
}
|
||||
}
|
||||
|
||||
fun readPoolFromNBT(nbt: CompoundTag): HabitatPool {
|
||||
val poolId = nbt.getString(DataKeys.HABITAT_POOL_ID).asIdentifierDefaultingNamespace()
|
||||
if (nbt.contains(DataKeys.HABITAT_POOL_NAME)) {
|
||||
// It's one that was stored on the block
|
||||
val pool = HabitatPool()
|
||||
pool.id = poolId
|
||||
pool.name = nbt.getString(DataKeys.HABITAT_POOL_NAME)
|
||||
val spawnsListNBT = nbt.getList(DataKeys.HABITAT_POOL_SPAWNS, Tag.TAG_COMPOUND.toInt())
|
||||
val spawns = mutableListOf<HabitatSpawn>()
|
||||
spawnsListNBT.forEach { spawnTag ->
|
||||
try {
|
||||
val spawn = HabitatSpawn().apply { readFromNBT(spawnTag as CompoundTag) }
|
||||
spawns.add(spawn)
|
||||
} catch (_: Exception) {
|
||||
// If there's an error reading a spawn, skip it and log the error.
|
||||
Cobblemon.LOGGER.error("Error reading activated habitat spawn from NBT for habitat block, skipping.")
|
||||
}
|
||||
}
|
||||
pool.spawns = spawns
|
||||
return pool
|
||||
} else {
|
||||
return HabitatPools.habitatPoolsById[poolId] ?: default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lateinit var id: ResourceLocation
|
||||
var name: String = ""
|
||||
abstract val type: ResourceLocation
|
||||
abstract var spawns: List<T>
|
||||
var spawns: List<HabitatSpawn> = listOf()
|
||||
|
||||
/** Whether a pool is editable is just down to whether it's not from a datapack. */
|
||||
@Transient
|
||||
var editable: Boolean = false
|
||||
|
||||
open fun validate() {
|
||||
fun validate() {
|
||||
for (spawn in spawns) {
|
||||
if (SpawnablePosition.getByName(spawn.spawnablePositionType) == null) {
|
||||
throw IllegalArgumentException("$id mentions non-existent spawnable position type ${spawn.spawnablePositionType} on spawn for ${spawn.species}")
|
||||
@@ -52,14 +94,23 @@ abstract class HabitatPool<T : HabitatSpawn> {
|
||||
return spawns.mapNotNull { it.createSpawnDetail(habitatBlockEntity) }
|
||||
}
|
||||
|
||||
fun getPhaseCount(): Int {
|
||||
return spawns
|
||||
.flatMap { it.phases?.ranges?.flatten() ?: emptySet() }
|
||||
.toSet()
|
||||
.count()
|
||||
.coerceAtLeast(1)
|
||||
}
|
||||
|
||||
fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(id)
|
||||
buffer.writeUtf(name)
|
||||
buffer.writeCollection(spawns) { _, it -> it.encode(buffer) }
|
||||
}
|
||||
|
||||
open fun decode(buffer: RegistryFriendlyByteBuf, buckets: List<SpawnBucket>) {
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
id = buffer.readResourceLocation()
|
||||
name = buffer.readUtf()
|
||||
spawns = buffer.readList { HabitatSpawn().apply { decode(buffer) } }
|
||||
}
|
||||
}
|
||||
@@ -12,16 +12,13 @@ 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.api.spawning.IntRanges
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.TimeRange
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePositionType
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.util.adapters.HabitatPoolAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IntRangeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IntRangesAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.RegisteredSpawnablePositionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.SpawnBucketAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.SpeciesAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.pokemonPropertiesShortAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
@@ -36,18 +33,16 @@ import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.server.packs.PackType
|
||||
import net.minecraft.world.level.storage.LevelResource
|
||||
|
||||
object HabitatPools : JsonDataRegistry<HabitatPool<*>> {
|
||||
object HabitatPools : JsonDataRegistry<HabitatPool> {
|
||||
override val id = cobblemonResource("habitat_pools")
|
||||
override val type = PackType.SERVER_DATA
|
||||
override val observable = SimpleObservable<HabitatPools>()
|
||||
override val typeToken: TypeToken<HabitatPool<*>> = TypeToken.get(HabitatPool::class.java)
|
||||
override val typeToken: TypeToken<HabitatPool> = TypeToken.get(HabitatPool::class.java)
|
||||
override val resourcePath = "habitat_pools"
|
||||
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
|
||||
.registerTypeAdapter(HabitatPool::class.java, HabitatPoolAdapter)
|
||||
.registerTypeAdapter(SpawnablePositionType::class.java, RegisteredSpawnablePositionAdapter)
|
||||
.registerTypeAdapter(SpawnBucket::class.java, SpawnBucketAdapter)
|
||||
.registerTypeAdapter(Species::class.java, SpeciesAdapter)
|
||||
.registerTypeAdapter(IntRange::class.java, IntRangeAdapter)
|
||||
.registerTypeAdapter(TimeRange::class.java, TimeRange.adapter)
|
||||
@@ -56,10 +51,10 @@ object HabitatPools : JsonDataRegistry<HabitatPool<*>> {
|
||||
.setPrettyPrinting()
|
||||
.create()
|
||||
|
||||
private val datapacked = mutableMapOf<ResourceLocation, HabitatPool<*>>()
|
||||
private val worldSaved = mutableMapOf<ResourceLocation, HabitatPool<*>>()
|
||||
private val datapacked = mutableMapOf<ResourceLocation, HabitatPool>()
|
||||
private val worldSaved = mutableMapOf<ResourceLocation, HabitatPool>()
|
||||
|
||||
val habitatPoolsById = mutableMapOf<ResourceLocation, HabitatPool<*>>()
|
||||
val habitatPoolsById = mutableMapOf<ResourceLocation, HabitatPool>()
|
||||
|
||||
private lateinit var worldSavedPoolsFolder: File
|
||||
|
||||
@@ -73,7 +68,7 @@ object HabitatPools : JsonDataRegistry<HabitatPool<*>> {
|
||||
|
||||
worldSavedPoolsFolder.listFiles { it.endsWith(".json") }.forEach {
|
||||
val identifier = ResourceLocation.parse(it.nameWithoutExtension)
|
||||
val habitat = gson.fromJson<HabitatPool<*>>(it.reader())
|
||||
val habitat = gson.fromJson<HabitatPool>(it.reader())
|
||||
habitat.id = identifier
|
||||
habitat.validate()
|
||||
habitat.editable = true
|
||||
@@ -82,7 +77,7 @@ object HabitatPools : JsonDataRegistry<HabitatPool<*>> {
|
||||
setupHabitatPoolsById()
|
||||
}
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, HabitatPool<*>>) {
|
||||
override fun reload(data: Map<ResourceLocation, HabitatPool>) {
|
||||
datapacked.clear()
|
||||
datapacked.putAll(data)
|
||||
data.entries.forEach { (identifier, habitat) ->
|
||||
|
||||
@@ -10,9 +10,7 @@ package com.cobblemon.mod.common.api.habitats
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.spawning.BestSpawner
|
||||
import com.cobblemon.mod.common.api.spawning.IntRanges
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.TimeRange
|
||||
import com.cobblemon.mod.common.api.spawning.condition.AppendageCondition
|
||||
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
|
||||
@@ -30,9 +28,7 @@ import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
/**
|
||||
* A kind of simplified spawn definition for the purposes of spawning from [HabitatBlockEntity] instances. This is a
|
||||
* very shallow class tree, with [ActivatedHabitatSpawn] being a trivial subclass but the other subclass being
|
||||
* [NaturalHabitatSpawn] which introduces the need to supply a spawn bucket.
|
||||
* A kind of simplified spawn definition for the purposes of spawning from [HabitatBlockEntity] instances.
|
||||
*
|
||||
* These have only a small subset of the properties that a regular [PokemonSpawnDetail] would have to align with the
|
||||
* fact that these are configured from a simple GUI. There are limits to how many properties and conditions could be
|
||||
@@ -46,11 +42,13 @@ import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
* @author Hiroku
|
||||
* @since February 13th, 2026
|
||||
*/
|
||||
sealed class HabitatSpawn {
|
||||
class HabitatSpawn {
|
||||
/** The species that will be spawned. */
|
||||
lateinit var species: Species
|
||||
/** The kind of position the Pokémon will spawn in. Things like "grounded", "seafloor", "fishing". */
|
||||
lateinit var spawnablePositionType: String
|
||||
/** The bucket to spawn from. */
|
||||
var bucket: String = "common"
|
||||
|
||||
/** Selection weight. */
|
||||
var weight: Float = 1F
|
||||
@@ -77,6 +75,7 @@ sealed class HabitatSpawn {
|
||||
timeRange?.let { nbt.putString(DataKeys.HABITAT_POOL_SPAWN_TIMES, TimeRange.adapter.serialize(it)) }
|
||||
minLight?.let { nbt.putInt(DataKeys.HABITAT_POOL_SPAWN_MIN_LIGHT, it) }
|
||||
maxLight?.let { nbt.putInt(DataKeys.HABITAT_POOL_SPAWN_MAX_LIGHT, it) }
|
||||
nbt.putString(DataKeys.HABITAT_POOL_SPAWN_BUCKET, bucket)
|
||||
}
|
||||
|
||||
open fun readFromNBT(nbt: CompoundTag) {
|
||||
@@ -89,6 +88,7 @@ sealed class HabitatSpawn {
|
||||
timeRange = if (nbt.contains(DataKeys.HABITAT_POOL_SPAWN_TIMES)) TimeRange.adapter.deserialize(nbt.getString(DataKeys.HABITAT_POOL_SPAWN_TIMES)) else null
|
||||
minLight = if (nbt.contains(DataKeys.HABITAT_POOL_SPAWN_MIN_LIGHT)) nbt.getInt(DataKeys.HABITAT_POOL_SPAWN_MIN_LIGHT) else null
|
||||
maxLight = if (nbt.contains(DataKeys.HABITAT_POOL_SPAWN_MAX_LIGHT)) nbt.getInt(DataKeys.HABITAT_POOL_SPAWN_MAX_LIGHT) else null
|
||||
bucket = if (nbt.contains(DataKeys.HABITAT_POOL_SPAWN_BUCKET)) nbt.getString(DataKeys.HABITAT_POOL_SPAWN_BUCKET) else "common"
|
||||
}
|
||||
|
||||
open fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
@@ -101,12 +101,10 @@ sealed class HabitatSpawn {
|
||||
buffer.writeNullable(timeRange) { _, value -> buffer.writeUtf(TimeRange.adapter.serialize(value)) }
|
||||
buffer.writeNullable(minLight) { _, value -> buffer.writeInt(value) }
|
||||
buffer.writeNullable(maxLight) { _, value -> buffer.writeInt(value) }
|
||||
buffer.writeUtf(bucket)
|
||||
}
|
||||
|
||||
open fun decode(
|
||||
buffer: RegistryFriendlyByteBuf,
|
||||
buckets: List<SpawnBucket>
|
||||
) {
|
||||
open fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
species = PokemonSpecies.getByIdentifier(buffer.readResourceLocation())!!
|
||||
spawnablePositionType = buffer.readUtf()
|
||||
weight = buffer.readFloat()
|
||||
@@ -116,6 +114,7 @@ sealed class HabitatSpawn {
|
||||
timeRange = buffer.readNullable { _ -> TimeRange.adapter.deserialize(buffer.readUtf()) }
|
||||
minLight = buffer.readNullable { _ -> buffer.readInt() }
|
||||
maxLight = buffer.readNullable { _ -> buffer.readInt() }
|
||||
bucket = buffer.readUtf()
|
||||
}
|
||||
|
||||
/** Creates the [PokemonSpawnDetail] that will be used in the spawner. This is done per habitat block. */
|
||||
@@ -138,7 +137,7 @@ sealed class HabitatSpawn {
|
||||
spawnDetail.apply {
|
||||
this.id = "habitat_${species.resourceIdentifier}"
|
||||
this.pokemon = properties
|
||||
this.bucket = BestSpawner.config.buckets.first { it.weight > 0 }
|
||||
this.bucket = this@HabitatSpawn.bucket
|
||||
this.weight = this@HabitatSpawn.weight
|
||||
this.levelRange = levelRange
|
||||
this.conditions = mutableListOf(condition)
|
||||
|
||||
@@ -1,37 +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.api.habitats
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
/**
|
||||
* A [HabitatPool] of [NaturalHabitatSpawn]s. Mainly just to help with deserialization and ensuring
|
||||
* a single type for everything that's applied to a habitat block.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since February 13th, 2026
|
||||
*/
|
||||
class NaturalHabitatPool : HabitatPool<NaturalHabitatSpawn>() {
|
||||
override val type: ResourceLocation = NaturalHabitatSpawn.TYPE
|
||||
override var spawns: List<NaturalHabitatSpawn> = listOf()
|
||||
|
||||
companion object {
|
||||
fun default() = NaturalHabitatPool().apply {
|
||||
id = ResourceLocation("cobblemon", "custom__default_natural_pool")
|
||||
name = "Custom"
|
||||
}
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf, buckets: List<SpawnBucket>) {
|
||||
super.decode(buffer, buckets)
|
||||
spawns = buffer.readList { NaturalHabitatSpawn().apply { decode(buffer, buckets) } }
|
||||
}
|
||||
}
|
||||
@@ -1,63 +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.api.habitats
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail
|
||||
import com.cobblemon.mod.common.block.habitat.HabitatBlockEntity
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
/**
|
||||
* A type of [HabitatSpawn] that spawns Pokémon as part of natural world spawning, and therefore
|
||||
* needs to indicate the [SpawnBucket] it will be part of.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since February 13th, 2026
|
||||
*/
|
||||
class NaturalHabitatSpawn : HabitatSpawn() {
|
||||
companion object {
|
||||
val TYPE = cobblemonResource("natural")
|
||||
}
|
||||
|
||||
lateinit var bucket: SpawnBucket
|
||||
|
||||
override fun createSpawnDetail(habitatBlockEntity: HabitatBlockEntity): PokemonSpawnDetail? {
|
||||
val spawnDetail = super.createSpawnDetail(habitatBlockEntity)
|
||||
spawnDetail?.bucket = bucket
|
||||
return spawnDetail
|
||||
}
|
||||
|
||||
override fun writeToNBT(nbt: CompoundTag) {
|
||||
super.writeToNBT(nbt)
|
||||
nbt.putString(DataKeys.HABITAT_POOL_SPAWN_BUCKET, bucket.name)
|
||||
}
|
||||
|
||||
override fun readFromNBT(nbt: CompoundTag) {
|
||||
super.readFromNBT(nbt)
|
||||
bucket = Cobblemon.bestSpawner.config.buckets.first { it.name == nbt.getString(DataKeys.HABITAT_POOL_SPAWN_BUCKET) }
|
||||
}
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
super.encode(buffer)
|
||||
buffer.writeUtf(bucket.name)
|
||||
}
|
||||
|
||||
override fun decode(
|
||||
buffer: RegistryFriendlyByteBuf,
|
||||
buckets: List<SpawnBucket>
|
||||
) {
|
||||
super.decode(buffer, buckets)
|
||||
val bucketName = buffer.readUtf()
|
||||
bucket = buckets.first { it.name == bucketName }
|
||||
}
|
||||
}
|
||||
+1
-11
@@ -8,9 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.habitats.dto
|
||||
|
||||
import com.cobblemon.mod.common.api.habitats.ActivatedHabitatPool
|
||||
import com.cobblemon.mod.common.api.habitats.spawningstyle.ActivatedHabitatSpawning
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
class ActivatedHabitatSettingsDTO() {
|
||||
@@ -20,7 +18,6 @@ class ActivatedHabitatSettingsDTO() {
|
||||
var spawnRange = 16
|
||||
var maxSpawns = -1
|
||||
var maxSpawnsPerActivation = 1
|
||||
var habitatPool: HabitatPoolSettingsDTO = HabitatPoolSettingsDTO(ActivatedHabitatPool.default())
|
||||
|
||||
constructor(activatedHabitatSpawning: ActivatedHabitatSpawning): this() {
|
||||
this.chance = activatedHabitatSpawning.chance
|
||||
@@ -29,7 +26,6 @@ class ActivatedHabitatSettingsDTO() {
|
||||
this.spawnRange = activatedHabitatSpawning.spawnRange
|
||||
this.maxSpawns = activatedHabitatSpawning.maxSpawns
|
||||
this.maxSpawnsPerActivation = activatedHabitatSpawning.maxSpawnsPerActivation
|
||||
this.habitatPool = HabitatPoolSettingsDTO(activatedHabitatSpawning.pool)
|
||||
}
|
||||
|
||||
fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
@@ -39,20 +35,14 @@ class ActivatedHabitatSettingsDTO() {
|
||||
buffer.writeInt(spawnRange)
|
||||
buffer.writeInt(maxSpawns)
|
||||
buffer.writeInt(maxSpawnsPerActivation)
|
||||
habitatPool.encode(buffer)
|
||||
}
|
||||
|
||||
fun decode(
|
||||
buffer: RegistryFriendlyByteBuf,
|
||||
buckets: List<SpawnBucket>
|
||||
) {
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
this.chance = buffer.readFloat()
|
||||
this.trigger = buffer.readEnum(ActivatedHabitatSpawning.Trigger::class.java)
|
||||
this.cancelledNaturalSpawningRange = buffer.readInt()
|
||||
this.spawnRange = buffer.readInt()
|
||||
this.maxSpawns = buffer.readInt()
|
||||
this.maxSpawnsPerActivation = buffer.readInt()
|
||||
this.habitatPool = HabitatPoolSettingsDTO()
|
||||
habitatPool.decode(buffer, buckets)
|
||||
}
|
||||
}
|
||||
+10
-36
@@ -9,30 +9,23 @@
|
||||
package com.cobblemon.mod.common.api.habitats.dto
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.habitats.ActivatedHabitatPool
|
||||
import com.cobblemon.mod.common.api.habitats.ActivatedHabitatSpawn
|
||||
import com.cobblemon.mod.common.api.habitats.HabitatPool
|
||||
import com.cobblemon.mod.common.api.habitats.HabitatPools
|
||||
import com.cobblemon.mod.common.api.habitats.HabitatSpawn
|
||||
import com.cobblemon.mod.common.api.habitats.NaturalHabitatPool
|
||||
import com.cobblemon.mod.common.api.habitats.NaturalHabitatSpawn
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
class HabitatPoolSettingsDTO() {
|
||||
lateinit var id: ResourceLocation
|
||||
var isReference = false
|
||||
var isActivated = false
|
||||
|
||||
// Below properties are only there when it's not a reference, otherwise the handler will have to look them up from the id
|
||||
var name: String? = null
|
||||
var spawns: MutableList<HabitatSpawn>? = null
|
||||
|
||||
constructor(habitatPool: HabitatPool<*>): this() {
|
||||
constructor(habitatPool: HabitatPool): this() {
|
||||
this.id = habitatPool.id
|
||||
this.isReference = !id.path.startsWith("custom__")
|
||||
this.isActivated = habitatPool is ActivatedHabitatPool
|
||||
if (!this.isReference) {
|
||||
this.name = habitatPool.name
|
||||
this.spawns = habitatPool.spawns.toMutableList()
|
||||
@@ -42,7 +35,6 @@ class HabitatPoolSettingsDTO() {
|
||||
fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(id)
|
||||
buffer.writeBoolean(isReference)
|
||||
buffer.writeBoolean(isActivated)
|
||||
if (!isReference) {
|
||||
buffer.writeUtf(name!!)
|
||||
buffer.writeCollection(spawns!!) { _, spawn ->
|
||||
@@ -52,50 +44,32 @@ class HabitatPoolSettingsDTO() {
|
||||
}
|
||||
|
||||
fun decode(
|
||||
buffer: RegistryFriendlyByteBuf,
|
||||
buckets: List<SpawnBucket>
|
||||
buffer: RegistryFriendlyByteBuf
|
||||
) {
|
||||
this.id = buffer.readResourceLocation()
|
||||
this.isReference = buffer.readBoolean()
|
||||
this.isActivated = buffer.readBoolean()
|
||||
if (!isReference) {
|
||||
this.name = buffer.readUtf()
|
||||
this.spawns = buffer.readList {
|
||||
val spawn = if (isActivated) {
|
||||
ActivatedHabitatSpawn()
|
||||
} else {
|
||||
NaturalHabitatSpawn()
|
||||
}
|
||||
spawn.decode(buffer, buckets)
|
||||
val spawn = HabitatSpawn()
|
||||
spawn.decode(buffer)
|
||||
spawn
|
||||
}.toMutableList()
|
||||
}
|
||||
}
|
||||
|
||||
fun toHabitatPool(): HabitatPool<*>? {
|
||||
fun toHabitatPool(): HabitatPool? {
|
||||
if (isReference) {
|
||||
val pool = HabitatPools.habitatPoolsById[id]
|
||||
if (pool == null) {
|
||||
Cobblemon.LOGGER.error("Could not find habitat pool with id $id")
|
||||
} else if (pool is ActivatedHabitatPool && !isActivated) {
|
||||
Cobblemon.LOGGER.error("Pool with id $id is an activated habitat pool but was deserialized as a natural pool")
|
||||
} else if (pool !is ActivatedHabitatPool && isActivated) {
|
||||
Cobblemon.LOGGER.error("Pool with id $id is a natural habitat pool but was deserialized as an activated pool")
|
||||
}
|
||||
return pool
|
||||
}
|
||||
return if (isActivated) {
|
||||
val pool = ActivatedHabitatPool()
|
||||
pool.id = id
|
||||
pool.name = name!!
|
||||
pool.spawns = spawns!!.map { it as ActivatedHabitatSpawn }
|
||||
pool
|
||||
} else {
|
||||
val pool = NaturalHabitatPool()
|
||||
pool.id = id
|
||||
pool.name = name!!
|
||||
pool.spawns = spawns!!.map { it as NaturalHabitatSpawn }
|
||||
pool
|
||||
}
|
||||
val pool = HabitatPool()
|
||||
pool.id = id
|
||||
pool.name = name!!
|
||||
pool.spawns = spawns!!
|
||||
return pool
|
||||
}
|
||||
}
|
||||
+9
-11
@@ -9,29 +9,29 @@
|
||||
package com.cobblemon.mod.common.api.habitats.dto
|
||||
|
||||
import com.cobblemon.mod.common.api.habitats.HabitatPhaseOrder
|
||||
import com.cobblemon.mod.common.api.habitats.HabitatPool
|
||||
import com.cobblemon.mod.common.api.habitats.spawningstyle.ActivatedHabitatSpawning
|
||||
import com.cobblemon.mod.common.api.habitats.spawningstyle.NaturalHabitatSpawning
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.block.habitat.HabitatBlockEntity
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
class HabitatSettingsDTO() {
|
||||
var numberOfPhases = 1
|
||||
var phaseOrder = HabitatPhaseOrder.SIMPLE
|
||||
lateinit var levelRange: IntRange
|
||||
var modifiers: String = ""
|
||||
lateinit var mimicId: ResourceLocation
|
||||
var isActivatedSpawning = false
|
||||
var pool: HabitatPoolSettingsDTO = HabitatPoolSettingsDTO(HabitatPool.default())
|
||||
var activatedSettings: ActivatedHabitatSettingsDTO? = null
|
||||
var naturalSettings: NaturalHabitatSettingsDTO? = null
|
||||
|
||||
constructor(habitatBlockEntity: HabitatBlockEntity) : this() {
|
||||
this.numberOfPhases = habitatBlockEntity.numberOfPhases
|
||||
this.phaseOrder = habitatBlockEntity.phaseOrder
|
||||
this.levelRange = habitatBlockEntity.levelRange
|
||||
this.modifiers = habitatBlockEntity.modifiers.asString()
|
||||
this.mimicId = habitatBlockEntity.mimicId
|
||||
this.pool = HabitatPoolSettingsDTO(habitatBlockEntity.pool)
|
||||
val style = habitatBlockEntity.spawningStyle
|
||||
if (style is ActivatedHabitatSpawning) {
|
||||
this.isActivatedSpawning = true
|
||||
@@ -42,12 +42,12 @@ class HabitatSettingsDTO() {
|
||||
}
|
||||
|
||||
fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeInt(numberOfPhases)
|
||||
buffer.writeEnum(phaseOrder)
|
||||
buffer.writeInt(levelRange.first)
|
||||
buffer.writeInt(levelRange.last)
|
||||
buffer.writeUtf(modifiers)
|
||||
buffer.writeResourceLocation(mimicId)
|
||||
pool.encode(buffer)
|
||||
buffer.writeBoolean(isActivatedSpawning)
|
||||
if (isActivatedSpawning) {
|
||||
activatedSettings?.encode(buffer)
|
||||
@@ -56,27 +56,25 @@ class HabitatSettingsDTO() {
|
||||
}
|
||||
}
|
||||
|
||||
fun decode(
|
||||
buffer: RegistryFriendlyByteBuf,
|
||||
buckets: List<SpawnBucket>
|
||||
) {
|
||||
this.numberOfPhases = buffer.readInt()
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
this.phaseOrder = buffer.readEnum(HabitatPhaseOrder::class.java)
|
||||
val levelRangeStart = buffer.readInt()
|
||||
val levelRangeEnd = buffer.readInt()
|
||||
this.levelRange = levelRangeStart..levelRangeEnd
|
||||
this.modifiers = buffer.readUtf()
|
||||
this.mimicId = buffer.readResourceLocation()
|
||||
this.pool = HabitatPoolSettingsDTO()
|
||||
this.pool.decode(buffer)
|
||||
if (buffer.readBoolean()) {
|
||||
this.isActivatedSpawning = true
|
||||
this.naturalSettings = null
|
||||
val activatedSettings = ActivatedHabitatSettingsDTO()
|
||||
activatedSettings.decode(buffer, buckets)
|
||||
activatedSettings.decode(buffer)
|
||||
this.activatedSettings = activatedSettings
|
||||
} else {
|
||||
this.activatedSettings = null
|
||||
val naturalSettings = NaturalHabitatSettingsDTO()
|
||||
naturalSettings.decode(buffer, buckets)
|
||||
naturalSettings.decode(buffer)
|
||||
this.naturalSettings = naturalSettings
|
||||
}
|
||||
}
|
||||
|
||||
+1
-11
@@ -8,35 +8,25 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.habitats.dto
|
||||
|
||||
import com.cobblemon.mod.common.api.habitats.NaturalHabitatPool
|
||||
import com.cobblemon.mod.common.api.habitats.spawningstyle.NaturalHabitatSpawning
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
class NaturalHabitatSettingsDTO() {
|
||||
var replaceSpawns = false
|
||||
var rangeOfInfluence = 16
|
||||
var habitatPool: HabitatPoolSettingsDTO = HabitatPoolSettingsDTO(NaturalHabitatPool.default())
|
||||
|
||||
constructor(naturalHabitatSpawning: NaturalHabitatSpawning): this() {
|
||||
this.replaceSpawns = naturalHabitatSpawning.replaceSpawns
|
||||
this.rangeOfInfluence = naturalHabitatSpawning.rangeOfInfluence
|
||||
this.habitatPool = HabitatPoolSettingsDTO(naturalHabitatSpawning.pool)
|
||||
}
|
||||
|
||||
fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeBoolean(replaceSpawns)
|
||||
buffer.writeInt(rangeOfInfluence)
|
||||
habitatPool.encode(buffer)
|
||||
}
|
||||
|
||||
fun decode(
|
||||
buffer: RegistryFriendlyByteBuf,
|
||||
buckets: List<SpawnBucket>
|
||||
) {
|
||||
fun decode(buffer: RegistryFriendlyByteBuf, ) {
|
||||
this.replaceSpawns = buffer.readBoolean()
|
||||
this.rangeOfInfluence = buffer.readInt()
|
||||
this.habitatPool = HabitatPoolSettingsDTO()
|
||||
habitatPool.decode(buffer, buckets)
|
||||
}
|
||||
}
|
||||
+12
-23
@@ -8,17 +8,16 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.habitats.spawningstyle
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.habitats.HabitatSpawnActivatedEvent
|
||||
import com.cobblemon.mod.common.api.habitats.ActivatedHabitatPool
|
||||
import com.cobblemon.mod.common.api.habitats.ActivatedHabitatSpawn
|
||||
import com.cobblemon.mod.common.api.habitats.ActivatedHabitatSpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnCause
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.FixedAreaSpawner
|
||||
import com.cobblemon.mod.common.block.habitat.HabitatBlockEntity
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
@@ -27,7 +26,7 @@ import net.minecraft.server.level.ServerLevel
|
||||
* A habitat spawning style defined by being triggered by something. The activation trigger, [trigger], is either
|
||||
* a redstone pulse, every tick, or every random tick.
|
||||
*
|
||||
* The spawn details are generated from the [pool] every time there is some change to the habitat block's settings,
|
||||
* The spawn details are generated from the pool every time there is some change to the habitat block's settings,
|
||||
* then those spawn details are used for spawning Pokémon when the habitat block is triggered.
|
||||
*
|
||||
* The [chance] property is applied after the trigger logic so that not every activation necessarily results in a spawn
|
||||
@@ -37,6 +36,10 @@ import net.minecraft.server.level.ServerLevel
|
||||
* @since February 14th, 2026
|
||||
*/
|
||||
class ActivatedHabitatSpawning(val habitatBlockEntity: HabitatBlockEntity) : HabitatSpawningStyle {
|
||||
companion object {
|
||||
val TYPE = cobblemonResource("activated")
|
||||
}
|
||||
|
||||
enum class Trigger {
|
||||
/** Requires a redstone pulse. */
|
||||
REDSTONE,
|
||||
@@ -46,7 +49,8 @@ class ActivatedHabitatSpawning(val habitatBlockEntity: HabitatBlockEntity) : Hab
|
||||
RANDOM_TICK
|
||||
}
|
||||
|
||||
override val type = ActivatedHabitatSpawn.TYPE
|
||||
@Transient
|
||||
override val type = TYPE
|
||||
|
||||
/** The chance that an activation by the [trigger] will result in a spawn attempt. The spawn attempt may still fail. */
|
||||
var chance = 1F
|
||||
@@ -60,11 +64,7 @@ class ActivatedHabitatSpawning(val habitatBlockEntity: HabitatBlockEntity) : Hab
|
||||
var maxSpawns = -1
|
||||
/** The maximum number of Pokémon that can spawn in a single activation. This will still be capped by [maxSpawns]. */
|
||||
var maxSpawnsPerActivation = 1
|
||||
/** The pool of spawns to choose from. */
|
||||
var pool: ActivatedHabitatPool = ActivatedHabitatPool.default()
|
||||
|
||||
// This is cached here so that it doesn't have to be regenerated every time the block is triggered, updated when settings change.
|
||||
var spawnDetails: List<SpawnDetail> = listOf()
|
||||
lateinit var spawner: FixedAreaSpawner
|
||||
|
||||
override fun writeToNBT(nbt: CompoundTag) {
|
||||
@@ -75,10 +75,6 @@ class ActivatedHabitatSpawning(val habitatBlockEntity: HabitatBlockEntity) : Hab
|
||||
nbt.putInt(DataKeys.HABITAT_ACTIVATED_SPAWN_RANGE, spawnRange)
|
||||
nbt.putInt(DataKeys.HABITAT_ACTIVATED_MAX_SPAWNS, maxSpawns)
|
||||
nbt.putInt(DataKeys.HABITAT_ACTIVATED_MAX_SPAWNS_PER_ACTIVATION, maxSpawnsPerActivation)
|
||||
|
||||
val poolNBT = CompoundTag()
|
||||
writePoolToNBT(pool, poolNBT)
|
||||
nbt.put(DataKeys.HABITAT_POOL, poolNBT)
|
||||
}
|
||||
|
||||
override fun readFromNBT(nbt: CompoundTag) {
|
||||
@@ -88,25 +84,18 @@ class ActivatedHabitatSpawning(val habitatBlockEntity: HabitatBlockEntity) : Hab
|
||||
spawnRange = nbt.getInt(DataKeys.HABITAT_ACTIVATED_SPAWN_RANGE)
|
||||
maxSpawns = nbt.getInt(DataKeys.HABITAT_ACTIVATED_MAX_SPAWNS)
|
||||
maxSpawnsPerActivation = nbt.getInt(DataKeys.HABITAT_ACTIVATED_MAX_SPAWNS_PER_ACTIVATION)
|
||||
|
||||
pool = HabitatSpawningStyle.readPoolFromNBT(
|
||||
nbt = nbt.getCompound(DataKeys.HABITAT_POOL),
|
||||
poolInitializer = ::ActivatedHabitatPool,
|
||||
spawnInitializer = ::ActivatedHabitatSpawn,
|
||||
defaultPool = ActivatedHabitatPool::default
|
||||
)
|
||||
}
|
||||
|
||||
fun generateSpawnDetails(world: ServerLevel, pos: BlockPos) {
|
||||
spawnDetails = pool.createSpawnDetails(habitatBlockEntity)
|
||||
spawner = FixedAreaSpawner(
|
||||
name = "habitat_spawner_$pos",
|
||||
world = world,
|
||||
position = pos,
|
||||
spawnPool = SpawnPool("habitat_block").also {
|
||||
it.details.addAll(spawnDetails)
|
||||
it.details.addAll(habitatBlockEntity.spawnDetails)
|
||||
it.precalculate()
|
||||
},
|
||||
buckets = Cobblemon.bestSpawner.config.activatedHabitatBuckets,
|
||||
maxPokemonPerChunk = 16F,
|
||||
verticalRadius = spawnRange,
|
||||
horizontalRadius = spawnRange
|
||||
@@ -118,7 +107,7 @@ class ActivatedHabitatSpawning(val habitatBlockEntity: HabitatBlockEntity) : Hab
|
||||
// Check if the spawn attempt should even happen based on chance.
|
||||
if (chance < 1F && world.random.nextFloat() >= chance) {
|
||||
return
|
||||
} else if (spawnDetails.isEmpty()) {
|
||||
} else if (habitatBlockEntity.spawnDetails.isEmpty()) {
|
||||
// If there are no spawn details, then there's no point in trying to spawn anything.
|
||||
return
|
||||
}
|
||||
|
||||
-51
@@ -8,15 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.habitats.spawningstyle
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.habitats.HabitatPool
|
||||
import com.cobblemon.mod.common.api.habitats.HabitatPools
|
||||
import com.cobblemon.mod.common.api.habitats.HabitatSpawn
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.nbt.Tag
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
/**
|
||||
@@ -33,47 +25,4 @@ sealed interface HabitatSpawningStyle {
|
||||
|
||||
fun writeToNBT(nbt: CompoundTag)
|
||||
fun readFromNBT(nbt: CompoundTag)
|
||||
|
||||
fun writePoolToNBT(pool: HabitatPool<*>, nbt: CompoundTag) {
|
||||
nbt.putString(DataKeys.HABITAT_POOL_ID, pool.id.toString())
|
||||
if (pool.id.path.startsWith("custom__")) {
|
||||
nbt.putString(DataKeys.HABITAT_POOL_NAME, pool.name)
|
||||
val spawnsListNBT = ListTag()
|
||||
for (spawn in pool.spawns) {
|
||||
val spawnTag = CompoundTag()
|
||||
spawn.writeToNBT(spawnTag)
|
||||
spawnsListNBT.add(spawnTag)
|
||||
}
|
||||
nbt.put(DataKeys.HABITAT_POOL_SPAWNS, spawnsListNBT)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun <T : HabitatSpawn, P : HabitatPool<T>> readPoolFromNBT(nbt: CompoundTag, poolInitializer: () -> P, spawnInitializer: () -> T, defaultPool: () -> P): P {
|
||||
var pool: P
|
||||
val poolId = nbt.getString(DataKeys.HABITAT_POOL_ID).asIdentifierDefaultingNamespace()
|
||||
if (nbt.contains(DataKeys.HABITAT_POOL_NAME)) {
|
||||
// It's one that was stored on the block
|
||||
pool = poolInitializer()
|
||||
pool.id = poolId
|
||||
pool.name = nbt.getString(DataKeys.HABITAT_POOL_NAME)
|
||||
val spawnsListNBT = nbt.getList(DataKeys.HABITAT_POOL_SPAWNS, Tag.TAG_COMPOUND.toInt())
|
||||
val spawns = mutableListOf<T>()
|
||||
spawnsListNBT.forEach { spawnTag ->
|
||||
try {
|
||||
val spawn = spawnInitializer().apply { readFromNBT(spawnTag as CompoundTag) }
|
||||
spawns.add(spawn)
|
||||
} catch (_: Exception) {
|
||||
// If there's an error reading a spawn, skip it and log the error.
|
||||
Cobblemon.LOGGER.error("Error reading activated habitat spawn from NBT for habitat block, skipping.")
|
||||
}
|
||||
}
|
||||
pool.spawns = spawns
|
||||
} else {
|
||||
pool = HabitatPools.habitatPoolsById[poolId] as? P ?: defaultPool()
|
||||
}
|
||||
|
||||
return pool
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-24
@@ -8,21 +8,18 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.habitats.spawningstyle
|
||||
|
||||
import com.cobblemon.mod.common.api.habitats.NaturalHabitatPool
|
||||
import com.cobblemon.mod.common.api.habitats.NaturalHabitatSpawn
|
||||
import com.cobblemon.mod.common.api.habitats.spawningstyle.HabitatSpawningStyle.Companion.readPoolFromNBT
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.block.habitat.HabitatBlockEntity
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
/**
|
||||
* A habitat spawning style defined by tapping into regular spawning methods. This works by adding to the spawn list
|
||||
* for spawning that's occurring nearby. When [replaceSpawns] is set to true, the original spawns will be
|
||||
* removed completely in favour of the spawns provided in this habitat's [pool].
|
||||
* removed completely in favour of the spawns provided in this habitat's pool.
|
||||
*
|
||||
* The spawn details are generated from the [pool] every time there is some change to the habitat block's settings,
|
||||
* The spawn details are generated from the pool every time there is some change to the habitat block's settings,
|
||||
* then those spawn details are used for spawning Pokémon when world spawning is occurring nearby.
|
||||
*
|
||||
* Whether or not this interactions with overworld or fishing spawns is determined by whether the habitat pool has
|
||||
@@ -32,10 +29,13 @@ import net.minecraft.resources.ResourceLocation
|
||||
* @since February 22nd, 2026
|
||||
*/
|
||||
class NaturalHabitatSpawning(val habitatBlockEntity: HabitatBlockEntity) : HabitatSpawningStyle {
|
||||
companion object {
|
||||
val TYPE = cobblemonResource("natural")
|
||||
}
|
||||
|
||||
@Transient
|
||||
override val type: ResourceLocation = NaturalHabitatSpawn.TYPE
|
||||
override val type: ResourceLocation = TYPE
|
||||
|
||||
var pool: NaturalHabitatPool = NaturalHabitatPool.default()
|
||||
var replaceSpawns = false
|
||||
var rangeOfInfluence = 16
|
||||
|
||||
@@ -43,33 +43,19 @@ class NaturalHabitatSpawning(val habitatBlockEntity: HabitatBlockEntity) : Habit
|
||||
var affectsFishing = false
|
||||
@Transient
|
||||
var affectsOverworld = false
|
||||
@Transient
|
||||
var spawnDetails: List<SpawnDetail> = listOf()
|
||||
|
||||
fun generateSpawnDetails() {
|
||||
spawnDetails = pool.createSpawnDetails(habitatBlockEntity = habitatBlockEntity)
|
||||
affectsFishing = spawnDetails.any { it.spawnablePositionType.name == "fishing" }
|
||||
affectsOverworld = spawnDetails.any { it.spawnablePositionType.name != "fishing" }
|
||||
affectsFishing = habitatBlockEntity.spawnDetails.any { it.spawnablePositionType.name == "fishing" }
|
||||
affectsOverworld = habitatBlockEntity.spawnDetails.any { it.spawnablePositionType.name != "fishing" }
|
||||
}
|
||||
|
||||
override fun writeToNBT(nbt: CompoundTag) {
|
||||
nbt.putBoolean(DataKeys.HABITAT_NATURAL_REPLACE_SPAWNS, replaceSpawns)
|
||||
nbt.putInt(DataKeys.HABITAT_NATURAL_RANGE_OF_INFLUENCE, rangeOfInfluence)
|
||||
|
||||
val poolNBT = CompoundTag()
|
||||
writePoolToNBT(pool, poolNBT)
|
||||
nbt.put(DataKeys.HABITAT_POOL, poolNBT)
|
||||
}
|
||||
|
||||
override fun readFromNBT(nbt: CompoundTag) {
|
||||
replaceSpawns = nbt.getBoolean(DataKeys.HABITAT_NATURAL_REPLACE_SPAWNS)
|
||||
rangeOfInfluence = nbt.getInt(DataKeys.HABITAT_NATURAL_RANGE_OF_INFLUENCE)
|
||||
|
||||
pool = readPoolFromNBT(
|
||||
nbt = nbt.getCompound(DataKeys.HABITAT_POOL),
|
||||
poolInitializer = ::NaturalHabitatPool,
|
||||
spawnInitializer = ::NaturalHabitatSpawn,
|
||||
defaultPool = NaturalHabitatPool::default
|
||||
)
|
||||
}
|
||||
}
|
||||
+8
-3
@@ -51,11 +51,15 @@ data class PokemonInteractionSet(
|
||||
}
|
||||
|
||||
data class PokemonInteraction(
|
||||
val grouping: ResourceLocation,
|
||||
val requirements: List<Requirement> = listOf(),
|
||||
val effects: List<InteractionEffect> = listOf(),
|
||||
val cooldown: ExpressionLike = "0".asExpressionLike()
|
||||
) {
|
||||
// Not put as a necessary constructor parameter because then there isn't a default constructor
|
||||
// and that means Gson just gives null for everything in the constructor and falls back to the JSON
|
||||
// properties - completely ignoring the default values above.
|
||||
lateinit var grouping: ResourceLocation
|
||||
|
||||
fun encode(buffer: FriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(grouping)
|
||||
buffer.writeCollection(requirements) { it, requirement ->
|
||||
@@ -76,11 +80,12 @@ data class PokemonInteraction(
|
||||
val cooldown = buffer.readExpressionLike()
|
||||
|
||||
return PokemonInteraction(
|
||||
grouping,
|
||||
requirements,
|
||||
effects,
|
||||
cooldown,
|
||||
)
|
||||
).also {
|
||||
it.grouping = grouping
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ import net.minecraft.world.phys.AABB
|
||||
* @since July 29th, 2023
|
||||
*/
|
||||
interface PokemonSelectingItem {
|
||||
fun use(player: ServerPlayer, stack: ItemStack): InteractionResultHolder<ItemStack> {
|
||||
fun use(player: ServerPlayer, stack: ItemStack, ignoreShift: Boolean = false): InteractionResultHolder<ItemStack> {
|
||||
val range = player.entityInteractionRange()
|
||||
val entity = player.level()
|
||||
.getEntities(player, AABB.ofSize(player.position(), range, range, range))
|
||||
@@ -60,7 +60,7 @@ interface PokemonSelectingItem {
|
||||
return interactWithSpecificBattle(player, stack, battlePokemon)
|
||||
}
|
||||
} ?: run {
|
||||
if (!player.isShiftKeyDown) {
|
||||
if (ignoreShift || !player.isShiftKeyDown) {
|
||||
return if (entity != null) {
|
||||
val pokemon = entity.pokemon
|
||||
if (entity.ownerUUID == player.uuid) {
|
||||
|
||||
+20
@@ -17,6 +17,8 @@ import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonBlockEntities
|
||||
import com.cobblemon.mod.common.api.moves.Moves
|
||||
import com.cobblemon.mod.common.api.tms.TechnicalMachines
|
||||
import com.cobblemon.mod.common.api.dialogue.PlayerDialogueFaceProvider
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
@@ -44,6 +46,7 @@ import com.cobblemon.mod.common.util.party
|
||||
import com.cobblemon.mod.common.util.pc
|
||||
import com.cobblemon.mod.common.util.pokedex
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import com.cobblemon.mod.common.util.tmList
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
@@ -312,6 +315,23 @@ object PlayerMoLangFunctions : AbstractMoLangFunctionHolder<Player>() {
|
||||
}
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
map["has_tm_move_unlocked"] = put@{ params ->
|
||||
val move = Moves.getByName(params.getString(0)) ?: return@put DoubleValue.ZERO
|
||||
val tm = TechnicalMachines.moveToTM[move] ?: return@put DoubleValue.ZERO
|
||||
DoubleValue(if (player.tmList().learnedTMs.contains(tm.id)) 1.0 else 0.0)
|
||||
}
|
||||
map["unlock_tm_move"] = put@{ params ->
|
||||
val move = Moves.getByName(params.getString(0)) ?: return@put DoubleValue.ZERO
|
||||
val tm = TechnicalMachines.moveToTM[move] ?: return@put DoubleValue.ZERO
|
||||
player.tmList().syncTMFromMove(move)
|
||||
DoubleValue(if (player.tmList().learnedTMs.contains(tm.id)) 1.0 else 0.0)
|
||||
}
|
||||
map["lock_tm_move"] = put@{ params ->
|
||||
val move = Moves.getByName(params.getString(0)) ?: return@put DoubleValue.ZERO
|
||||
val tm = TechnicalMachines.moveToTM[move] ?: return@put DoubleValue.ZERO
|
||||
player.tmList().syncTMLockFromMove(move)
|
||||
DoubleValue(if (player.tmList().learnedTMs.contains(tm.id)) 0.0 else 1.0)
|
||||
}
|
||||
map["start_battle"] = put@{ params ->
|
||||
val opponentValue = params.get<MoValue>(0)
|
||||
val opponent = if (opponentValue is ObjectValue<*>) {
|
||||
|
||||
+1
-1
@@ -109,7 +109,7 @@ object PokemonMoLangFunctions : AbstractMoLangFunctionHolder<Pokemon>() {
|
||||
DoubleValue(pokemon.species.nationalPokedexNumber.toDouble())
|
||||
}
|
||||
map["types"] = {
|
||||
pokemon.form.types.map { it.toString() }.asArrayValue(::StringValue)
|
||||
pokemon.form.types.map { it.showdownId }.asArrayValue(::StringValue)
|
||||
}
|
||||
map["gender_ratio"] = {
|
||||
DoubleValue(pokemon.form.maleRatio.toDouble())
|
||||
|
||||
@@ -49,7 +49,12 @@ class FormDexRecord {
|
||||
it.genders.addAll(genders.map(Gender::valueOf))
|
||||
it.seenShinyStates.addAll(seenShinyStates)
|
||||
it.highestLevel = highestLevel
|
||||
it.knowledge = PokedexEntryProgress.valueOf(knowledge)
|
||||
it.knowledge = when (knowledge) { // The string checks are due to legacy enum names which got changes in 1.8
|
||||
"NONE" -> PokedexEntryProgress.UNREGISTERED
|
||||
"ENCOUNTERED" -> PokedexEntryProgress.SEEN
|
||||
"CAUGHT" -> PokedexEntryProgress.OWNED
|
||||
else -> PokedexEntryProgress.valueOf(knowledge)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,11 +25,4 @@ enum class PokedexEntryProgress : StringRepresentable, Comparable<PokedexEntryPr
|
||||
OWNED;
|
||||
|
||||
override fun getSerializedName() = this.name
|
||||
companion object {
|
||||
val CODEC: Codec<PokedexEntryProgress> = RecordCodecBuilder.create { instance ->
|
||||
instance.map ({
|
||||
PokedexEntryProgress.valueOf(it)
|
||||
}, PrimitiveCodec.STRING.fieldOf("name").forGetter { it.name })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-5
@@ -56,10 +56,8 @@ class AggregatePokedexDef(
|
||||
return speciesToEntry.values.toList()
|
||||
}
|
||||
}
|
||||
|
||||
override fun shouldSynchronize(other: PokedexDef) = true
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
sortOrder = buffer.readSizedInt(IntSize.U_BYTE)
|
||||
val size = buffer.readInt()
|
||||
for (i in 0 until size) {
|
||||
@@ -67,7 +65,7 @@ class AggregatePokedexDef(
|
||||
}
|
||||
}
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeSizedInt(IntSize.U_BYTE, sortOrder)
|
||||
buffer.writeInt(subDexIds.size)
|
||||
subDexIds.forEach {
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.pokedex.def
|
||||
|
||||
import com.cobblemon.mod.common.api.data.ClientDataSynchronizer
|
||||
import com.cobblemon.mod.common.api.pokedex.entry.DexEntries
|
||||
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.MapCodec
|
||||
@@ -23,7 +21,7 @@ import net.minecraft.resources.ResourceLocation
|
||||
* @since August 24, 2024
|
||||
* @author Apion
|
||||
*/
|
||||
abstract class PokedexDef: ClientDataSynchronizer<PokedexDef> {
|
||||
abstract class PokedexDef {
|
||||
//The ID used to find the codecs for this "type" of PokedexDef
|
||||
abstract val typeId: ResourceLocation
|
||||
//The ID of this dex in the Dexes registry
|
||||
|
||||
@@ -45,9 +45,7 @@ class SimplePokedexDef(
|
||||
|
||||
override fun getEntries() = entries.mapNotNull { DexEntries.entries[it] }
|
||||
|
||||
override fun shouldSynchronize(other: PokedexDef) = true
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
sortOrder = buffer.readSizedInt(IntSize.U_BYTE)
|
||||
val size = buffer.readInt()
|
||||
for (i in 0 until size) {
|
||||
@@ -55,7 +53,7 @@ class SimplePokedexDef(
|
||||
}
|
||||
}
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeSizedInt(IntSize.U_BYTE, sortOrder)
|
||||
buffer.writeInt(entries.size)
|
||||
entries.forEach {
|
||||
|
||||
+6
-4
@@ -41,16 +41,18 @@ class PokedexCategoryFilter(
|
||||
PokedexCategoryFilterType.UNDISCOVERED_TM_MOVE -> hasUndiscoveredLevelUpTM(entry)
|
||||
PokedexCategoryFilterType.RIDEABLE -> {
|
||||
val species = PokemonSpecies.getByIdentifier(entry.speciesId)
|
||||
species?.forms?.any { form -> !form.riding.behaviours.isNullOrEmpty() } == true
|
||||
&& pokedexManager.getHighestKnowledgeFor(entry) >= PokedexEntryProgress.OWNED
|
||||
// we were silly as standard forms also can be rideable and we were ingoring those
|
||||
(species?.forms.orEmpty() + listOfNotNull(species?.standardForm)).any { form -> !form.riding.behaviours.isNullOrEmpty() }
|
||||
&& (pokedexManager.getHighestKnowledgeFor(entry) >= PokedexEntryProgress.OWNED ||
|
||||
pokedexManager.getHighestKnowledgeFor(entry) >= PokedexEntryProgress.SEEN)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun hasUndiscoveredLevelUpTM(entry: PokedexEntry): Boolean {
|
||||
if (pokedexManager.getHighestKnowledgeFor(entry) != PokedexEntryProgress.OWNED) return false
|
||||
if (pokedexManager.getHighestKnowledgeFor(entry) == PokedexEntryProgress.UNREGISTERED) return false
|
||||
val species = PokemonSpecies.getByIdentifier(entry.speciesId) ?: return false
|
||||
val forms = pokedexManager.getCaughtForms(entry)
|
||||
val forms = pokedexManager.getEncounteredForms(entry)
|
||||
val formData = if (forms.isEmpty()) {
|
||||
listOf(species.standardForm)
|
||||
} else {
|
||||
|
||||
@@ -72,7 +72,7 @@ class SearchFilter(val pokedexManager: AbstractPokedexManager, val searchString:
|
||||
}
|
||||
}
|
||||
SearchByType.DROPS -> {
|
||||
if (pokedexManager.getHighestKnowledgeFor(entry) !== PokedexEntryProgress.OWNED) return false
|
||||
if (pokedexManager.getHighestKnowledgeFor(entry) == PokedexEntryProgress.UNREGISTERED) return false
|
||||
val dropsList = mutableListOf<String>()
|
||||
val formsList = if (species.forms.isEmpty()) mutableListOf(species.standardForm) else species.forms
|
||||
formsList.forEach {
|
||||
@@ -131,9 +131,7 @@ class SearchFilter(val pokedexManager: AbstractPokedexManager, val searchString:
|
||||
form.moves.tutorMoves,
|
||||
form.moves.eggMoves,
|
||||
form.moves.evolutionMoves,
|
||||
form.moves.formChangeMoves,
|
||||
form.moves.specialMoves,
|
||||
form.moves.legacyMoves
|
||||
form.moves.formChangeMoves
|
||||
)
|
||||
|
||||
for (moves in alwaysDiscovered) {
|
||||
|
||||
@@ -674,9 +674,6 @@ open class PokemonProperties {
|
||||
@JvmOverloads
|
||||
fun createEntity(world: Level, player: ServerPlayer? = null): PokemonEntity {
|
||||
val pokemon = create(player)
|
||||
if (pokemon.isAlpha) {
|
||||
pokemon.initializeMovesetWithRandomTm()
|
||||
}
|
||||
return PokemonEntity(world, pokemon).also { applyCustomProperties(it) }
|
||||
}
|
||||
|
||||
@@ -762,6 +759,7 @@ open class PokemonProperties {
|
||||
shiny?.let { json.addProperty(DataKeys.POKEMON_SHINY, it) }
|
||||
gender?.let { json.addProperty(DataKeys.POKEMON_GENDER, it.name) }
|
||||
species?.let { json.addProperty(DataKeys.POKEMON_SPECIES_TEXT, it) }
|
||||
nickname?.let { json.addProperty(DataKeys.POKEMON_NICKNAME, it.string) }
|
||||
form?.let { json.addProperty(DataKeys.POKEMON_FORM_ID, it) }
|
||||
friendship?.let { json.addProperty(DataKeys.POKEMON_FRIENDSHIP, it) }
|
||||
fullness?.let { json.addProperty(DataKeys.POKEMON_FULLNESS, it) }
|
||||
@@ -798,6 +796,7 @@ open class PokemonProperties {
|
||||
shiny = json.get(DataKeys.POKEMON_SHINY)?.asBoolean
|
||||
gender = json.get(DataKeys.POKEMON_GENDER)?.asString?.let { Gender.valueOf(it) }
|
||||
species = json.get(DataKeys.POKEMON_SPECIES_TEXT)?.asString
|
||||
nickname = json.get(DataKeys.POKEMON_NICKNAME)?.asString?.let(Component::literal)
|
||||
form = json.get(DataKeys.POKEMON_FORM_ID)?.asString
|
||||
friendship = json.get(DataKeys.POKEMON_FRIENDSHIP)?.asInt
|
||||
fullness = json.get(DataKeys.POKEMON_FULLNESS)?.asInt
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.moves
|
||||
|
||||
import com.cobblemon.mod.common.api.data.ClientDataSynchronizer
|
||||
import com.cobblemon.mod.common.api.moves.MoveTemplate
|
||||
import com.cobblemon.mod.common.api.moves.Moves
|
||||
import com.cobblemon.mod.common.net.IntSize
|
||||
@@ -18,7 +17,7 @@ import com.cobblemon.mod.common.util.writeSizedInt
|
||||
import com.google.gson.JsonElement
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
open class Learnset : ClientDataSynchronizer<Learnset> {
|
||||
open class Learnset {
|
||||
class Interpreter(val loadMove: (JsonElement, Learnset) -> Boolean) {
|
||||
companion object {
|
||||
fun parseFromPrefixIntoList(prefix: String, list: (Learnset) -> MutableList<MoveTemplate>): Interpreter {
|
||||
@@ -111,9 +110,9 @@ open class Learnset : ClientDataSynchronizer<Learnset> {
|
||||
}
|
||||
|
||||
// We only sync level up moves atm
|
||||
override fun shouldSynchronize(other: Learnset) = other.levelUpMoves != this.levelUpMoves
|
||||
fun shouldSynchronize(other: Learnset) = other.levelUpMoves != this.levelUpMoves
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
this.levelUpMoves.clear()
|
||||
repeat(times = buffer.readSizedInt(IntSize.U_BYTE)) {
|
||||
val level = buffer.readSizedInt(IntSize.U_SHORT)
|
||||
@@ -125,7 +124,7 @@ open class Learnset : ClientDataSynchronizer<Learnset> {
|
||||
}
|
||||
}
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeSizedInt(IntSize.U_BYTE, levelUpMoves.size)
|
||||
for ((level, moves) in levelUpMoves) {
|
||||
buffer.writeSizedInt(IntSize.U_SHORT, level)
|
||||
|
||||
@@ -22,8 +22,8 @@ import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
*/
|
||||
data class Seat(
|
||||
val locator: String = "",
|
||||
val condition: Expression?,
|
||||
val poseAnimations: MutableList<SeatPoseAnimations>?,
|
||||
val condition: Expression? = null,
|
||||
val poseAnimations: MutableList<SeatPoseAnimations>? = null,
|
||||
val handsBusy: Boolean = false,
|
||||
) : Encodable {
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.snowstorm
|
||||
|
||||
import com.cobblemon.mod.common.client.render.shader.CobblemonShaders
|
||||
import com.mojang.blaze3d.platform.GlStateManager
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import com.mojang.blaze3d.vertex.BufferBuilder
|
||||
@@ -16,6 +15,7 @@ import com.mojang.blaze3d.vertex.DefaultVertexFormat
|
||||
import com.mojang.blaze3d.vertex.Tesselator
|
||||
import com.mojang.blaze3d.vertex.VertexFormat
|
||||
import net.minecraft.client.particle.ParticleRenderType
|
||||
import net.minecraft.client.renderer.GameRenderer
|
||||
import net.minecraft.client.renderer.texture.TextureAtlas
|
||||
import net.minecraft.client.renderer.texture.TextureManager
|
||||
|
||||
@@ -23,8 +23,9 @@ object ParticleMaterials {
|
||||
val ALPHA = object : ParticleRenderType {
|
||||
override fun begin(tessellator: Tesselator, textureManager: TextureManager): BufferBuilder {
|
||||
RenderSystem.enableBlend()
|
||||
RenderSystem.enableCull()
|
||||
RenderSystem.depthMask(true)
|
||||
RenderSystem.setShader { CobblemonShaders.PARTICLE_CUTOUT }
|
||||
RenderSystem.setShader { GameRenderer.getParticleShader() }
|
||||
RenderSystem.setShaderTexture(0, TextureAtlas.LOCATION_PARTICLES)
|
||||
RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA)
|
||||
return tessellator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.PARTICLE)
|
||||
@@ -36,10 +37,11 @@ object ParticleMaterials {
|
||||
val ADD = object : ParticleRenderType {
|
||||
override fun begin(tessellator: Tesselator, textureManager: TextureManager): BufferBuilder {
|
||||
RenderSystem.enableBlend()
|
||||
RenderSystem.disableCull()
|
||||
RenderSystem.depthMask(true)
|
||||
RenderSystem.setShader { CobblemonShaders.PARTICLE_BLEND }
|
||||
RenderSystem.setShader { GameRenderer.getParticleShader() }
|
||||
RenderSystem.setShaderTexture(0, TextureAtlas.LOCATION_PARTICLES)
|
||||
RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA)
|
||||
RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE)
|
||||
return tessellator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.PARTICLE)
|
||||
}
|
||||
|
||||
@@ -49,10 +51,11 @@ object ParticleMaterials {
|
||||
val BLEND = object : ParticleRenderType {
|
||||
override fun begin(tessellator: Tesselator, textureManager: TextureManager): BufferBuilder {
|
||||
RenderSystem.enableBlend()
|
||||
RenderSystem.disableCull()
|
||||
RenderSystem.depthMask(true)
|
||||
RenderSystem.setShader { CobblemonShaders.PARTICLE_BLEND }
|
||||
RenderSystem.setShader { GameRenderer.getParticleShader() }
|
||||
RenderSystem.setShaderTexture(0, TextureAtlas.LOCATION_PARTICLES)
|
||||
RenderSystem.blendFunc(GlStateManager.SourceFactor.DST_COLOR, GlStateManager.DestFactor.ZERO)
|
||||
RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA)
|
||||
return tessellator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.PARTICLE)
|
||||
}
|
||||
|
||||
@@ -62,10 +65,11 @@ object ParticleMaterials {
|
||||
val OPAQUE = object : ParticleRenderType {
|
||||
override fun begin(tessellator: Tesselator, textureManager: TextureManager): BufferBuilder {
|
||||
RenderSystem.enableBlend()
|
||||
RenderSystem.enableCull()
|
||||
RenderSystem.depthMask(true)
|
||||
RenderSystem.setShader { CobblemonShaders.PARTICLE_BLEND }
|
||||
RenderSystem.setShader { GameRenderer.getParticleShader() }
|
||||
RenderSystem.setShaderTexture(0, TextureAtlas.LOCATION_PARTICLES)
|
||||
RenderSystem.blendFunc(GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE)
|
||||
RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_COLOR, GlStateManager.DestFactor.ZERO)
|
||||
return tessellator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.PARTICLE)
|
||||
}
|
||||
|
||||
|
||||
@@ -18,12 +18,12 @@ import com.cobblemon.mod.common.api.spawning.condition.SeafloorSpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.condition.SubmergedSpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.condition.SurfaceSpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.detail.EmptySpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.detail.NPCSpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.detail.PokemonHerdSpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.influence.BucketMultiplyingInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.position.AreaSpawnablePositionResolver
|
||||
import com.cobblemon.mod.common.api.spawning.position.FishingSpawnablePosition
|
||||
@@ -121,6 +121,7 @@ object BestSpawner {
|
||||
SpawnDetail.registerSpawnType(name = PokemonSpawnDetail.TYPE, PokemonSpawnDetail::class.java)
|
||||
SpawnDetail.registerSpawnType(name = NPCSpawnDetail.TYPE, NPCSpawnDetail::class.java)
|
||||
SpawnDetail.registerSpawnType(name = PokemonHerdSpawnDetail.TYPE, PokemonHerdSpawnDetail::class.java)
|
||||
SpawnDetail.registerSpawnType(name = EmptySpawnDetail.TYPE, EmptySpawnDetail::class.java)
|
||||
LOGGER.info("Loaded ${SpawnDetail.spawnDetailTypes.size} spawn detail types.")
|
||||
|
||||
loadConfig()
|
||||
|
||||
@@ -1,33 +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.api.spawning
|
||||
|
||||
/**
|
||||
* A spawn bucket is a simple referenceable object by spawn files. The bucket is used at the beginning of
|
||||
* the selection process to decide which set of spawns will be used for spawning on that attempt. Weights are used to
|
||||
* make entire buckets more or less likely, and then weighted selections will occur within whichever bucket
|
||||
* was chosen.
|
||||
*
|
||||
* Spawn buckets are configured in the main config.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since June 20th, 2022
|
||||
*/
|
||||
class SpawnBucket() {
|
||||
lateinit var name: String
|
||||
var weight = 0F
|
||||
|
||||
constructor(name: String, weight: Float): this() {
|
||||
this.name = name
|
||||
this.weight = weight
|
||||
}
|
||||
|
||||
override fun hashCode() = name.hashCode()
|
||||
override fun equals(other: Any?) = other is SpawnBucket && other.name == name
|
||||
}
|
||||
@@ -49,7 +49,6 @@ object SpawnDetailPresets : JsonDataRegistry<SpawnDetailPreset> {
|
||||
.setPrettyPrinting()
|
||||
.setLenient()
|
||||
.disableHtmlEscaping()
|
||||
.registerTypeAdapter(SpawnBucket::class.java, SpawnBucketAdapter)
|
||||
.registerTypeAdapter(SpawnablePositionType::class.java, RegisteredSpawnablePositionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, BiomeLikeConditionAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Block::class.java).type, BlockLikeConditionAdapter)
|
||||
|
||||
@@ -67,7 +67,6 @@ object SpawnLoader {
|
||||
.registerTypeAdapter(MoonPhaseRange::class.java, IntRangesAdapter(MoonPhaseRange.moonPhaseRanges) { MoonPhaseRange(*it) })
|
||||
.registerTypeAdapter(ItemDropMethod::class.java, ItemDropMethod.adapter)
|
||||
.registerTypeAdapter(PokemonProperties::class.java, pokemonPropertiesShortAdapter)
|
||||
.registerTypeAdapter(SpawnBucket::class.java, SpawnBucketAdapter)
|
||||
.registerTypeAdapter(CompoundTag::class.java, NbtCompoundAdapter)
|
||||
.registerTypeAdapter(IntRange::class.java, IntRangeAdapter)
|
||||
.registerTypeAdapter(PossibleHeldItem::class.java, PossibleHeldItemAdapter)
|
||||
|
||||
+13
-14
@@ -8,10 +8,9 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.condition
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
/**
|
||||
@@ -22,8 +21,8 @@ import net.minecraft.resources.ResourceLocation
|
||||
* time as sharing that value. The requirement of implementations is only to get that
|
||||
* key from both a [SpawnDetail] and a [SpawnablePosition].
|
||||
*
|
||||
* When a precalculation has been registered with a [Spawner] by adding to [Spawner.precalculators],
|
||||
* the precalculation result will need to be updated by running [Spawner.precalculate]. That
|
||||
* When a precalculation has been registered with a [SpawnPool] by adding to [SpawnPool.precalculators],
|
||||
* the precalculation result will need to be updated by running [SpawnPool.precalculate]. That
|
||||
* might take it a hot minute, but the result will be that there is an extra layer of
|
||||
* shortcutting to the matching algorithm.
|
||||
*
|
||||
@@ -34,7 +33,7 @@ interface SpawningPrecalculation<T : Any> {
|
||||
/** Retrieves the precalculation keys for the given spawn detail. */
|
||||
fun select(detail: SpawnDetail): Collection<T>
|
||||
/** Retrieves the precalculation key for the given spawnable position, if that key exists for this position. */
|
||||
fun select(bucket: SpawnBucket, spawnablePosition: SpawnablePosition): T?
|
||||
fun select(bucket: String, spawnablePosition: SpawnablePosition): T?
|
||||
|
||||
/**
|
||||
* Generates a precalculation result for the list of [SpawnDetail]s and the subsequent precalculations.
|
||||
@@ -74,7 +73,7 @@ interface SpawningPrecalculation<T : Any> {
|
||||
object RootPrecalculation : SpawningPrecalculation<Any> {
|
||||
val list = listOf(Unit)
|
||||
override fun select(detail: SpawnDetail): List<Any> = list
|
||||
override fun select(bucket: SpawnBucket, spawnablePosition: SpawnablePosition): Any = Unit
|
||||
override fun select(bucket: String, spawnablePosition: SpawnablePosition): Any = Unit
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,12 +84,12 @@ object RootPrecalculation : SpawningPrecalculation<Any> {
|
||||
*/
|
||||
object SpawnablePositionTypePrecalculation : SpawningPrecalculation<Class<out SpawnablePosition>> {
|
||||
override fun select(detail: SpawnDetail) = listOf(detail.spawnablePositionType.clazz)
|
||||
override fun select(bucket: SpawnBucket, spawnablePosition: SpawnablePosition) = spawnablePosition::class.java
|
||||
override fun select(bucket: String, spawnablePosition: SpawnablePosition) = spawnablePosition::class.java
|
||||
}
|
||||
|
||||
object BucketPrecalculation : SpawningPrecalculation<SpawnBucket> {
|
||||
object BucketPrecalculation : SpawningPrecalculation<String> {
|
||||
override fun select(detail: SpawnDetail) = listOf(detail.bucket)
|
||||
override fun select(bucket: SpawnBucket, spawnablePosition: SpawnablePosition) = bucket
|
||||
override fun select(bucket: String, spawnablePosition: SpawnablePosition) = bucket
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,7 +98,7 @@ object BucketPrecalculation : SpawningPrecalculation<SpawnBucket> {
|
||||
*/
|
||||
object BiomePrecalculation : SpawningPrecalculation<ResourceLocation> {
|
||||
override fun select(detail: SpawnDetail) = detail.validBiomes
|
||||
override fun select(bucket: SpawnBucket, spawnablePosition: SpawnablePosition) = spawnablePosition.biomeHolder.unwrapKey().map { it.location() }.orElse(null)
|
||||
override fun select(bucket: String, spawnablePosition: SpawnablePosition) = spawnablePosition.biomeHolder.unwrapKey().map { it.location() }.orElse(null)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,7 +113,7 @@ sealed class PrecalculationResult<T : Any>(
|
||||
val calculation: SpawningPrecalculation<*>
|
||||
) {
|
||||
/** Gets the list of spawn details that fit this spawnable position. */
|
||||
abstract fun retrieve(bucket: SpawnBucket, spawnablePosition: SpawnablePosition): List<SpawnDetail>
|
||||
abstract fun retrieve(bucket: String, spawnablePosition: SpawnablePosition): List<SpawnDetail>
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,7 +126,7 @@ class NestedPrecalculationResult<T : Any>(
|
||||
calculation: SpawningPrecalculation<T>,
|
||||
val mapping: Map<T, PrecalculationResult<*>> = mutableMapOf()
|
||||
) : PrecalculationResult<T>(calculation) {
|
||||
override fun retrieve(bucket: SpawnBucket, spawnablePosition: SpawnablePosition) = mapping[calculation.select(bucket, spawnablePosition)]?.retrieve(bucket, spawnablePosition) ?: emptyList()
|
||||
override fun retrieve(bucket: String, spawnablePosition: SpawnablePosition) = mapping[calculation.select(bucket, spawnablePosition)]?.retrieve(bucket, spawnablePosition) ?: emptyList()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,5 +140,5 @@ class FinalPrecalculationResult<T : Any>(
|
||||
calculation: SpawningPrecalculation<*>,
|
||||
val mapping: Map<T, List<SpawnDetail>>
|
||||
) : PrecalculationResult<T>(calculation) {
|
||||
override fun retrieve(bucket: SpawnBucket, spawnablePosition: SpawnablePosition) = mapping[calculation.select(bucket, spawnablePosition)] ?: emptyList()
|
||||
override fun retrieve(bucket: String, spawnablePosition: SpawnablePosition) = mapping[calculation.select(bucket, spawnablePosition)] ?: emptyList()
|
||||
}
|
||||
+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.spawning.detail
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
|
||||
/**
|
||||
* Does a whole lot of nothing. Spawns nothing.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since May 16th, 2026
|
||||
*/
|
||||
class EmptySpawnAction(
|
||||
spawnablePosition: SpawnablePosition,
|
||||
bucket: String,
|
||||
detail: EmptySpawnDetail
|
||||
) : SpawnAction<Unit>(spawnablePosition, bucket, detail) {
|
||||
override fun run() {}
|
||||
}
|
||||
+48
@@ -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.spawning.detail
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
import com.cobblemon.mod.common.api.spawning.selection.SpawnSelectionData
|
||||
|
||||
/**
|
||||
* A spawn detail for nothing. It is used to take a slot, like to weigh down a spawn attempt,
|
||||
* with something that ultimately doesn't spawn anything.
|
||||
*
|
||||
* The use case for this is very niche. With 1.8, the buckets that can be selected by a spawner
|
||||
* during a spawn attempt will be narrowed down to the buckets that are used by the spawn
|
||||
* pool. That means that if a bucket is never used by the pool, it will never be selected. That
|
||||
* way, a bucket won't be selected when it never had any chance of being selected. This is what
|
||||
* you would want in almost every case.
|
||||
*
|
||||
* However, in some cases you may want spawning to not spawn anything or you may want to preserve
|
||||
* the relative rarity of the other buckets, and in that case you'd put something like this in a
|
||||
* bucket so that it technically exists in the spawn pool without actually resulting in a spawned
|
||||
* entity.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since May 16th, 2026
|
||||
*/
|
||||
class EmptySpawnDetail : SpawnDetail() {
|
||||
companion object {
|
||||
val TYPE = "empty"
|
||||
}
|
||||
|
||||
override val type: String = TYPE
|
||||
|
||||
override fun createSpawnAction(
|
||||
spawnablePosition: SpawnablePosition,
|
||||
bucket: String,
|
||||
selectionData: SpawnSelectionData
|
||||
) = EmptySpawnAction(
|
||||
spawnablePosition = spawnablePosition,
|
||||
bucket = bucket,
|
||||
detail = this
|
||||
)
|
||||
}
|
||||
+1
-2
@@ -9,7 +9,6 @@
|
||||
package com.cobblemon.mod.common.api.spawning.detail
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.util.resolveInt
|
||||
@@ -20,7 +19,7 @@ import com.cobblemon.mod.common.util.resolveInt
|
||||
* @author Hiroku
|
||||
* @since October 8th, 2023
|
||||
*/
|
||||
class NPCSpawnAction(spawnablePosition: SpawnablePosition, bucket: SpawnBucket, override val detail: NPCSpawnDetail) : SingleEntitySpawnAction<NPCEntity>(spawnablePosition, bucket, detail) {
|
||||
class NPCSpawnAction(spawnablePosition: SpawnablePosition, bucket: String, override val detail: NPCSpawnDetail) : SingleEntitySpawnAction<NPCEntity>(spawnablePosition, bucket, detail) {
|
||||
override fun createEntity(): NPCEntity {
|
||||
val npc = NPCEntity(spawnablePosition.world)
|
||||
npc.npc = detail.npcClass
|
||||
|
||||
+1
-3
@@ -11,13 +11,11 @@ package com.cobblemon.mod.common.api.spawning.detail
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.npc.NPCClass
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
import com.cobblemon.mod.common.api.spawning.selection.SpawnSelectionData
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlin.math.ceil
|
||||
|
||||
/**
|
||||
* A [SpawnDetail] describing an [NPCEntity] spawn.
|
||||
@@ -51,7 +49,7 @@ class NPCSpawnDetail : SpawnDetail() {
|
||||
|
||||
override fun createSpawnAction(
|
||||
spawnablePosition: SpawnablePosition,
|
||||
bucket: SpawnBucket,
|
||||
bucket: String,
|
||||
selectionData: SpawnSelectionData
|
||||
) = NPCSpawnAction(spawnablePosition, bucket, this)
|
||||
}
|
||||
+11
-8
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.api.spawning.detail
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.api.drop.DropTable
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
import com.cobblemon.mod.common.api.spawning.selection.SpawnSelectionData
|
||||
import com.cobblemon.mod.common.util.weightedSelection
|
||||
@@ -54,8 +53,10 @@ class PokemonHerdSpawnDetail : SpawnDetail() {
|
||||
var pokemon: PokemonProperties = PokemonProperties()
|
||||
val levelRange: IntRange? = null
|
||||
var levelRangeOffset: IntRange? = null
|
||||
val herdLevelRange: IntRange? = null
|
||||
var dropTable: DropTable? = null
|
||||
var isLeader: Boolean? = null
|
||||
var isLeader: Boolean = false
|
||||
var isFollower: Boolean = true
|
||||
var weight: Float = 1F
|
||||
var maxTimes = 10
|
||||
var heldItem: ResourceLocation? = null
|
||||
@@ -83,7 +84,7 @@ class PokemonHerdSpawnDetail : SpawnDetail() {
|
||||
val herdable = getValidHerdMembers(selectionData)
|
||||
val herdCounts = getHerdMemberCounts(selectionData)
|
||||
|
||||
val leaderIsPossible = herdable.any { it.levelRange?.contains(level) != false && it.isLeader == true }
|
||||
val leaderIsPossible = herdable.any { it.herdLevelRange?.contains(level) != false && it.isLeader }
|
||||
val leaderIsSelected = herdCounts.any { it.key?.isLeader == true && it.value > 0 }
|
||||
return leaderIsPossible && !leaderIsSelected
|
||||
}
|
||||
@@ -98,14 +99,16 @@ class PokemonHerdSpawnDetail : SpawnDetail() {
|
||||
|
||||
override fun createSpawnAction(
|
||||
spawnablePosition: SpawnablePosition,
|
||||
bucket: SpawnBucket,
|
||||
bucket: String,
|
||||
selectionData: SpawnSelectionData
|
||||
): PokemonSpawnAction {
|
||||
val validHerdMembers = getValidHerdMembers(selectionData)
|
||||
var searchedForLeader = false
|
||||
val herdable = if (lacksPossibleLeader(selectionData)) {
|
||||
validHerdMembers.filter { it.isLeader == true }
|
||||
searchedForLeader = true
|
||||
validHerdMembers.filter { it.isLeader }
|
||||
} else {
|
||||
validHerdMembers
|
||||
validHerdMembers.filter { it.isFollower }
|
||||
}.weightedSelection { it.weight } ?: herdablePokemon[0]
|
||||
|
||||
val level = selectionData.context[herdLevelKey] as? Int ?: 1
|
||||
@@ -134,7 +137,7 @@ class PokemonHerdSpawnDetail : SpawnDetail() {
|
||||
heldItem = heldItem,
|
||||
levelRange = levelRange
|
||||
).also {
|
||||
if (herdable.isLeader == true) {
|
||||
if (herdable.isLeader && searchedForLeader) {
|
||||
it.labels += HERD_LEADER
|
||||
}
|
||||
}
|
||||
@@ -153,7 +156,7 @@ class PokemonHerdSpawnDetail : SpawnDetail() {
|
||||
val count = counts[herdable] ?: 0
|
||||
return@filter when {
|
||||
count >= herdable.maxTimes -> false
|
||||
herdable.levelRange != null && level !in herdable.levelRange -> false
|
||||
herdable.herdLevelRange != null && level !in herdable.herdLevelRange -> false
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.api.spawning.detail
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.drop.DropTable
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.feature.SeasonFeatureHandler
|
||||
@@ -26,7 +25,7 @@ import net.minecraft.world.item.ItemStack
|
||||
*/
|
||||
class PokemonSpawnAction(
|
||||
spawnablePosition: SpawnablePosition,
|
||||
bucket: SpawnBucket,
|
||||
bucket: String,
|
||||
override val detail: SpawnDetail,
|
||||
/**
|
||||
* The [PokemonProperties] that are about to be used. When using it, a copy will be taken.
|
||||
|
||||
+2
-2
@@ -14,7 +14,6 @@ import com.cobblemon.mod.common.api.drop.DropTable
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
import com.cobblemon.mod.common.api.spawning.selection.SpawnSelectionData
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
@@ -104,7 +103,8 @@ class PokemonSpawnDetail : SpawnDetail() {
|
||||
}
|
||||
|
||||
override fun createSpawnAction(
|
||||
spawnablePosition: SpawnablePosition, bucket: SpawnBucket,
|
||||
spawnablePosition: SpawnablePosition,
|
||||
bucket: String,
|
||||
selectionData: SpawnSelectionData
|
||||
): SingleEntitySpawnAction<PokemonEntity> {
|
||||
val levelRange = pokemon.deriveLevelRange(levelRange)
|
||||
|
||||
+1
-2
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.api.spawning.detail
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.entity.SpawnEvent
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
import com.cobblemon.mod.common.util.toVec3d
|
||||
import net.minecraft.world.entity.Entity
|
||||
@@ -26,7 +25,7 @@ import net.minecraft.world.entity.MobSpawnType
|
||||
*/
|
||||
abstract class SingleEntitySpawnAction<T : Entity>(
|
||||
spawnablePosition: SpawnablePosition,
|
||||
bucket: SpawnBucket,
|
||||
bucket: String,
|
||||
detail: SpawnDetail
|
||||
) : SpawnAction<EntitySpawnResult>(spawnablePosition, bucket, detail) {
|
||||
abstract fun createEntity(): T?
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.detail
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
@@ -21,7 +20,7 @@ import java.util.concurrent.CompletableFuture
|
||||
*/
|
||||
abstract class SpawnAction<R>(
|
||||
val spawnablePosition: SpawnablePosition,
|
||||
val bucket: SpawnBucket,
|
||||
val bucket: String,
|
||||
open val detail: SpawnDetail
|
||||
) {
|
||||
val labels = mutableListOf<String>()
|
||||
|
||||
@@ -15,7 +15,6 @@ import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.api.ModDependant
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.queryStructOf
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.condition.CompositeSpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.multiplier.WeightMultiplier
|
||||
@@ -54,7 +53,7 @@ abstract class SpawnDetail : ModDependant {
|
||||
var displayName: String? = null
|
||||
@SerializedName("spawnablePositionType", alternate = ["context"])
|
||||
lateinit var spawnablePositionType: SpawnablePositionType<*>
|
||||
var bucket = SpawnBucket("", 0F)
|
||||
var bucket = ""
|
||||
var conditions = mutableListOf<SpawningCondition<*>>()
|
||||
var anticonditions = mutableListOf<SpawningCondition<*>>()
|
||||
var compositeCondition: CompositeSpawningCondition? = null
|
||||
@@ -79,7 +78,7 @@ abstract class SpawnDetail : ModDependant {
|
||||
"weight" to { DoubleValue(weight) },
|
||||
"percentage" to { DoubleValue(percentage) },
|
||||
"id" to { StringValue(id) },
|
||||
"bucket" to { StringValue(bucket.name) },
|
||||
"bucket" to { StringValue(bucket) },
|
||||
"width" to { DoubleValue(width.toDouble()) },
|
||||
"height" to { DoubleValue(height.toDouble()) },
|
||||
"spawnable_position_type" to { StringValue(spawnablePositionType.name) },
|
||||
@@ -136,6 +135,10 @@ abstract class SpawnDetail : ModDependant {
|
||||
containsNullValues = true
|
||||
LOGGER.error("Spawn Detail with id $id is invalid as it contains invalid values in its anticonditions (commonly caused by trailing comma in biomes or other arrays)")
|
||||
}
|
||||
if (bucket.isBlank()) {
|
||||
containsNullValues = true
|
||||
LOGGER.error("Spawn Detail with id $id is invalid as it does not have a bucket assigned")
|
||||
}
|
||||
return super.isModDependencySatisfied() && !containsNullValues
|
||||
}
|
||||
|
||||
@@ -163,7 +166,7 @@ abstract class SpawnDetail : ModDependant {
|
||||
*/
|
||||
fun choose(
|
||||
spawnablePosition: SpawnablePosition,
|
||||
bucket: SpawnBucket,
|
||||
bucket: String,
|
||||
selectionData: SpawnSelectionData
|
||||
): SpawnAction<*> {
|
||||
val action = createSpawnAction(spawnablePosition, bucket, selectionData)
|
||||
@@ -175,10 +178,10 @@ abstract class SpawnDetail : ModDependant {
|
||||
return action
|
||||
}
|
||||
|
||||
/** Instantiates an action at the given [SpawnablePosition] for the given [SpawnBucket]. */
|
||||
/** Instantiates an action at the given [SpawnablePosition] for the given spawn bucket. */
|
||||
protected abstract fun createSpawnAction(
|
||||
spawnablePosition: SpawnablePosition,
|
||||
bucket: SpawnBucket,
|
||||
bucket: String,
|
||||
selectionData: SpawnSelectionData
|
||||
): SpawnAction<*>
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.api.spawning.detail
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnLoader
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnSet
|
||||
import com.cobblemon.mod.common.api.spawning.condition.PrecalculationResult
|
||||
@@ -61,12 +60,13 @@ class SpawnPool(val name: String) : JsonDataRegistry<SpawnSet>, Iterable<SpawnDe
|
||||
}
|
||||
|
||||
val details = mutableListOf<SpawnDetail>()
|
||||
/** Tracks which buckets are in use by the pool, to prevent spawners for rolling buckets that don't exist. */
|
||||
val buckets = mutableListOf<String>()
|
||||
var precalculation: PrecalculationResult<*> = RootPrecalculation.generate(details, emptyList())
|
||||
val precalculators = mutableListOf<SpawningPrecalculation<*>>()
|
||||
|
||||
override fun iterator() = details.iterator()
|
||||
|
||||
|
||||
fun addPrecalculators(vararg precalculators: SpawningPrecalculation<*>): SpawnPool {
|
||||
this.precalculators.addAll(precalculators)
|
||||
precalculate()
|
||||
@@ -88,6 +88,9 @@ class SpawnPool(val name: String) : JsonDataRegistry<SpawnSet>, Iterable<SpawnDe
|
||||
* be slow, especially if there are many precalculators and spawns.
|
||||
*/
|
||||
fun precalculate() {
|
||||
buckets.clear()
|
||||
buckets.addAll(details.asSequence().map(SpawnDetail::bucket).distinct())
|
||||
|
||||
if (precalculators.isEmpty()) {
|
||||
precalculation = RootPrecalculation.generate(details, emptyList())
|
||||
} else {
|
||||
@@ -103,7 +106,7 @@ class SpawnPool(val name: String) : JsonDataRegistry<SpawnSet>, Iterable<SpawnDe
|
||||
* to leverage the precalculation to get a smaller list of spawns as quickly
|
||||
* as possible.
|
||||
*/
|
||||
fun retrieve(bucket: SpawnBucket, spawnablePosition: SpawnablePosition): List<SpawnDetail> {
|
||||
fun retrieve(bucket: String, spawnablePosition: SpawnablePosition): List<SpawnDetail> {
|
||||
return precalculation.retrieve(bucket, spawnablePosition)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -145,7 +145,7 @@ class FishingSpawnCause(
|
||||
return
|
||||
}
|
||||
pokemonEntity.pokemon.isAlpha = true
|
||||
pokemonEntity.pokemon.initializeMovesetWithRandomTm(2)
|
||||
pokemonEntity.pokemon.initializeMovesetFromDefault()
|
||||
if (!pokemonEntity.level().isClientSide) {
|
||||
// Alpha status is applied after entity creation in bait flows, so rebuild the brain
|
||||
// to ensure alpha-only sensors/memories are actually attached.
|
||||
|
||||
+5
-5
@@ -8,19 +8,19 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.influence
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
|
||||
/**
|
||||
* A [SpawningInfluence] that multiplies bucket weights by the provided values
|
||||
* and then normalizes the resulting weights so that their total adds up to 100.
|
||||
*
|
||||
* No longer used by the mod, but kept for external suers.
|
||||
*/
|
||||
class BucketMultiplyingInfluence(
|
||||
val multipliers: Map<String, Float>,
|
||||
) : SpawningInfluence {
|
||||
override fun affectBucketWeights(bucketWeights: MutableMap<SpawnBucket, Float>) {
|
||||
val updates = mutableMapOf<SpawnBucket, Float>()
|
||||
override fun affectBucketWeights(bucketWeights: MutableMap<String, Float>) {
|
||||
val updates = mutableMapOf<String, Float>()
|
||||
for ((bucket, weight) in bucketWeights) {
|
||||
val multiplier = multipliers[bucket.name]
|
||||
val multiplier = multipliers[bucket]
|
||||
if (multiplier != null) {
|
||||
updates[bucket] = weight * multiplier
|
||||
}
|
||||
|
||||
+1
-2
@@ -8,7 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.influence
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import kotlin.math.pow
|
||||
|
||||
/**
|
||||
@@ -33,7 +32,7 @@ open class BucketNormalizingInfluence(
|
||||
val gradient: Float = 0.2F,
|
||||
val firstTier: Float = 1.29F
|
||||
) : SpawningInfluence {
|
||||
override fun affectBucketWeights(bucketWeights: MutableMap<SpawnBucket, Float>) {
|
||||
override fun affectBucketWeights(bucketWeights: MutableMap<String, Float>) {
|
||||
if (tier == 0) {
|
||||
return
|
||||
}
|
||||
|
||||
+1
-1
@@ -150,7 +150,7 @@ class SaccharineLogSlatheredInfluence(val pos: BlockPos? = null) : SpawningInflu
|
||||
val chance = Cobblemon.config.honeySlatherAlphaChance
|
||||
if (chance > 0 && Random.nextInt(chance) == 0) {
|
||||
pokemon.isAlpha = true
|
||||
pokemon.initializeMovesetWithRandomTm(2)
|
||||
pokemon.initializeMovesetFromDefault()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-1
@@ -21,6 +21,8 @@ import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.sensors.AlphaLevelMatchingSensor
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.entity.Entity
|
||||
|
||||
/**
|
||||
@@ -47,6 +49,13 @@ open class SpawnBaitInfluence(val effects: List<SpawnBait.Effect>, val onUsed: (
|
||||
Effects.getEffectFunction(effect.type)?.invoke(entity, effect)
|
||||
}
|
||||
}
|
||||
|
||||
if (entity.pokemon.isAlpha) {
|
||||
val spawningPlayer = action.spawnablePosition.cause.entity as? ServerPlayer
|
||||
if (spawningPlayer != null) {
|
||||
AlphaLevelMatchingSensor.applyLevelMatching(entity, spawningPlayer)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,4 +139,4 @@ open class SpawnBaitInfluence(val effects: List<SpawnBait.Effect>, val onUsed: (
|
||||
if (used) markUsed()
|
||||
return super.affectWeight(detail, spawnablePosition, newWeight)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-4
@@ -9,7 +9,6 @@
|
||||
package com.cobblemon.mod.common.api.spawning.influence
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.BestSpawner
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
@@ -39,9 +38,9 @@ interface SpawningInfluence {
|
||||
/** Applies some influence over the entity that's been spawned. */
|
||||
fun affectSpawn(action: SpawnAction<*>, entity: Entity) {}
|
||||
/** Applies some influence over the weight of spawn buckets. */
|
||||
fun affectBucketWeights(bucketWeights: MutableMap<SpawnBucket, Float>) {}
|
||||
fun affectBucketWeights(bucketWeights: MutableMap<String, Float>) {}
|
||||
/** Normalizes all bucket weights to add up to 100 */
|
||||
fun normalizeBucketWeights(bucketWeights: MutableMap<SpawnBucket, Float>) {
|
||||
fun normalizeBucketWeights(bucketWeights: MutableMap<String, Float>) {
|
||||
val sum = bucketWeights.values.sum()
|
||||
val to100 = 100F / sum
|
||||
bucketWeights.keys.toList().forEach {
|
||||
@@ -56,5 +55,5 @@ interface SpawningInfluence {
|
||||
*
|
||||
* You should make sure the spawn position satisfies any spawn details that you inject.
|
||||
*/
|
||||
fun injectSpawns(bucket: SpawnBucket, spawnablePosition: SpawnablePosition): List<SpawnDetail>? = null
|
||||
fun injectSpawns(bucket: String, spawnablePosition: SpawnablePosition): List<SpawnDetail>? = null
|
||||
}
|
||||
+28
-6
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.api.spawning.preset
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.api.spawning.BestSpawner
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePositionType
|
||||
import com.cobblemon.mod.common.util.adapters.RegisteredSpawnablePositionAdapter
|
||||
import com.google.gson.GsonBuilder
|
||||
@@ -39,11 +38,34 @@ class BestSpawnerConfig {
|
||||
"surface" to 0.01F,
|
||||
"seafloor" to 1F
|
||||
)
|
||||
val buckets = mutableListOf(
|
||||
SpawnBucket("common", 94.3F),
|
||||
SpawnBucket("uncommon", 5F),
|
||||
SpawnBucket("rare", 0.5F),
|
||||
SpawnBucket("ultra-rare", 0.2F)
|
||||
|
||||
val worldBuckets = mutableMapOf(
|
||||
"common" to 94F,
|
||||
"uncommon" to 5F,
|
||||
"rare" to 0.5F,
|
||||
"ultra-rare" to 0.2F,
|
||||
"boss" to 0.3F,
|
||||
)
|
||||
|
||||
val fishingBuckets = mutableMapOf(
|
||||
"common" to 83.25F,
|
||||
"uncommon" to 11.25F,
|
||||
"rare" to 4.125F,
|
||||
"ultra-rare" to 1.375F
|
||||
)
|
||||
|
||||
val activatedHabitatBuckets: MutableMap<String, Float> = mutableMapOf(
|
||||
"common" to 83.25F,
|
||||
"uncommon" to 11.25F,
|
||||
"rare" to 4.125F,
|
||||
"ultra-rare" to 1.375F
|
||||
)
|
||||
|
||||
val pokeSnackBuckets = mutableMapOf(
|
||||
"common" to 83.25F,
|
||||
"uncommon" to 11.25F,
|
||||
"rare" to 4.125F,
|
||||
"ultra-rare" to 1.375F
|
||||
)
|
||||
|
||||
companion object {
|
||||
|
||||
+2
-3
@@ -8,13 +8,12 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.preset
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnDetailPresets
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnLoader
|
||||
import com.cobblemon.mod.common.api.spawning.condition.SpawningCondition
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePositionType
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.multiplier.WeightMultiplier
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePositionType
|
||||
import com.cobblemon.mod.common.util.MergeMode
|
||||
import com.cobblemon.mod.common.util.adapters.SpawnDetailAdapter
|
||||
import com.google.gson.JsonObject
|
||||
@@ -41,7 +40,7 @@ import com.google.gson.annotations.SerializedName
|
||||
* @since July 8th, 2022
|
||||
*/
|
||||
abstract class SpawnDetailPreset {
|
||||
var bucket: SpawnBucket? = null
|
||||
var bucket: String? = null
|
||||
var spawnDetailType: String? = null
|
||||
@SerializedName("spawnablePositionType", alternate = ["context"])
|
||||
var spawnablePositionType: SpawnablePositionType<*>? = null
|
||||
|
||||
+6
-7
@@ -9,7 +9,6 @@
|
||||
package com.cobblemon.mod.common.api.spawning.selection
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
@@ -88,12 +87,12 @@ open class FlatSelector : SpawningSelector<FlatSelector.SpawnablePositionSelecti
|
||||
class SpawnablePositionSelectionData(
|
||||
val spawner: Spawner,
|
||||
val spawnablePositions: List<SpawnablePosition>,
|
||||
val selectingSpawnInformation: MutableMap<SpawnBucket, SpawnablePositionBucketSelectionData>,
|
||||
val selectingSpawnInformation: MutableMap<String, SpawnablePositionBucketSelectionData>,
|
||||
): SpawnSelectionData {
|
||||
override val spawnActions = mutableListOf<SpawnAction<*>>()
|
||||
override val context = mutableMapOf<String, Any>()
|
||||
|
||||
fun getDataForBucket(bucket: SpawnBucket): SpawnablePositionBucketSelectionData {
|
||||
fun getDataForBucket(bucket: String): SpawnablePositionBucketSelectionData {
|
||||
val existing = selectingSpawnInformation[bucket]
|
||||
if (existing != null) {
|
||||
return existing
|
||||
@@ -130,14 +129,14 @@ open class FlatSelector : SpawningSelector<FlatSelector.SpawnablePositionSelecti
|
||||
spawner: Spawner,
|
||||
spawnablePositions: List<SpawnablePosition>
|
||||
): SpawnablePositionSelectionData {
|
||||
val selectingSpawnInformation: MutableMap<SpawnBucket, SpawnablePositionBucketSelectionData> = mutableMapOf()
|
||||
val selectingSpawnInformation: MutableMap<String, SpawnablePositionBucketSelectionData> = mutableMapOf()
|
||||
|
||||
return SpawnablePositionSelectionData(spawner, spawnablePositions, selectingSpawnInformation)
|
||||
}
|
||||
|
||||
override fun selectSpawnAction(
|
||||
spawner: Spawner,
|
||||
bucket: SpawnBucket,
|
||||
bucket: String,
|
||||
selectionData: SpawnablePositionSelectionData,
|
||||
): SpawnAction<*>? {
|
||||
val selectingSpawnInformation = selectionData.getDataForBucket(bucket) ?: return null
|
||||
@@ -149,7 +148,7 @@ open class FlatSelector : SpawningSelector<FlatSelector.SpawnablePositionSelecti
|
||||
if (percentSum > 100) {
|
||||
Cobblemon.LOGGER.warn(
|
||||
"""
|
||||
A spawn list for ${spawner.name} exceeded 100% on percentage sums in bucket ${bucket.name}...
|
||||
A spawn list for ${spawner.name} exceeded 100% on percentage sums in bucket $bucket...
|
||||
This means you don't understand how this option works.
|
||||
""".trimIndent()
|
||||
)
|
||||
@@ -186,7 +185,7 @@ open class FlatSelector : SpawningSelector<FlatSelector.SpawnablePositionSelecti
|
||||
|
||||
override fun getTotalWeights(
|
||||
spawner: Spawner,
|
||||
bucket: SpawnBucket,
|
||||
bucket: String,
|
||||
spawnablePositions: List<SpawnablePosition>
|
||||
): Map<SpawnDetail, Float> {
|
||||
val selectionData = getSelectionData(spawner, spawnablePositions).getDataForBucket(bucket)
|
||||
|
||||
+5
-6
@@ -9,7 +9,6 @@
|
||||
package com.cobblemon.mod.common.api.spawning.selection
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
@@ -105,7 +104,7 @@ open class FlatSpawnablePositionWeightedSelector : SpawningSelector<FlatSpawnabl
|
||||
override val spawnActions = mutableListOf<SpawnAction<*>>()
|
||||
override val context = mutableMapOf<String, Any>()
|
||||
|
||||
val bucketData = mutableMapOf<SpawnBucket, MutableMap<SpawnablePositionType<*>, SpawnablePositionSelectionData>>()
|
||||
val bucketData = mutableMapOf<String, MutableMap<SpawnablePositionType<*>, SpawnablePositionSelectionData>>()
|
||||
|
||||
override fun removeSpawnDetails(shouldRemove: (SpawnDetail) -> Boolean) {
|
||||
bucketData.values.forEach {
|
||||
@@ -121,7 +120,7 @@ open class FlatSpawnablePositionWeightedSelector : SpawningSelector<FlatSpawnabl
|
||||
}
|
||||
}
|
||||
|
||||
fun getDataForBucket(bucket: SpawnBucket): MutableMap<SpawnablePositionType<*>, SpawnablePositionSelectionData> {
|
||||
fun getDataForBucket(bucket: String): MutableMap<SpawnablePositionType<*>, SpawnablePositionSelectionData> {
|
||||
bucketData[bucket]?.let { return it }
|
||||
|
||||
val spawnablePositionTypeToSpawns = mutableMapOf<SpawnablePositionType<*>, SpawnablePositionSelectionData>()
|
||||
@@ -149,7 +148,7 @@ open class FlatSpawnablePositionWeightedSelector : SpawningSelector<FlatSpawnabl
|
||||
|
||||
override fun selectSpawnAction(
|
||||
spawner: Spawner,
|
||||
bucket: SpawnBucket,
|
||||
bucket: String,
|
||||
selectionData: SeparatedSelectionData
|
||||
): SpawnAction<*>? {
|
||||
val bucketData = selectionData.getDataForBucket(bucket)
|
||||
@@ -172,7 +171,7 @@ open class FlatSpawnablePositionWeightedSelector : SpawningSelector<FlatSpawnabl
|
||||
if (percentSum > 100) {
|
||||
LOGGER.warn(
|
||||
"""
|
||||
A spawn list for ${spawner.name} exceeded 100% on percentage sums in bucket ${bucket.name}...
|
||||
A spawn list for ${spawner.name} exceeded 100% on percentage sums in bucket $bucket...
|
||||
This means you don't understand how this option works.
|
||||
""".trimIndent()
|
||||
)
|
||||
@@ -244,7 +243,7 @@ open class FlatSpawnablePositionWeightedSelector : SpawningSelector<FlatSpawnabl
|
||||
|
||||
override fun getTotalWeights(
|
||||
spawner: Spawner,
|
||||
bucket: SpawnBucket,
|
||||
bucket: String,
|
||||
spawnablePositions: List<SpawnablePosition>
|
||||
): Map<SpawnDetail, Float> {
|
||||
val selectionData = getSelectionData(spawner, spawnablePositions).getDataForBucket(bucket)
|
||||
|
||||
+4
-5
@@ -8,7 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.selection
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
@@ -33,13 +32,13 @@ interface SpawningSelector<T : SpawnSelectionData> {
|
||||
|
||||
fun selectSpawnAction(
|
||||
spawner: Spawner,
|
||||
bucket: SpawnBucket,
|
||||
bucket: String,
|
||||
selectionData: T
|
||||
): SpawnAction<*>?
|
||||
|
||||
fun select(
|
||||
spawner: Spawner,
|
||||
bucketSelector: () -> SpawnBucket,
|
||||
bucketSelector: () -> String,
|
||||
spawnablePositions: List<SpawnablePosition>,
|
||||
maxSpawns: Int
|
||||
): List<SpawnAction<*>> {
|
||||
@@ -65,7 +64,7 @@ interface SpawningSelector<T : SpawnSelectionData> {
|
||||
return spawnActions
|
||||
}
|
||||
|
||||
fun getProbabilities(spawner: Spawner, bucket: SpawnBucket, spawnablePositions: List<SpawnablePosition>): Map<SpawnDetail, Float> {
|
||||
fun getProbabilities(spawner: Spawner, bucket: String, spawnablePositions: List<SpawnablePosition>): Map<SpawnDetail, Float> {
|
||||
val weights = getTotalWeights(spawner, bucket, spawnablePositions)
|
||||
val totalWeight = weights.values.sum()
|
||||
val percentages = mutableMapOf<SpawnDetail, Float>()
|
||||
@@ -73,5 +72,5 @@ interface SpawningSelector<T : SpawnSelectionData> {
|
||||
return percentages
|
||||
}
|
||||
|
||||
fun getTotalWeights(spawner: Spawner, bucket: SpawnBucket, spawnablePositions: List<SpawnablePosition>): Map<SpawnDetail, Float>
|
||||
fun getTotalWeights(spawner: Spawner, bucket: String, spawnablePositions: List<SpawnablePosition>): Map<SpawnDetail, Float>
|
||||
}
|
||||
+2
-1
@@ -25,7 +25,8 @@ import com.cobblemon.mod.common.api.spawning.selection.SpawningSelector
|
||||
open class BasicSpawner(
|
||||
override val name: String,
|
||||
override var spawnPool: SpawnPool,
|
||||
override var maxPokemonPerChunk: Float = Cobblemon.config.pokemonPerChunk
|
||||
override var maxPokemonPerChunk: Float = Cobblemon.config.pokemonPerChunk,
|
||||
override val buckets: Map<String, Float>
|
||||
) : Spawner {
|
||||
override var selector: SpawningSelector<*> = SpawningSelector.DEFAULT
|
||||
override var generator: SpawningZoneGenerator = Cobblemon.spawningZoneGenerator
|
||||
|
||||
+4
-11
@@ -8,11 +8,11 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.spawner
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonPoiTypes
|
||||
import com.cobblemon.mod.common.api.spawning.BestSpawner
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
|
||||
import com.cobblemon.mod.common.api.spawning.influence.BucketMultiplyingInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.BucketNormalizingInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.PlayerLevelRangeInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.PlayerLevelRangeInfluence.Companion.TYPICAL_VARIATION
|
||||
@@ -72,16 +72,9 @@ object FishingSpawnerFactory {
|
||||
fun createSharedSpawner(): BasicSpawner {
|
||||
return BasicSpawner(
|
||||
name = "fishing",
|
||||
spawnPool = spawnPool
|
||||
).also { spawner ->
|
||||
spawner.influences += BucketMultiplyingInfluence(
|
||||
multipliers = mapOf(
|
||||
"uncommon" to 2.25f,
|
||||
"rare" to 5.5f,
|
||||
"ultra-rare" to 5.5f,
|
||||
)
|
||||
)
|
||||
}
|
||||
spawnPool = spawnPool,
|
||||
buckets = Cobblemon.bestSpawner.config.fishingBuckets,
|
||||
)
|
||||
}
|
||||
|
||||
fun findHabitatInfluences(world: ServerLevel, position: BlockPos, spawner: Spawner): Array<HabitatBlockEntity> {
|
||||
|
||||
+3
-2
@@ -11,8 +11,8 @@ package com.cobblemon.mod.common.api.spawning.spawner
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnCause
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
|
||||
/**
|
||||
* A spawner that works within a fixed area. Instances provide the center point and the radii and then the spawner
|
||||
@@ -24,12 +24,13 @@ import net.minecraft.core.BlockPos
|
||||
open class FixedAreaSpawner(
|
||||
name: String,
|
||||
spawnPool: SpawnPool,
|
||||
buckets: Map<String, Float>,
|
||||
val world: ServerLevel,
|
||||
val position: BlockPos,
|
||||
val horizontalRadius: Int,
|
||||
val verticalRadius: Int,
|
||||
maxPokemonPerChunk: Float = Cobblemon.config.pokemonPerChunk
|
||||
) : BasicSpawner(name, spawnPool, maxPokemonPerChunk) {
|
||||
) : BasicSpawner(name, spawnPool, maxPokemonPerChunk, buckets) {
|
||||
fun run(cause: SpawnCause, maxSpawns: Int? = null): List<Any> {
|
||||
return runForArea(
|
||||
zoneInput = getZoneInput(cause),
|
||||
|
||||
+8
-6
@@ -8,20 +8,21 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.spawner
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Cobblemon.config
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnCause
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
|
||||
import com.cobblemon.mod.common.util.getPlayer
|
||||
import com.cobblemon.mod.common.util.nextBetween
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.util.Mth.PI
|
||||
import net.minecraft.util.Mth.ceil
|
||||
import java.util.*
|
||||
import java.util.UUID
|
||||
import kotlin.math.atan
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
import kotlin.random.Random
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.util.Mth.PI
|
||||
import net.minecraft.util.Mth.ceil
|
||||
|
||||
/**
|
||||
* A spawner that works around a single player. It will do basic tracking of a player's speed
|
||||
@@ -35,7 +36,8 @@ open class PlayerSpawner(
|
||||
spawnPool: SpawnPool
|
||||
) : BasicSpawner(
|
||||
name = player.name.string,
|
||||
spawnPool = spawnPool
|
||||
spawnPool = spawnPool,
|
||||
buckets = Cobblemon.bestSpawner.config.worldBuckets
|
||||
) {
|
||||
val uuid: UUID = player.uuid
|
||||
|
||||
|
||||
+2
-10
@@ -8,11 +8,11 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.spawner
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.fishing.SpawnBait
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnRules
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnPool
|
||||
import com.cobblemon.mod.common.api.spawning.influence.BucketMultiplyingInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.BucketNormalizingInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawnBaitInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
@@ -61,15 +61,6 @@ object PokeSnackSpawnerFactory {
|
||||
firstTier = 1.2F
|
||||
)
|
||||
},
|
||||
{ _ ->
|
||||
BucketMultiplyingInfluence(
|
||||
mapOf(
|
||||
"uncommon" to 2.25f,
|
||||
"rare" to 5.5f,
|
||||
"ultra-rare" to 5.5f,
|
||||
)
|
||||
)
|
||||
},
|
||||
{ ctx ->
|
||||
SpawnBaitInfluence(effects = ctx.baitEffects)
|
||||
},
|
||||
@@ -81,6 +72,7 @@ object PokeSnackSpawnerFactory {
|
||||
return FixedAreaSpawner(
|
||||
name = ctx.name,
|
||||
spawnPool = spawnPool,
|
||||
buckets = Cobblemon.bestSpawner.config.pokeSnackBuckets,
|
||||
world = ctx.world,
|
||||
position = ctx.pos,
|
||||
horizontalRadius = ctx.horizontalRadius,
|
||||
|
||||
@@ -12,7 +12,6 @@ import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.entity.SpawnBucketChosenEvent
|
||||
import com.cobblemon.mod.common.api.spawning.BestSpawner
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnCause
|
||||
import com.cobblemon.mod.common.api.spawning.SpawningZoneGenerator
|
||||
import com.cobblemon.mod.common.api.spawning.detail.EntitySpawnResult
|
||||
@@ -26,6 +25,7 @@ import com.cobblemon.mod.common.api.spawning.position.calculators.SpawnablePosit
|
||||
import com.cobblemon.mod.common.api.spawning.selection.SpawningSelector
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.isBoxLoaded
|
||||
import com.cobblemon.mod.common.util.removeIf
|
||||
import com.cobblemon.mod.common.util.squeezeWithinBounds
|
||||
import com.cobblemon.mod.common.util.toVec3f
|
||||
import com.cobblemon.mod.common.util.weightedSelection
|
||||
@@ -52,6 +52,7 @@ import net.minecraft.world.phys.Vec3
|
||||
interface Spawner {
|
||||
val name: String
|
||||
val influences: MutableList<SpawningInfluence>
|
||||
val buckets: Map<String, Float>
|
||||
var spawnPool: SpawnPool
|
||||
var selector: SpawningSelector<*>
|
||||
var generator: SpawningZoneGenerator
|
||||
@@ -65,7 +66,7 @@ interface Spawner {
|
||||
const val ENTITY_LIMIT_CHUNK_RANGE = 3
|
||||
}
|
||||
|
||||
fun getMatchingSpawns(bucket: SpawnBucket, spawnablePosition: SpawnablePosition): List<SpawnDetail> {
|
||||
fun getMatchingSpawns(bucket: String, spawnablePosition: SpawnablePosition): List<SpawnDetail> {
|
||||
val spawns = mutableListOf<SpawnDetail>()
|
||||
spawns.addAll(spawnPool.retrieve(bucket, spawnablePosition).filter { it.isSatisfiedBy(spawnablePosition) })
|
||||
spawnablePosition.influences.forEach { influence ->
|
||||
@@ -172,11 +173,12 @@ interface Spawner {
|
||||
|
||||
fun copyInfluences() = influences.filter { !it.isExpired() }.toMutableList()
|
||||
|
||||
fun chooseBucket(cause: SpawnCause, influences: List<SpawningInfluence>): SpawnBucket {
|
||||
val buckets = Cobblemon.bestSpawner.config.buckets
|
||||
val bucketWeights = buckets.associateWith { it.weight }.toMutableMap()
|
||||
fun chooseBucket(cause: SpawnCause, influences: List<SpawningInfluence>): String {
|
||||
val bucketWeights = buckets.toMutableMap()
|
||||
influences.forEach { it.affectBucketWeights(bucketWeights) }
|
||||
val bucket = bucketWeights.entries.weightedSelection { it.value }?.key ?: buckets.first()
|
||||
val usedBuckets = spawnPool.buckets.intersect(bucketWeights.keys)
|
||||
bucketWeights.removeIf { it.key !in usedBuckets }
|
||||
val bucket = bucketWeights.entries.weightedSelection { it.value }?.key ?: buckets.keys.first()
|
||||
val event = SpawnBucketChosenEvent(
|
||||
spawner = this,
|
||||
spawnCause = cause,
|
||||
|
||||
@@ -51,6 +51,8 @@ object CobblemonBiomeTags {
|
||||
@JvmField
|
||||
val IS_FUNGUS = create("nether/is_fungus")
|
||||
@JvmField
|
||||
val IS_WASTELAND = create("nether/is_wasteland")
|
||||
@JvmField
|
||||
val IS_GLACIAL = create("is_glacial")
|
||||
@JvmField
|
||||
val IS_TEMPERATE_OCEAN = create("is_temperate_ocean")
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.api.tms
|
||||
|
||||
import com.cobblemon.mod.common.tms.obtain.DefaultObtainMethod
|
||||
import com.cobblemon.mod.common.tms.obtain.ImpossibleObtainMethod
|
||||
import com.cobblemon.mod.common.tms.obtain.PlayerHasAdvancementObtainMethod
|
||||
import com.cobblemon.mod.common.tms.obtain.PlayerYObtainMethod
|
||||
import com.cobblemon.mod.common.tms.obtain.UnlockableObtainMethod
|
||||
@@ -36,6 +37,7 @@ interface ObtainMethod {
|
||||
val variant = buffer.readUtf()
|
||||
return when (variant) {
|
||||
"cobblemon:unlockable" -> UnlockableObtainMethod()
|
||||
"cobblemon:impossible" -> ImpossibleObtainMethod()
|
||||
"cobblemon:default" -> DefaultObtainMethod()
|
||||
"cobblemon:advancement" -> {
|
||||
val advancement = buffer.readResourceLocation()
|
||||
|
||||
@@ -14,6 +14,8 @@ import com.cobblemon.mod.common.advancement.CobblemonCriteria
|
||||
import com.cobblemon.mod.common.advancement.criterion.CountableContext
|
||||
import com.cobblemon.mod.common.advancement.criterion.LearnAllTMContext
|
||||
import com.cobblemon.mod.common.advancement.criterion.LearnTMContext
|
||||
import com.cobblemon.mod.common.api.abilities.Ability
|
||||
import com.cobblemon.mod.common.api.abilities.AbilityPool
|
||||
import com.cobblemon.mod.common.api.moves.MoveTemplate
|
||||
import com.cobblemon.mod.common.api.scheduling.ScheduledTask
|
||||
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
|
||||
@@ -50,6 +52,11 @@ class TMMoveManager(
|
||||
learn(listOf(tmId))
|
||||
}
|
||||
|
||||
fun syncTMLockFromMove(moveTemplate: MoveTemplate) {
|
||||
val tmId = TechnicalMachines.moveToTM[moveTemplate]?.id ?: return
|
||||
unlearn(listOf(tmId))
|
||||
}
|
||||
|
||||
fun getLearnableTMsFromPokemon(pokemon: Pokemon): Collection<ResourceLocation> {
|
||||
val learnableMoves = pokemon.allAccessibleMoves.toMutableSet()
|
||||
learnableMoves.addAll(pokemon.moveSet.map { it.template })
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.moves.MoveTemplate
|
||||
import com.cobblemon.mod.common.api.moves.adapters.MoveTemplateAdapter
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.net.messages.client.tms.TechnicalMachineRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.util.adapters.TMObtainMethodAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
@@ -70,5 +71,7 @@ object TechnicalMachines : JsonDataRegistry<TechnicalMachine> {
|
||||
|
||||
fun getByResourceLocation(resourceLocation: ResourceLocation) = tmMap[resourceLocation]
|
||||
fun getAllResourceLocations() = tmMap.keys.toSet()
|
||||
override fun sync(player: ServerPlayer) {}
|
||||
override fun sync(player: ServerPlayer) {
|
||||
TechnicalMachineRegistrySyncPacket(tmMap.values.toList()).sendToPlayer(player)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,10 +42,12 @@ class ElementalType(
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
val BY_STRING_CODEC: Codec<ElementalType> = CodecUtils.createByStringCodec(
|
||||
ElementalTypes::get,
|
||||
{it.showdownId}
|
||||
) { id -> "No ElementalType for ID $id" }
|
||||
val BY_STRING_CODEC: Codec<ElementalType> by lazy {
|
||||
CodecUtils.createByStringCodec(
|
||||
ElementalTypes::get,
|
||||
{ it.showdownId }
|
||||
) { id -> "No ElementalType for ID $id" }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,11 +349,12 @@ object BattleBuilder {
|
||||
npcPartyStores.add(npcParty)
|
||||
}
|
||||
|
||||
if (playerActor.pokemonList.size < battleFormat.battleType.slotsPerActor) {
|
||||
val playerAvailablePokemon = playerActor.pokemonList.count { it.health > 0 }
|
||||
if (playerAvailablePokemon < battleFormat.battleType.slotsPerActor) {
|
||||
errors.participantErrors[playerActor] += BattleStartError.insufficientPokemon(
|
||||
actorEntity = player,
|
||||
requiredCount = battleFormat.battleType.slotsPerActor,
|
||||
hadCount = playerActor.pokemonList.size
|
||||
hadCount = playerAvailablePokemon
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ object ShowdownInterpreter {
|
||||
updateInstructionParser["-endability"] = { _, _, message, _ -> EndAbilityInstruction(message) }
|
||||
updateInstructionParser["-end"] = { _, _, message, _ -> EndInstruction(message) }
|
||||
updateInstructionParser["-enditem"] = { _, _, message, _ -> EndItemInstruction(message) }
|
||||
updateInstructionParser["-fail"] = { _, _, message, _ -> FailInstruction(message) }
|
||||
updateInstructionParser["-fail"] = { battle, _, message, _ -> FailInstruction(battle, message) }
|
||||
updateInstructionParser["faint"] = { battle, _, message, _ -> FaintInstruction(battle, message) }
|
||||
updateInstructionParser["-fieldactivate"] = { _, _, message, _ -> FieldActivateInstruction(message) }
|
||||
updateInstructionParser["-fieldend"] = { _, _, message, _ -> FieldEndInstruction(message) }
|
||||
|
||||
@@ -38,15 +38,8 @@ class ShowdownThread : Thread("Cobblemon Showdown") {
|
||||
|
||||
override fun run() {
|
||||
LOGGER.info("Starting showdown service...")
|
||||
try {
|
||||
ShowdownService.service.openConnection()
|
||||
LOGGER.info("Showdown has been started!")
|
||||
} catch (e: Exception) {
|
||||
LOGGER.error("Failed to start showdown service!", e)
|
||||
} finally {
|
||||
this.latch.countDown()
|
||||
throw RuntimeException("Showdown service failed to initialize...")
|
||||
}
|
||||
|
||||
ShowdownService.service.openConnection()
|
||||
LOGGER.info("Showdown has been started!")
|
||||
this.latch.countDown()
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import com.cobblemon.mod.common.battles.PassActionResponse
|
||||
import com.cobblemon.mod.common.battles.ShowdownActionResponse
|
||||
import com.cobblemon.mod.common.battles.ShowdownMoveset
|
||||
import com.cobblemon.mod.common.battles.SwitchActionResponse
|
||||
import com.cobblemon.mod.common.exception.IllegalActionChoiceException
|
||||
|
||||
/**
|
||||
* AI that randomly chooses a move from its moveset at a random target.
|
||||
@@ -40,17 +41,19 @@ class RandomBattleAI : BattleAI {
|
||||
return SwitchActionResponse(switchTo.uuid)
|
||||
}
|
||||
|
||||
if (moveset == null) {
|
||||
if (moveset == null)
|
||||
return PassActionResponse
|
||||
|
||||
val move = moveset.moves.filter { it.canBeUsed() }.randomOrNull()
|
||||
if (move == null) {
|
||||
if (moveset.moves.any { it.id == "struggle" })
|
||||
return MoveActionResponse("struggle")
|
||||
else throw IllegalActionChoiceException(activeBattlePokemon.actor,
|
||||
"No valid AI move choices, but Showdown never injected Struggle!")
|
||||
}
|
||||
val move = moveset.moves
|
||||
.filter { it.canBeUsed() }
|
||||
.filter { it.mustBeUsed() || it.target.targetList(activeBattlePokemon)?.isEmpty() != true }
|
||||
.randomOrNull()
|
||||
?: return MoveActionResponse("struggle")
|
||||
|
||||
val target = if (move.mustBeUsed()) null else move.target.targetList(activeBattlePokemon)
|
||||
return if (target == null) {
|
||||
return if (target.isNullOrEmpty()) {
|
||||
MoveActionResponse(move.id)
|
||||
} else {
|
||||
// prioritize opponents rather than allies
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.cobblemon.mod.common.battles.ai.strongBattleAI.AIUtility
|
||||
import com.cobblemon.mod.common.battles.ai.strongBattleAI.ActiveTracker
|
||||
import com.cobblemon.mod.common.battles.ai.strongBattleAI.TrackerPokemon
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.exception.IllegalActionChoiceException
|
||||
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
|
||||
import kotlin.random.Random
|
||||
import kotlin.collections.associateWith
|
||||
@@ -94,14 +95,14 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
return null to 0.0 // we do not care about moves that dont target opponents during damage calculations
|
||||
val singleTargetList = move.first.target.targetList.invoke(attacker)?.map { it as ActiveBattlePokemon }?.filter { it.battlePokemon != null }
|
||||
val multiTargetList = attacker.getMultiTargetList(move.first.target)?.map { it as ActiveBattlePokemon }?.filter { it.battlePokemon != null }
|
||||
if (singleTargetList != null && singleTargetList.isNotEmpty()) {
|
||||
if (!singleTargetList.isNullOrEmpty()) {
|
||||
// figure out target that will take the most damage
|
||||
val potentialTargets = activeTracker.opponentSide.activePokemon
|
||||
.filter { opp -> opp.id in singleTargetList.map { it.battlePokemon!!.uuid } }
|
||||
.map { opp -> singleTargetList.first { it.battlePokemon!!.uuid == opp.id} to calculateDamage(move.first, attackerTracker, opp) }
|
||||
|
||||
return potentialTargets.maxBy { it.second }
|
||||
} else if (multiTargetList != null && multiTargetList.isNotEmpty()) {
|
||||
} else if (!multiTargetList.isNullOrEmpty()) {
|
||||
val (allies, opponents) = multiTargetList.partition { it.isAllied(attacker) }
|
||||
// weigh up allied damage against opponents
|
||||
val totalOpponentDamage = activeTracker.opponentSide.activePokemon
|
||||
@@ -188,10 +189,8 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
|
||||
// function for finding the most damaging moves in the moveset
|
||||
fun mostDamagingMove(selectedMove: InBattleMove, moveset: ShowdownMoveset?, mon: TrackerPokemon, opponent: TrackerPokemon): Boolean {
|
||||
|
||||
if (moveset != null) {
|
||||
for (move in moveset.moves.filter { !it.disabled && it.id != selectedMove.id}) {
|
||||
|
||||
if (calculateDamage(move, mon, opponent) > calculateDamage(selectedMove, mon, opponent)) {
|
||||
return false
|
||||
}
|
||||
@@ -251,18 +250,19 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
|
||||
val availableMoves = moveset.moves.filter { it.canBeUsed() }.map { Pair(it, Moves.getByName(it.id)!!)}
|
||||
|
||||
if (!checkSkillLevel()){
|
||||
val move = availableMoves
|
||||
.filter { it.first.target.targetList(activeBattlePokemon)?.isEmpty() != true }
|
||||
.randomOrNull()
|
||||
?: return MoveActionResponse("struggle")
|
||||
|
||||
return chooseMove(move.first, activeBattlePokemon)
|
||||
val randomMove = availableMoves.randomOrNull()
|
||||
if (randomMove == null) {
|
||||
if (moveset.moves.any { it.id == "struggle" })
|
||||
return MoveActionResponse("struggle")
|
||||
else throw IllegalActionChoiceException(activeBattlePokemon.actor,
|
||||
"No valid AI move choices, but Showdown never injected Struggle!")
|
||||
}
|
||||
|
||||
if (!checkSkillLevel()) return chooseMove(randomMove.first, activeBattlePokemon)
|
||||
|
||||
// switch out based on current matchup on the field
|
||||
if (checkSwitchOutSkill() && shouldSwitchOut(aiSide, battle, activeBattlePokemon, moveset)) {
|
||||
considerSwitching(activeBattlePokemon, activeTrackerPokemon, opponents, availableMoves, availableSwitches, battle, aiSide)
|
||||
considerSwitching(activeBattlePokemon, activeTrackerPokemon, opponents, availableMoves, availableSwitches, battle, aiSide)?.let { return it }
|
||||
}
|
||||
|
||||
// If HP is below 30% and not switching out, always use the most damaging move
|
||||
@@ -358,7 +358,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
}
|
||||
}
|
||||
|
||||
considerAntiBoost(activeBattlePokemon, activeTrackerPokemon, opponents, availableMoves)
|
||||
considerAntiBoost(activeBattlePokemon, activeTrackerPokemon, opponents, availableMoves)?.let { return it }
|
||||
|
||||
// Court Change
|
||||
for (move in availableMoves) {
|
||||
@@ -414,7 +414,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
}
|
||||
}
|
||||
|
||||
considerInflictingStatus(activeBattlePokemon, activeTrackerPokemon, opponents, availableMoves, battle, aiSide)
|
||||
considerInflictingStatus(activeBattlePokemon, activeTrackerPokemon, opponents, availableMoves, battle, aiSide)?.let { return it }
|
||||
|
||||
// Protect style moves
|
||||
for (move in availableMoves) {
|
||||
@@ -430,7 +430,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
}
|
||||
}
|
||||
|
||||
findAndUseMostDamagingMove(activeBattlePokemon, activeTrackerPokemon, opponents, availableMoves, moveset, battle, aiSide)
|
||||
findAndUseMostDamagingMove(activeBattlePokemon, activeTrackerPokemon, opponents, availableMoves, moveset, battle, aiSide)?.let { return it }
|
||||
}
|
||||
|
||||
// healing wish (dealing with it here because you'd only use it if you should switch out anyway)
|
||||
@@ -450,13 +450,7 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
}
|
||||
activeTrackerPokemon.firstTurn = false
|
||||
|
||||
val move = availableMoves
|
||||
.filter { it.first.canBeUsed() }
|
||||
.filter { it.first.mustBeUsed() || it.first.target.targetList(activeBattlePokemon)?.isEmpty() != true }
|
||||
.randomOrNull()
|
||||
?: return MoveActionResponse("struggle")
|
||||
|
||||
return chooseMove(move.first, activeBattlePokemon)
|
||||
return chooseMove(randomMove.first, activeBattlePokemon)
|
||||
}
|
||||
|
||||
// estimate mid-battle switch in value
|
||||
@@ -978,12 +972,12 @@ class StrongBattleAI(skill: Int) : BattleAI {
|
||||
|
||||
val bestMove = moveValues.maxBy { it.value.second }
|
||||
val target = if (bestMove.key.first.mustBeUsed()) null else bestMove.value.first
|
||||
return MoveActionResponse(bestMove.key.first.id, target?.getPNX())
|
||||
return chooseMove(bestMove.key.first, activeBattlePokemon, target)
|
||||
}
|
||||
|
||||
private fun chooseMove(move: InBattleMove, activeBattlePokemon: ActiveBattlePokemon, target: ActiveBattlePokemon? = null): MoveActionResponse {
|
||||
val targets = if (move.mustBeUsed()) null else move.target.targetList(activeBattlePokemon)
|
||||
if (targets == null)
|
||||
if (targets.isNullOrEmpty())
|
||||
return MoveActionResponse(move.id)
|
||||
else {
|
||||
val chosenTarget = target ?: targets.filter { !it.isAllied(activeBattlePokemon) }.randomOrNull() ?: targets.random()
|
||||
|
||||
+4
-2
@@ -163,7 +163,8 @@ class TrackerActor(val uuid: UUID) {
|
||||
//we assume that AI knows it all about our allies
|
||||
trackerActor.party.addAll(actor.pokemonList.map { createAllied(it) })
|
||||
actor.activePokemon.forEach {
|
||||
val active = trackerActor.party.first { trackMon -> trackMon.id == it.battlePokemon!!.uuid }
|
||||
val battlePokemon = it.battlePokemon ?: return@forEach
|
||||
val active = trackerActor.party.first { trackMon -> trackMon.id == battlePokemon.uuid }
|
||||
trackerActor.party.remove(active)
|
||||
trackerActor.activePokemon.add(active)
|
||||
}
|
||||
@@ -176,7 +177,8 @@ class TrackerActor(val uuid: UUID) {
|
||||
//only know basics of what we see right now
|
||||
trackerActor.party.addAll(actor.pokemonList.map { createOpposing(it) })
|
||||
actor.activePokemon.forEach {
|
||||
val active = trackerActor.party.first { trackMon -> trackMon.id == it.battlePokemon!!.uuid }
|
||||
val battlePokemon = it.battlePokemon ?: return@forEach
|
||||
val active = trackerActor.party.first { trackMon -> trackMon.id == battlePokemon.uuid }
|
||||
trackerActor.party.remove(active)
|
||||
trackerActor.activePokemon.add(active)
|
||||
}
|
||||
|
||||
+2
-2
@@ -22,8 +22,8 @@ import com.cobblemon.mod.common.util.battleLang
|
||||
* @author Hunter
|
||||
* @since September 25th, 2022
|
||||
*/
|
||||
class FailInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
class FailInstruction(val battle: PokemonBattle, val message: BattleMessage): InterpreterInstruction {
|
||||
val target = message.battlePokemon(0, battle)
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting(1.5F){
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
|
||||
+11
@@ -137,6 +137,8 @@ class MoveInstruction(
|
||||
|
||||
val subsequentInstructions = instructionSet.findInstructionsCausedBy(this)
|
||||
val missedTargets = subsequentInstructions.filterIsInstance<MissInstruction>().mapNotNull { it.target }
|
||||
val failed = subsequentInstructions.any { it is FailInstruction }
|
||||
val failedTargets = subsequentInstructions.filterIsInstance<FailInstruction>().mapNotNull { it.target }
|
||||
val hitCountInstruction = subsequentInstructions.filterIsInstance<HitCountInstruction>().firstOrNull()
|
||||
|
||||
runtime.environment.query.addFunction("missed") { params ->
|
||||
@@ -148,6 +150,15 @@ class MoveInstruction(
|
||||
}
|
||||
}
|
||||
|
||||
runtime.environment.query.addFunction("failed") { params ->
|
||||
if (params.params.size == 0) {
|
||||
return@addFunction DoubleValue(failed)
|
||||
} else {
|
||||
val entityUUID = params.getString(0)
|
||||
return@addFunction DoubleValue(failedTargets.any { it.entity?.stringUUID == entityUUID })
|
||||
}
|
||||
}
|
||||
|
||||
val hurtTargets = subsequentInstructions.filterIsInstance<DamageInstruction>().mapNotNull { it.expectedTarget }
|
||||
runtime.environment.query.addFunction("hurt") { params ->
|
||||
if (params.params.size == 0) {
|
||||
|
||||
+1
@@ -66,6 +66,7 @@ class GraalShowdownService : ShowdownService {
|
||||
.allowArrayAccess(true)
|
||||
.allowListAccess(true)
|
||||
.allowMapAccess(true)
|
||||
.allowAccessAnnotatedBy(Export::class.java)
|
||||
.build()
|
||||
context = Context.newBuilder("js")
|
||||
.allowIO(true)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.block
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.apricorn.Apricorn
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.farming.ApricornHarvestEvent
|
||||
@@ -176,7 +177,7 @@ class ApricornBlock(settings: Properties, val apricorn: Apricorn) : HorizontalDi
|
||||
world.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(player, resetState))
|
||||
|
||||
if (!world.isClientSide) {
|
||||
world.playSoundServer(position = pos.toVec3d(), sound = SoundEvents.ITEM_PICKUP, volume = 0.7F, pitch = 1.4F)
|
||||
world.playSoundServer(position = pos.toVec3d(), sound = CobblemonSounds.APRICORN_HARVEST, volume = 1.0F, pitch = 1.0F)
|
||||
|
||||
if (world is ServerLevel && player is ServerPlayer) {
|
||||
CobblemonEvents.APRICORN_HARVESTED.post(ApricornHarvestEvent(player, apricorn, world, pos))
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
package com.cobblemon.mod.common.block
|
||||
|
||||
//import dev.lambdaurora.lambdynlights.util.SodiumDynamicLightHandler.pos
|
||||
import com.cobblemon.mod.common.CobblemonBlockEntities
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.berry.Berries
|
||||
import com.cobblemon.mod.common.api.berry.Berry
|
||||
@@ -40,7 +39,11 @@ import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.LevelAccessor
|
||||
import net.minecraft.world.level.LevelReader
|
||||
import net.minecraft.world.level.block.*
|
||||
import net.minecraft.world.level.block.BaseEntityBlock
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.BonemealableBlock
|
||||
import net.minecraft.world.level.block.RenderShape
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.entity.BlockEntityTicker
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||
@@ -70,7 +73,7 @@ class BerryBlock(private val berryIdentifier: ResourceLocation, settings: Proper
|
||||
override fun playerWillDestroy(world: Level, pos: BlockPos, state: BlockState, player: Player): BlockState {
|
||||
if (!player.isCreative && state.getValue(AGE) == FRUIT_AGE) {
|
||||
val treeEntity = world.getBlockEntity(pos) as BerryBlockEntity
|
||||
treeEntity.harvest(world, state, pos, player).forEach { drop -> Block.popResource(world, pos, drop) }
|
||||
treeEntity.harvest(world, state, pos, player).forEach { drop -> popResource(world, pos, drop) }
|
||||
}
|
||||
return super.playerWillDestroy(world, pos, state, player)
|
||||
}
|
||||
@@ -92,7 +95,7 @@ class BerryBlock(private val berryIdentifier: ResourceLocation, settings: Proper
|
||||
// Random Tick handler: uses time compensation to ensure correct growth speed
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun randomTick(state: BlockState, world: ServerLevel, pos: BlockPos, random: RandomSource) {
|
||||
val blockEntity = world.getBlockEntity(pos) as? BerryBlockEntity ?: return
|
||||
val blockEntity = world.getBlockEntity(pos) as? BerryBlockEntity? ?: return
|
||||
|
||||
// processTick calculates elapsed time and updates timer, returns whether growth is needed
|
||||
if (blockEntity.processTick(world, pos, state) && !world.getBlockTicks().hasScheduledTick(pos, this)) {
|
||||
@@ -128,7 +131,10 @@ class BerryBlock(private val berryIdentifier: ResourceLocation, settings: Proper
|
||||
val newAge = curAge + 1
|
||||
if (newAge > FRUIT_AGE) return
|
||||
val newState = state.setValue(AGE, newAge)
|
||||
val treeEntity = world.getBlockEntity(pos) as BerryBlockEntity
|
||||
val treeEntity = world.getBlockEntity(pos) as? BerryBlockEntity? ?: run {
|
||||
world.setBlock(pos, Blocks.AIR.defaultBlockState(), UPDATE_CLIENTS)
|
||||
return
|
||||
}
|
||||
if (curAge == MATURE_AGE) {
|
||||
treeEntity.generateGrowthPoints(world, newState, pos, null)
|
||||
determineMutation(world, random, pos, newState)
|
||||
@@ -146,7 +152,7 @@ class BerryBlock(private val berryIdentifier: ResourceLocation, settings: Proper
|
||||
for (direction in this.lookupDirections) {
|
||||
val redirectedPos = pos.offset(direction.normal)
|
||||
val redirectedState = world.getBlockState(redirectedPos)
|
||||
val berryBlock = redirectedState.block as? BerryBlock ?: continue
|
||||
val berryBlock = redirectedState.block as? BerryBlock? ?: continue
|
||||
val berry = berryBlock.berry() ?: continue
|
||||
val mutation = this.berry()?.mutationWith(berry) ?: continue
|
||||
mutations += mutation
|
||||
@@ -160,7 +166,7 @@ class BerryBlock(private val berryIdentifier: ResourceLocation, settings: Proper
|
||||
treeEntity.decrementMulchDuration(world, pos, state)
|
||||
}
|
||||
val mutation = if (random.nextInt(1000) < mutateChance) mutations.random() else null
|
||||
(world.getBlockEntity(pos) as? BerryBlockEntity)?.let { blockEntity ->
|
||||
(world.getBlockEntity(pos) as? BerryBlockEntity?)?.let { blockEntity ->
|
||||
CobblemonEvents.BERRY_MUTATION_RESULT.post(BerryMutationResultEvent(berry, world, state, pos, berryMutationOffer.mutations, mutation)) { berryMutationResult ->
|
||||
berryMutationResult.pickedMutation?.let { mutation -> blockEntity.mutate(mutation) }
|
||||
}
|
||||
@@ -178,7 +184,7 @@ class BerryBlock(private val berryIdentifier: ResourceLocation, settings: Proper
|
||||
): Boolean {
|
||||
val underBlockState = world.getBlockState(pos.below())
|
||||
val validSoil = state.getValue(IS_ROOTED) || underBlockState.`is`(CobblemonBlockTags.BERRY_SOIL)
|
||||
val treeEntity = world.getBlockEntity(pos) as? BerryBlockEntity ?: return false
|
||||
val treeEntity = world.getBlockEntity(pos) as? BerryBlockEntity? ?: return false
|
||||
return getMulch(treeEntity) == MulchVariant.NONE && state.getValue(AGE) < FLOWER_AGE && validSoil
|
||||
}
|
||||
|
||||
@@ -203,6 +209,7 @@ class BerryBlock(private val berryIdentifier: ResourceLocation, settings: Proper
|
||||
): InteractionResult {
|
||||
val treeEntity = world.getBlockEntity(pos) as BerryBlockEntity
|
||||
if (player.getItemInHand(InteractionHand.MAIN_HAND).item is ShovelItem && getMulch(treeEntity) != MulchVariant.NONE) {
|
||||
treeEntity.setMulch(MulchVariant.NONE, world, state, pos)
|
||||
treeEntity.setChanged()
|
||||
world.playSound(null, pos, CobblemonSounds.MULCH_REMOVE, SoundSource.BLOCKS, 0.6F, 1F)
|
||||
this.spawnDestroyParticles(world, player, pos, state.setValue(AGE, 0))
|
||||
@@ -352,7 +359,7 @@ class BerryBlock(private val berryIdentifier: ResourceLocation, settings: Proper
|
||||
fun getMulch(entity: BerryBlockEntity) = entity.mulchVariant
|
||||
|
||||
fun convertMulchToEntity(world: ServerLevel, state: BlockState, pos: BlockPos) {
|
||||
val entity = world.getBlockEntity(pos) as? BerryBlockEntity ?: return
|
||||
val entity = world.getBlockEntity(pos) as? BerryBlockEntity? ?: return
|
||||
if (state.getValue(MULCH) != MulchVariant.NONE && state.getValue(MULCH) != entity.mulchVariant) {
|
||||
entity.mulchVariant = state.getValue(MULCH)
|
||||
world.setBlockAndUpdate(pos, state.setValue(MULCH, MulchVariant.NONE))
|
||||
@@ -369,9 +376,9 @@ class BerryBlock(private val berryIdentifier: ResourceLocation, settings: Proper
|
||||
}
|
||||
|
||||
private fun harvestBerry(world: Level, state: BlockState, pos: BlockPos, player: Player? = null): Boolean {
|
||||
val blockEntity = world.getBlockEntity(pos) as? BerryBlockEntity ?: return false
|
||||
val blockEntity = world.getBlockEntity(pos) as? BerryBlockEntity? ?: return false
|
||||
blockEntity.harvest(world, state, pos, player).forEach { drop ->
|
||||
Block.popResource(world, pos, drop)
|
||||
popResource(world, pos, drop)
|
||||
}
|
||||
|
||||
val sound = if (player != null) CobblemonSounds.BERRY_HARVEST else SoundEvents.SHEEP_SHEAR
|
||||
|
||||
@@ -24,7 +24,6 @@ import net.minecraft.world.level.block.*
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.StateDefinition
|
||||
import net.minecraft.world.level.block.state.properties.BooleanProperty
|
||||
import net.minecraft.world.level.block.state.properties.DirectionProperty
|
||||
import net.minecraft.world.Containers
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
@@ -34,16 +33,10 @@ class DiscShelfBlock(properties: Properties) : BaseEntityBlock(properties) {
|
||||
companion object {
|
||||
val CODEC: MapCodec<DiscShelfBlock> = simpleCodec(::DiscShelfBlock)
|
||||
val FACING: DirectionProperty = HorizontalDirectionalBlock.FACING
|
||||
val SLOT_OCCUPIED_PROPERTIES = (0 until 14).map {
|
||||
BooleanProperty.create("slot_${it}_occupied")
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
val baseState = stateDefinition.any().setValue(FACING, Direction.NORTH)
|
||||
registerDefaultState(SLOT_OCCUPIED_PROPERTIES.fold(baseState) { state, prop ->
|
||||
state.setValue(prop, false)
|
||||
})
|
||||
registerDefaultState(stateDefinition.any().setValue(FACING, Direction.NORTH))
|
||||
}
|
||||
|
||||
override fun codec() = CODEC
|
||||
@@ -54,7 +47,6 @@ class DiscShelfBlock(properties: Properties) : BaseEntityBlock(properties) {
|
||||
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
|
||||
builder.add(FACING)
|
||||
SLOT_OCCUPIED_PROPERTIES.forEach { builder.add(it) }
|
||||
}
|
||||
|
||||
override fun getRenderShape(state: BlockState): RenderShape = RenderShape.MODEL
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user