Compare commits
544
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
488f38c690 | ||
|
|
d1b7dc6934 | ||
|
|
282bb4784e | ||
|
|
a8267b8ee0 | ||
|
|
81f36b2b15 | ||
|
|
73e96740d6 | ||
|
|
d53f9e5c63 | ||
|
|
560bd75fd0 | ||
|
|
8850d38820 | ||
|
|
34232b33c7 | ||
|
|
03c5a34fc8 | ||
|
|
866db3d350 | ||
|
|
ee51a8a34b | ||
|
|
2769733c51 | ||
|
|
8ae79d8e44 | ||
|
|
6f08d610eb | ||
|
|
75f3db16aa | ||
|
|
e4ee6b29ab | ||
|
|
cb6b2b9ec5 | ||
|
|
8eafe14f66 | ||
|
|
8176e14981 | ||
|
|
7d956500f2 | ||
|
|
c6853b84a6 | ||
|
|
3cb4984d51 | ||
|
|
930ed59234 | ||
|
|
3ea1918bc2 | ||
|
|
1dee9bc630 | ||
|
|
d761f2b4dc | ||
|
|
0d6028706d | ||
|
|
63d6851482 | ||
|
|
7c3158c63b | ||
|
|
e9e41933fe | ||
|
|
7c7fd6c982 | ||
|
|
6ec2820dd8 | ||
|
|
b1054bdf11 | ||
|
|
3b227ba3a2 | ||
|
|
96049abb98 | ||
|
|
d661e88a96 | ||
|
|
8510e05177 | ||
|
|
af4fe4d09d | ||
|
|
8b2ffd0f29 | ||
|
|
18cebc794b | ||
|
|
64e84dab64 | ||
|
|
9c5535a014 | ||
|
|
5993c1e588 | ||
|
|
e8f7983dd2 | ||
|
|
bdd172bd2d | ||
|
|
13842de7d6 | ||
|
|
f05e059445 | ||
|
|
038d9e858c | ||
|
|
9913826e24 | ||
|
|
8f971cc3d6 | ||
|
|
33c74372a4 | ||
|
|
5f11f4bdd6 | ||
|
|
13b4bdc204 | ||
|
|
451ae00da1 | ||
|
|
a8cc8278d3 | ||
|
|
58c0136ad1 | ||
|
|
45238058cb | ||
|
|
a326befcef | ||
|
|
52d8887514 | ||
|
|
02ae8065ac | ||
|
|
c37c608010 | ||
|
|
09c4ae96bf | ||
|
|
be466d1610 | ||
|
|
d75faae1a0 | ||
|
|
367264b06e | ||
|
|
3631fa909d | ||
|
|
fc29826bc7 | ||
|
|
202bee5690 | ||
|
|
730dc88ede | ||
|
|
4f0a667f23 | ||
|
|
f1186f469c | ||
|
|
91eeecf6e4 | ||
|
|
f6cae9d52e | ||
|
|
ed94d76e98 | ||
|
|
6e2b76d6a1 | ||
|
|
2b70b222df | ||
|
|
e9f0ef6497 | ||
|
|
8fb93dd488 | ||
|
|
b863554c84 | ||
|
|
699d6fea17 | ||
|
|
a4dd34235a | ||
|
|
8501fd3b18 | ||
|
|
52896b208e | ||
|
|
6ad6487dbe | ||
|
|
2cd066a4c1 | ||
|
|
703ccb9d8e | ||
|
|
c33d4b591e | ||
|
|
e31f2a2598 | ||
|
|
68b44db35c | ||
|
|
513c958da1 | ||
|
|
18d3fb288a | ||
|
|
725b4b7e48 | ||
|
|
28ae27b926 | ||
|
|
21e9e73eee | ||
|
|
6bfb318e2d | ||
|
|
9e1fde04ef | ||
|
|
6e4565d49b | ||
|
|
91f1523ef5 | ||
|
|
e949626f06 | ||
|
|
9678fcc009 | ||
|
|
4fbe3e406d | ||
|
|
00a1e77a9f | ||
|
|
e055dede73 | ||
|
|
b7550f7699 | ||
|
|
98cfa0ac91 | ||
|
|
f2441e7b27 | ||
|
|
46c247c742 | ||
|
|
9770d8ca6b | ||
|
|
04c3e182e7 | ||
|
|
3d99db64b9 | ||
|
|
bbcfe95bac | ||
|
|
4f07746355 | ||
|
|
82088651c2 | ||
|
|
2f0a201cf1 | ||
|
|
778f24acf1 | ||
|
|
e3ead8e3e5 | ||
|
|
9c4b9b35ab | ||
|
|
aa9c7b4f55 | ||
|
|
96e2e4a6fe | ||
|
|
20d903cffe | ||
|
|
d4383fa317 | ||
|
|
1687fa12db | ||
|
|
cf599de339 | ||
|
|
c5f92c1ad4 | ||
|
|
1d99da78e0 | ||
|
|
050a2a6a4b | ||
|
|
c80e7f4a51 | ||
|
|
f4fbdf8735 | ||
|
|
ae6091fc01 | ||
|
|
f2aa4141c0 | ||
|
|
aeded69b25 | ||
|
|
16b25a2e6e | ||
|
|
e66ebfb7a8 | ||
|
|
70e79e6fe4 | ||
|
|
b905888a0b | ||
|
|
5917e52ffc | ||
|
|
deb20cb418 | ||
|
|
797e0704e9 | ||
|
|
0b184a722b | ||
|
|
1a34c2942f | ||
|
|
2a20398b42 | ||
|
|
929e4b2391 | ||
|
|
3931295086 | ||
|
|
c593a8b7e6 | ||
|
|
d0fc166e09 | ||
|
|
78f752b4a1 | ||
|
|
b4c971398d | ||
|
|
f0f78a01e0 | ||
|
|
8c36ee15cd | ||
|
|
3231d97cd3 | ||
|
|
9fce4d3b6b | ||
|
|
550e579190 | ||
|
|
e7d710e0a3 | ||
|
|
acb86b1935 | ||
|
|
fd8e9b49b5 | ||
|
|
0f031545c1 | ||
|
|
1fdbee91df | ||
|
|
2b80189a79 | ||
|
|
2e88b0194e | ||
|
|
b0e278d1a7 | ||
|
|
9c646d9d53 | ||
|
|
bfab1d7070 | ||
|
|
e61e1390cb | ||
|
|
18151ff2f0 | ||
|
|
dd19140a83 | ||
|
|
d5b1dfa9da | ||
|
|
9f0ddf4dd3 | ||
|
|
ef3ea62ae0 | ||
|
|
6b43bf9f48 | ||
|
|
a4012895f3 | ||
|
|
7f6a3e8e87 | ||
|
|
7a84ea723f | ||
|
|
2aad33ded5 | ||
|
|
254c95fa15 | ||
|
|
5aab7f67e1 | ||
|
|
ae4decacc7 | ||
|
|
ae5a9be626 | ||
|
|
05faea4ec8 | ||
|
|
05edd34db6 | ||
|
|
c198f8fccd | ||
|
|
521f9aaafa | ||
|
|
8d38505993 | ||
|
|
7c5fab02a8 | ||
|
|
7e5a267c89 | ||
|
|
5b23b0cfbe | ||
|
|
778ceff183 | ||
|
|
f32050c8b5 | ||
|
|
3522bac72a | ||
|
|
ecf037666f | ||
|
|
618d062ca9 | ||
|
|
49841b40ec | ||
|
|
87141e1137 | ||
|
|
1f962d664f | ||
|
|
09797f25b1 | ||
|
|
3911413c69 | ||
|
|
e075e60231 | ||
|
|
acdd98573b | ||
|
|
12f3e7b78b | ||
|
|
a462fe5efc | ||
|
|
2390662fc8 | ||
|
|
1bd5d2372f | ||
|
|
12f6bb55c2 | ||
|
|
fdb37ba5e8 | ||
|
|
7a99845d0f | ||
|
|
54d183c8d3 | ||
|
|
29713bbe1f | ||
|
|
247052ee67 | ||
|
|
14b7e93965 | ||
|
|
85a4793a1e | ||
|
|
29f6524c49 | ||
|
|
1e617a684b | ||
|
|
c9a0352a7c | ||
|
|
1a5808e5a6 | ||
|
|
f14d242907 | ||
|
|
4998ee2c5b | ||
|
|
be96e45c4e | ||
|
|
015402d54b | ||
|
|
6f697d2b9a | ||
|
|
f18752d484 | ||
|
|
5876c02d44 | ||
|
|
c890f6910c | ||
|
|
d157536e1e | ||
|
|
dac2d9e96e | ||
|
|
5c71680db9 | ||
|
|
5f5c036f8d | ||
|
|
1f16c2d542 | ||
|
|
2da9dc50f7 | ||
|
|
092f9ef9f9 | ||
|
|
2f12b05d43 | ||
|
|
42eb08e715 | ||
|
|
03470aa623 | ||
|
|
4299aff1bf | ||
|
|
fb90ccb86e | ||
|
|
c112f9615c | ||
|
|
fc882190fe | ||
|
|
15d7cd815d | ||
|
|
6b5969fff6 | ||
|
|
5053c633b7 | ||
|
|
c4294697e6 | ||
|
|
dfa1c5e369 | ||
|
|
51f3b4357d | ||
|
|
220a9741ae | ||
|
|
48a9446f73 | ||
|
|
f1edfc453e | ||
|
|
8d612ec395 | ||
|
|
6d9daf3cf6 | ||
|
|
c7ecfc74de | ||
|
|
fefdfd877b | ||
|
|
35fb170225 | ||
|
|
d2e405131f | ||
|
|
b6ec0205ef | ||
|
|
e57a42e755 | ||
|
|
f34a03c8d6 | ||
|
|
8b1599705f | ||
|
|
e7f6fc32c4 | ||
|
|
5119617f00 | ||
|
|
6e84efb53c | ||
|
|
de3191b768 | ||
|
|
76ec4b4d5a | ||
|
|
25702ade61 | ||
|
|
c6da88d0b2 | ||
|
|
c4acc09fbd | ||
|
|
53b434906b | ||
|
|
b22a31909d | ||
|
|
cbbbacc215 | ||
|
|
d22d81209d | ||
|
|
89b989c46c | ||
|
|
714d51b26e | ||
|
|
8571d78894 | ||
|
|
72c57fde39 | ||
|
|
fc5c479f31 | ||
|
|
d3c54924be | ||
|
|
65c5e95ddf | ||
|
|
fc1dec6b4b | ||
|
|
7604af9308 | ||
|
|
ab1e138ace | ||
|
|
62ee94c71d | ||
|
|
0fae95aabc | ||
|
|
bbfd864b33 | ||
|
|
b107d76762 | ||
|
|
8d4f10349c | ||
|
|
f36787e67f | ||
|
|
fc198c599e | ||
|
|
26f753880c | ||
|
|
a9ebb0b6f2 | ||
|
|
a7158ee57a | ||
|
|
06c3fd3f09 | ||
|
|
4e196e8a29 | ||
|
|
871f33f442 | ||
|
|
21c1f912a7 | ||
|
|
a0d9ce12a6 | ||
|
|
c07173fc0f | ||
|
|
3faf8ac302 | ||
|
|
e85b3f3cc5 | ||
|
|
251a09f78c | ||
|
|
776fb5413f | ||
|
|
f645fd9b60 | ||
|
|
ac161ae5b4 | ||
|
|
fc3542e3eb | ||
|
|
7c44dd204e | ||
|
|
88932c8c41 | ||
|
|
411f98d0ae | ||
|
|
02a1929ede | ||
|
|
ff90059eec | ||
|
|
eca14f61ac | ||
|
|
9ccf2bb9ad | ||
|
|
d09d636113 | ||
|
|
ff335f779f | ||
|
|
b70316e347 | ||
|
|
eacb0fe587 | ||
|
|
1752588cbc | ||
|
|
9e09ac52fc | ||
|
|
845ade1aeb | ||
|
|
f6bd04f016 | ||
|
|
afa1d9af8b | ||
|
|
bf6db8b745 | ||
|
|
a352e67c1b | ||
|
|
71297dfb3a | ||
|
|
9141694c2a | ||
|
|
9aef7b9c3b | ||
|
|
c5bebb1abb | ||
|
|
990fed2fe0 | ||
|
|
4a30bb3b04 | ||
|
|
fe77a3cd30 | ||
|
|
de9e1949fe | ||
|
|
fac8c5f510 | ||
|
|
2d077c607a | ||
|
|
f75e3d11da | ||
|
|
f46968f878 | ||
|
|
3439aeff1e | ||
|
|
1f8fa8cae3 | ||
|
|
42e405530c | ||
|
|
2ada7e0b68 | ||
|
|
b8f73f277d | ||
|
|
7f6197ab8b | ||
|
|
6df2b996e2 | ||
|
|
ddc4bd358d | ||
|
|
e197287775 | ||
|
|
be019c79df | ||
|
|
73fe851c58 | ||
|
|
8544744530 | ||
|
|
32d7bfcef3 | ||
|
|
27263cd057 | ||
|
|
55f0962205 | ||
|
|
63143832e0 | ||
|
|
29215f5c0c | ||
|
|
70bf3e7805 | ||
|
|
40c5df46ce | ||
|
|
b4d9d1b963 | ||
|
|
e753c75c31 | ||
|
|
4e96222a4d | ||
|
|
4ee90d4cfb | ||
|
|
540cd612c1 | ||
|
|
c76dfc3130 | ||
|
|
1b1d22fdf3 | ||
|
|
1ee1001774 | ||
|
|
533272ef09 | ||
|
|
cf5e1bf142 | ||
|
|
4b8196685a | ||
|
|
d1053468bf | ||
|
|
f0c41865db | ||
|
|
cca9de04a7 | ||
|
|
2b2264bdca | ||
|
|
78d47004bf | ||
|
|
30f97e6243 | ||
|
|
d117d79d28 | ||
|
|
1e32f7b80a | ||
|
|
3d4d797e7f | ||
|
|
39feb9cf6c | ||
|
|
8f53757879 | ||
|
|
e1d2f125d6 | ||
|
|
cfc8edfa9e | ||
|
|
fa3ed69ee2 | ||
|
|
417b49beda | ||
|
|
a2f6a35227 | ||
|
|
b9f1cc5883 | ||
|
|
ad132fe729 | ||
|
|
f33892fcd1 | ||
|
|
91300e4d03 | ||
|
|
2a56709395 | ||
|
|
fc135faf57 | ||
|
|
8c02ca3576 | ||
|
|
cdd72c664e | ||
|
|
5f025d0f68 | ||
|
|
6af2c807ab | ||
|
|
c45c90c6c7 | ||
|
|
1ec97c4c90 | ||
|
|
f0bcd38ac7 | ||
|
|
f4ba446c79 | ||
|
|
60f98ebfce | ||
|
|
08c2a0d07b | ||
|
|
1f68fdac8c | ||
|
|
e8d4f0fcf4 | ||
|
|
36a93bda5a | ||
|
|
5d522bd608 | ||
|
|
8d60b07c54 | ||
|
|
5f9cc86044 | ||
|
|
35436c1d09 | ||
|
|
a6b7e07cf5 | ||
|
|
0ba6215b8d | ||
|
|
e2f6fae689 | ||
|
|
296aa01d0f | ||
|
|
12ab3f2d07 | ||
|
|
5a7a374bc9 | ||
|
|
ceece45ad4 | ||
|
|
b344ad66c5 | ||
|
|
d66793d186 | ||
|
|
cc00962752 | ||
|
|
dbc7af4ad4 | ||
|
|
5f5bf01cb5 | ||
|
|
04f2af22f3 | ||
|
|
ea916a0db8 | ||
|
|
3f03afc7eb | ||
|
|
e940483863 | ||
|
|
9e3d3df3a9 | ||
|
|
c18368d777 | ||
|
|
3894a99bc4 | ||
|
|
aab5b55204 | ||
|
|
3e6e346eb9 | ||
|
|
3a83ed424f | ||
|
|
7bef6db7b7 | ||
|
|
71775328ef | ||
|
|
cbccc612a4 | ||
|
|
63fd5d90c1 | ||
|
|
92336d6107 | ||
|
|
727785b0b3 | ||
|
|
762241420e | ||
|
|
93011f084b | ||
|
|
7c90a8425e | ||
|
|
8674cbe788 | ||
|
|
8075fe0bae | ||
|
|
f3f29ca0ea | ||
|
|
0152803192 | ||
|
|
2544cbc252 | ||
|
|
5e094241e3 | ||
|
|
bd028c328d | ||
|
|
598cb1d964 | ||
|
|
79d264fd94 | ||
|
|
5f691d3f1c | ||
|
|
7be0163e76 | ||
|
|
c0b3068824 | ||
|
|
9036a2f317 | ||
|
|
dd35adc05d | ||
|
|
26b5707317 | ||
|
|
75e39f5595 | ||
|
|
7fdeaeabef | ||
|
|
c75ab28002 | ||
|
|
809ffd8b90 | ||
|
|
da7610951d | ||
|
|
62a8320068 | ||
|
|
f21b38f66a | ||
|
|
76fdd1fa98 | ||
|
|
596765bb52 | ||
|
|
297aafba45 | ||
|
|
156983bf58 | ||
|
|
c69930b836 | ||
|
|
6926932340 | ||
|
|
221b3308fa | ||
|
|
66840670b6 | ||
|
|
28887d9116 | ||
|
|
6ef1bac1d7 | ||
|
|
5d6a7807e5 | ||
|
|
20b7eb17f3 | ||
|
|
a0a682e224 | ||
|
|
103ac86345 | ||
|
|
8f705a698d | ||
|
|
f4fb09947e | ||
|
|
97e31e341b | ||
|
|
813789235d | ||
|
|
d161b11892 | ||
|
|
5a82e7e185 | ||
|
|
3bc8d3ce75 | ||
|
|
d9e9fd0f4e | ||
|
|
fddb203db3 | ||
|
|
8a8cace5e8 | ||
|
|
5f5b4ee3c1 | ||
|
|
aa6581ae39 | ||
|
|
8aa9e0191f | ||
|
|
8dc09796f8 | ||
|
|
8f93712edb | ||
|
|
b91d1b931e | ||
|
|
9d84cbb3ac | ||
|
|
8e730f2b5c | ||
|
|
7b5809fd55 | ||
|
|
bc682ddf62 | ||
|
|
990ead0544 | ||
|
|
4cf55dc95d | ||
|
|
27a9f3c704 | ||
|
|
d70bb243b2 | ||
|
|
301a3efb7c | ||
|
|
05b7cbe20a | ||
|
|
48cbbc1bef | ||
|
|
f8f7c28274 | ||
|
|
0ebb53888a | ||
|
|
83aba7e4a6 | ||
|
|
c0071c1525 | ||
|
|
71f7b3b3d8 | ||
|
|
bd6d7b7149 | ||
|
|
73275626a3 | ||
|
|
0686428138 | ||
|
|
f05e6008e5 | ||
|
|
63de8fe44a | ||
|
|
4450164d9c | ||
|
|
b99899353c | ||
|
|
608b711833 | ||
|
|
3adc1b9f30 | ||
|
|
478cbc2489 | ||
|
|
03edb5a385 | ||
|
|
cf77713860 | ||
|
|
0494193c9b | ||
|
|
7bee34170d | ||
|
|
3a22e387b6 | ||
|
|
956b3bfcbd | ||
|
|
a9ceddd94a | ||
|
|
e99c55e812 | ||
|
|
5053d559bc | ||
|
|
1a30109f1c | ||
|
|
5088497575 | ||
|
|
31129ef14d | ||
|
|
17c71efb17 | ||
|
|
e80eb91e69 | ||
|
|
a5b6a954fd | ||
|
|
2a295a8796 | ||
|
|
245226f4f6 | ||
|
|
d3e1c2c79d | ||
|
|
e04e82c6de | ||
|
|
95589dd48b | ||
|
|
4cb17135bd | ||
|
|
8dc23160fc | ||
|
|
4a96a41c8e | ||
|
|
3f18e7c0bf | ||
|
|
3c3a23a397 | ||
|
|
438de6ed6d | ||
|
|
95399a32a8 | ||
|
|
7089ff68d4 | ||
|
|
c754d820a5 | ||
|
|
81c819ddd3 | ||
|
|
ec3e0bfd04 | ||
|
|
b61d739e46 | ||
|
|
7a050d5374 | ||
|
|
52076de76a | ||
|
|
be8dfd7fa2 |
No files matched your search
+2
-1
@@ -12,7 +12,8 @@ out
|
||||
*.ipr
|
||||
*.iws
|
||||
*.iml
|
||||
.idea
|
||||
.idea/*
|
||||
!.idea/icon.png
|
||||
|
||||
# gradle
|
||||
build
|
||||
|
||||
Generated
BIN
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
@@ -12,6 +12,14 @@
|
||||
- SpawningContext is now SpawnablePosition
|
||||
- WorldSlice is SpawningZone
|
||||
- SpawningProspector is now SpawningZoneGenerator
|
||||
- Majorly refactored the hierarchy of Spawner
|
||||
- The base Spawner interface provides more functions to allow single-point and area spawning given appropriate inputs.
|
||||
- TickingSpawner is removed in favour of outside code handling ticking logic.
|
||||
- AreaSpawner is removed.
|
||||
- BasicSpawner is the first implementation of Spawner which can be used for any purpose.
|
||||
- PlayerSpawners are now mixin'd into ServerPlayer and ticked from ServerPlayer#tick.
|
||||
- A hierarchy diagram can be found at `./docs/spawner-hierarchy.png` in the mod repository.
|
||||
- The SpawnerManager class has been removed as its functionality is all now handled elsewhere.
|
||||
- Renamed things in Spawn Rules to go with the other renames:
|
||||
- contextSelector is now spawnablePositionSelector
|
||||
- contextSelector is now spawnablePositionSelector
|
||||
- context is now spawnable_position
|
||||
+94
-2
@@ -34,10 +34,11 @@
|
||||
- Added Hyper Training items (IV Modification) as well as some additional candy items to do so (Health Candy, Sickly Candy)
|
||||
- Added Galarica Nut Bushes
|
||||
- Many Pokémon (mostly cats) are now feared by phantoms
|
||||
- Combees are now capable of gathering nectar from flowers and delivering it to either Saccharine leaves or hives. (Hive interactions are restricted to wild Combees)
|
||||
- Lightning is now affected by a Pokemon's ability/typing
|
||||
- Pokémon with the ability Lightning Rod draw in lightning similar to a lightning rod block albeit with a lower priority and range, gain immunity to lightning damage, and receive a temporary damage buff.
|
||||
- Pokémon with the ability Motor Drive are immune to lightning damage and receive a temporary speed buff when struck by lightning
|
||||
- Pokémon with the ability Volt Absorb are immune to lightning damage and receive Regeneration II for a short duration
|
||||
- Pokémon with the ability Volt Absorb are immune to lightning damage and receive Instant Health II for a short duration
|
||||
- Ground type Pokémon are immune to lightning damage
|
||||
- Added functionality to Everstone when held by a Pokémon; suppresses evolution notification and hides evolve button in summary interface.
|
||||
- Added optional `filePath` parameter to MoLang functions to allow for global stores (ex. `../global/`). Path must end in a forward slash.
|
||||
@@ -48,11 +49,18 @@
|
||||
- Berries can now be smelted into their respective dyes.
|
||||
- Added Syrupy Apples.
|
||||
- Added `/runmolang <molang> [<npc>|<player>|<pokemon>]` command that executes a MoLang expression with the provided options as environment variables, as well as the entity (as `q.entity`) that executed the command.
|
||||
- Added new 69th berry, Eggant.
|
||||
- Added bubble quirk to Kingler; like Krabby, Kingler will blows bubbles during dusk.
|
||||
- Added `.Pre` and `.Post` to the following events:
|
||||
- `PokemonRecallEvent`
|
||||
- `TradeEvent`
|
||||
- Added a new gamerule, 'healerHealsPC', when set to true a successful use of a healer will also heal all of the Pokemon in that player's PC.
|
||||
- Mooshtanks will switch between their red and brown variant when hit by lightning
|
||||
- Smeargle spawns with differing tail colour depending on its [Characteristic](https://bulbapedia.bulbagarden.net/wiki/Characteristic) stat
|
||||
- Added smooth level-up animations to the party overlay to replace chat messages.
|
||||
- Added `min_perfect_ivs` property to PokemonProperties to specify the minimum number of perfect IVs of the Pokemon.
|
||||
- Added `defaultKeyItems` config option to specify which key items players always have.
|
||||
- Added `scale_modifier` property to PokemonProperties to modify the scale of the Pokemon.
|
||||
|
||||
### Pokémon Added
|
||||
|
||||
@@ -84,6 +92,8 @@
|
||||
- Altaria
|
||||
- Snorunt
|
||||
- Glalie
|
||||
- Shuppet
|
||||
- Banette
|
||||
- Latias
|
||||
- Latios
|
||||
|
||||
@@ -132,6 +142,11 @@
|
||||
- Swadloon
|
||||
- Leavanny
|
||||
- Druddigon
|
||||
- Minccino
|
||||
- Cinccino
|
||||
- Vanillite
|
||||
- Vanillish
|
||||
- Vanilluxe
|
||||
|
||||
#### Gen 6
|
||||
- Skiddo
|
||||
@@ -293,6 +308,24 @@
|
||||
- Tauros - Paldea Blaze
|
||||
- Tauros - Paldea Combat
|
||||
- Dewgong
|
||||
- Exeggutor - Kanto
|
||||
- Corphish (updated placeholders for crustaceous tripod gait legs)
|
||||
- Crawdaunt (updated placeholders for crustaceous bipedal legs)
|
||||
- Dragapult
|
||||
- Camerupt
|
||||
- Relicanth
|
||||
- Heracross
|
||||
- Salamence
|
||||
- Staraptor
|
||||
- Dusknoir
|
||||
- Arcanine
|
||||
- Carvanha
|
||||
- Sharpedo
|
||||
- Mimikyu
|
||||
- Dewgong
|
||||
- Mime Jr
|
||||
- Gyarados
|
||||
- Lapras
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
- Cleffa
|
||||
@@ -320,6 +353,8 @@
|
||||
- Nosepass
|
||||
- Probopass
|
||||
- Kangaskhan
|
||||
- Scorbunny
|
||||
- Raboot
|
||||
- Cinderace
|
||||
- Magnemite
|
||||
- Magneton
|
||||
@@ -403,6 +438,21 @@
|
||||
- Revavroom
|
||||
- Nickit
|
||||
- Thievul
|
||||
- Litwick
|
||||
- Lampent
|
||||
- Chandelure
|
||||
- Rayquaza
|
||||
- Aerodactyl
|
||||
- Basculin
|
||||
- Basculegion
|
||||
- Shroodle
|
||||
- Grafaiai
|
||||
- Steelix
|
||||
- Dratini
|
||||
- Dragonair
|
||||
- Dragonite
|
||||
- Cutiefly
|
||||
- Ribombee
|
||||
|
||||
### Changes
|
||||
- Changed pokemon caught and seen count to update based on the current pokedex being looked
|
||||
@@ -416,6 +466,8 @@
|
||||
- Updated some item tags to better integrate behaviours between Cobblemon, Vanilla Minecraft, and other mods
|
||||
- Removed Cooked Meat, Raw Meat, Protein Ingredients, and Zinc Ingredients, the first two are now using `c` namespace tags, the latter have better integrated use of tags within their recipes which removes need for custom tags.
|
||||
- Added our seeds tag into `#c:seeds`, which is now made use of for the Miracle Seed recipe.
|
||||
- Updated the `#cobblemon:berries` tag to use subtags located in `data/cobblemon/tags/item/berries`, such as `#cobblemon:berries/hp_recovery` for sorting purposes
|
||||
- Moved the tag `#cobblemon:mutated_berries` to `#cobblemon:berries/mutation_result`
|
||||
- Added herbs and snowballs to the consumable in PvE and Wild battle tags
|
||||
- Tweaked the Natural Materials Vanilla file to fit with the changes to tags
|
||||
- Substantially optimised spawning checks mainly by front-loading biome filtering.
|
||||
@@ -467,6 +519,10 @@
|
||||
- Updated `HatchEggEvent.Post` to include the Pokemon that hatched.
|
||||
- Roseli Berry Trees now naturally generate in their preferred biomes.
|
||||
- Refactored dynamic lights compat to be more future proof. The dynamic light support is only tested with LambDynamicLights, on NeoForged use that mod in combination with Sinytra Connector
|
||||
- Shulker Boxes and Traveler's Backpacks AND Packed Up backpacks can no longer be held by Pokémon. Thanks Monocle ;) You could re-enable this with our datapack (but you'd be crazy).
|
||||
- Moomoo Milk now clears Pokémon stat changes when used in battle.
|
||||
- Updated Evolution Stone Block light levels
|
||||
- Added light levels to Evolution Stone Ores. These levels are reduced versions of the full blocks light levels
|
||||
|
||||
### Fixes
|
||||
- Fixed game crashing when removing national pokedex using datapacks
|
||||
@@ -551,6 +607,11 @@
|
||||
- Fixed singular Pokémon corruption causing entire storage corruption. Storages will now skip corrupted Pokémon and print an error to console.
|
||||
- Fixed species additions not being able to properly mark a species as implemented.
|
||||
- Fixed Pokémon item models not showing a glint when enchanted.
|
||||
- Fixed some specific bag items not being dropped when used in battle.
|
||||
- The Corphish line will now sink in water.
|
||||
- Fixed the "use all berry bait" achievement not being progressed
|
||||
- Fixed bobber hook and berry sprouts texture sizes causing mipmap issues.
|
||||
- Fixed head locator not taking into account scale for positioning.
|
||||
|
||||
### Developer
|
||||
- A finished battle now has winners and losers set inside of `PokemonBattle` instead of them always being empty.
|
||||
@@ -588,10 +649,34 @@
|
||||
- Added a `hoverText` option to PartySelectCallback, to display a tooltip on hovering over a Pokémon in the selection screen.
|
||||
- `PokemonEntity` instances spawned into the world now appropriately finalize the spawn for mod compatibility.
|
||||
- Added PokedexManager.obtain as a replacement for .catch which is not a friendly function name in Java.
|
||||
|
||||
- Added `Pokemon#hyperTrainIV()` and `IVs#setHyperTrainedIV(Stat, Int)`
|
||||
- `ElementalType` now implements `ShowdownIdentifiable` to ensure the communcation with showdown stays consistent (also in regards to TeraTypes)
|
||||
- Pokemon no longer have a change observable
|
||||
- Pokémon can now have a behaviour changing the value of a species feature on lightning hit:
|
||||
```JSON
|
||||
{
|
||||
"behaviour": {
|
||||
"lightningHit": {
|
||||
"rotateFeatures": [
|
||||
{
|
||||
"key": "mooshtank",
|
||||
"chain": ["red", "brown"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
This will change the value of `mooshtank` from `red` to `brown` and vice versa when a lightning strikes this Pokémon. Only chains of which a value is the current value will be considered, so multiple entries for the same key with different chains can be added.
|
||||
- Removed Npc interface from NPCEntity, the interface is unused and in vanilla is only implemented by VillagerEntity as a means to disable villagers with the `spawn-npcs` server property.
|
||||
- Added new `Observable#subscribe` methods that take Java Consumers to make usage in Java a little cleaner.
|
||||
- Annotated a bunch of Kotlin methods and fields for cleaner Java names.
|
||||
- Added `PartyStore#isEmpty()`.
|
||||
- Added `ElementalTypes#getRandomType()`.
|
||||
- Added `IVs#getEffectiveBattleTotal()`.
|
||||
- Added `IVs.MAX_TOTAL` constant.
|
||||
- Added `PokemonStats#total()`.
|
||||
- Add `NatureAdapter` for serializing and deserializing Natures using Gson.
|
||||
|
||||
### MoLang & Datapacks
|
||||
- The following usages for item predicates can now use item conditions like advancements do, you can learn about them in the [Minecraft wiki](https://minecraft.wiki/w/Advancement_definition#minecraft:filled_bucket)
|
||||
@@ -695,6 +780,12 @@
|
||||
- Mechanics
|
||||
- Unlockable Wallpapers
|
||||
- Starter Data
|
||||
- Fixed `cobblemon:reel_in_pokemon` criteria not working when used together with a `baitId`
|
||||
- Also changed the default from `cobblemon:empty_bait` to `any`
|
||||
- The previous default is still available by using the above as baitId
|
||||
- Added support for species-specific move action effects, using the format `{move_id}_{species}.json`.
|
||||
- Added `look_at_entity_types` variable for look_at_entities to specify what entity type or entity tag to look at.
|
||||
- Added `Looks At Players` behaviour preset that only sets the look target to players.
|
||||
|
||||
### Particles
|
||||
Added new/updated particles for the following moves:
|
||||
@@ -990,6 +1081,7 @@ Added new/updated particles for the following moves:
|
||||
- Parametric particle motion now works.
|
||||
- Event-spawned particles now work.
|
||||
- Particles can now have independent coordinate spaces.
|
||||
- Fixed suffocation of Pokémon when a pokeball breaks near a wall
|
||||
|
||||
### Developer
|
||||
- Updated the Pokédex data updated events to always include a `Pokemon` instance, and optionally a `DisguiseData` instance.
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common;
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner;
|
||||
|
||||
/**
|
||||
* Used for mixin shenanigans. ServerPlayers now store their Cobblemon spawner
|
||||
* inside, so this interface helps execute that.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 27th, 2025
|
||||
*/
|
||||
public interface PlayerSpawnerAccessor {
|
||||
PlayerSpawner getPlayerSpawner();
|
||||
void setPlayerSpawner(PlayerSpawner spawner);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.duck;
|
||||
|
||||
import com.mongodb.lang.Nullable;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
public interface CameraDuck {
|
||||
BlockGetter cobblemon$getLevel();
|
||||
|
||||
@Nullable
|
||||
Entity cobblemon$getEntity();
|
||||
|
||||
Quaternionf cobblemon$getRotation();
|
||||
|
||||
Vector3f cobblemon$getForwards();
|
||||
|
||||
Vector3f cobblemon$getUp();
|
||||
|
||||
Vector3f cobblemon$getLeft();
|
||||
|
||||
float cobblemon$getXRot();
|
||||
void cobblemon$setXRot(float xRot);
|
||||
|
||||
float cobblemon$getYRot();
|
||||
void cobblemon$setYRot(float yRot);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.duck;
|
||||
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public interface RidePassenger {
|
||||
void cobblemon$setRideXRot(float rideXRot);
|
||||
float cobblemon$getRideXRot();
|
||||
void cobblemon$setRideYRot(float rideYRot);
|
||||
float cobblemon$getRideYRot();
|
||||
void cobblemon$setRideEyePos(Vec3 rideEyePos);
|
||||
Vec3 cobblemon$getRideEyePos();
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.projectile.AbstractArrow;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(AbstractArrow.class)
|
||||
public abstract class AbstractArrowMixin {
|
||||
|
||||
@Inject(
|
||||
method = "<init>(Lnet/minecraft/world/entity/EntityType;Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/level/Level;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/item/ItemStack;)V",
|
||||
at = @At("TAIL")
|
||||
)
|
||||
private void cobblemon$adjustSpawnPosition(
|
||||
EntityType<? extends AbstractArrow> entityType,
|
||||
LivingEntity owner,
|
||||
Level level,
|
||||
ItemStack pickupItemStack,
|
||||
@Nullable ItemStack firedFromWeapon,
|
||||
CallbackInfo ci
|
||||
) {
|
||||
AbstractArrow arrow = (AbstractArrow)(Object)this;
|
||||
if(!(owner.getVehicle() instanceof OrientationControllable vehicle)) return;
|
||||
if(!(vehicle instanceof PokemonEntity)) return;
|
||||
var vehicleController = vehicle.getOrientationController();
|
||||
|
||||
// If this is a pokemon ride passenger then use the rider eye position to set the arrow spawn position.
|
||||
if (owner instanceof RidePassenger ridePassenger && vehicleController != null ) {
|
||||
var eyePos = ridePassenger.cobblemon$getRideEyePos(); //.add(0.0, -2.0, 0.0);
|
||||
arrow.setPos(eyePos);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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.CobblemonMemories;
|
||||
import com.cobblemon.mod.common.api.ai.config.task.PathToBeeHiveTaskConfig;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.item.component.CustomData;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.BeehiveBlock;
|
||||
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
|
||||
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Mixin(BeehiveBlockEntity.Occupant.class)
|
||||
public abstract class BeeOccupantMixin {
|
||||
|
||||
@Inject(method = "createEntity", at = @At("RETURN"), cancellable = true)
|
||||
private void cobblemon$createEntity(Level level, BlockPos pos, CallbackInfoReturnable<Entity> cir) {
|
||||
// Needing to replicate all the post op stuff on the hive isn't great
|
||||
if (cir.getReturnValue() == null) {
|
||||
final BeehiveBlockEntity.Occupant occupant = (BeehiveBlockEntity.Occupant) (Object) this;
|
||||
CompoundTag compoundTag = occupant.entityData().copyTag();
|
||||
Entity entity = EntityType.loadEntityRecursive(compoundTag, level, (entityx) -> entityx);
|
||||
if (entity instanceof PokemonEntity pokemonEntity) {
|
||||
var state = level.getBlockState(pos);
|
||||
var newPos = Vec3.ZERO;
|
||||
var newYaw = 0f;
|
||||
var brain = pokemonEntity.getBrain();
|
||||
if (state.is(BlockTags.BEEHIVES)) {
|
||||
// position in front of the entrance, face away from the block
|
||||
var facing = state.getValue(HorizontalDirectionalBlock.FACING);
|
||||
newPos = pos.relative(facing).getCenter();
|
||||
newYaw = facing.toYRot();
|
||||
brain.setMemory(CobblemonMemories.HIVE_LOCATION, pos); // This needs to be set in the case that the hive was picked up and moved.
|
||||
} else {
|
||||
// Block has likely been destroyed
|
||||
var center = pos.getCenter();
|
||||
newPos = new Vec3(
|
||||
center.x + level.random.nextFloat() * 0.6 - 0.3,
|
||||
center.y + level.random.nextFloat() * 0.6 - 0.3,
|
||||
center.z + level.random.nextFloat() * 0.6 - 0.3
|
||||
);
|
||||
newYaw = level.random.nextFloat() * 360F;
|
||||
brain.eraseMemory(CobblemonMemories.HIVE_LOCATION);
|
||||
}
|
||||
entity.yRotO = newYaw;
|
||||
entity.setPos(newPos);
|
||||
// Do honey logic
|
||||
var hasNectar = brain.getMemory(CobblemonMemories.HAS_NECTAR).orElse(false);
|
||||
if (hasNectar) {
|
||||
// Remove nectar and reset got to hive cooldown
|
||||
brain.eraseMemory(CobblemonMemories.HAS_NECTAR);
|
||||
brain.setMemoryWithExpiry(CobblemonMemories.HIVE_COOLDOWN, true, PathToBeeHiveTaskConfig.STAY_OUT_OF_HIVE_COOLDOWN);
|
||||
// Increment honey level of the hive
|
||||
if (state.is(BlockTags.BEEHIVES, (blockStateBase) -> blockStateBase.hasProperty(BeehiveBlock.HONEY_LEVEL))) {
|
||||
int i = state.getValue(BeehiveBlock.HONEY_LEVEL);
|
||||
if (i < 5) {
|
||||
int j = level.random.nextInt(100) == 0 ? 2 : 1;
|
||||
if (i + j > 5) {
|
||||
--j;
|
||||
}
|
||||
level.setBlockAndUpdate(pos, state.setValue(BeehiveBlock.HONEY_LEVEL, i + j));
|
||||
}
|
||||
}
|
||||
}
|
||||
cir.setReturnValue(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "of", at = @At("HEAD"), cancellable = true)
|
||||
private static void cobblemon$of(Entity entity, CallbackInfoReturnable<BeehiveBlockEntity.Occupant> cir) {
|
||||
if (entity instanceof PokemonEntity pokemonEntity) {
|
||||
List<String> IGNORED_BEE_TAGS = Arrays.asList("Air", "ArmorDropChances", "ArmorItems", "Brain", "CanPickUpLoot", "DeathTime", "FallDistance", "FallFlying", "Fire", "HandDropChances", "HandItems", "HurtByTimestamp", "HurtTime", "LeftHanded", "Motion", "NoGravity", "OnGround", "PortalCooldown", "Pos", "Rotation", "Passengers", "leash", "UUID");
|
||||
CompoundTag compoundTag = new CompoundTag();
|
||||
entity.save(compoundTag);
|
||||
Objects.requireNonNull(compoundTag);
|
||||
IGNORED_BEE_TAGS.forEach(compoundTag::remove);
|
||||
Boolean hasNectar = pokemonEntity.getBrain().getMemory(CobblemonMemories.HAS_NECTAR).orElse(false);
|
||||
cir.setReturnValue(new BeehiveBlockEntity.Occupant(CustomData.of(compoundTag), 0, hasNectar ? 2400 : 600));
|
||||
cir.cancel();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.mixin.accessor.BeeDataAccessor;
|
||||
import com.cobblemon.mod.common.mixin.accessor.BeehiveBlockEntityAccessor;
|
||||
import com.cobblemon.mod.common.mixin.accessor.BlockEntityAccessor;
|
||||
import com.google.common.collect.Lists;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(BeehiveBlockEntity.class)
|
||||
public abstract class BeehiveBlockEntityMixin {
|
||||
|
||||
|
||||
// Accessor for the private 'stored' field in BeehiveBlockEntity
|
||||
@Accessor("stored")
|
||||
public abstract List<BeeDataAccessor> getStored();
|
||||
|
||||
@Inject(method = "emptyAllLivingFromHive", at = @At("HEAD"))
|
||||
private void cobblemon$emptyAllLivingFromHive(@Nullable Player player, BlockState state, BeehiveBlockEntity.BeeReleaseStatus releaseStatus, CallbackInfo ci) {
|
||||
if (player != null) {
|
||||
final BeehiveBlockEntity blockEntity = (BeehiveBlockEntity) (Object) this;
|
||||
// if the block is sedated or the player is too far away, no aggro should be applied
|
||||
if (blockEntity.isSedated() || player.position().distanceToSqr(blockEntity.getBlockPos().getCenter()) > 16.0)
|
||||
return;
|
||||
// from this point need to access private members of the block entity
|
||||
final BeehiveBlockEntityAccessor blockEntityAccessor = (BeehiveBlockEntityAccessor) this;
|
||||
List<Object> storedList = blockEntityAccessor.getStored();
|
||||
|
||||
List<Entity> list = Lists.newArrayList();
|
||||
storedList.removeIf((beeData) -> {
|
||||
BeehiveBlockEntity.Occupant occupant = ((BeeDataAccessor) beeData).invokeToOccupant();
|
||||
// Checking the for the tag allows us to make sure it's one of our pokemon before trying to rehydrate it into an entity
|
||||
boolean isPokemon = false;
|
||||
if (occupant.entityData().contains("id")) {
|
||||
isPokemon = "cobblemon:pokemon".equals(occupant.entityData().getUnsafe().getString("id"));
|
||||
}
|
||||
if (isPokemon) {
|
||||
return BeehiveBlockEntityAccessor.releaseOccupant(
|
||||
((BlockEntityAccessor) blockEntityAccessor).getLevel(),
|
||||
((BlockEntityAccessor) blockEntityAccessor).getWorldPosition(),
|
||||
state,
|
||||
occupant,
|
||||
list,
|
||||
releaseStatus,
|
||||
blockEntityAccessor.savedFlowerPos());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
);
|
||||
for (Entity entity : list) {
|
||||
if (entity instanceof PokemonEntity) {
|
||||
((PokemonEntity) entity).getBrain().setMemory(MemoryModuleType.ATTACK_TARGET, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(
|
||||
method = "releaseOccupant",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/level/Level;addFreshEntity(Lnet/minecraft/world/entity/Entity;)Z"
|
||||
)
|
||||
)
|
||||
private static boolean cobblemon$captureReleasedEntity(
|
||||
Level level, Entity entity,
|
||||
Level lvl, BlockPos pos, BlockState state,
|
||||
BeehiveBlockEntity.Occupant occupant, @Nullable List<Entity> bees,
|
||||
BeehiveBlockEntity.BeeReleaseStatus releaseStatus, @Nullable BlockPos flowerPos) {
|
||||
|
||||
if (bees != null && !bees.contains(entity)) {
|
||||
// Avoid duplicates if vanilla also adds bees to the list on your version
|
||||
bees.add(entity);
|
||||
}
|
||||
return level.addFreshEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.duck.ChannelDuck;
|
||||
import com.mojang.blaze3d.audio.Channel;
|
||||
import org.lwjgl.openal.AL10;
|
||||
|
||||
@@ -8,18 +8,25 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.api.pokemon.effect.ShoulderEffectRegistry;
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle;
|
||||
import com.cobblemon.mod.common.api.riding.Seat;
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.SubmarineBehaviour;
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate;
|
||||
import com.cobblemon.mod.common.client.render.MatrixWrapper;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.ClipContext;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
@@ -32,6 +39,7 @@ import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(LivingEntity.class)
|
||||
public abstract class LivingEntityMixin extends Entity implements OrientationControllable {
|
||||
@@ -55,6 +63,14 @@ public abstract class LivingEntityMixin extends Entity implements OrientationCon
|
||||
}
|
||||
}
|
||||
|
||||
@WrapOperation(method = "baseTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;isInWall()Z"))
|
||||
public boolean cobblemon$preventMountSuffocation(LivingEntity instance, Operation<Boolean> original) {
|
||||
if (instance.getVehicle() instanceof PokemonEntity) {
|
||||
return false;
|
||||
}
|
||||
return original.call(instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HitResult pick(double hitDistance, float partialTicks, boolean hitFluids) {
|
||||
Entity vehicle = this.getVehicle();
|
||||
@@ -116,4 +132,31 @@ public abstract class LivingEntityMixin extends Entity implements OrientationCon
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "decreaseAirSupply", at = @At("HEAD"), cancellable = true)
|
||||
private void cobblemon$conditionalWaterBreathing(
|
||||
int currentAir,
|
||||
CallbackInfoReturnable<Integer> cir
|
||||
) {
|
||||
var entity = (LivingEntity) (Object) this;
|
||||
if (!(entity instanceof Player player)) return;
|
||||
if (!(player.getVehicle() instanceof PokemonEntity vehicle)) return;
|
||||
|
||||
var ridingController = vehicle.getRidingController();
|
||||
if (ridingController == null) return;
|
||||
|
||||
var activeContext = ridingController.getContext();
|
||||
if (activeContext == null) return;
|
||||
|
||||
// If the rider is currently on a submarine and the ride still has stamina.
|
||||
var stamina = activeContext.getState().getStamina().get();
|
||||
if (
|
||||
activeContext.getStyle() == RidingStyle.LIQUID &&
|
||||
activeContext.getBehaviour().equals(SubmarineBehaviour.Companion.getKEY()) &&
|
||||
stamina > 0.0f
|
||||
) {
|
||||
cir.setReturnValue(currentAir);
|
||||
cir.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import com.cobblemon.mod.common.api.storage.party.PartyStore;
|
||||
import com.cobblemon.mod.common.api.storage.party.PlayerPartyStore;
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags;
|
||||
import com.cobblemon.mod.common.duck.PlayerDuck;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexEntityData;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.ScannableEntity;
|
||||
@@ -37,6 +38,7 @@ import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.entity.EntityDimensions;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
@@ -47,6 +49,7 @@ import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.food.FoodProperties;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Vector3f;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
@@ -63,7 +66,7 @@ import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Mixin(Player.class)
|
||||
public abstract class PlayerMixin extends LivingEntity implements ScannableEntity, OrientationControllable, PlayerDuck {
|
||||
public abstract class PlayerMixin extends LivingEntity implements ScannableEntity, OrientationControllable, PlayerDuck, RidePassenger {
|
||||
|
||||
@Unique
|
||||
private Vector3f cobblemon$driverInput;
|
||||
@@ -91,6 +94,12 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
@Shadow protected int jumpTriggerTime;
|
||||
@Unique private final OrientationController cobblemon$orientationController = new OrientationController(this);
|
||||
|
||||
@Unique private float cobblemon$rideXRot = 0.0f;
|
||||
|
||||
@Unique private float cobblemon$rideYRot = 0.0f;
|
||||
|
||||
@Unique private Vec3 cobblemon$rideEyePos = Vec3.ZERO;
|
||||
|
||||
protected PlayerMixin(EntityType<? extends LivingEntity> p_20966_, Level p_20967_) {
|
||||
super(p_20966_, p_20967_);
|
||||
}
|
||||
@@ -117,11 +126,6 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At("HEAD"))
|
||||
private void cobblemon$updateRenderOrientation(CallbackInfo ci) {
|
||||
this.cobblemon$orientationController.tick();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityDimensions getDefaultDimensions(Pose pose) {
|
||||
if (this.getVehicle() instanceof PokemonEntity) {
|
||||
@@ -307,4 +311,34 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
return cobblemon$lastSentDriverInput;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float cobblemon$getRideXRot() {
|
||||
return this.cobblemon$rideXRot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$setRideXRot(float rideXRot) {
|
||||
this.cobblemon$rideXRot = Mth.wrapDegrees(rideXRot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float cobblemon$getRideYRot() {
|
||||
return this.cobblemon$rideYRot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$setRideYRot(float rideYRot) {
|
||||
this.cobblemon$rideYRot = Mth.wrapDegrees(rideYRot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3 cobblemon$getRideEyePos() {
|
||||
return this.cobblemon$rideEyePos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cobblemon$setRideEyePos(Vec3 rideEyePos) {
|
||||
this.cobblemon$rideEyePos = rideEyePos;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,8 +15,10 @@ import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(RecipeBookSettings.class)
|
||||
@@ -30,4 +32,14 @@ public class RecipeBookSettingsMixin {
|
||||
states.put(RecipeBookType.valueOf("COOKING_POT"), new RecipeBookSettings.TypeSettings(true, true));
|
||||
}
|
||||
|
||||
@Redirect( method = "read(Lnet/minecraft/network/FriendlyByteBuf;)Lnet/minecraft/stats/RecipeBookSettings;", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/inventory/RecipeBookType;values()[Lnet/minecraft/world/inventory/RecipeBookType;"))
|
||||
private static RecipeBookType[] cobblemon$valuesReadRedirect() {
|
||||
return Arrays.stream(RecipeBookType.values()).filter( recipeBookType -> !RecipeBookType.valueOf("COOKING_POT").equals(recipeBookType) ).toArray(RecipeBookType[]::new);
|
||||
}
|
||||
|
||||
@Redirect( method = "write(Lnet/minecraft/network/FriendlyByteBuf;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/inventory/RecipeBookType;values()[Lnet/minecraft/world/inventory/RecipeBookType;"))
|
||||
private RecipeBookType[] cobblemon$valuesWriteRedirect() {
|
||||
return Arrays.stream(RecipeBookType.values()).filter( recipeBookType -> !RecipeBookType.valueOf("COOKING_POT").equals(recipeBookType) ).toArray(RecipeBookType[]::new);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,33 +8,70 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.PlayerSpawnerAccessor;
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner;
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawnerFactory;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ServerPlayer.class)
|
||||
public abstract class ServerPlayerMixin {
|
||||
public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
|
||||
@Shadow
|
||||
public abstract ServerLevel serverLevel();
|
||||
|
||||
@Unique
|
||||
public PlayerSpawner cobblemon$spawner;
|
||||
|
||||
@Override
|
||||
public PlayerSpawner getPlayerSpawner() {
|
||||
ServerPlayer player = (ServerPlayer)(Object)this;
|
||||
if (cobblemon$spawner == null) {
|
||||
cobblemon$spawner = PlayerSpawnerFactory.INSTANCE.create(player);
|
||||
}
|
||||
return cobblemon$spawner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerSpawner(PlayerSpawner spawner) {
|
||||
this.cobblemon$spawner = spawner;
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At("TAIL"))
|
||||
private void cobblemon$tickSpawner(CallbackInfo ci) {
|
||||
if (!Cobblemon.config.getEnableSpawning()) {
|
||||
return;
|
||||
} else if (!serverLevel().getGameRules().getBoolean(CobblemonGameRules.DO_POKEMON_SPAWNING)) {
|
||||
return;
|
||||
}
|
||||
getPlayerSpawner().tick();
|
||||
}
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
private void cobblemon$updateOrientationControllerRideTick(CallbackInfo ci) {
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
var shouldUseCustomOrientation = cobblemon$shouldUseCustomOrientation((ServerPlayer)(Object)this);
|
||||
controllable.getOrientationController().setActive(shouldUseCustomOrientation);
|
||||
ServerPlayer player = (ServerPlayer)(Object)this;
|
||||
Entity vehicle = player.getVehicle();
|
||||
if (!(vehicle instanceof OrientationControllable controllableVehicle)) return;
|
||||
var shouldUseCustomOrientation = cobblemon$shouldUseCustomOrientation(vehicle);
|
||||
controllableVehicle.getOrientationController().setActive(shouldUseCustomOrientation);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean cobblemon$shouldUseCustomOrientation(ServerPlayer player) {
|
||||
var playerVehicle = player.getVehicle();
|
||||
if (playerVehicle == null) return false;
|
||||
if (!(playerVehicle instanceof PokemonEntity pokemonEntity)) return false;
|
||||
private boolean cobblemon$shouldUseCustomOrientation(Entity entity) {
|
||||
if (entity == null) return false;
|
||||
if (!(entity instanceof PokemonEntity pokemonEntity)) return false;
|
||||
return pokemonEntity.ifRidingAvailableSupply(false, (behaviour, settings, state) -> {
|
||||
return behaviour.shouldRoll(settings, state, pokemonEntity);
|
||||
});
|
||||
@@ -42,8 +79,9 @@ public abstract class ServerPlayerMixin {
|
||||
|
||||
@Inject(method = "stopRiding", at = @At("HEAD"))
|
||||
public void cobblemon$resetOrientationOnDismount(CallbackInfo ci) {
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
controllable.getOrientationController().setActive(false);
|
||||
ServerPlayer player = (ServerPlayer)(Object)this;
|
||||
if (!(player.getVehicle() instanceof OrientationControllable controllableVehicle)) return;
|
||||
controllableVehicle.getOrientationController().setActive(false);
|
||||
}
|
||||
|
||||
//TODO: Switch to sending out on load instead of preventing saving
|
||||
@@ -51,5 +89,4 @@ public abstract class ServerPlayerMixin {
|
||||
private boolean cobblemon$cancelSavingPokemonMounts(boolean original, @Local(ordinal=0) Entity entity) {
|
||||
return original && !(entity instanceof PokemonEntity);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -55,86 +55,6 @@ public abstract class SoundEngineMixin implements SoundEngineDuck {
|
||||
@Shadow
|
||||
public abstract boolean isActive(SoundInstance sound);
|
||||
|
||||
@Inject(method = "play",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/client/sounds/ChannelAccess$ChannelHandle;execute(Ljava/util/function/Consumer;)V"
|
||||
),
|
||||
cancellable = true
|
||||
)
|
||||
private void cobblemon$overrideChannelExecute(
|
||||
SoundInstance sound,
|
||||
CallbackInfo ci,
|
||||
@Local(name = "h") float h,
|
||||
@Local(name = "i") float i,
|
||||
@Local(name = "g") float g,
|
||||
@Local(name = "bl2") boolean bl2,
|
||||
@Local(name = "bl3") boolean bl3,
|
||||
@Local(name = "bl") boolean bl,
|
||||
@Local(name = "vec3") Vec3 vec3,
|
||||
@Local(name = "channelHandle") ChannelAccess.ChannelHandle handle
|
||||
) {
|
||||
if (!(sound instanceof RideLoopSound rideSound)) return;
|
||||
|
||||
if (handle == null) return;
|
||||
|
||||
handle.execute((channel) -> {
|
||||
channel.setPitch(i);
|
||||
channel.setVolume(h);
|
||||
|
||||
if (rideSound.getRideAttenuation() == RideAttenuationModel.LINEAR) {
|
||||
channel.linearAttenuation(g);
|
||||
} else if (rideSound.getRideAttenuation() == RideAttenuationModel.EXPONENTIAL){
|
||||
((ChannelDuck) channel).cobblemon$inverseAttenuation(g);
|
||||
} else {
|
||||
channel.disableAttenuation();
|
||||
}
|
||||
|
||||
// Apply low pass filter if the rideSound dictate that it should be muffled
|
||||
if (rideSound.getShouldMuffle()) {
|
||||
((ChannelDuck) channel).cobblemon$applyLowPassFilter(1.0f, rideSound.getMuffleAmount());
|
||||
} else {
|
||||
((ChannelDuck) channel).cobblemon$clearFilters();
|
||||
}
|
||||
|
||||
channel.setLooping(bl2 && !bl3);
|
||||
channel.setSelfPosition(vec3);
|
||||
channel.setRelative(bl);
|
||||
});
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "tickNonPaused",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/client/sounds/ChannelAccess$ChannelHandle;execute(Ljava/util/function/Consumer;)V",
|
||||
ordinal = 0
|
||||
)
|
||||
)
|
||||
private void cobblemon$tickableSoundTick(
|
||||
CallbackInfo ci,
|
||||
@Local(name = "tickableSoundInstance") TickableSoundInstance instance,
|
||||
@Local(name = "channelHandle", ordinal = 0) ChannelAccess.ChannelHandle handle,
|
||||
@Local(name = "f", ordinal = 0) float volume,
|
||||
@Local(name = "g", ordinal = 0) float pitch,
|
||||
@Local(name = "vec3", ordinal = 0) Vec3 vec3
|
||||
) {
|
||||
if (!(instance instanceof RideLoopSound rideSound)) return;
|
||||
|
||||
handle.execute(channel -> {
|
||||
channel.setVolume(volume);
|
||||
channel.setPitch(pitch);
|
||||
channel.setSelfPosition(vec3);
|
||||
|
||||
// Apply low pass filter if the rideSound dictate that it should be muffled
|
||||
if (rideSound.getShouldMuffle()) {
|
||||
((ChannelDuck) channel).cobblemon$applyLowPassFilter(1.0f, rideSound.getMuffleAmount());
|
||||
} else {
|
||||
((ChannelDuck) channel).cobblemon$clearFilters();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Resumes the Source belonging to the queried SoundInstance. */
|
||||
private void resume(SoundInstance sound) {
|
||||
ChannelAccess.ChannelHandle sourceManager = this.instanceToChannel.get(sound);
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
|
||||
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
@Mixin(targets = "net.minecraft.world.level.block.entity.BeehiveBlockEntity$BeeData")
|
||||
public interface BeeDataAccessor {
|
||||
@Invoker("toOccupant")
|
||||
BeehiveBlockEntity.Occupant invokeToOccupant();
|
||||
}
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.BlockPos;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(BeehiveBlockEntity.class)
|
||||
public interface BeehiveBlockEntityAccessor {
|
||||
@Accessor("stored")
|
||||
List<Object> getStored();
|
||||
@Accessor("savedFlowerPos")
|
||||
BlockPos savedFlowerPos();
|
||||
|
||||
|
||||
/**
|
||||
* Access the private static method:
|
||||
* private static void releaseOccupant(Level level, BlockPos pos, BeeData beeData, ...)
|
||||
*/
|
||||
@Invoker("releaseOccupant")
|
||||
static boolean releaseOccupant(Level level, BlockPos pos, BlockState state, BeehiveBlockEntity.Occupant occupant, @Nullable List<Entity> storedInHives, BeehiveBlockEntity.BeeReleaseStatus releaseStatus, @Nullable BlockPos storedFlowerPos) {
|
||||
throw new AssertionError(); // Mixin will overwrite
|
||||
}
|
||||
}
|
||||
|
||||
+8
-7
@@ -8,13 +8,14 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(Camera.class)
|
||||
public interface CameraAccessor {
|
||||
@Accessor("level")
|
||||
BlockGetter getLevel();
|
||||
}
|
||||
@Mixin(BlockEntity.class)
|
||||
public interface BlockEntityAccessor {
|
||||
@Accessor("level") Level getLevel();
|
||||
@Accessor("worldPosition") BlockPos getWorldPosition();
|
||||
}
|
||||
@@ -27,7 +27,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(BrewingStandMenu.class)
|
||||
public abstract class BrewingStandMenuMixin {
|
||||
|
||||
@Inject(method = "<init>(ILnet/minecraft/world/entity/player/Inventory;Lnet/minecraft/world/Container;Lnet/minecraft/world/inventory/ContainerData;)V", at = @At("TAIL"))
|
||||
private void captureLevel(int containerId, Inventory playerInventory, Container brewingStandContainer, ContainerData brewingStandData, CallbackInfo ci) {
|
||||
var recipeManager = playerInventory.player.level().getRecipeManager();
|
||||
@@ -37,9 +36,4 @@ public abstract class BrewingStandMenuMixin {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@WrapOperation(method = "quickMoveStack", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/inventory/BrewingStandMenu$PotionSlot;mayPlaceItem(Lnet/minecraft/world/item/ItemStack;)Z"))
|
||||
private boolean cobblemon$isPotionBottle(ItemStack stack, Operation<Boolean> original, @Local(argsOnly = true) Player player) {
|
||||
return BrewingStandRecipe.Companion.isBottle(stack, player.level().getRecipeManager()) || original.call(stack);
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -34,7 +34,8 @@ public class AbstractClientPlayerMixin {
|
||||
} else {
|
||||
// Only modify fov through riding if the pokedex is not open
|
||||
LocalPlayer player = (LocalPlayer) (Object) this;
|
||||
if (player != null && player.isPassenger() && player.getVehicle() instanceof PokemonEntity) {
|
||||
// Only modify fov for the driver and not the passengers
|
||||
if (player != null && player.isPassenger() && player.getVehicle() instanceof PokemonEntity && player.getVehicle().getControllingPassenger() == player) {
|
||||
PokemonEntity ride = (PokemonEntity) player.getVehicle();
|
||||
|
||||
// Return custom fov mult for riding
|
||||
|
||||
@@ -8,87 +8,61 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.api.riding.Rideable;
|
||||
import com.cobblemon.mod.common.client.MountedPokemonAnimationRenderController;
|
||||
import com.cobblemon.mod.common.client.render.camera.MountedCameraRenderer;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.duck.CameraDuck;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Vector3f;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(Camera.class)
|
||||
public abstract class CameraMixin {
|
||||
@Shadow private Entity entity;
|
||||
@Shadow @Final private Quaternionf rotation;
|
||||
@Shadow @Final private Vector3f forwards;
|
||||
@Shadow @Final private Vector3f up;
|
||||
@Shadow @Final private Vector3f left;
|
||||
@Shadow private float xRot;
|
||||
@Shadow private float yRot;
|
||||
|
||||
public abstract class CameraMixin implements CameraDuck {
|
||||
@Shadow private float eyeHeight;
|
||||
@Shadow private float eyeHeightOld;
|
||||
@Shadow private BlockGetter level;
|
||||
@Shadow private Entity entity;
|
||||
@Final @Shadow private Quaternionf rotation;
|
||||
@Final @Shadow private Vector3f forwards;
|
||||
@Final @Shadow private Vector3f up;
|
||||
@Final @Shadow private Vector3f left;
|
||||
@Shadow private float yRot;
|
||||
@Shadow private float xRot;
|
||||
|
||||
@Shadow protected abstract void setPosition(Vec3 pos);
|
||||
|
||||
@Unique private float returnTimer = 0;
|
||||
@Unique private float rollAngleStart = 0;
|
||||
@Unique Minecraft minecraft = Minecraft.getInstance();
|
||||
|
||||
@Inject(method = "setRotation", at = @At("HEAD"), cancellable = true)
|
||||
|
||||
public void cobblemon$setRotation(float f, float g, CallbackInfo ci) {
|
||||
if (!(this.entity instanceof OrientationControllable controllable)) return;
|
||||
var controller = controllable.getOrientationController();
|
||||
if (!controller.isActive() && controller.getOrientation() != null) {
|
||||
if(this.returnTimer < 1) {
|
||||
//Rotation is taken from entity since we no longer handle mouse ourselves
|
||||
//Stops a period of time when you can't input anything.
|
||||
controller.getOrientation().set(
|
||||
new Matrix3f()
|
||||
.rotateY((float) Math.toRadians(180 - this.entity.getYRot()))
|
||||
.rotateX((float) Math.toRadians(-this.entity.getXRot()))
|
||||
);
|
||||
if(rollAngleStart == 0){
|
||||
this.returnTimer = 1;
|
||||
controller.reset();
|
||||
return;
|
||||
}
|
||||
controller.getOrientation().rotateZ((float) Math.toRadians(-rollAngleStart*(1-returnTimer)));
|
||||
cobblemon$applyRotation();
|
||||
this.returnTimer += .05F;
|
||||
ci.cancel();
|
||||
} else {
|
||||
this.returnTimer = 1;
|
||||
controller.reset();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (controller.getOrientation() == null) return;
|
||||
cobblemon$applyRotation();
|
||||
|
||||
this.returnTimer = 0;
|
||||
this.rollAngleStart = controller.getRoll();
|
||||
ci.cancel();
|
||||
@Override public BlockGetter cobblemon$getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
@Override public Entity cobblemon$getEntity() {
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override public Quaternionf cobblemon$getRotation() { return rotation; }
|
||||
|
||||
@Override public Vector3f cobblemon$getForwards() { return forwards; }
|
||||
|
||||
@Override public Vector3f cobblemon$getUp() { return up; }
|
||||
|
||||
@Override public Vector3f cobblemon$getLeft() { return left; }
|
||||
|
||||
@Override public float cobblemon$getXRot() { return xRot; }
|
||||
@Override public void cobblemon$setXRot(float xRot) { this.xRot = xRot; }
|
||||
|
||||
@Override public float cobblemon$getYRot() { return yRot; }
|
||||
@Override public void cobblemon$setYRot(float yRot) { this.yRot = yRot; }
|
||||
|
||||
@WrapOperation(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;setPosition(DDD)V"))
|
||||
public void cobblemon$positionCamera(Camera instance, double x, double y, double z, Operation<Void> original, @Local(ordinal = 1, argsOnly = true) boolean thirdPersonReverse) {
|
||||
Entity entity = instance.getEntity();
|
||||
@@ -97,49 +71,22 @@ public abstract class CameraMixin {
|
||||
|
||||
if(vehicle instanceof Rideable){
|
||||
Vec3 position = MountedCameraRenderer.INSTANCE.getCameraPosition(
|
||||
instance,
|
||||
entity,
|
||||
vehicle,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
thirdPersonReverse,
|
||||
eyeHeightOld,
|
||||
eyeHeight
|
||||
instance,
|
||||
entity,
|
||||
vehicle,
|
||||
thirdPersonReverse,
|
||||
eyeHeight,
|
||||
eyeHeightOld
|
||||
);
|
||||
|
||||
if(position != null){
|
||||
if(position != null) {
|
||||
setPosition(position);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// reset the rotation values if it is now not being ridden.
|
||||
MountedCameraRenderer.INSTANCE.setSmoothRotation(null);
|
||||
original.call(instance, x, y, z);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void cobblemon$applyRotation(){
|
||||
if (!(this.entity instanceof OrientationControllable controllable) || controllable.getOrientationController().getOrientation() == null) return;
|
||||
var controller = controllable.getOrientationController();
|
||||
var newRotation = controller.getOrientation().normal(new Matrix3f()).getNormalizedRotation(new Quaternionf());
|
||||
if (this.minecraft.options.getCameraType().isMirrored()) {
|
||||
newRotation.rotateY((float)Math.toRadians(180));
|
||||
}
|
||||
this.rotation.set(newRotation);
|
||||
this.xRot = controller.getPitch();
|
||||
this.yRot = controller.getYaw();
|
||||
OrientationController.Companion.getFORWARDS().rotate(this.rotation, this.forwards);
|
||||
OrientationController.Companion.getUP().rotate(this.rotation, this.up);
|
||||
OrientationController.Companion.getLEFT().rotate(this.rotation, this.left);
|
||||
}
|
||||
|
||||
@WrapOperation(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;move(FFF)V", ordinal = 0))
|
||||
public void stopMoveIfRolling(Camera instance, float zoom, float dy, float dx, Operation<Void> original) {
|
||||
Entity entity = instance.getEntity();
|
||||
Entity vehicle = entity.getVehicle();
|
||||
|
||||
if (!(vehicle instanceof PokemonEntity) || Cobblemon.config.getThirdPersonViewBobbing()) {
|
||||
original.call(instance, zoom, dy, dx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,15 +9,21 @@
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.client.DeltaTracker;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
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.ModifyArg;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@Mixin(GameRenderer.class)
|
||||
public class GameRendererMixin {
|
||||
@Unique
|
||||
@@ -42,4 +48,16 @@ public class GameRendererMixin {
|
||||
lastTime = newTime;
|
||||
}
|
||||
|
||||
@ModifyArg(
|
||||
method = "pick(Lnet/minecraft/world/entity/Entity;DDF)Lnet/minecraft/world/phys/HitResult;",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/entity/projectile/ProjectileUtil;getEntityHitResult(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/phys/AABB;Ljava/util/function/Predicate;D)Lnet/minecraft/world/phys/EntityHitResult;"
|
||||
),
|
||||
index = 4
|
||||
)
|
||||
private Predicate<Entity> filterPokemonVehicle(Predicate<Entity> original, @Local(ordinal = 0, argsOnly = true) Entity entity) {
|
||||
return (entityX) -> !(entity.getVehicle() == entityX && entityX instanceof PokemonEntity) && original.test(entityX);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.client.render.player.MountedPlayerRenderer;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.client.model.HumanoidModel;
|
||||
import net.minecraft.client.model.geom.ModelPart;
|
||||
@@ -68,6 +69,17 @@ public class HumanoidModelMixin {
|
||||
behaviour.shouldRotateRiderHead(settings, state, pokemonEntity)
|
||||
);
|
||||
|
||||
// If the player is on a rollable ride then use the ride local rotations to rotate the head
|
||||
// This is to allow the player head to face the correct direction when "freelooking"
|
||||
if (entity instanceof RidePassenger playerRotater &&
|
||||
vehicle instanceof OrientationControllable controller &&
|
||||
controller.getOrientationController().isActive()) {
|
||||
this.head.xRot = playerRotater.cobblemon$getRideXRot();
|
||||
headPitch = playerRotater.cobblemon$getRideXRot();
|
||||
this.head.yRot = playerRotater.cobblemon$getRideYRot();
|
||||
netHeadYaw = playerRotater.cobblemon$getRideYRot();
|
||||
}
|
||||
|
||||
if (!shouldRotatePlayerHead) {
|
||||
netHeadYaw = 0f;
|
||||
headPitch = 0f;
|
||||
|
||||
+2
-2
@@ -36,9 +36,9 @@ public class ItemInHandRendererMixin {
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(method = "renderHandsWithItems", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;mulPose(Lorg/joml/Quaternionf;)V", ordinal = 1))
|
||||
@Redirect(method = "renderHandsWithItems", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;mulPose(Lorg/joml/Quaternionf;)V"))
|
||||
private void cobblemon$renderHandswithItems(PoseStack instance, Quaternionf quaternion) {
|
||||
if (!(Minecraft.getInstance().player instanceof OrientationControllable controllable && controllable.getOrientationController().isActive())) {
|
||||
if (!(Minecraft.getInstance().player != null && Minecraft.getInstance().player.getVehicle() instanceof OrientationControllable controllable && controllable.getOrientationController().isActive())) {
|
||||
instance.mulPose(quaternion);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,11 @@ import com.cobblemon.mod.common.client.render.models.blockbench.FloatingState;
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableModel;
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.VaryingModelRepository;
|
||||
import com.cobblemon.mod.common.duck.PlayerDuck;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket;
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateDriverInputPacket;
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateRiderRotationPacket;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import net.minecraft.client.CameraType;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -29,12 +31,10 @@ import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.player.Input;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.ClipContext;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -55,6 +55,10 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
|
||||
@Unique Matrix3f cobblemon$lastOrientation;
|
||||
|
||||
@Unique float cobblemon$lastRideXRot;
|
||||
@Unique float cobblemon$lastRideYRot;
|
||||
@Unique Vec3 cobblemon$lastRideEyePos;
|
||||
|
||||
@Unique boolean cobblemon$isDoubleJumping = false;
|
||||
|
||||
@Shadow
|
||||
@@ -72,30 +76,35 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
super(clientLevel, gameProfile);
|
||||
}
|
||||
|
||||
// @Inject(method = "sendPosition", at = @At("TAIL"))
|
||||
// private void cobblemon$updateRotationMatrix(CallbackInfo ci) {
|
||||
// if (!(this instanceof OrientationControllable controllable)) return;
|
||||
// var controller = controllable.getOrientationController();
|
||||
// if (!controller.isActive() || controller.getOrientation() == cobblemon$lastOrientation) return;
|
||||
// cobblemon$lastOrientation = controller.getOrientation() != null ? new Matrix3f(controller.getOrientation()) : null;
|
||||
// CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateOrientationPacket(controller.getOrientation()));
|
||||
// }
|
||||
|
||||
@Inject(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/ClientPacketListener;send(Lnet/minecraft/network/protocol/Packet;)V"))
|
||||
private void cobblemon$updateRotationMatrixPassenger(CallbackInfo ci) {
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
var controller = controllable.getOrientationController();
|
||||
if (!controller.isActive() || controller.getOrientation() == cobblemon$lastOrientation) return;
|
||||
cobblemon$lastOrientation = controller.getOrientation() != null ? new Matrix3f(controller.getOrientation()) : null;
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateOrientationPacket(controller.getOrientation()));
|
||||
if (!(this.getVehicle() instanceof OrientationControllable controllableVehicle)) return;
|
||||
var vehicleController = controllableVehicle.getOrientationController();
|
||||
if (!vehicleController.isActive() || vehicleController.getOrientation() == cobblemon$lastOrientation) return;
|
||||
cobblemon$lastOrientation = vehicleController.getOrientation() != null ? new Matrix3f(vehicleController.getOrientation()) : null;
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateOrientationPacket(this.getVehicle().getId(), vehicleController.getOrientation()));
|
||||
}
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
private void cobblemon$updateOrientationControllerRideTick(CallbackInfo ci) {
|
||||
if (Minecraft.getInstance().player != (Object)this) return;
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
var driver = (LocalPlayer)(Object)this;
|
||||
var vehicle = driver.getVehicle();
|
||||
if (!(this.getVehicle() instanceof OrientationControllable controllableVehicle)) return;
|
||||
var shouldUseCustomOrientation = cobblemon$shouldUseCustomOrientation((LocalPlayer)(Object)this);
|
||||
controllable.getOrientationController().setActive(shouldUseCustomOrientation);
|
||||
var vehicleController = controllableVehicle.getOrientationController();
|
||||
|
||||
// If the player has just switched to riding a custom orientation ride then set their
|
||||
// x and y rots local to the vehicle rots(if the controller wasn't active and will now be active)
|
||||
// This ensures that on transition your camera stays in the same spot
|
||||
if (!vehicleController.isActive() && shouldUseCustomOrientation) {
|
||||
// Set local to the vehicle x and yrot so
|
||||
var playerRotater = (RidePassenger)driver;
|
||||
playerRotater.cobblemon$setRideXRot(Mth.wrapDegrees(driver.getXRot() - vehicle.getXRot()));
|
||||
playerRotater.cobblemon$setRideYRot(Mth.wrapDegrees(driver.getYRot() - vehicle.getYRot()));
|
||||
}
|
||||
|
||||
vehicleController.setActive(shouldUseCustomOrientation);
|
||||
}
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
@@ -115,6 +124,36 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateDriverInputPacket(driverInput));
|
||||
}
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
private void cobblemon$updateRiderRotationsRideTick(CallbackInfo ci) {
|
||||
if (Minecraft.getInstance().player != (Object)this) return;
|
||||
if (!(this.getVehicle() instanceof PokemonEntity pokemonEntity)) return;
|
||||
|
||||
var passenger = (LocalPlayer)(Object)this;
|
||||
var playerRotater = (RidePassenger)passenger;
|
||||
|
||||
// Gather Rider Rotation info
|
||||
var rideXRot = playerRotater.cobblemon$getRideXRot();
|
||||
var rideYRot = playerRotater.cobblemon$getRideYRot();
|
||||
var rideEyePos = playerRotater.cobblemon$getRideEyePos();
|
||||
|
||||
// Check for a change in the values before sending them.
|
||||
if (cobblemon$lastRideXRot != rideXRot ||
|
||||
cobblemon$lastRideYRot != rideYRot ||
|
||||
cobblemon$lastRideEyePos != rideEyePos
|
||||
) {
|
||||
|
||||
// Update 'last' values
|
||||
cobblemon$lastRideXRot = rideXRot;
|
||||
cobblemon$lastRideYRot = rideYRot;
|
||||
cobblemon$lastRideEyePos = rideEyePos;
|
||||
|
||||
CobblemonNetwork.INSTANCE.sendToServer(new ServerboundUpdateRiderRotationPacket(rideXRot, rideYRot, rideEyePos));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean cobblemon$shouldUseCustomOrientation(LocalPlayer player) {
|
||||
var playerVehicle = player.getVehicle();
|
||||
@@ -129,8 +168,8 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
public void stopRiding() {
|
||||
super.stopRiding();
|
||||
if (Minecraft.getInstance().player != (Object)this) return;
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
controllable.getOrientationController().setActive(false);
|
||||
if (!(this instanceof OrientationControllable controllableVehicle)) return;
|
||||
controllableVehicle.getOrientationController().setActive(false);
|
||||
}
|
||||
|
||||
@Inject(method = "getJumpRidingScale", at = @At("HEAD"), cancellable = true)
|
||||
@@ -161,7 +200,7 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
this.cobblemon$survivalJumpTriggerTime = 0;
|
||||
}
|
||||
else {
|
||||
this.cobblemon$survivalJumpTriggerTime = 7;
|
||||
this.cobblemon$survivalJumpTriggerTime = 12;
|
||||
}
|
||||
}
|
||||
else if (this.cobblemon$survivalJumpTriggerTime > 0) {
|
||||
@@ -188,33 +227,17 @@ public abstract class LocalPlayerMixin extends AbstractClientPlayer implements O
|
||||
public HitResult pick(double hitDistance, float partialTicks, boolean hitFluids) {
|
||||
Entity vehicle = this.getVehicle();
|
||||
if (vehicle instanceof PokemonEntity pokemonEntity) {
|
||||
PokemonClientDelegate delegate = (PokemonClientDelegate) pokemonEntity.getDelegate();
|
||||
String locatorName = delegate.getSeatLocator(this);
|
||||
MatrixWrapper locator = delegate.getLocatorStates().get(locatorName);
|
||||
|
||||
if (locator == null) {
|
||||
return super.pick(hitDistance, partialTicks, hitFluids);
|
||||
}
|
||||
// Get player object
|
||||
var passenger = (LocalPlayer)(Object)this;
|
||||
var playerRotater = (RidePassenger)passenger;
|
||||
|
||||
Vec3 locatorOffset = locator != null ? new Vec3(locator.getMatrix().getTranslation(new Vector3f())) : Vec3.ZERO;
|
||||
|
||||
OrientationController controller = this.getOrientationController();
|
||||
|
||||
float currEyeHeight = this.getEyeHeight();
|
||||
Vector3f offset = new Vector3f(new Vector3f(0f, currEyeHeight - (this.getBbHeight() / 2), 0f));
|
||||
|
||||
if (Minecraft.getInstance().options.getCameraType() == CameraType.FIRST_PERSON) {
|
||||
PosableModel model = VaryingModelRepository.INSTANCE.getPoser(pokemonEntity.getPokemon().getSpecies().getResourceIdentifier(), new FloatingState());
|
||||
offset.add(cobblemon$getFirstPersonOffset(model, locatorName));
|
||||
}
|
||||
|
||||
Matrix3f orientation = controller.isActive() && controller.getOrientation() != null ? controller.getOrientation() : new Matrix3f();
|
||||
Vec3 rotatedEyeHeight = new Vec3(orientation.transform(offset));
|
||||
|
||||
Vec3 eyePosition = locatorOffset.add(pokemonEntity.position()).add(rotatedEyeHeight);
|
||||
// Gather eye position from stored 1st person camera position calculation
|
||||
var eyePosition = playerRotater.cobblemon$getRideEyePos();
|
||||
|
||||
Vec3 viewVector = this.getViewVector(partialTicks);
|
||||
Vec3 viewDistanceVector = eyePosition.add(viewVector.x * hitDistance, viewVector.y * hitDistance, viewVector.z * hitDistance);
|
||||
|
||||
return this.level()
|
||||
.clip(
|
||||
new ClipContext(
|
||||
|
||||
@@ -10,13 +10,16 @@ package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.client.CobblemonClient;
|
||||
import com.cobblemon.mod.common.client.keybind.keybinds.PartySendBinding;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexUsageContext;
|
||||
import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import com.mojang.blaze3d.Blaze3D;
|
||||
import kotlin.Pair;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.MouseHandler;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
@@ -32,6 +35,9 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import static com.google.common.primitives.Floats.min;
|
||||
import static net.minecraft.util.Mth.lerp;
|
||||
|
||||
@Mixin(MouseHandler.class)
|
||||
public abstract class MouseHandlerMixin {
|
||||
@Shadow private double accumulatedScrollY;
|
||||
@@ -117,8 +123,6 @@ public abstract class MouseHandlerMixin {
|
||||
@Local(argsOnly = true) double d,
|
||||
@Local(argsOnly = true) double movementTime
|
||||
) {
|
||||
boolean returnValue = true;
|
||||
|
||||
PokedexUsageContext usageContext = CobblemonClient.INSTANCE.getPokedexUsageContext();
|
||||
if (usageContext.getScanningGuiOpen()) {
|
||||
this.smoothTurnY.reset();
|
||||
@@ -126,34 +130,78 @@ public abstract class MouseHandlerMixin {
|
||||
var defaultSensitivity = this.minecraft.options.sensitivity().get() * 0.6 + 0.2;
|
||||
var spyglassSensitivity = Math.pow(defaultSensitivity, 3);
|
||||
var lookSensitivity = spyglassSensitivity * 8.0;
|
||||
var sensitivity = Mth.lerp(usageContext.getFovMultiplier(), spyglassSensitivity, lookSensitivity);
|
||||
var sensitivity = lerp(usageContext.getFovMultiplier(), spyglassSensitivity, lookSensitivity);
|
||||
var yRotationFlip = this.minecraft.options.invertYMouse().get() ? -1 : 1;
|
||||
player.turn(this.accumulatedDX * sensitivity, (this.accumulatedDY * sensitivity * yRotationFlip));
|
||||
returnValue = false;
|
||||
}
|
||||
|
||||
var vehicle = player.getVehicle();
|
||||
if (!(vehicle instanceof PokemonEntity)) return true;
|
||||
|
||||
// Clamp player rotation if riding and the vehicle demands it
|
||||
if (player.isPassenger() && player.getVehicle() instanceof PokemonEntity vehicle) {
|
||||
vehicle.clampPassengerRotation(player);
|
||||
if (player.isPassenger() && vehicle instanceof PokemonEntity pokeVehicle) {
|
||||
pokeVehicle.clampPassengerRotation(player);
|
||||
}
|
||||
|
||||
if (!(player instanceof OrientationControllable controllable)) return true;
|
||||
|
||||
if (!controllable.getOrientationController().isActive()) {
|
||||
// If the ride is not orientation controllable then return and perform the normal turnPlayer logic
|
||||
if (!(vehicle instanceof OrientationControllable controllableVehicle) || !controllableVehicle.getOrientationController().isActive()) {
|
||||
xMouseSmoother.reset();
|
||||
yMouseSmoother.reset();
|
||||
pitchSmoother.reset();
|
||||
rollSmoother.reset();
|
||||
yawSmoother.reset();
|
||||
return returnValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Send mouse input to be interpreted into rotation
|
||||
// deltas by the ride controller
|
||||
var vehicleController = controllableVehicle.getOrientationController();
|
||||
var lookaroundButtonPressed = Minecraft.getInstance().mouseHandler.isMiddlePressed();
|
||||
Pair<Boolean, Boolean> mouseShouldModifyDriver = ((PokemonEntity) vehicle).ifRidingAvailableSupply(new Pair(false, false), (behaviour, settings, state) -> {
|
||||
return behaviour.mouseModifiesDriverRotation(
|
||||
settings,
|
||||
state,
|
||||
(PokemonEntity) vehicle
|
||||
);
|
||||
});
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// If looking around then modify the players orientation instead and zero the mouse deltas so the mouse doesn't
|
||||
// affect the vehicle orientation when looking around.
|
||||
// If the client is a passenger it will modify these rotations and return
|
||||
//-------------------------------------------------------------------------
|
||||
if (lookaroundButtonPressed || player.getControlledVehicle() == null) {
|
||||
// Modify driver rotations
|
||||
cobblemon$setDriverRotations(player, cursorDeltaX, cursorDeltaY);
|
||||
|
||||
// If the player/passenger is not the driver then return and ignore all vehicle rotation logic
|
||||
if (player.getControlledVehicle() == null) return false;
|
||||
|
||||
// Set to zero so that vehicle rotations don't also get affected by movement.
|
||||
cursorDeltaX = 0.0;
|
||||
cursorDeltaY = 0.0;
|
||||
} else if (mouseShouldModifyDriver.getFirst()) { // If not freelooking then check modification per mouse input dimension
|
||||
cobblemon$setDriverRotations(player, cursorDeltaX, 0.0);
|
||||
cursorDeltaX = 0.0;
|
||||
} else if (mouseShouldModifyDriver.getSecond()) {
|
||||
cobblemon$setDriverRotations(player, 0.0, cursorDeltaY);
|
||||
cursorDeltaY = 0.0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Smoothly return driver rotations to zero when needed
|
||||
//-------------------------------------------------------------------------
|
||||
var playerRotater = (RidePassenger)player;
|
||||
if( !lookaroundButtonPressed && !mouseShouldModifyDriver.getFirst()){
|
||||
playerRotater.cobblemon$setRideYRot(lerp(min(5.0f * (float)movementTime, 1.0f), Mth.wrapDegrees(playerRotater.cobblemon$getRideYRot()), 0.0f));
|
||||
}
|
||||
if( !lookaroundButtonPressed && !mouseShouldModifyDriver.getSecond()) {
|
||||
playerRotater.cobblemon$setRideXRot(lerp(min(5.0f * (float)movementTime, 1.0f), Mth.wrapDegrees(playerRotater.cobblemon$getRideXRot()), 0.0f));
|
||||
}
|
||||
|
||||
// Send mouse input to be interpreted into rotation deltas by the ride controller
|
||||
Vec3 angVecMouse = cobblemon$getRideMouseRotation(cursorDeltaX, cursorDeltaY, movementTime);
|
||||
|
||||
// Perform Rotation using mouse influenced rotation deltas.
|
||||
controllable.getOrientationController().rotate(
|
||||
vehicleController.rotate(
|
||||
(float) angVecMouse.x,
|
||||
(float) angVecMouse.y,
|
||||
(float) angVecMouse.z
|
||||
@@ -163,17 +211,16 @@ public abstract class MouseHandlerMixin {
|
||||
var angRot = cobblemon$getAngularVelocity(movementTime);
|
||||
|
||||
// Apply smoothing if requested by the controller.
|
||||
// This Might be best if done by the controller itself?
|
||||
if(cobblemon$shouldUseAngVelSmoothing()) {
|
||||
var yaw = yawSmoother.getNewDeltaValue(angRot.x * 0.5f, d);
|
||||
var pitch = pitchSmoother.getNewDeltaValue(angRot.y * 0.5f, d);
|
||||
var roll = rollSmoother.getNewDeltaValue(angRot.z * 0.5f, d);
|
||||
controllable.getOrientationController().rotate((float) yaw, (float) pitch, (float) roll);
|
||||
vehicleController.rotate((float) yaw, (float) pitch, (float) roll);
|
||||
}
|
||||
// Otherwise simply apply the smoothing
|
||||
else {
|
||||
controllable.getOrientationController().rotate((float) (angRot.x * 10 * d), (float) (angRot.y * 10 * d), (float) (angRot.z * 10 * d));
|
||||
vehicleController.rotate((float) (angRot.x * 10 * d), (float) (angRot.y * 10 * d), (float) (angRot.z * 10 * d));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -186,10 +233,11 @@ public abstract class MouseHandlerMixin {
|
||||
@Inject(method = "handleAccumulatedMovement", at = @At("TAIL"))
|
||||
private void cobblemon$maintainMovementWhenInScreens(CallbackInfo ci) {
|
||||
if (minecraft.player == null) return;
|
||||
if (!(minecraft.player instanceof OrientationControllable controllable)) return;
|
||||
if (!controllable.getOrientationController().isActive()) return;
|
||||
if (!(minecraft.player.getVehicle() instanceof OrientationControllable vehicleControllable)) return;
|
||||
if (!(vehicleControllable.getOrientationController() instanceof OrientationController vehicleController)) return;
|
||||
if (vehicleController.getOrientation() == null) return;
|
||||
if (minecraft.isPaused()) return;
|
||||
if (isMouseGrabbed()) return;
|
||||
if (this.isMouseGrabbed()) return; // return if turnPlayer() has already run this pass
|
||||
|
||||
this.turnPlayer(cobblemon$timeDelta);
|
||||
}
|
||||
@@ -251,6 +299,21 @@ public abstract class MouseHandlerMixin {
|
||||
return Math.pow(sensitivity, 3);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void cobblemon$setDriverRotations(LocalPlayer player, double cursorDeltaX, double cursorDeltaY) {
|
||||
// the vanilla turn() method redone so that it uses rideRotations.
|
||||
float f = (float)cursorDeltaY * 0.15F; // Note: turn() uses xRot for pitch (up/down)
|
||||
float g = (float)cursorDeltaX * 0.15F; // Note: turn() uses yRot for yaw (left/right)
|
||||
var playerRotater = (RidePassenger)player;
|
||||
playerRotater.cobblemon$setRideXRot(playerRotater.cobblemon$getRideXRot() + f);
|
||||
playerRotater.cobblemon$setRideYRot(playerRotater.cobblemon$getRideYRot() + g);
|
||||
playerRotater.cobblemon$setRideXRot(Mth.clamp(playerRotater.cobblemon$getRideXRot(), -90.0F, 90.0F));
|
||||
playerRotater.cobblemon$setRideYRot(Mth.clamp(playerRotater.cobblemon$getRideYRot(), -105.0F, 105.0F));
|
||||
if (player.getVehicle() != null) {
|
||||
player.getVehicle().onPassengerTurned(player);
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean cobblemon$shouldUseAngVelSmoothing() {
|
||||
var player = minecraft.player;
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.client;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import net.minecraft.client.CameraType;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.Options;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(Options.class)
|
||||
public abstract class OptionsMixin {
|
||||
|
||||
/**
|
||||
* Only allow third person on rollables when motion sick cam is enabled
|
||||
*/
|
||||
@Inject(
|
||||
method = "getCameraType",
|
||||
at = @At("HEAD"),
|
||||
cancellable = true
|
||||
)
|
||||
private void cobblemon$forceThirdPerson(CallbackInfoReturnable<CameraType> cir) {
|
||||
var mc = Minecraft.getInstance();
|
||||
if(!(mc.player instanceof Player player)) return;
|
||||
if(!(player.getVehicle() instanceof OrientationControllable vehicle)) return;
|
||||
if(vehicle.getOrientationController() == null) return;
|
||||
|
||||
// Force third person if on an active rollable vehicle and roll is disabled.
|
||||
if (Cobblemon.config.getDisableRoll() && vehicle.getOrientationController().isActive()) {
|
||||
cir.setReturnValue(CameraType.THIRD_PERSON_BACK);
|
||||
cir.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,20 +8,25 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin.entity;
|
||||
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.duck.RidePassenger;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(Entity.class)
|
||||
public abstract class EntityMixin {
|
||||
@@ -57,5 +62,43 @@ public abstract class EntityMixin {
|
||||
return original.call(entity);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "getEyePosition(F)Lnet/minecraft/world/phys/Vec3;",
|
||||
at = @At("HEAD"),
|
||||
cancellable = true
|
||||
)
|
||||
private void cobblemon$modifyEyePosition_partial(float partialTicks, CallbackInfoReturnable<Vec3> cir) {
|
||||
var entity = (Entity)(Object)this;
|
||||
if (entity.level().isClientSide) return;
|
||||
if (!(entity instanceof Player player)) return;
|
||||
if (!(player instanceof RidePassenger ridePassenger)) return;
|
||||
if (!(player.getVehicle() instanceof OrientationControllable vehicle)) return;
|
||||
var vehicleController = vehicle.getOrientationController();
|
||||
if (vehicleController == null) return;
|
||||
|
||||
|
||||
// TODO: Determine if it needs partialtick involved.
|
||||
Vec3 customEyePos = ridePassenger.cobblemon$getRideEyePos();
|
||||
cir.setReturnValue(customEyePos);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "getEyePosition()Lnet/minecraft/world/phys/Vec3;",
|
||||
at = @At("HEAD"),
|
||||
cancellable = true
|
||||
)
|
||||
private void cobblemon$modifyEyePosition_noPartial(CallbackInfoReturnable<Vec3> cir) {
|
||||
var entity = (Entity)(Object)this;
|
||||
if (entity.level().isClientSide) return;
|
||||
if (!(entity instanceof Player player)) return;
|
||||
if (!(player instanceof RidePassenger ridePassenger)) return;
|
||||
if (!(player.getVehicle() instanceof OrientationControllable vehicle)) return;
|
||||
var vehicleController = vehicle.getOrientationController();
|
||||
if (vehicleController == null) return;
|
||||
|
||||
// TODO: Determine if it needs partialtick involved.
|
||||
Vec3 customEyePos = ridePassenger.cobblemon$getRideEyePos();
|
||||
cir.setReturnValue(customEyePos);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -83,6 +83,7 @@ import com.cobblemon.mod.common.net.messages.client.settings.ServerSettingsPacke
|
||||
import com.cobblemon.mod.common.permission.LaxPermissionValidator
|
||||
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.aspects.CHARACTERISTIC_RAINBOW_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.aspects.COSMETIC_SLOT_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.aspects.GENDER_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.aspects.SHINY_ASPECT
|
||||
@@ -293,6 +294,7 @@ object Cobblemon {
|
||||
SHINY_ASPECT.register()
|
||||
GENDER_ASPECT.register()
|
||||
COSMETIC_SLOT_ASPECT.register()
|
||||
CHARACTERISTIC_RAINBOW_ASPECT.register()
|
||||
|
||||
SpeciesFeatures.types["choice"] = ChoiceSpeciesFeatureProvider::class.java
|
||||
SpeciesFeatures.types["flag"] = FlagSpeciesFeatureProvider::class.java
|
||||
|
||||
@@ -11,16 +11,26 @@ package com.cobblemon.mod.common
|
||||
import net.minecraft.world.entity.schedule.Activity
|
||||
|
||||
object CobblemonActivities {
|
||||
@JvmField
|
||||
val activities = mutableListOf<Activity>()
|
||||
@JvmField
|
||||
val BATTLING = register(Activity("battling"))
|
||||
@JvmField
|
||||
val ACTION_EFFECT = register(Activity("action_effect"))
|
||||
@JvmField
|
||||
val NPC_CHATTING = register(Activity("npc_chatting"))
|
||||
@JvmField
|
||||
val POKEMON_SLEEPING_ACTIVITY = register(Activity("pokemon_sleeping"))
|
||||
@JvmField
|
||||
val POKEMON_GROW_CROP = register(Activity("pokemon_grow_crop"))
|
||||
@JvmField
|
||||
val POKEMON_SLEEP_ON_TRAINER_BED = register(Activity("pokemon_sleep_on_trainer_bed"))
|
||||
@JvmField
|
||||
val POKEMON_HERD = register(Activity("pokemon_herd"))
|
||||
@JvmField
|
||||
val POKEMON_POLLINATION = register(Activity("pokemon_pollination"))
|
||||
|
||||
@JvmStatic
|
||||
fun register(activity: Activity): Activity {
|
||||
activities.add(activity)
|
||||
return activity
|
||||
|
||||
@@ -60,13 +60,13 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
|
||||
// Evolution Ores
|
||||
@JvmField
|
||||
val DAWN_STONE_ORE = evolutionStoneOre("dawn_stone_ore")
|
||||
val DAWN_STONE_ORE = evolutionStoneOre("dawn_stone_ore", 7)
|
||||
@JvmField
|
||||
val DUSK_STONE_ORE = evolutionStoneOre("dusk_stone_ore")
|
||||
@JvmField
|
||||
val FIRE_STONE_ORE = evolutionStoneOre("fire_stone_ore")
|
||||
val FIRE_STONE_ORE = evolutionStoneOre("fire_stone_ore", 10)
|
||||
@JvmField
|
||||
val NETHER_FIRE_STONE_ORE = evolutionStoneOre("nether_fire_stone_ore")
|
||||
val NETHER_FIRE_STONE_ORE = this.create("nether_fire_stone_ore", DropExperienceBlock(UniformInt.of(1, 2), BlockBehaviour.Properties.of().mapColor(MapColor.NETHER).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(3.0F, 3.0F).sound(SoundType.NETHER_ORE).lightLevel{10}))
|
||||
@JvmField
|
||||
val ICE_STONE_ORE = evolutionStoneOre("ice_stone_ore")
|
||||
@JvmField
|
||||
@@ -74,24 +74,24 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
@JvmField
|
||||
val MOON_STONE_ORE = evolutionStoneOre("moon_stone_ore")
|
||||
@JvmField
|
||||
val DRIPSTONE_MOON_STONE_ORE = evolutionStoneOre("dripstone_moon_stone_ore")
|
||||
val DRIPSTONE_MOON_STONE_ORE = this.create("dripstone_moon_stone_ore", DropExperienceBlock(UniformInt.of(1, 2), BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_BROWN).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(3.0F, 3.0F).sound(SoundType.DRIPSTONE_BLOCK)))
|
||||
@JvmField
|
||||
val SHINY_STONE_ORE = evolutionStoneOre("shiny_stone_ore")
|
||||
val SHINY_STONE_ORE = evolutionStoneOre("shiny_stone_ore", 12)
|
||||
@JvmField
|
||||
val SUN_STONE_ORE = evolutionStoneOre("sun_stone_ore")
|
||||
val SUN_STONE_ORE = evolutionStoneOre("sun_stone_ore", 2)
|
||||
@JvmField
|
||||
val TERRACOTTA_SUN_STONE_ORE = evolutionStoneOre("terracotta_sun_stone_ore")
|
||||
val TERRACOTTA_SUN_STONE_ORE = this.create("terracotta_sun_stone_ore", DropExperienceBlock(UniformInt.of(1, 2), BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_ORANGE).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(3.0F, 3.0F).lightLevel{2}))
|
||||
@JvmField
|
||||
val THUNDER_STONE_ORE = evolutionStoneOre("thunder_stone_ore")
|
||||
val THUNDER_STONE_ORE = evolutionStoneOre("thunder_stone_ore", 6)
|
||||
@JvmField
|
||||
val WATER_STONE_ORE = evolutionStoneOre("water_stone_ore")
|
||||
|
||||
@JvmField
|
||||
val DEEPSLATE_DAWN_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_dawn_stone_ore")
|
||||
val DEEPSLATE_DAWN_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_dawn_stone_ore", 7)
|
||||
@JvmField
|
||||
val DEEPSLATE_DUSK_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_dusk_stone_ore")
|
||||
@JvmField
|
||||
val DEEPSLATE_FIRE_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_fire_stone_ore")
|
||||
val DEEPSLATE_FIRE_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_fire_stone_ore", 10)
|
||||
@JvmField
|
||||
val DEEPSLATE_ICE_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_ice_stone_ore")
|
||||
@JvmField
|
||||
@@ -99,11 +99,11 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
@JvmField
|
||||
val DEEPSLATE_MOON_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_moon_stone_ore")
|
||||
@JvmField
|
||||
val DEEPSLATE_SHINY_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_shiny_stone_ore")
|
||||
val DEEPSLATE_SHINY_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_shiny_stone_ore", 12)
|
||||
@JvmField
|
||||
val DEEPSLATE_SUN_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_sun_stone_ore")
|
||||
val DEEPSLATE_SUN_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_sun_stone_ore", 2)
|
||||
@JvmField
|
||||
val DEEPSLATE_THUNDER_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_thunder_stone_ore")
|
||||
val DEEPSLATE_THUNDER_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_thunder_stone_ore", 6)
|
||||
@JvmField
|
||||
val DEEPSLATE_WATER_STONE_ORE = this.deepslateEvolutionStoneOre("deepslate_water_stone_ore")
|
||||
|
||||
@@ -454,7 +454,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
|
||||
@JvmField
|
||||
val SOUL_CAMPFIRE = create("soul_campfire", CampfireBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOD).noOcclusion().pushReaction(PushReaction.BLOCK).mapColor(MapColor.PODZOL).strength(2.0F).lightLevel{9}, true))
|
||||
|
||||
|
||||
@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
|
||||
@@ -577,74 +577,145 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
|
||||
private val berries = mutableMapOf<ResourceLocation, BerryBlock>()
|
||||
|
||||
@JvmField
|
||||
val AGUAV_BERRY = this.berryBlock("aguav")
|
||||
@JvmField
|
||||
val APICOT_BERRY = this.berryBlock("apicot")
|
||||
@JvmField
|
||||
val ASPEAR_BERRY = this.berryBlock("aspear")
|
||||
@JvmField
|
||||
val BABIRI_BERRY = this.berryBlock("babiri")
|
||||
@JvmField
|
||||
val BELUE_BERRY = this.berryBlock("belue")
|
||||
@JvmField
|
||||
val BLUK_BERRY = this.berryBlock("bluk")
|
||||
@JvmField
|
||||
val CHARTI_BERRY = this.berryBlock("charti")
|
||||
@JvmField
|
||||
val CHERI_BERRY = this.berryBlock("cheri")
|
||||
@JvmField
|
||||
val CHESTO_BERRY = this.berryBlock("chesto")
|
||||
@JvmField
|
||||
val CHILAN_BERRY = this.berryBlock("chilan")
|
||||
@JvmField
|
||||
val CHOPLE_BERRY = this.berryBlock("chople")
|
||||
@JvmField
|
||||
val COBA_BERRY = this.berryBlock("coba")
|
||||
@JvmField
|
||||
val COLBUR_BERRY = this.berryBlock("colbur")
|
||||
@JvmField
|
||||
val CORNN_BERRY = this.berryBlock("cornn")
|
||||
@JvmField
|
||||
val CUSTAP_BERRY = this.berryBlock("custap")
|
||||
@JvmField
|
||||
val DURIN_BERRY = this.berryBlock("durin")
|
||||
@JvmField
|
||||
val EGGANT_BERRY = this.berryBlock("eggant")
|
||||
@JvmField
|
||||
val ENIGMA_BERRY = this.berryBlock("enigma")
|
||||
@JvmField
|
||||
val FIGY_BERRY = this.berryBlock("figy")
|
||||
@JvmField
|
||||
val GANLON_BERRY = this.berryBlock("ganlon")
|
||||
@JvmField
|
||||
val GREPA_BERRY = this.berryBlock("grepa")
|
||||
@JvmField
|
||||
val HABAN_BERRY = this.berryBlock("haban")
|
||||
@JvmField
|
||||
val HONDEW_BERRY = this.berryBlock("hondew")
|
||||
@JvmField
|
||||
val HOPO_BERRY = this.berryBlock("hopo")
|
||||
@JvmField
|
||||
val IAPAPA_BERRY = this.berryBlock("iapapa")
|
||||
@JvmField
|
||||
val JABOCA_BERRY = this.berryBlock("jaboca")
|
||||
@JvmField
|
||||
val KASIB_BERRY = this.berryBlock("kasib")
|
||||
@JvmField
|
||||
val KEBIA_BERRY = this.berryBlock("kebia")
|
||||
@JvmField
|
||||
val KEE_BERRY = this.berryBlock("kee")
|
||||
@JvmField
|
||||
val KELPSY_BERRY = this.berryBlock("kelpsy")
|
||||
@JvmField
|
||||
val LANSAT_BERRY = this.berryBlock("lansat")
|
||||
@JvmField
|
||||
val LEPPA_BERRY = this.berryBlock("leppa")
|
||||
@JvmField
|
||||
val LIECHI_BERRY = this.berryBlock("liechi")
|
||||
@JvmField
|
||||
val LUM_BERRY = this.berryBlock("lum")
|
||||
@JvmField
|
||||
val MAGO_BERRY = this.berryBlock("mago")
|
||||
@JvmField
|
||||
val MAGOST_BERRY = this.berryBlock("magost")
|
||||
@JvmField
|
||||
val MARANGA_BERRY = this.berryBlock("maranga")
|
||||
@JvmField
|
||||
val MICLE_BERRY = this.berryBlock("micle")
|
||||
@JvmField
|
||||
val NANAB_BERRY = this.berryBlock("nanab")
|
||||
@JvmField
|
||||
val NOMEL_BERRY = this.berryBlock("nomel")
|
||||
@JvmField
|
||||
val OCCA_BERRY = this.berryBlock("occa")
|
||||
@JvmField
|
||||
val ORAN_BERRY = this.berryBlock("oran")
|
||||
@JvmField
|
||||
val PAMTRE_BERRY = this.berryBlock("pamtre")
|
||||
@JvmField
|
||||
val PASSHO_BERRY = this.berryBlock("passho")
|
||||
@JvmField
|
||||
val PAYAPA_BERRY = this.berryBlock("payapa")
|
||||
@JvmField
|
||||
val PECHA_BERRY = this.berryBlock("pecha")
|
||||
@JvmField
|
||||
val PERSIM_BERRY = this.berryBlock("persim")
|
||||
@JvmField
|
||||
val PETAYA_BERRY = this.berryBlock("petaya")
|
||||
@JvmField
|
||||
val PINAP_BERRY = this.berryBlock("pinap")
|
||||
@JvmField
|
||||
val POMEG_BERRY = this.berryBlock("pomeg")
|
||||
@JvmField
|
||||
val QUALOT_BERRY = this.berryBlock("qualot")
|
||||
@JvmField
|
||||
val RABUTA_BERRY = this.berryBlock("rabuta")
|
||||
@JvmField
|
||||
val RAWST_BERRY = this.berryBlock("rawst")
|
||||
@JvmField
|
||||
val RAZZ_BERRY = this.berryBlock("razz")
|
||||
@JvmField
|
||||
val RINDO_BERRY = this.berryBlock("rindo")
|
||||
@JvmField
|
||||
val ROSELI_BERRY = this.berryBlock("roseli")
|
||||
@JvmField
|
||||
val ROWAP_BERRY = this.berryBlock("rowap")
|
||||
@JvmField
|
||||
val SALAC_BERRY = this.berryBlock("salac")
|
||||
@JvmField
|
||||
val SHUCA_BERRY = this.berryBlock("shuca")
|
||||
@JvmField
|
||||
val SITRUS_BERRY = this.berryBlock("sitrus")
|
||||
@JvmField
|
||||
val SPELON_BERRY = this.berryBlock("spelon")
|
||||
@JvmField
|
||||
val STARF_BERRY = this.berryBlock("starf")
|
||||
@JvmField
|
||||
val TAMATO_BERRY = this.berryBlock("tamato")
|
||||
@JvmField
|
||||
val TANGA_BERRY = this.berryBlock("tanga")
|
||||
@JvmField
|
||||
val TOUGA_BERRY = this.berryBlock("touga")
|
||||
@JvmField
|
||||
val WACAN_BERRY = this.berryBlock("wacan")
|
||||
@JvmField
|
||||
val WATMEL_BERRY = this.berryBlock("watmel")
|
||||
@JvmField
|
||||
val WEPEAR_BERRY = this.berryBlock("wepear")
|
||||
@JvmField
|
||||
val WIKI_BERRY = this.berryBlock("wiki")
|
||||
@JvmField
|
||||
val YACHE_BERRY = this.berryBlock("yache")
|
||||
//val BINDING_SOIL = this.create("binding_soil", BindingSoilBlock(BlockBehaviour.Properties.of()))
|
||||
|
||||
@@ -712,8 +783,10 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
}
|
||||
|
||||
private fun evolutionStoneOre(name: String) = this.create(name, DropExperienceBlock(UniformInt.of(1, 2), BlockBehaviour.Properties.ofFullCopy(Blocks.IRON_ORE)))
|
||||
private fun evolutionStoneOre(name: String, lightLevel: Int) = this.create(name, DropExperienceBlock(UniformInt.of(1, 2), BlockBehaviour.Properties.ofFullCopy(Blocks.IRON_ORE).lightLevel { lightLevel }))
|
||||
|
||||
private fun deepslateEvolutionStoneOre(name: String) = this.create(name, DropExperienceBlock(UniformInt.of(1, 2), BlockBehaviour.Properties.ofFullCopy(Blocks.DEEPSLATE_IRON_ORE)))
|
||||
private fun deepslateEvolutionStoneOre(name: String, lightLevel: Int) = this.create(name, DropExperienceBlock(UniformInt.of(1, 2), BlockBehaviour.Properties.ofFullCopy(Blocks.DEEPSLATE_IRON_ORE).lightLevel { lightLevel }))
|
||||
|
||||
/**
|
||||
* Helper method for creating leaves
|
||||
|
||||
@@ -43,6 +43,7 @@ object CobblemonCosmeticItems : JsonDataRegistry<CosmeticItemAssignment> {
|
||||
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
|
||||
.create()
|
||||
|
||||
@JvmField
|
||||
val cosmeticItems = mutableListOf<CosmeticItemAssignment>()
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, CosmeticItemAssignment>) {
|
||||
@@ -55,7 +56,9 @@ object CobblemonCosmeticItems : JsonDataRegistry<CosmeticItemAssignment> {
|
||||
CosmeticItemAssignmentSyncPacket(cosmeticItems).sendToPlayer(player)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun findValidForPokemon(pokemon: Pokemon) = cosmeticItems.filter { it.pokemon.any { it.matches(pokemon) } }
|
||||
@JvmStatic
|
||||
fun findValidCosmeticForPokemonAndItem(registryAccess: RegistryAccess, pokemon: Pokemon, itemStack: ItemStack) = cosmeticItems
|
||||
.filter { it.pokemon.any { it.matches(pokemon) } }
|
||||
.flatMap { it.cosmeticItems }
|
||||
|
||||
@@ -21,56 +21,73 @@ import net.minecraft.resources.ResourceLocation
|
||||
|
||||
object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>, ResourceKey<Registry<DataComponentType<*>>>, DataComponentType<*>>() {
|
||||
|
||||
@JvmField
|
||||
val POKEMON_ITEM: DataComponentType<PokemonItemComponent> = create("pokemon_item", DataComponentType.builder<PokemonItemComponent>()
|
||||
.persistent(PokemonItemComponent.CODEC)
|
||||
.networkSynchronized(PokemonItemComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val HELD_ITEM_EFFECT: DataComponentType<HeldItemEffectComponent> = create("held_item_effect", DataComponentType.builder<HeldItemEffectComponent>()
|
||||
.persistent(HeldItemEffectComponent.CODEC)
|
||||
.networkSynchronized(HeldItemEffectComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val BAIT: DataComponentType<RodBaitComponent> = create("bait", DataComponentType.builder<RodBaitComponent>()
|
||||
.persistent(RodBaitComponent.CODEC)
|
||||
.networkSynchronized(RodBaitComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val POT_DATA: DataComponentType<PotComponent> = create("cooking_pot_item", DataComponentType.builder<PotComponent>()
|
||||
.persistent(PotComponent.CODEC)
|
||||
.networkSynchronized(PotComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val BAIT_EFFECTS: DataComponentType<BaitEffectsComponent> = create("bait_effects", DataComponentType.builder<BaitEffectsComponent>()
|
||||
.persistent(BaitEffectsComponent.CODEC)
|
||||
.networkSynchronized(BaitEffectsComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val FLAVOUR: DataComponentType<FlavourComponent> = create("flavour", DataComponentType.builder<FlavourComponent>()
|
||||
.persistent(FlavourComponent.CODEC)
|
||||
.networkSynchronized(FlavourComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val RIDE_BOOST: DataComponentType<RideBoostsComponent> = create("ride_boosts", DataComponentType.builder<RideBoostsComponent>()
|
||||
.persistent(RideBoostsComponent.CODEC)
|
||||
.networkSynchronized(RideBoostsComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val FOOD_COLOUR: DataComponentType<FoodColourComponent> = create("food_colour", DataComponentType.builder<FoodColourComponent>()
|
||||
.persistent(FoodColourComponent.CODEC)
|
||||
.networkSynchronized(FoodColourComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val INGREDIENT: DataComponentType<IngredientComponent> = create("ingredient", DataComponentType.builder<IngredientComponent>()
|
||||
.persistent(IngredientComponent.CODEC)
|
||||
.networkSynchronized(IngredientComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val FOOD: DataComponentType<FoodComponent> = create("food", DataComponentType.builder<FoodComponent>()
|
||||
.persistent(FoodComponent.CODEC)
|
||||
.networkSynchronized(FoodComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val MOB_EFFECTS: DataComponentType<MobEffectsComponent> = create("mob_effects", DataComponentType.builder<MobEffectsComponent>()
|
||||
.persistent(MobEffectsComponent.CODEC)
|
||||
.networkSynchronized(MobEffectsComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
@JvmField
|
||||
val CRAFTED: DataComponentType<Boolean> = create("crafted", DataComponentType.builder<Boolean>()
|
||||
.persistent(Codec.BOOL)
|
||||
.networkSynchronized(ByteBufCodecs.BOOL)
|
||||
@@ -82,6 +99,7 @@ object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:cooking_pot_item"), POT_DATA)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:bait_effects"), BAIT_EFFECTS)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:flavour"), FLAVOUR)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:ride_boosts"), RIDE_BOOST)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:food_colour"), FOOD_COLOUR)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:ingredient"), INGREDIENT)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:food"), FOOD)
|
||||
|
||||
@@ -36,7 +36,7 @@ import com.cobblemon.mod.common.item.berry.PPRestoringBerryItem
|
||||
import com.cobblemon.mod.common.item.berry.PortionHealingBerryItem
|
||||
import com.cobblemon.mod.common.item.berry.StatusCuringBerryItem
|
||||
import com.cobblemon.mod.common.item.berry.VolatileCuringBerryItem
|
||||
import com.cobblemon.mod.common.item.food.PonigiriItem
|
||||
import com.cobblemon.mod.common.item.interactive.PonigiriItem
|
||||
import com.cobblemon.mod.common.item.food.SinisterTeaItem
|
||||
import com.cobblemon.mod.common.item.interactive.*
|
||||
import com.cobblemon.mod.common.item.interactive.ability.AbilityChangeItem
|
||||
@@ -517,6 +517,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField val RAWST_BERRY = berryItem("rawst", StatusCuringBerryItem(CobblemonBlocks.RAWST_BERRY, Statuses.BURN))
|
||||
@JvmField val ASPEAR_BERRY = berryItem("aspear", StatusCuringBerryItem(CobblemonBlocks.ASPEAR_BERRY, Statuses.FROZEN))
|
||||
@JvmField val PERSIM_BERRY = berryItem("persim", VolatileCuringBerryItem(CobblemonBlocks.PERSIM_BERRY, "confusion"))
|
||||
@JvmField val EGGANT_BERRY = berryItem("eggant", VolatileCuringBerryItem(CobblemonBlocks.EGGANT_BERRY, "attract"))
|
||||
@JvmField val RAZZ_BERRY = berryItem("razz", CobblemonBlocks.RAZZ_BERRY)
|
||||
@JvmField val BLUK_BERRY = berryItem("bluk", CobblemonBlocks.BLUK_BERRY)
|
||||
@JvmField val NANAB_BERRY = berryItem("nanab", CobblemonBlocks.NANAB_BERRY)
|
||||
@@ -696,7 +697,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val SUPERB_REMEDY = compostableItem("superb_remedy", RemedyItem(RemedyItem.SUPERB), 0.85f)
|
||||
@JvmField
|
||||
val MOOMOO_MILK = create("moomoo_milk", CobblemonItem(Item.Properties().craftRemainder(Items.GLASS_BOTTLE).stacksTo((16))))
|
||||
val MOOMOO_MILK = create("moomoo_milk", MoomooMilk(Item.Properties().craftRemainder(Items.GLASS_BOTTLE).stacksTo((16))))
|
||||
|
||||
@JvmField
|
||||
val POTION = create("potion", PotionItem(PotionType.POTION))
|
||||
|
||||
@@ -12,9 +12,11 @@ import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.data.DataRegistry
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.mechanics.AprijuicesMechanic
|
||||
import com.cobblemon.mod.common.mechanics.BerriesMechanic
|
||||
import com.cobblemon.mod.common.mechanics.PotionsMechanic
|
||||
import com.cobblemon.mod.common.mechanics.RemediesMechanic
|
||||
import com.cobblemon.mod.common.net.messages.client.data.CobblemonMechanicsSyncPacket
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
@@ -37,13 +39,22 @@ object CobblemonMechanics : DataRegistry {
|
||||
var remedies = RemediesMechanic()
|
||||
var berries = BerriesMechanic()
|
||||
var potions = PotionsMechanic()
|
||||
var aprijuices = AprijuicesMechanic()
|
||||
|
||||
override fun sync(player: ServerPlayer) {}
|
||||
override fun sync(player: ServerPlayer) {
|
||||
CobblemonMechanicsSyncPacket(
|
||||
this.remedies,
|
||||
this.berries,
|
||||
this.potions,
|
||||
this.aprijuices,
|
||||
).sendToPlayer(player)
|
||||
}
|
||||
|
||||
override fun reload(manager: ResourceManager) {
|
||||
remedies = loadMechanic(manager, "remedies", RemediesMechanic::class.java)
|
||||
berries = loadMechanic(manager, "berries", BerriesMechanic::class.java)
|
||||
potions = loadMechanic(manager, "potions", PotionsMechanic::class.java)
|
||||
aprijuices = loadMechanic(manager, "aprijuices", AprijuicesMechanic::class.java)
|
||||
}
|
||||
|
||||
private fun <T> loadMechanic(manager: ResourceManager, name: String, clazz: Class<T>): T {
|
||||
|
||||
@@ -15,12 +15,12 @@ import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.ListCodec
|
||||
import com.mojang.serialization.codecs.PrimitiveCodec
|
||||
import net.minecraft.core.UUIDUtil
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import java.util.Optional
|
||||
import java.util.UUID
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.GlobalPos
|
||||
import net.minecraft.core.UUIDUtil
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import java.util.*
|
||||
|
||||
object CobblemonMemories {
|
||||
val memories = mutableMapOf<String, MemoryModuleType<*>>()
|
||||
@@ -30,46 +30,80 @@ object CobblemonMemories {
|
||||
* get serialized during relogs. This makes sense for things like battles which
|
||||
* do not survive a relog therefore any memory of it should be temporary.
|
||||
*/
|
||||
|
||||
@JvmField
|
||||
val BATTLING_POKEMON = register("battling_pokemon", ListCodec(UUIDUtil.CODEC, 0, 31))
|
||||
@JvmField
|
||||
val NPC_BATTLING = register("npc_battling", PrimitiveCodec.BOOL)
|
||||
@JvmField
|
||||
val DIALOGUES = register<List<ActiveDialogue>>("npc_dialogues")
|
||||
@JvmField
|
||||
val ACTIVE_ACTION_EFFECT = register<ActionEffectContext>("active_action_effect")
|
||||
@JvmField
|
||||
val POKEMON_FLYING = register("pokemon_flying", PrimitiveCodec.BOOL)
|
||||
@JvmField
|
||||
val POKEMON_DROWSY = register("pokemon_drowsy", PrimitiveCodec.BOOL)
|
||||
@JvmField
|
||||
val POKEMON_SLEEPING = register("pokemon_sleeping", PrimitiveCodec.BOOL)
|
||||
@JvmField
|
||||
val POKEMON_BATTLE = register<UUID>("pokemon_battle")
|
||||
@JvmField
|
||||
val PATH_COOLDOWN = register<Boolean>("path_cooldown")
|
||||
@JvmField
|
||||
val TARGETED_BATTLE_POKEMON = register<UUID>("targeted_battle_pokemon")
|
||||
@JvmField
|
||||
val NEAREST_VISIBLE_ATTACKER = register<LivingEntity>("nearest_visible_attacker")
|
||||
@JvmField
|
||||
val NEARBY_GROWABLE_CROPS = register<BlockPos>("nearby_growable_crops")
|
||||
@JvmField
|
||||
val NEARBY_SWEET_BERRY_BUSH = register<BlockPos>("nearest_sweet_berry_bush")
|
||||
@JvmField
|
||||
val DISABLE_WALK_TO_BERRY_BUSH = register<Boolean>("disable_walk_to_berry_bush")
|
||||
@JvmField
|
||||
val TIME_TRYING_TO_REACH_BERRY_BUSH = register<Int>("time_trying_to_reach_berry_bush")
|
||||
@JvmField
|
||||
val IS_CONSUMING_ITEM = register<Boolean>("is_consuming_item")
|
||||
@JvmField
|
||||
val RECENTLY_ATE_GRASS = register<Boolean>("recently_ate_grass")
|
||||
val HIVE_LOCATION = register<BlockPos>("hive_location")
|
||||
@JvmField
|
||||
val HIVE_LOCATION = register<BlockPos>("hive_location", BlockPos.CODEC)
|
||||
@JvmField
|
||||
val HIVE_BLACKLIST = register<List<BlockPos>>("hive_blacklist")
|
||||
@JvmField
|
||||
val HIVE_COOLDOWN = register<Boolean>("hive_cooldown")
|
||||
val NEARBY_FLOWERS = register<List<BlockPos>>("nearby_flower")
|
||||
val POLLINATED = register<Boolean>("pollinated", PrimitiveCodec.BOOL)
|
||||
@JvmField
|
||||
val NEARBY_FLOWER = register<BlockPos>("nearby_flower", BlockPos.CODEC)
|
||||
@JvmField
|
||||
val PATH_TO_NEARBY_FLOWER_COOLDOWN = register<Boolean>("path_to_nearby_flower_cooldown")
|
||||
@JvmField
|
||||
val HAS_NECTAR = register<Boolean>("has_nectar", PrimitiveCodec.BOOL)
|
||||
@JvmField
|
||||
val NEARBY_SACC_LEAVES = register<BlockPos>("nearby_sacc_leaves", BlockPos.CODEC)
|
||||
/** who am i following rn? */
|
||||
@JvmField
|
||||
val HERD_LEADER = register<String>("herd_leader", PrimitiveCodec.STRING)
|
||||
/** how many are following me rn? */
|
||||
@JvmField
|
||||
val HERD_SIZE = register<Int>("herd_size") // Don't bother saving it, we'll try to keep count roughly.
|
||||
@JvmField
|
||||
val ATTACK_TARGET_DATA = register<CobblemonAttackTargetData>("attack_target_data") // This is used to store additional information about the attack target, such as when to give up pursuit.
|
||||
@JvmField
|
||||
val WANDER_CONTROL = register<CobblemonWanderControl>("wander_control")
|
||||
@JvmField
|
||||
val DISABLE_WALK_TO_WANTED_ITEM = register<Boolean>("disable_walk_to_wanted_item")
|
||||
@JvmField
|
||||
val TIME_TRYING_TO_REACH_WANTED_ITEM = register<Int>("time_trying_to_wanted_item")
|
||||
|
||||
@JvmStatic
|
||||
fun <U> register(id: String, codec: Codec<U>): MemoryModuleType<U> {
|
||||
val memoryModule = MemoryModuleType(Optional.of(codec))
|
||||
memories[id] = memoryModule
|
||||
return memoryModule
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun <U> register(id: String): MemoryModuleType<U> {
|
||||
val memoryModule = MemoryModuleType<U>(Optional.empty())
|
||||
memories[id] = memoryModule
|
||||
return memoryModule
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import com.cobblemon.mod.common.client.net.callback.move.OpenMoveCallbackHandler
|
||||
import com.cobblemon.mod.common.client.net.callback.party.OpenPartyCallbackHandler
|
||||
import com.cobblemon.mod.common.client.net.callback.partymove.OpenPartyMoveCallbackHandler
|
||||
import com.cobblemon.mod.common.client.net.cooking.ToggleCookingPotLidHandler
|
||||
import com.cobblemon.mod.common.client.net.data.CobblemonMechanicsSyncHandler
|
||||
import com.cobblemon.mod.common.client.net.data.DataRegistrySyncPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.data.RideSettingsSyncHandler
|
||||
import com.cobblemon.mod.common.client.net.dialogue.DialogueClosedHandler
|
||||
@@ -28,12 +29,13 @@ import com.cobblemon.mod.common.client.net.effect.RunPosableMoLangHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.SaccharineLogBlockParticlesHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormEntityParticleHandler
|
||||
import com.cobblemon.mod.common.client.net.effect.SpawnSnowstormParticleHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.ExpGainedDataPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.InteractPokemonUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.PokedexUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.gui.SummaryUIPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.npc.CloseNPCEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.npc.OpenNPCEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.orientation.S2CUpdateOrientationHandler
|
||||
import com.cobblemon.mod.common.client.net.orientation.ClientboundUpdateOrientationHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.ClosePastureHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.OpenPastureHandler
|
||||
import com.cobblemon.mod.common.client.net.pasture.PokemonPasturedHandler
|
||||
@@ -132,6 +134,7 @@ import com.cobblemon.mod.common.net.messages.client.trade.TradeOfferNotification
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeProcessStartedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeStartedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.trade.TradeUpdatedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.ExpGainedDataPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.InteractPokemonUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.PokedexUIPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.ui.SummaryUIPacket
|
||||
@@ -179,6 +182,7 @@ import com.cobblemon.mod.common.net.messages.server.pokemon.update.SetNicknamePa
|
||||
import com.cobblemon.mod.common.net.messages.server.pokemon.update.evolution.AcceptEvolutionPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.DismountPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateDriverInputPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.riding.ServerboundUpdateRiderRotationPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.starter.RequestStarterScreenPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.SwapPCPartyPokemonPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.storage.party.MovePartyPokemonPacket
|
||||
@@ -216,7 +220,7 @@ import com.cobblemon.mod.common.net.serverhandling.dialogue.EscapeDialogueHandle
|
||||
import com.cobblemon.mod.common.net.serverhandling.dialogue.InputToDialogueHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.evolution.AcceptEvolutionHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.npc.SaveNPCHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.orientation.OrientationPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.orientation.ServerboundUpdateOrientationHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pasture.PasturePokemonHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pasture.SetPastureConflictHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.pasture.UnpastureAllPokemonHandler
|
||||
@@ -231,6 +235,7 @@ import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetMarkingsHan
|
||||
import com.cobblemon.mod.common.net.serverhandling.pokemon.update.SetNicknameHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.riding.DismountPokemonPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.riding.DriverInputPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.riding.ServerboundUpdateRiderRotationHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.starter.RequestStarterScreenHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.starter.SelectStarterPacketHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.storage.BenchMoveHandler
|
||||
@@ -263,10 +268,13 @@ object CobblemonNetwork {
|
||||
fun ServerPlayer.sendPacket(packet: NetworkPacket<*>) {
|
||||
sendPacketToPlayer(this, packet)
|
||||
}
|
||||
@JvmStatic
|
||||
fun sendToServer(packet: NetworkPacket<*>) {
|
||||
Cobblemon.implementation.networkManager.sendToServer(packet)
|
||||
}
|
||||
@JvmStatic
|
||||
fun sendToAllPlayers(packet: NetworkPacket<*>) = sendPacketToPlayers(server()!!.playerList.players, packet)
|
||||
@JvmStatic
|
||||
fun sendPacketToPlayers(players: Iterable<ServerPlayer>, packet: NetworkPacket<*>) = players.forEach { sendPacketToPlayer(it, packet) }
|
||||
|
||||
val s2cPayloads = generateS2CPacketInfoList()
|
||||
@@ -345,6 +353,7 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(InteractPokemonUIPacket.ID, InteractPokemonUIPacket::decode, InteractPokemonUIPacketHandler))
|
||||
list.add(PacketRegisterInfo(PlayerInteractOptionsPacket.ID, PlayerInteractOptionsPacket::decode, PlayerInteractOptionsHandler))
|
||||
list.add(PacketRegisterInfo(PokedexUIPacket.ID, PokedexUIPacket::decode, PokedexUIPacketHandler))
|
||||
list.add(PacketRegisterInfo(ExpGainedDataPacket.ID, ExpGainedDataPacket::decode, ExpGainedDataPacketHandler))
|
||||
|
||||
// Starter packets
|
||||
list.add(PacketRegisterInfo(OpenStarterUIPacket.ID, OpenStarterUIPacket::decode, StarterUIPacketHandler))
|
||||
@@ -387,6 +396,7 @@ object CobblemonNetwork {
|
||||
|
||||
// Data registries
|
||||
list.add(PacketRegisterInfo(AbilityRegistrySyncPacket.ID, AbilityRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(CobblemonMechanicsSyncPacket.ID, CobblemonMechanicsSyncPacket::decode, CobblemonMechanicsSyncHandler))
|
||||
list.add(PacketRegisterInfo(MovesRegistrySyncPacket.ID, MovesRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(BerryRegistrySyncPacket.ID, BerryRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(SpeciesRegistrySyncPacket.ID, SpeciesRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
@@ -442,7 +452,7 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(UpdatePastureConflictFlagPacket.ID, UpdatePastureConflictFlagPacket::decode, UpdatePastureConflictFlagHandler))
|
||||
|
||||
// Orientation
|
||||
list.add(PacketRegisterInfo(ClientboundUpdateOrientationPacket.ID, ClientboundUpdateOrientationPacket::decode, S2CUpdateOrientationHandler))
|
||||
list.add(PacketRegisterInfo(ClientboundUpdateOrientationPacket.ID, ClientboundUpdateOrientationPacket::decode, ClientboundUpdateOrientationHandler))
|
||||
|
||||
// Behaviours
|
||||
list.add(PacketRegisterInfo(PlayPosableAnimationPacket.ID, PlayPosableAnimationPacket::decode, PlayPosableAnimationHandler))
|
||||
@@ -577,13 +587,14 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(SaveNPCPacket.ID, SaveNPCPacket::decode, SaveNPCHandler))
|
||||
|
||||
// Riding packet(s)
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateOrientationPacket.ID, ServerboundUpdateOrientationPacket::decode, OrientationPacketHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateOrientationPacket.ID, ServerboundUpdateOrientationPacket::decode, ServerboundUpdateOrientationHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatePacket.ID, ServerboundUpdateRidingStatePacket::decode, ServerboundUpdateRidingStateHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatsPacket.ID, ServerboundUpdateRidingStatsPacket::decode, ServerboundUpdateRidingStatsHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatRangePacket.ID, ServerboundUpdateRidingStatRangePacket::decode, ServerboundUpdateRidingStatRangeHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRidingSettingsPacket.ID, ServerboundUpdateRidingSettingsPacket::decode, ServerboundUpdateRidingSettingsHandler))
|
||||
list.add(PacketRegisterInfo(DismountPokemonPacket.ID, DismountPokemonPacket::decode, DismountPokemonPacketHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateDriverInputPacket.ID, ServerboundUpdateDriverInputPacket::decode, DriverInputPacketHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRiderRotationPacket.ID, ServerboundUpdateRiderRotationPacket::decode, ServerboundUpdateRiderRotationHandler))
|
||||
|
||||
// Cooking
|
||||
list.add(PacketRegisterInfo(ToggleCookingPotLidPacket.ID, ToggleCookingPotLidPacket::decode, ToggleCookingPotLidHandler))
|
||||
@@ -598,4 +609,4 @@ object CobblemonNetwork {
|
||||
fun sendPacketToPlayer(player: ServerPlayer, packet: NetworkPacket<*>) {
|
||||
Cobblemon.implementation.networkManager.sendPacketToPlayer(player, packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,8 +26,6 @@ object CobblemonPoiTypes: PlatformRegistry<Registry<PoiType>, ResourceKey<Regist
|
||||
@JvmField
|
||||
val NURSE_KEY = createKey("nurse", CobblemonBlocks.HEALING_MACHINE, 1, 1)
|
||||
@JvmField
|
||||
val POKE_SNACK_KEY = createKey("poke_snack", CobblemonBlocks.POKE_SNACK, 0, 1)
|
||||
@JvmField
|
||||
val SACCHARINE_LOG_SLATHERED_KEY = createKey("saccharine_log_slathered", CobblemonBlocks.SACCHARINE_LOG_SLATHERED, 0, 1)
|
||||
// TODO after 1.7
|
||||
// @JvmField
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.cobblemon.mod.common.api.riding.behaviour.types.land.VehicleSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BoatSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BurstSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.DolphinSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.SubmarineSettings
|
||||
import com.cobblemon.mod.common.net.messages.client.data.RideSettingsSyncPacket
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
|
||||
@@ -63,6 +64,7 @@ object CobblemonRideSettings : DataRegistry {
|
||||
var boat = BoatSettings()
|
||||
var burst = BurstSettings()
|
||||
var dolphin = DolphinSettings()
|
||||
var submarine = SubmarineSettings()
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
player.sendPacket(
|
||||
@@ -78,7 +80,8 @@ object CobblemonRideSettings : DataRegistry {
|
||||
vehicle = vehicle,
|
||||
boat = boat,
|
||||
burst = burst,
|
||||
dolphin = dolphin
|
||||
dolphin = dolphin,
|
||||
submarine = submarine
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -96,6 +99,7 @@ object CobblemonRideSettings : DataRegistry {
|
||||
boat = loadStyle(manager, "boat", BoatSettings::class.java)
|
||||
burst = loadStyle(manager, "burst", BurstSettings::class.java)
|
||||
dolphin = loadStyle(manager, "dolphin", DolphinSettings::class.java)
|
||||
submarine = loadStyle(manager, "submarine", SubmarineSettings::class.java)
|
||||
}
|
||||
|
||||
private fun <T : RidingBehaviourSettings> loadStyle(manager: ResourceManager, name: String, clazz: Class<T>): T {
|
||||
|
||||
@@ -20,30 +20,45 @@ import net.minecraft.world.entity.ai.sensing.SensorType
|
||||
object CobblemonSensors {
|
||||
val sensors = mutableMapOf<String, SensorType<*>>()
|
||||
|
||||
@JvmField
|
||||
val NPC_BATTLING = register("npc_battling", ::NPCBattlingSensor)
|
||||
@JvmField
|
||||
val BATTLING_POKEMON = register("battling_pokemon", ::BattlingPokemonSensor)
|
||||
// val NPC_BATTLING = register("npc_battling", ::NPCBattlingSensor)
|
||||
@JvmField
|
||||
val POKEMON_DROWSY = register("pokemon_drowsy", ::DrowsySensor)
|
||||
|
||||
@JvmField
|
||||
val POKEMON_ADULT = register("pokemon_adult_sensor", ::PokemonAdultSensor)
|
||||
|
||||
@JvmField
|
||||
val POKEMON_DISTURBANCE = register("pokemon_disturbance_sensor", ::PokemonDisturbancesSensor)
|
||||
|
||||
@JvmField
|
||||
val POKEMON_DEFEND_OWNER = register("pokemon_owner_under_attack", ::DefendOwnerSensor)
|
||||
|
||||
@JvmField
|
||||
val NEARBY_GROWABLE_CROPS = register("nearby_growable_crops", ::PokemonGrowableCropSensor)
|
||||
|
||||
@JvmField
|
||||
val NEARBY_BEE_HIVE = register("nearby_bee_hive", ::BeeHiveSensor)
|
||||
|
||||
@JvmField
|
||||
val NEARBY_FLOWER = register("nearby_flower", ::FlowerSensor)
|
||||
|
||||
@JvmField
|
||||
val NEARBY_SWEET_BERRY_BUSH = register("nearby_sweet_berry_bush", ::SweetBerryBushSensor)
|
||||
|
||||
@JvmField
|
||||
val POKEMON_NEARBY_WANTED_ITEM = register("pokemon_nearby_wanted_item", ::PokemonItemSensor)
|
||||
|
||||
@JvmField
|
||||
val NEARBY_SACC_LEAVES = register("nearby_sacc_leaves", ::SacLeavesSensor)
|
||||
|
||||
@JvmStatic
|
||||
fun <E : Entity, U : Sensor<E>> register(id: String, supplier: Supplier<U>): SensorType<U> {
|
||||
val sensor = SensorType(supplier)
|
||||
sensors[id] = sensor
|
||||
return sensor
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,6 +103,11 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
@JvmField
|
||||
val EVOLUTION = this.create("evolution.full")
|
||||
|
||||
@JvmField
|
||||
val LEVELUP_START = this.create("gui.levelup_start")
|
||||
@JvmField
|
||||
val LEVELUP = this.create("gui.levelup")
|
||||
|
||||
@JvmField
|
||||
val PVN_BATTLE = this.create("battle.pvn.default")
|
||||
@JvmField
|
||||
|
||||
@@ -23,43 +23,61 @@ import net.minecraft.resources.ResourceKey
|
||||
* @since October 26th, 2022
|
||||
*/
|
||||
object CobblemonCriteria : PlatformRegistry<Registry<CriterionTrigger<*>>, ResourceKey<Registry<CriterionTrigger<*>>>, CriterionTrigger<*>>(){
|
||||
@JvmField
|
||||
val PICK_STARTER = this.create("pick_starter", SimpleCriterionTrigger(PokemonCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val CATCH_POKEMON = this.create("catch_pokemon", SimpleCriterionTrigger(CaughtPokemonCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val CATCH_SHINY_POKEMON = this.create("catch_shiny_pokemon", SimpleCriterionTrigger(CountableCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val EGG_COLLECT = this.create("eggs_collected", SimpleCriterionTrigger(CountableCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val EGG_HATCH = this.create("eggs_hatched", SimpleCriterionTrigger(CountableCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val EVOLVE_POKEMON = this.create("pokemon_evolved", SimpleCriterionTrigger(EvolvePokemonCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val WIN_BATTLE = this.create("battles_won", SimpleCriterionTrigger(BattleCountableCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val DEFEAT_POKEMON = this.create("pokemon_defeated", SimpleCriterionTrigger(CountableCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val COLLECT_ASPECT = this.create("aspects_collected", SimpleCriterionTrigger(AspectCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val POKEMON_INTERACT = this.create("pokemon_interact", SimpleCriterionTrigger(PokemonInteractCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val PARTY_CHECK = this.create("party", SimpleCriterionTrigger(PartyCheckCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val LEVEL_UP = this.create("level_up", SimpleCriterionTrigger(LevelUpCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val PASTURE_USE = this.create("pasture_use", SimpleCriterionTrigger(PokemonCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val RESURRECT_POKEMON = this.create("resurrect_pokemon", SimpleCriterionTrigger(PokemonCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val TRADE_POKEMON = this.create("trade_pokemon", SimpleCriterionTrigger(TradePokemonCriterion.CODEC))
|
||||
|
||||
@JvmField
|
||||
val CAST_POKE_ROD = this.create("cast_poke_rod", SimpleCriterionTrigger(CastPokeRodCriterionCondition.CODEC))
|
||||
|
||||
@JvmField
|
||||
val REEL_IN_POKEMON = this.create("reel_in_pokemon", SimpleCriterionTrigger(ReelInPokemonCriterionCondition.CODEC))
|
||||
|
||||
// Advancement criteria for [grow_tumblestone.json]
|
||||
@JvmField
|
||||
val PLANT_TUMBLESTONE = this.create("plant_tumblestone", SimpleCriterionTrigger(PlantTumblestoneCriterion.CODEC))
|
||||
|
||||
override val registry = BuiltInRegistries.TRIGGER_TYPES
|
||||
override val resourceKey = Registries.TRIGGER_TYPE
|
||||
}
|
||||
}
|
||||
+5
-4
@@ -22,18 +22,19 @@ class ReelInPokemonContext(val species : ResourceLocation, val baitId: ResourceL
|
||||
class ReelInPokemonCriterionCondition(
|
||||
playerCtx: Optional<ContextAwarePredicate>,
|
||||
val species: String,
|
||||
val baitId: String
|
||||
val baitId: String // also allows "cobblemon:empty_bait" to indicate that no bait is allowed for this criterion to match
|
||||
) : SimpleCriterionCondition<ReelInPokemonContext>(playerCtx) {
|
||||
|
||||
companion object {
|
||||
val CODEC: Codec<ReelInPokemonCriterionCondition> = RecordCodecBuilder.create { it.group(
|
||||
EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter { it.playerCtx },
|
||||
Codec.STRING.optionalFieldOf("species", "any").forGetter { it.species },
|
||||
Codec.STRING.optionalFieldOf("baitId", "empty_bait").forGetter { it.baitId }
|
||||
).apply(it, { playerCtx, pokemonId, baitId -> ReelInPokemonCriterionCondition(playerCtx, pokemonId, baitId.ifEmpty { "empty_bait" }) }) }
|
||||
Codec.STRING.optionalFieldOf("baitId", "any").forGetter { it.baitId }
|
||||
).apply(it, { playerCtx, pokemonId, baitId -> ReelInPokemonCriterionCondition(playerCtx, pokemonId, baitId) }) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayer, context: ReelInPokemonContext): Boolean {
|
||||
return (context.species == this.species.asIdentifierDefaultingNamespace() || this.species == "any") && (context.baitId == this.baitId.asIdentifierDefaultingNamespace() || this.baitId == "empty_bait")
|
||||
return (context.species == this.species.asIdentifierDefaultingNamespace() || this.species == "any")
|
||||
&& (context.baitId == this.baitId.asIdentifierDefaultingNamespace() || this.baitId == "any")
|
||||
}
|
||||
}
|
||||
@@ -70,16 +70,23 @@ object Abilities : DataRegistry {
|
||||
AbilityRegistrySyncPacket(all()).sendToPlayer(player)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun register(ability: AbilityTemplate): AbilityTemplate {
|
||||
this.abilityMap[ability.name.lowercase()] = ability
|
||||
return ability
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun all() = this.abilityMap.values.toList()
|
||||
@JvmStatic
|
||||
fun first() = this.abilityMap.values.first()
|
||||
@JvmStatic
|
||||
fun get(name: String) = abilityMap[name.lowercase()]
|
||||
@JvmStatic
|
||||
fun getOrDummy(name: String) = get(name) ?: DUMMY
|
||||
@JvmStatic
|
||||
fun getOrException(name: String) = get(name) ?: throw IllegalArgumentException("Unable to find ability of name: $name")
|
||||
@JvmStatic
|
||||
fun count() = this.abilityMap.size
|
||||
|
||||
internal fun receiveSyncPacket(abilities: Collection<AbilityTemplate>) {
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai
|
||||
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.Behavior
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||
import net.minecraft.world.entity.schedule.Activity
|
||||
|
||||
/**
|
||||
* A [Behavior] subclass that represents tasks that check that the entity is still in one
|
||||
* of the activities that this task is part of. If the entity is no longer doing any of those
|
||||
* activities, the task will be interrupted and you can handle any cleanup in [onInterrupted].
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since October 17th, 2025
|
||||
*/
|
||||
abstract class ActivityAwareBehavior<E : LivingEntity> : Behavior<E> {
|
||||
constructor(entryCondition: Map<MemoryModuleType<*>, MemoryStatus>) : super(entryCondition)
|
||||
constructor(entryCondition: Map<MemoryModuleType<*>, MemoryStatus>, duration: Int) : super(entryCondition, duration)
|
||||
constructor(entryCondition: Map<MemoryModuleType<*>, MemoryStatus>, minDuration: Int, maxDuration: Int) : super(entryCondition, minDuration, maxDuration)
|
||||
|
||||
val activities: MutableSet<Activity> = mutableSetOf()
|
||||
|
||||
fun isStillDoingActivity(entity: E): Boolean {
|
||||
return activities.any(entity.brain::isActive)
|
||||
}
|
||||
|
||||
override fun canStillUse(level: ServerLevel, entity: E, gameTime: Long) = isStillDoingActivity(entity)
|
||||
|
||||
open fun onInterrupted(level: ServerLevel, entity: E, gameTime: Long) {
|
||||
// No-op
|
||||
}
|
||||
|
||||
override fun stop(level: ServerLevel, entity: E, gameTime: Long) {
|
||||
super.stop(level, entity, gameTime)
|
||||
if (!isStillDoingActivity(entity)) {
|
||||
onInterrupted(level, entity, gameTime)
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-1
@@ -11,7 +11,6 @@ package com.cobblemon.mod.common.api.ai
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.mojang.datafixers.util.Pair
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.Mob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.schedule.Activity
|
||||
|
||||
@@ -23,6 +22,13 @@ class ActivityConfigurationContext(val activity: Activity) {
|
||||
}
|
||||
|
||||
fun apply(entity: LivingEntity) {
|
||||
tasks.forEach {
|
||||
val activityAwareBehavior = it.second as? ActivityAwareBehavior<*>
|
||||
?: (it.second as? WrapperLivingEntityTask<*>)?.task as? ActivityAwareBehavior
|
||||
?: return@forEach
|
||||
activityAwareBehavior.activities += activity
|
||||
}
|
||||
|
||||
entity.brain.addActivity(activity, ImmutableList.copyOf(tasks))
|
||||
}
|
||||
}
|
||||
@@ -47,12 +47,23 @@ class ApplyBehaviours : BehaviourConfig {
|
||||
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
|
||||
if (!checkCondition(behaviourConfigurationContext, condition)) return
|
||||
|
||||
val configurations = behaviours.map { CobblemonBehaviours.behaviours[it]?.takeIf { it.canBeApplied(entity) } ?: return Cobblemon.LOGGER.warn("Behaviour $it not found") }
|
||||
val applicableBehaviours = behaviours.mapNotNull {
|
||||
val resolvedBehaviour = CobblemonBehaviours.behaviours[it]
|
||||
if (resolvedBehaviour == null) {
|
||||
Cobblemon.LOGGER.warn("Behaviour $it not found while configuring entity of type ${entity.type}")
|
||||
} else if (!resolvedBehaviour.canBeApplied(entity)) {
|
||||
Cobblemon.LOGGER.warn("Behaviour $it cannot be applied to entity ${entity.id}")
|
||||
} else {
|
||||
return@mapNotNull resolvedBehaviour
|
||||
}
|
||||
null
|
||||
}
|
||||
|
||||
// Why not just add the presets to the context directly?
|
||||
// Nested preset application is a thing, and I only want to track the top level presets.
|
||||
// i.e. if a preset applies another preset, I don't want to track the inner preset, since it's redundant if we track the top one.
|
||||
val originalContextBehaviours = behaviourConfigurationContext.appliedBehaviours.toMutableSet()
|
||||
configurations.forEach {
|
||||
applicableBehaviours.forEach {
|
||||
it.configure(entity, behaviourConfigurationContext)
|
||||
}
|
||||
originalContextBehaviours.addAll(behaviours)
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ import net.minecraft.world.entity.schedule.Activity
|
||||
|
||||
class ActivityChangeTaskConfig : SingleTaskConfig {
|
||||
val activity: Activity = Activity.IDLE
|
||||
val condition: ExpressionLike = "false".asExpressionLike()
|
||||
val condition: ExpressionLike = "true".asExpressionLike()
|
||||
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): List<MoLangConfigVariable> = emptyList()
|
||||
|
||||
|
||||
+17
-3
@@ -11,8 +11,7 @@ package com.cobblemon.mod.common.api.ai.config.task
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.SEE_DISTANCE
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.cobblemon.mod.common.util.resolveEntityTypes
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.SetEntityLookTarget
|
||||
@@ -22,13 +21,16 @@ import net.minecraft.world.entity.ai.sensing.SensorType
|
||||
class LookAtEntitiesTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val LOOK_AT_ENTITIES = "look_at_entities"
|
||||
const val LOOK_AT_ENTITY_TYPES = "look_at_entity_types"
|
||||
}
|
||||
|
||||
val condition = booleanVariable(SharedEntityVariables.LOOKING_CATEGORY, LOOK_AT_ENTITIES, true).asExpressible()
|
||||
val maxDistance = numberVariable(SharedEntityVariables.LOOKING_CATEGORY, SEE_DISTANCE, 15).asExpressible()
|
||||
val entityTypes = stringVariable(SharedEntityVariables.LOOKING_CATEGORY, LOOK_AT_ENTITY_TYPES, "").asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = listOf(
|
||||
condition,
|
||||
entityTypes,
|
||||
maxDistance
|
||||
).asVariables()
|
||||
|
||||
@@ -39,6 +41,18 @@ class LookAtEntitiesTaskConfig : SingleTaskConfig {
|
||||
if (!condition.resolveBoolean(behaviourConfigurationContext.runtime)) return null
|
||||
behaviourConfigurationContext.addMemories(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryModuleType.LOOK_TARGET)
|
||||
behaviourConfigurationContext.addSensors(SensorType.NEAREST_LIVING_ENTITIES)
|
||||
return SetEntityLookTarget.create(maxDistance.resolveFloat(behaviourConfigurationContext.runtime))
|
||||
|
||||
val lookDistance = maxDistance.resolveFloat(behaviourConfigurationContext.runtime)
|
||||
val lookAtTypesText = entityTypes.resolveString(behaviourConfigurationContext.runtime)
|
||||
if (lookAtTypesText.isBlank()) {
|
||||
return SetEntityLookTarget.create(lookDistance)
|
||||
}
|
||||
|
||||
val lookAtTypes = resolveEntityTypes(entity.registryAccess(), lookAtTypesText)
|
||||
return if (lookAtTypes.isNotEmpty()) {
|
||||
SetEntityLookTarget.create({ lookAtTypes.contains(it.type) }, lookDistance)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -17,6 +17,7 @@ import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import com.cobblemon.mod.common.util.resolveString
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
@@ -62,7 +63,7 @@ class MemoryAspectTaskConfig : SingleTaskConfig {
|
||||
override fun canStillUse(level: ServerLevel, entity: LivingEntity, gameTime: Long) = true
|
||||
|
||||
override fun tick(level: ServerLevel, owner: LivingEntity, gameTime: Long) {
|
||||
val hasMemory = !owner.brain.hasMemoryValue(memory)
|
||||
val hasMemory = owner.brain.hasMemoryValue(memory)
|
||||
if (owner is PokemonEntity) {
|
||||
if (!hasMemory && aspect in owner.pokemon.forcedAspects) {
|
||||
owner.pokemon.forcedAspects -= aspect
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ class MoveToOwnerTaskConfig : SingleTaskConfig {
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
): BehaviorControl<in LivingEntity> {
|
||||
behaviourConfigurationContext.addMemories(
|
||||
MemoryModuleType.WALK_TARGET,
|
||||
MemoryModuleType.LOOK_TARGET
|
||||
|
||||
+118
-2
@@ -8,16 +8,31 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.CobblemonSensors
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PathToBeeHiveTask
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PlaceHoneyInHiveTask
|
||||
import com.cobblemon.mod.common.util.distanceTo
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.Behavior
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class PathToBeeHiveTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val HONEY = "honey"
|
||||
const val STAY_OUT_OF_HIVE_COOLDOWN = 400
|
||||
|
||||
}
|
||||
|
||||
val condition = booleanVariable(HONEY, "can_add_honey", true).asExpressible()
|
||||
@@ -36,6 +51,107 @@ class PathToBeeHiveTaskConfig : SingleTaskConfig {
|
||||
if (!checkCondition(behaviourConfigurationContext.runtime, condition)) {
|
||||
return null
|
||||
}
|
||||
return PathToBeeHiveTask.create()
|
||||
behaviourConfigurationContext.addSensors(CobblemonSensors.NEARBY_BEE_HIVE)
|
||||
return object : Behavior<LivingEntity>(
|
||||
mapOf(
|
||||
MemoryModuleType.LOOK_TARGET to MemoryStatus.REGISTERED,
|
||||
MemoryModuleType.WALK_TARGET to MemoryStatus.VALUE_ABSENT,
|
||||
CobblemonMemories.HAS_NECTAR to MemoryStatus.REGISTERED,
|
||||
CobblemonMemories.HIVE_LOCATION to MemoryStatus.VALUE_PRESENT,
|
||||
CobblemonMemories.HIVE_COOLDOWN to MemoryStatus.VALUE_ABSENT,
|
||||
CobblemonMemories.HIVE_BLACKLIST to MemoryStatus.REGISTERED,
|
||||
),
|
||||
400,
|
||||
400
|
||||
) {
|
||||
|
||||
val maxTicks = 400
|
||||
var traveledTicks = 0
|
||||
|
||||
override fun checkExtraStartConditions(level: ServerLevel, owner: LivingEntity): Boolean {
|
||||
return (owner is PathfinderMob && owner.isAlive && (owner is PokemonEntity && PlaceHoneyInHiveTask.wantsToEnterHive(owner))) && owner.brain.checkMemory(
|
||||
MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT)
|
||||
}
|
||||
|
||||
override fun canStillUse(level: ServerLevel, entity: LivingEntity, gameTime: Long): Boolean {
|
||||
if (maxTicks >= traveledTicks) return false
|
||||
val pos = entity.brain.getMemory(CobblemonMemories.HIVE_LOCATION)
|
||||
return !pos.isEmpty && entity.distanceTo(pos.get()) > 1.0
|
||||
}
|
||||
|
||||
override fun start(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
super.start(level, entity, gameTime)
|
||||
val hiveLocation = entity.brain.getMemorySafely(CobblemonMemories.HIVE_LOCATION).orElse(null)
|
||||
val world = entity.level()
|
||||
val sidesByClosest = listOf(
|
||||
hiveLocation.north(),
|
||||
hiveLocation.south(),
|
||||
hiveLocation.east(),
|
||||
hiveLocation.west()
|
||||
).sortedBy { it.distSqr(entity.blockPosition()) }
|
||||
|
||||
var openSide = BlockPos.ZERO
|
||||
for (side in sidesByClosest) {
|
||||
if (world.getBlockState(side).isAir) {
|
||||
openSide = side
|
||||
break
|
||||
}
|
||||
}
|
||||
if (openSide == BlockPos.ZERO) {
|
||||
if (world.getBlockState(hiveLocation.above()).isAir) {
|
||||
// If the above position is also air, we can use it
|
||||
openSide = hiveLocation.above() // Fallback to above if no open sides found
|
||||
} else if (world.getBlockState(hiveLocation.below()).isAir) {
|
||||
// If the below position is also air, we can use it
|
||||
openSide = hiveLocation.below() // Fallback to below if no open sides found
|
||||
} else {
|
||||
// If no open sides or above/below positions are found, we cannot proceed
|
||||
return
|
||||
}
|
||||
}
|
||||
val targetVec = Vec3.atCenterOf(openSide)
|
||||
|
||||
// Set path target toward hive
|
||||
if (pathfindDirectlyTowards(openSide, entity)) {
|
||||
entity.brain.setMemory(MemoryModuleType.WALK_TARGET,WalkTarget(targetVec, 0.35F, 0))
|
||||
entity.brain.setMemory(MemoryModuleType.LOOK_TARGET,BlockPosTracker(targetVec.add(0.0, entity.eyeHeight.toDouble(), 0.0)))
|
||||
traveledTicks = 0
|
||||
} else {
|
||||
dropAndBlackListHive(entity)
|
||||
}
|
||||
}
|
||||
|
||||
override fun tick(level: ServerLevel, owner: LivingEntity, gameTime: Long) {
|
||||
traveledTicks++
|
||||
}
|
||||
|
||||
override fun stop(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
if (maxTicks < traveledTicks) {
|
||||
dropAndBlackListHive(entity)
|
||||
entity.brain.setMemoryWithExpiry(CobblemonMemories.HIVE_COOLDOWN, true, 100)
|
||||
}
|
||||
}
|
||||
|
||||
fun dropAndBlackListHive(entity: LivingEntity) {
|
||||
val hivePos = entity.brain.getMemorySafely(CobblemonMemories.HIVE_LOCATION).orElse(null)
|
||||
if (hivePos == null) return
|
||||
val blackList = entity.brain.getMemorySafely(CobblemonMemories.HIVE_BLACKLIST).orElse(emptyList()).toMutableList()
|
||||
|
||||
blackList.add(hivePos)
|
||||
if (blackList.count() > 3) {
|
||||
blackList.removeFirst()
|
||||
}
|
||||
entity.brain.eraseMemory(CobblemonMemories.HIVE_LOCATION)
|
||||
entity.brain.setMemory(CobblemonMemories.HIVE_BLACKLIST, blackList)
|
||||
|
||||
}
|
||||
|
||||
private fun pathfindDirectlyTowards(pos: BlockPos, entity: LivingEntity): Boolean {
|
||||
if (entity !is PathfinderMob) return false
|
||||
val nav = entity.navigation
|
||||
val path = nav. createPath(pos, 0)
|
||||
return path != null && path.canReach()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-4
@@ -8,7 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.CobblemonSensors
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
@@ -41,12 +40,14 @@ class PathToFlowerTaskConfig : SingleTaskConfig {
|
||||
return null
|
||||
}
|
||||
behaviourConfigurationContext.addMemories(
|
||||
CobblemonMemories.NEARBY_FLOWERS,
|
||||
CobblemonMemories.NEARBY_FLOWER,
|
||||
CobblemonMemories.PATH_TO_NEARBY_FLOWER_COOLDOWN,
|
||||
CobblemonMemories.HIVE_COOLDOWN,
|
||||
CobblemonMemories.HIVE_LOCATION,
|
||||
CobblemonMemories.POLLINATED
|
||||
CobblemonMemories.HIVE_BLACKLIST,
|
||||
CobblemonMemories.HAS_NECTAR,
|
||||
)
|
||||
behaviourConfigurationContext.addSensors(CobblemonSensors.NEARBY_BEE_HIVE, CobblemonSensors.NEARBY_FLOWER)
|
||||
behaviourConfigurationContext.addSensors(CobblemonSensors.NEARBY_FLOWER)
|
||||
return PathToFlowerTask.create()
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.CobblemonSensors
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PathToSacLeafTask
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class PathToSaccLeavesTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val POLLINATE = "pollinate"
|
||||
}
|
||||
|
||||
val condition = booleanVariable(POLLINATE, "can_pollinate", true).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = listOf(
|
||||
condition
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
if (entity !is PokemonEntity) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (!checkCondition(behaviourConfigurationContext.runtime, condition)) {
|
||||
return null
|
||||
}
|
||||
behaviourConfigurationContext.addMemories(
|
||||
CobblemonMemories.NEARBY_SACC_LEAVES,
|
||||
CobblemonMemories.HAS_NECTAR
|
||||
)
|
||||
behaviourConfigurationContext.addSensors(CobblemonSensors.NEARBY_SACC_LEAVES, CobblemonSensors.NEARBY_FLOWER)
|
||||
return PathToSacLeafTask.create()
|
||||
}
|
||||
}
|
||||
+5
-2
@@ -8,8 +8,8 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.PlaceHoneyInHiveTask
|
||||
@@ -37,6 +37,9 @@ class PlaceHoneyInHiveTaskConfig : SingleTaskConfig {
|
||||
if (!checkCondition(behaviourConfigurationContext.runtime, condition)) {
|
||||
return null
|
||||
}
|
||||
return PlaceHoneyInHiveTask.create()
|
||||
return WrapperLivingEntityTask(
|
||||
PlaceHoneyInHiveTask.create(),
|
||||
PokemonEntity::class.java
|
||||
)
|
||||
}
|
||||
}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonActivities
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.block.SaccharineLeafBlock
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.Behavior
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class PlaceHoneyInSaccLeavesTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val POLLINATE = "pollinate"
|
||||
const val MIN_DURATION : Int = 300
|
||||
const val MAX_DURATION : Int = 400
|
||||
const val REQUIRED_SUCCESSFUL_POLLINATION_TICKS = 250
|
||||
}
|
||||
|
||||
val condition = booleanVariable(POLLINATE, "can_pollinate", true).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = listOf(
|
||||
condition
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
if (entity !is PokemonEntity) {
|
||||
return null
|
||||
}
|
||||
if (!checkCondition(behaviourConfigurationContext.runtime, condition)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return object : Behavior<LivingEntity>(
|
||||
mapOf(
|
||||
CobblemonMemories.NEARBY_SACC_LEAVES to MemoryStatus.VALUE_PRESENT,
|
||||
MemoryModuleType.WALK_TARGET to MemoryStatus.VALUE_ABSENT,
|
||||
CobblemonMemories.HAS_NECTAR to MemoryStatus.VALUE_PRESENT,
|
||||
),
|
||||
MIN_DURATION,
|
||||
MAX_DURATION
|
||||
) {
|
||||
var successfulPollinationTicks = 0
|
||||
var lastSoundPlayedTick = 0
|
||||
var hoverPos: Vec3? = null
|
||||
|
||||
override fun checkExtraStartConditions(level: ServerLevel, owner: LivingEntity): Boolean {
|
||||
if (level.isNight || level.isRaining || !(entity.brain.getMemorySafely(CobblemonMemories.HAS_NECTAR).orElse(false))) return false
|
||||
val optionalBlockPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_SACC_LEAVES)
|
||||
if (!optionalBlockPos.isPresent || level.getBlockState(optionalBlockPos.get()).block != CobblemonBlocks.SACCHARINE_LEAVES) return false
|
||||
return Vec3.atCenterOf(optionalBlockPos.get()).distanceTo(entity.position()) <= 0.6
|
||||
}
|
||||
|
||||
override fun canStillUse(level: ServerLevel, entity: LivingEntity, gameTime: Long): Boolean {
|
||||
return checkExtraStartConditions(level, entity) && entity.brain.activeActivities.indexOf(
|
||||
CobblemonActivities.POKEMON_POLLINATION) != -1
|
||||
}
|
||||
|
||||
override fun start(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
super.start(level, entity, gameTime)
|
||||
hoverPos = null
|
||||
}
|
||||
|
||||
override fun tick(level: ServerLevel, owner: LivingEntity, gameTime: Long) {
|
||||
++successfulPollinationTicks
|
||||
if (entity.random.nextFloat() < 0.05f && successfulPollinationTicks > this.lastSoundPlayedTick + 60) {
|
||||
this.lastSoundPlayedTick = successfulPollinationTicks
|
||||
entity.playSound(SoundEvents.BEEHIVE_DRIP, 1.0f, 1.0f)
|
||||
}
|
||||
val leavesPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_SACC_LEAVES).orElse(null)
|
||||
|
||||
val bl = hoverPos == null || entity.position().distanceTo(hoverPos!!) <= 0.1
|
||||
val bl3 = entity.random.nextInt(40) == 0
|
||||
if (bl && bl3) {
|
||||
// mimics the wriggling over a flower the vanilla bees do
|
||||
if (hoverPos == null) {
|
||||
hoverPos = leavesPos.bottomCenter.add(0.0, 0.4, 0.0)
|
||||
}
|
||||
if (leavesPos != null) {
|
||||
hoverPos = leavesPos.bottomCenter.add(Vec3((entity.random.nextDouble() * 2.0 - 1.0) * (1.0/5.0), 0.3 + (entity.random.nextDouble() * 2.0 - 1.0) * (1.0/7.0), (entity.random.nextDouble() * 2.0 - 1.0) * (1.0/5.0)))
|
||||
entity.getMoveControl()
|
||||
.setWantedPosition(hoverPos!!.x(), hoverPos!!.y(), hoverPos!!.z(), 0.35)
|
||||
entity.lookControl.setLookAt(leavesPos.bottomCenter.add(0.0,0.5,0.0))
|
||||
}
|
||||
} else if (!bl) {
|
||||
entity.getMoveControl()
|
||||
.setWantedPosition(hoverPos!!.x(), hoverPos!!.y(), hoverPos!!.z(), 0.35)
|
||||
}
|
||||
}
|
||||
|
||||
override fun stop(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
if (successfulPollinationTicks > REQUIRED_SUCCESSFUL_POLLINATION_TICKS) {
|
||||
val blockPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_SACC_LEAVES).orElse(null)
|
||||
blockPos?.let {
|
||||
val blockState = level.getBlockState(blockPos)
|
||||
if (blockState.block == CobblemonBlocks.SACCHARINE_LEAVES) {
|
||||
val saccAge = blockState.getValue( SaccharineLeafBlock.AGE)
|
||||
if (saccAge < SaccharineLeafBlock.MAX_AGE) {
|
||||
entity.brain.eraseMemory(CobblemonMemories.HAS_NECTAR)
|
||||
val newBlockState = blockState.setValue(SaccharineLeafBlock.AGE, saccAge + 1)
|
||||
level.setBlock(blockPos, newBlockState, 3)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
successfulPollinationTicks = 0
|
||||
entity.brain.eraseMemory(MemoryModuleType.WALK_TARGET)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+52
-24
@@ -8,17 +8,14 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonActivities
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.getMemorySafely
|
||||
import com.cobblemon.mod.common.util.sendParticlesServer
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.core.particles.ParticleTypes
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.Behavior
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
@@ -29,10 +26,11 @@ import net.minecraft.world.phys.Vec3
|
||||
class PollinateFlowerTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val POLLINATE = "pollinate"
|
||||
const val PATH_TO_FLOWER_COOLDOWN_TICKS : Long = 200
|
||||
const val HAS_NECTAR_ASPECT = "has_nectar"
|
||||
}
|
||||
|
||||
val condition = booleanVariable(POLLINATE, "can_pollinate", true).asExpressible()
|
||||
val durationTicks: ExpressionOrEntityVariable = Either.left("30".asExpression())
|
||||
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = listOf(
|
||||
condition
|
||||
@@ -51,22 +49,28 @@ class PollinateFlowerTaskConfig : SingleTaskConfig {
|
||||
|
||||
return object : Behavior<LivingEntity>(
|
||||
mapOf(
|
||||
CobblemonMemories.NEARBY_FLOWERS to MemoryStatus.VALUE_PRESENT,
|
||||
CobblemonMemories.NEARBY_FLOWER to MemoryStatus.VALUE_PRESENT,
|
||||
MemoryModuleType.WALK_TARGET to MemoryStatus.VALUE_ABSENT,
|
||||
CobblemonMemories.POLLINATED to MemoryStatus.VALUE_ABSENT,
|
||||
CobblemonMemories.HAS_NECTAR to MemoryStatus.REGISTERED,
|
||||
CobblemonMemories.HIVE_COOLDOWN to MemoryStatus.VALUE_ABSENT,
|
||||
),
|
||||
15,
|
||||
45
|
||||
600,
|
||||
625
|
||||
) {
|
||||
val REQUIRED_SUCCESSFUL_POLLINATION_TICKS = 400
|
||||
var successfulPollinationTicks = 0
|
||||
var lastSoundPlayedTick = 0
|
||||
var hoverPos: Vec3? = null
|
||||
|
||||
override fun checkExtraStartConditions(level: ServerLevel, owner: LivingEntity): Boolean {
|
||||
return entity.brain.getMemorySafely(CobblemonMemories.NEARBY_FLOWERS).orElse(emptyList()).any {
|
||||
Vec3.atCenterOf(it).distanceTo(entity.position()) <= 1.0
|
||||
}
|
||||
if (level.isNight || level.isRaining || entity.brain.getMemorySafely(CobblemonMemories.HAS_NECTAR).orElse(false)) return false
|
||||
val optionalBlockPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_FLOWER)
|
||||
return optionalBlockPos.isPresent && Vec3.atCenterOf(optionalBlockPos.get()).distanceTo(entity.position()) <= 1.0
|
||||
}
|
||||
|
||||
override fun canStillUse(level: ServerLevel, entity: LivingEntity, gameTime: Long): Boolean {
|
||||
return checkExtraStartConditions(level, entity)
|
||||
return checkExtraStartConditions(level, entity) && entity.brain.activeActivities.indexOf(
|
||||
CobblemonActivities.POKEMON_POLLINATION) != -1
|
||||
}
|
||||
|
||||
override fun start(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
@@ -74,20 +78,44 @@ class PollinateFlowerTaskConfig : SingleTaskConfig {
|
||||
}
|
||||
|
||||
override fun tick(level: ServerLevel, owner: LivingEntity, gameTime: Long) {
|
||||
level.sendParticlesServer(
|
||||
particleType = ParticleTypes.DRIPPING_HONEY,
|
||||
position = owner.eyePosition,
|
||||
particles = 3,
|
||||
offset = Vec3.ZERO,
|
||||
speed = 0.0
|
||||
)
|
||||
++successfulPollinationTicks
|
||||
if (entity.random.nextFloat() < 0.05f && successfulPollinationTicks > this.lastSoundPlayedTick + 60) {
|
||||
this.lastSoundPlayedTick = successfulPollinationTicks
|
||||
entity.playSound(SoundEvents.BEE_POLLINATE, 1.0f, 1.0f)
|
||||
}
|
||||
val flowerPos = entity.brain.getMemorySafely(CobblemonMemories.NEARBY_FLOWER).orElse(null)
|
||||
|
||||
|
||||
val bl = hoverPos == null || entity.position().distanceTo(hoverPos!!) <= 0.1
|
||||
val bl3 = entity.random.nextInt(40) == 0
|
||||
if (bl && bl3) {
|
||||
// mimics the wriggling over a flower the vanilla bees do
|
||||
if (hoverPos == null) {
|
||||
hoverPos = flowerPos.bottomCenter.add(0.0, 0.4, 0.0)
|
||||
}
|
||||
|
||||
if (flowerPos != null) {
|
||||
hoverPos = flowerPos.bottomCenter.add(Vec3((entity.random.nextDouble() * 2.0 - 1.0) * (1.0/5.0), 0.3 + (entity.random.nextDouble() * 2.0 - 1.0) * (1.0/7.0), (entity.random.nextDouble() * 2.0 - 1.0) * (1.0/5.0)))
|
||||
entity.getMoveControl()
|
||||
.setWantedPosition(hoverPos!!.x(), hoverPos!!.y(), hoverPos!!.z(), 0.35)
|
||||
entity.lookControl.setLookAt(flowerPos.bottomCenter.add(0.0,0.5,0.0))
|
||||
}
|
||||
} else if (!bl) {
|
||||
entity.getMoveControl()
|
||||
.setWantedPosition(hoverPos!!.x(), hoverPos!!.y(), hoverPos!!.z(), 0.35)
|
||||
}
|
||||
entity.lookControl.setLookAt(flowerPos.bottomCenter.add(0.0,0.5,0.0))
|
||||
|
||||
}
|
||||
|
||||
override fun stop(level: ServerLevel, entity: LivingEntity, gameTime: Long) {
|
||||
val flowerStillThere = canStillUse(level, entity, gameTime)
|
||||
if (flowerStillThere) {
|
||||
entity.brain.setMemory(CobblemonMemories.POLLINATED, true)
|
||||
|
||||
if (successfulPollinationTicks > REQUIRED_SUCCESSFUL_POLLINATION_TICKS) {
|
||||
entity.brain.setMemory(CobblemonMemories.HAS_NECTAR, true)
|
||||
}
|
||||
successfulPollinationTicks = 0
|
||||
entity.brain.setMemoryWithExpiry(CobblemonMemories.PATH_TO_NEARBY_FLOWER_COOLDOWN, true, PATH_TO_FLOWER_COOLDOWN_TICKS)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,9 @@ interface TaskConfig {
|
||||
cobblemonResource("go_to_land") to GoToLandTaskConfig::class.java,
|
||||
cobblemonResource("path_to_hive") to PathToBeeHiveTaskConfig::class.java,
|
||||
cobblemonResource("place_honey_in_hive") to PlaceHoneyInHiveTaskConfig::class.java,
|
||||
cobblemonResource("place_honey_in_sacc_leaves") to PlaceHoneyInSaccLeavesTaskConfig::class.java,
|
||||
cobblemonResource("path_to_flower") to PathToFlowerTaskConfig::class.java,
|
||||
cobblemonResource("path_to_sacc_leaves") to PathToSaccLeavesTaskConfig::class.java,
|
||||
cobblemonResource("pollinate_flower") to PollinateFlowerTaskConfig::class.java,
|
||||
cobblemonResource("go_to_land") to GoToLandTaskConfig::class.java,
|
||||
cobblemonResource("manage_flight_in_battle") to ManageFlightInBattleTaskConfig::class.java,
|
||||
|
||||
@@ -10,7 +10,6 @@ package com.cobblemon.mod.common.api.apricorn
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.api.cooking.Flavour
|
||||
import com.cobblemon.mod.common.block.ApricornBlock
|
||||
import com.cobblemon.mod.common.block.ApricornSaplingBlock
|
||||
import com.cobblemon.mod.common.item.ApricornItem
|
||||
@@ -28,43 +27,14 @@ import net.minecraft.world.level.material.MapColor
|
||||
* @author Licious
|
||||
* @since October 29th, 2022
|
||||
*/
|
||||
enum class Apricorn(
|
||||
/** A value of true means it buffs that flavour, a value of false means it weakens that flavour. */
|
||||
val flavourStrength: Map<Flavour, Boolean> = emptyMap()
|
||||
) : StringRepresentable {
|
||||
|
||||
enum class Apricorn : StringRepresentable {
|
||||
BLACK,
|
||||
BLUE(
|
||||
mapOf(
|
||||
Flavour.DRY to true,
|
||||
Flavour.BITTER to false
|
||||
)
|
||||
),
|
||||
GREEN(
|
||||
mapOf(
|
||||
Flavour.BITTER to true,
|
||||
Flavour.SWEET to false
|
||||
)
|
||||
),
|
||||
PINK(
|
||||
mapOf(
|
||||
Flavour.SWEET to true,
|
||||
Flavour.SPICY to false
|
||||
)
|
||||
),
|
||||
RED(
|
||||
mapOf(
|
||||
Flavour.SPICY to true,
|
||||
Flavour.SOUR to false
|
||||
)
|
||||
),
|
||||
BLUE,
|
||||
GREEN,
|
||||
PINK,
|
||||
RED,
|
||||
WHITE,
|
||||
YELLOW(
|
||||
mapOf(
|
||||
Flavour.SOUR to true,
|
||||
Flavour.DRY to false
|
||||
)
|
||||
);
|
||||
YELLOW;
|
||||
|
||||
fun item(): ApricornItem = when(this) {
|
||||
BLACK -> CobblemonItems.BLACK_APRICORN
|
||||
@@ -131,5 +101,4 @@ enum class Apricorn(
|
||||
companion object {
|
||||
val CODEC: Codec<Apricorn> = StringRepresentable.fromValues(::values)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -85,6 +85,7 @@ object Berries : JsonDataRegistry<Berry> {
|
||||
BerryRegistrySyncPacket(this.all()).sendToPlayer(player)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun all() = this.berries.values.toList()
|
||||
|
||||
/**
|
||||
@@ -93,6 +94,7 @@ object Berries : JsonDataRegistry<Berry> {
|
||||
* @param identifier The identifier of the berry.
|
||||
* @return The [Berry] if loaded otherwise null.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getByIdentifier(identifier: ResourceLocation): Berry? = this.berries[identifier]
|
||||
|
||||
/**
|
||||
@@ -101,6 +103,7 @@ object Berries : JsonDataRegistry<Berry> {
|
||||
* @param name The path of the identifier of the berry under the [Cobblemon.MODID] namespace.
|
||||
* @return The [Berry] if loaded otherwise null.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getByName(name: String): Berry? = this.getByIdentifier(cobblemonResource(name))
|
||||
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.berry.spawncondition
|
||||
|
||||
import com.cobblemon.mod.common.api.berry.Berry
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.core.Holder
|
||||
import net.minecraft.tags.TagKey
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.world.level.biome.Biome
|
||||
|
||||
class SpecificBiomeCondition : BerrySpawnCondition {
|
||||
lateinit var biome: TagKey<Biome>
|
||||
val minGroveSize: Int = 1
|
||||
val maxGroveSize: Int = 1
|
||||
|
||||
override fun canSpawn(berry: Berry, biome: Holder<Biome>) = biome.`is`(this.biome)
|
||||
override fun getGroveSize(random: RandomSource) = random.nextIntBetweenInclusive(minGroveSize, maxGroveSize)
|
||||
|
||||
companion object {
|
||||
val ID = cobblemonResource("specific_biome")
|
||||
}
|
||||
}
|
||||
+105
-25
@@ -8,8 +8,14 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.cooking
|
||||
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.util.math.geometry.toDegrees
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import net.minecraft.util.FastColor
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import kotlin.math.atan2
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
private val colourMap = mapOf(
|
||||
Flavour.SPICY to 0xFEB37D,
|
||||
@@ -49,37 +55,111 @@ fun getColourMixFromFlavours(dominantFlavours: List<Flavour>, forBubbles: Boolea
|
||||
|
||||
if (colors.isEmpty()) return null
|
||||
|
||||
val (alphaSum, redSum, greenSum, blueSum) = colors.fold(IntArray(4)) { acc, color ->
|
||||
acc[0] += FastColor.ARGB32.alpha(color)
|
||||
acc[1] += FastColor.ARGB32.red(color)
|
||||
acc[2] += FastColor.ARGB32.green(color)
|
||||
acc[3] += FastColor.ARGB32.blue(color)
|
||||
acc
|
||||
}
|
||||
|
||||
return FastColor.ARGB32.color(
|
||||
alphaSum / colors.size,
|
||||
redSum / colors.size,
|
||||
greenSum / colors.size,
|
||||
blueSum / colors.size
|
||||
)
|
||||
return getColourMixFromColors(colors)
|
||||
}
|
||||
|
||||
fun getColourMixFromRideStatBoosts(dominantBoosts: Iterable<RidingStat>, forBubbles: Boolean = false): Int? {
|
||||
return getColourMixFromFlavours(dominantBoosts.map { it.flavour }, forBubbles)
|
||||
}
|
||||
|
||||
// Mixing RGB colors directly often gives poor results
|
||||
// Converting them to HSL and averaging hues circularly produces more natural blends
|
||||
fun getColourMixFromColors(colors: List<Int>): Int? {
|
||||
if (colors.isEmpty()) return null
|
||||
if (colors.size == 1) return colors[0]
|
||||
|
||||
val (alphaSum, redSum, greenSum, blueSum) = colors.fold(IntArray(4)) { acc, color ->
|
||||
acc[0] += FastColor.ARGB32.alpha(color)
|
||||
acc[1] += FastColor.ARGB32.red(color)
|
||||
acc[2] += FastColor.ARGB32.green(color)
|
||||
acc[3] += FastColor.ARGB32.blue(color)
|
||||
acc
|
||||
val hslColors = colors.map {
|
||||
val red = FastColor.ARGB32.red(it)
|
||||
val green = FastColor.ARGB32.green(it)
|
||||
val blue = FastColor.ARGB32.blue(it)
|
||||
|
||||
rgbToHsl(red, green, blue)
|
||||
}
|
||||
|
||||
return FastColor.ARGB32.color(
|
||||
alphaSum / colors.size,
|
||||
redSum / colors.size,
|
||||
greenSum / colors.size,
|
||||
blueSum / colors.size
|
||||
val hues = hslColors.map { it.h.toDouble() }
|
||||
val huesAverage = hueAverage(hues).toFloat()
|
||||
val saturations = hslColors.map { it.s }
|
||||
val saturationsAverage = average(saturations)
|
||||
val lightness = hslColors.map { it.l }
|
||||
val lightnessAverage = average(lightness)
|
||||
|
||||
val rgbColor = hslToRgb(huesAverage, saturationsAverage, lightnessAverage)
|
||||
|
||||
return FastColor.ARGB32.color(rgbColor.r, rgbColor.g, rgbColor.b)
|
||||
}
|
||||
|
||||
// Based on https://iter.ca/post/hue-avg
|
||||
fun hueAverage(hues: List<Double>): Float {
|
||||
val points = hues.map { hue ->
|
||||
val rad = hue.toRadians()
|
||||
Pair(cos(rad), sin(rad))
|
||||
}
|
||||
|
||||
val avgX = points.sumOf { it.first.toDouble() } / points.size
|
||||
val avgY = points.sumOf { it.second.toDouble() } / points.size
|
||||
|
||||
var degrees = atan2(avgY, avgX).toDegrees()
|
||||
if (degrees < 0) {
|
||||
degrees += 360f
|
||||
} else if (degrees > 360) {
|
||||
degrees -= 360f
|
||||
}
|
||||
|
||||
return degrees
|
||||
}
|
||||
|
||||
fun average(values: List<Float>): Float {
|
||||
if (values.isEmpty()) return 0f
|
||||
return values.sum() / values.size
|
||||
}
|
||||
|
||||
data class HSL(val h: Float, val s: Float, val l: Float)
|
||||
|
||||
fun rgbToHsl(r: Int, g: Int, b: Int): HSL {
|
||||
val rf = r / 255f
|
||||
val gf = g / 255f
|
||||
val bf = b / 255f
|
||||
|
||||
val max = maxOf(rf, gf, bf)
|
||||
val min = minOf(rf, gf, bf)
|
||||
val delta = max - min
|
||||
|
||||
var h = 0f
|
||||
val l = (max + min) / 2f
|
||||
val s = if (delta == 0f) 0f else delta / (1f - kotlin.math.abs(2f * l - 1f))
|
||||
|
||||
if (delta != 0f) {
|
||||
h = when (max) {
|
||||
rf -> ((gf - bf) / delta) % 6f
|
||||
gf -> ((bf - rf) / delta) + 2f
|
||||
else -> ((rf - gf) / delta) + 4f
|
||||
}
|
||||
h *= 60f
|
||||
if (h < 0) h += 360f
|
||||
}
|
||||
|
||||
return HSL(h, s, l)
|
||||
}
|
||||
|
||||
data class RGB(val r: Int, val g: Int, val b: Int)
|
||||
|
||||
fun hslToRgb(h: Float, s: Float, l: Float): RGB {
|
||||
val c = (1f - kotlin.math.abs(2f * l - 1f)) * s
|
||||
val x = c * (1f - kotlin.math.abs((h / 60f) % 2f - 1f))
|
||||
val m = l - c / 2f
|
||||
|
||||
val (rf, gf, bf) = when {
|
||||
h < 60f -> Triple(c, x, 0f)
|
||||
h < 120f -> Triple(x, c, 0f)
|
||||
h < 180f -> Triple(0f, c, x)
|
||||
h < 240f -> Triple(0f, x, c)
|
||||
h < 300f -> Triple(x, 0f, c)
|
||||
else -> Triple(c, 0f, x)
|
||||
}
|
||||
|
||||
return RGB(
|
||||
((rf + m) * 255).toInt().coerceIn(0, 255),
|
||||
((gf + m) * 255).toInt().coerceIn(0, 255),
|
||||
((bf + m) * 255).toInt().coerceIn(0, 255)
|
||||
)
|
||||
}
|
||||
@@ -28,12 +28,14 @@ import net.minecraft.server.level.ServerPlayer
|
||||
object DialogueManager {
|
||||
val activeDialogues = mutableMapOf<UUID, ActiveDialogue>()
|
||||
|
||||
@JvmStatic
|
||||
fun startDialogue(playerEntity: ServerPlayer, dialogue: Dialogue): ActiveDialogue {
|
||||
val activeDialogue = ActiveDialogue(playerEntity, dialogue)
|
||||
startDialogue(activeDialogue)
|
||||
return activeDialogue
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun startDialogue(playerEntity: ServerPlayer, npcEntity: NPCEntity, dialogue: Dialogue): ActiveDialogue {
|
||||
val activeDialogue = ActiveDialogue(playerEntity, dialogue)
|
||||
activeDialogue.runtime.withNPCValue("npc", npcEntity)
|
||||
@@ -42,6 +44,7 @@ object DialogueManager {
|
||||
return activeDialogue
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun startDialogue(activeDialogue: ActiveDialogue) {
|
||||
activeDialogue.initialize()
|
||||
if (!activeDialogue.completion.isDone) {
|
||||
@@ -49,6 +52,7 @@ object DialogueManager {
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun stopDialogue(playerEntity: ServerPlayer) {
|
||||
val activeDialogue = playerEntity.activeDialogue ?: return
|
||||
DialogueClosedPacket(activeDialogue.dialogueId).sendToPlayer(playerEntity)
|
||||
|
||||
@@ -10,14 +10,12 @@ package com.cobblemon.mod.common.api.drop
|
||||
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents.LOOT_DROPPED
|
||||
import com.cobblemon.mod.common.api.events.drops.LootDroppedEvent
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import kotlin.random.Random
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
/**
|
||||
@@ -95,6 +93,16 @@ class DropTable {
|
||||
pokemon: Pokemon? = null,
|
||||
) {
|
||||
val drops = getDrops(amount, pokemon).toMutableList()
|
||||
postLootDroppedEvent(drops, entity, world, pos, player)
|
||||
}
|
||||
|
||||
fun postLootDroppedEvent(
|
||||
drops: MutableList<DropEntry>,
|
||||
entity: LivingEntity?,
|
||||
world: ServerLevel,
|
||||
pos: Vec3,
|
||||
player: ServerPlayer?,
|
||||
) {
|
||||
LOOT_DROPPED.postThen(
|
||||
event = LootDroppedEvent(this, player, entity, drops),
|
||||
ifSucceeded = { it.drops.forEach { it.drop(entity, world, pos, player) } }
|
||||
@@ -110,4 +118,4 @@ class DropTable {
|
||||
val entries = buffer.readInt()
|
||||
repeat(entries) { this.entries.add(ItemDropEntry().decode(buffer)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ interface PokemonSideDelegate : EntitySideDelegate<PokemonEntity> {
|
||||
fun handleStatus(status: Byte) {}
|
||||
fun spawnShinyParticle(player: Player) {}
|
||||
fun spawnAspectParticle() {}
|
||||
fun applyRenderRotation(partialTick: Float) {}
|
||||
fun positionRider(passenger: Entity, positionUpdater: MoveFunction)
|
||||
fun updateAge(age: Int) {}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import com.cobblemon.mod.common.api.events.berry.BerryHarvestEvent
|
||||
import com.cobblemon.mod.common.api.events.berry.BerryMutationOfferEvent
|
||||
import com.cobblemon.mod.common.api.events.berry.BerryMutationResultEvent
|
||||
import com.cobblemon.mod.common.api.events.berry.BerryYieldCalculationEvent
|
||||
import com.cobblemon.mod.common.api.events.cooking.PokeSnackSpawnPokemonEvent
|
||||
import com.cobblemon.mod.common.api.events.drops.LootDroppedEvent
|
||||
import com.cobblemon.mod.common.api.events.entity.*
|
||||
import com.cobblemon.mod.common.api.events.farming.ApricornHarvestEvent
|
||||
@@ -327,6 +328,12 @@ object CobblemonEvents {
|
||||
@JvmField
|
||||
val BOBBER_SPAWN_POKEMON_POST = EventObservable<BobberSpawnPokemonEvent.Post>()
|
||||
|
||||
@JvmField
|
||||
val POKE_SNACK_SPAWN_POKEMON_PRE = CancelableObservable<PokeSnackSpawnPokemonEvent.Pre>()
|
||||
|
||||
@JvmField
|
||||
val POKE_SNACK_SPAWN_POKEMON_POST = EventObservable<PokeSnackSpawnPokemonEvent.Post>()
|
||||
|
||||
@JvmField
|
||||
val BAIT_EFFECT_REGISTRATION = EventObservable<BaitEffectFunctionRegistryEvent>()
|
||||
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.events.cooking
|
||||
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.api.events.Cancelable
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
|
||||
import com.cobblemon.mod.common.block.entity.PokeSnackBlockEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
|
||||
interface PokeSnackSpawnPokemonEvent {
|
||||
|
||||
data class Pre(
|
||||
val pokeSnackBlockEntity: PokeSnackBlockEntity,
|
||||
val spawnAction: SpawnAction<*>,
|
||||
) : Cancelable(), PokeSnackSpawnPokemonEvent {
|
||||
val context = mapOf<String, MoValue>()
|
||||
val functions = moLangFunctionMap(
|
||||
cancelFunc
|
||||
)
|
||||
}
|
||||
|
||||
data class Post(
|
||||
val pokeSnackBlockEntity: PokeSnackBlockEntity,
|
||||
val spawnAction: SpawnAction<*>,
|
||||
val pokemonEntity: PokemonEntity,
|
||||
) : PokeSnackSpawnPokemonEvent {
|
||||
val context = mapOf<String, MoValue>()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -57,6 +57,7 @@ object PokeRods : JsonDataRegistry<PokeRod> {
|
||||
* Gets a Pokerod from registry name.
|
||||
* @return the pokerod object if found otherwise null.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getPokeRod(name : ResourceLocation): PokeRod? = rods[name]
|
||||
|
||||
}
|
||||
@@ -68,6 +68,7 @@ class SpawnBait(
|
||||
val TYPING = cobblemonResource("typing")
|
||||
val EGG_GROUP = cobblemonResource("egg_group")
|
||||
val SHINY_REROLL = cobblemonResource("shiny_reroll")
|
||||
val DROPS_REROLL = cobblemonResource("drops_reroll")
|
||||
val HIDDEN_ABILITY_CHANCE = cobblemonResource("ha_chance")
|
||||
val POKEMON_CHANCE = cobblemonResource("pokemon_chance")
|
||||
val FRIENDSHIP = cobblemonResource("friendship")
|
||||
@@ -85,6 +86,7 @@ class SpawnBait(
|
||||
registerEffect(NATURE) { entity, effect -> FishingSpawnCause.alterNatureAttempt(entity, effect) }
|
||||
registerEffect(IV) { entity, effect -> FishingSpawnCause.alterIVAttempt(entity, effect) }
|
||||
registerEffect(SHINY_REROLL) { entity, effect -> FishingSpawnCause.shinyReroll(entity, effect) }
|
||||
registerEffect(DROPS_REROLL) { entity, effect -> FishingSpawnCause.saveDropsReroll(entity, effect) }
|
||||
registerEffect(GENDER_CHANCE) { entity, effect -> FishingSpawnCause.alterGenderAttempt(entity, effect) }
|
||||
registerEffect(LEVEL_RAISE) { entity, effect -> FishingSpawnCause.alterLevelAttempt(entity, effect) }
|
||||
registerEffect(HIDDEN_ABILITY_CHANCE) { entity, _ -> FishingSpawnCause.alterHAAttempt(entity) }
|
||||
|
||||
@@ -53,20 +53,24 @@ object SpawnBaitEffects : JsonDataRegistry<SpawnBait> {
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getEffectsFromRodItemStack(stack: ItemStack): List<SpawnBait.Effect> {
|
||||
return getEffectsFromItemStack(stack.components.get(CobblemonItemComponents.BAIT)?.stack ?: ItemStack.EMPTY)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getEffectsFromItemStack(stack: ItemStack): List<SpawnBait.Effect> {
|
||||
val componentEffects = stack.get(CobblemonItemComponents.BAIT_EFFECTS)?.effects ?: emptyList()
|
||||
return componentEffects.mapNotNull(::getFromIdentifier).flatMap { it.effects } +
|
||||
getEffectsFromItem(stack.itemHolder)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getBaitIdentifiersFromItem(holder: Holder<Item>): List<ResourceLocation> {
|
||||
return effectsMap.entries.filter { it.value.item.fits(holder) }.map { it.key }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getBaitFromItemStack(holder: Holder<Item>): List<SpawnBait> {
|
||||
return effectsMap.values.filter { it.item.fits(holder) }
|
||||
}
|
||||
@@ -75,6 +79,7 @@ object SpawnBaitEffects : JsonDataRegistry<SpawnBait> {
|
||||
return getBaitFromItemStack(holder).flatMap { it.effects }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getFromIdentifier(identifier: ResourceLocation): SpawnBait? {
|
||||
// Check normal spawn bait registry
|
||||
effectsMap[identifier]?.let { return it }
|
||||
@@ -98,6 +103,7 @@ object SpawnBaitEffects : JsonDataRegistry<SpawnBait> {
|
||||
}
|
||||
|
||||
// if it has bait effects and is not listed as a seasoning then it is a bait
|
||||
@JvmStatic
|
||||
fun isFishingBait(stack: ItemStack): Boolean {
|
||||
val holder = stack.itemHolder
|
||||
return effectsMap.values.any { it.item.fits(holder) }
|
||||
|
||||
@@ -11,24 +11,18 @@ package com.cobblemon.mod.common.api.fishing
|
||||
import kotlin.math.ceil
|
||||
|
||||
object SpawnBaitUtils {
|
||||
@JvmStatic
|
||||
fun mergeEffects(effects: List<SpawnBait.Effect>): List<SpawnBait.Effect> {
|
||||
val grouped = effects.groupBy { Pair(it.type, it.subcategory) }
|
||||
|
||||
return grouped.map { (key, groupEffects) ->
|
||||
val (type, subcategory) = key
|
||||
|
||||
val count = groupEffects.size
|
||||
val totalChance = groupEffects.sumOf { it.chance }
|
||||
val totalValue = groupEffects.sumOf { it.value }
|
||||
|
||||
val multiplier = when (count) {
|
||||
2 -> 0.8
|
||||
3 -> 0.6
|
||||
else -> 1.0
|
||||
}
|
||||
|
||||
val adjustedChance = (totalChance * multiplier).coerceAtMost(1.0)
|
||||
val adjustedValue = ceil(totalValue * multiplier)
|
||||
val adjustedChance = totalChance.coerceAtMost(1.0)
|
||||
val adjustedValue = ceil(totalValue)
|
||||
|
||||
SpawnBait.Effect(type, subcategory, adjustedChance, adjustedValue)
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ object Fossils: JsonDataRegistry<Fossil> {
|
||||
/**
|
||||
* Gets all loaded [Fossil]s.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun all() = this.fossils.values.toList()
|
||||
|
||||
/**
|
||||
@@ -76,6 +77,7 @@ object Fossils: JsonDataRegistry<Fossil> {
|
||||
* @param identifier The identifier of the fossil.
|
||||
* @return The [Fossil] if loaded, otherwise null.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getByIdentifier(identifier: ResourceLocation): Fossil? = this.fossils[identifier]
|
||||
|
||||
/**
|
||||
@@ -83,6 +85,7 @@ object Fossils: JsonDataRegistry<Fossil> {
|
||||
* @param fossilStacks The fossil [ItemStack]'s.
|
||||
* @return The [Fossil] if found, otherwise null.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getFossilByItemStacks(fossilStacks: List<ItemStack>): Fossil? {
|
||||
return this.all().firstOrNull { it.matchesIngredients(fossilStacks) }
|
||||
}
|
||||
@@ -92,6 +95,7 @@ object Fossils: JsonDataRegistry<Fossil> {
|
||||
* @param fossilStacks The fossil [ItemStack]'s.
|
||||
* @return The [Fossil] if found to be a superset, otherwise null.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getSubFossilByItemStacks(fossilStacks: List<ItemStack>): Fossil? {
|
||||
return this.all().firstOrNull { it.matchesIngredientsSubSet(fossilStacks) }
|
||||
}
|
||||
@@ -100,6 +104,7 @@ object Fossils: JsonDataRegistry<Fossil> {
|
||||
* @param itemStack The ingredient [ItemStack].
|
||||
* @return true if it's a fossil ingredient, otherwise false.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun isFossilIngredient(itemStack: ItemStack): Boolean {
|
||||
return this.all().any { it.isIngredient(itemStack) }
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ object NaturalMaterials : JsonDataRegistry<List<NaturalMaterial>>{
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isNaturalMaterial(item: ItemStack): Boolean {
|
||||
val itemId = BuiltInRegistries.ITEM.getKey(item.item)
|
||||
return itemId in itemMap.keys || tagMap.keys.any {
|
||||
@@ -64,6 +65,7 @@ object NaturalMaterials : JsonDataRegistry<List<NaturalMaterial>>{
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getContent(item: ItemStack): Int? {
|
||||
val itemId = BuiltInRegistries.ITEM.getKey(item.item)
|
||||
if (itemId in itemMap.keys) {
|
||||
@@ -76,6 +78,7 @@ object NaturalMaterials : JsonDataRegistry<List<NaturalMaterial>>{
|
||||
return null
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getReturnItem(item: ItemStack): ResourceLocation? {
|
||||
val itemId = BuiltInRegistries.ITEM.getKey(item.item)
|
||||
if (itemId in itemMap.keys) {
|
||||
@@ -87,4 +90,4 @@ object NaturalMaterials : JsonDataRegistry<List<NaturalMaterial>>{
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,9 @@ object Marks: JsonDataRegistry<Mark> {
|
||||
/**
|
||||
* Gets all loaded [Mark]s.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun all() = this.marks.values.toList()
|
||||
@JvmStatic
|
||||
fun identifiers(): Collection<String> = marks.keys.toSet().map { it.toString() }
|
||||
|
||||
/**
|
||||
@@ -64,5 +66,6 @@ object Marks: JsonDataRegistry<Mark> {
|
||||
* @param identifier The identifier of the mark.
|
||||
* @return The [Mark] if loaded, otherwise null.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getByIdentifier(identifier: ResourceLocation): Mark? = this.marks[identifier]
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@ import com.bedrockk.molang.runtime.MoLangEnvironment
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.MoParams
|
||||
import com.bedrockk.molang.runtime.struct.ArrayStruct
|
||||
import com.bedrockk.molang.runtime.struct.MoStruct
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.struct.VariableStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
@@ -40,7 +39,6 @@ import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||
import com.cobblemon.mod.common.api.moves.animations.NPCProvider
|
||||
import com.cobblemon.mod.common.api.moves.animations.TargetsProvider
|
||||
import com.cobblemon.mod.common.api.npc.NPCClass
|
||||
import com.cobblemon.mod.common.api.npc.NPCClasses
|
||||
import com.cobblemon.mod.common.api.npc.configuration.interaction.DialogueNPCInteractionConfiguration
|
||||
import com.cobblemon.mod.common.api.npc.configuration.interaction.ScriptNPCInteractionConfiguration
|
||||
@@ -57,7 +55,6 @@ import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.api.pokemon.experience.SidemodExperienceSource
|
||||
import com.cobblemon.mod.common.api.pokemon.moves.LearnsetQuery
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.riding.Rideable
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker
|
||||
import com.cobblemon.mod.common.api.scheduling.Schedulable
|
||||
@@ -137,7 +134,6 @@ import net.minecraft.world.entity.LightningBolt
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.Mob
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.PlayerRideable
|
||||
import net.minecraft.world.entity.TamableAnimal
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
@@ -145,7 +141,6 @@ import net.minecraft.world.entity.ai.memory.MemoryStatus
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.entity.animal.Animal
|
||||
import net.minecraft.world.entity.item.ItemEntity
|
||||
import net.minecraft.world.entity.monster.Enemy
|
||||
import net.minecraft.world.entity.monster.Monster
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.ItemStack
|
||||
@@ -160,9 +155,6 @@ import net.minecraft.world.level.levelgen.Heightmap
|
||||
import net.minecraft.world.level.pathfinder.PathType
|
||||
import net.minecraft.world.phys.AABB
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import kotlin.text.get
|
||||
import kotlin.text.toInt
|
||||
import kotlin.toString
|
||||
|
||||
/**
|
||||
* Holds a bunch of useful MoLang trickery that can be used or extended in API
|
||||
@@ -598,10 +590,10 @@ object MoLangFunctions {
|
||||
}
|
||||
if (player is ServerPlayer) {
|
||||
map.put("seen_credits") { _ ->
|
||||
DoubleValue( DoubleValue(player.seenCredits) )
|
||||
DoubleValue(player.seenCredits)
|
||||
}
|
||||
map.put("is_in_dialogue") { _ ->
|
||||
DoubleValue( DoubleValue(player.isInDialogue) )
|
||||
DoubleValue(player.isInDialogue)
|
||||
}
|
||||
map.put("active_dialogue") { _ ->
|
||||
if (player.isInDialogue) {
|
||||
@@ -1185,16 +1177,28 @@ object MoLangFunctions {
|
||||
return@put DoubleValue.ONE
|
||||
}
|
||||
map.put("has_memory_value") { params ->
|
||||
val memoryTypes = params.params.map {
|
||||
it.asString().asIdentifierDefaultingNamespace()
|
||||
}.map(BuiltInRegistries.MEMORY_MODULE_TYPE::get)
|
||||
return@put DoubleValue(memoryTypes.all { entity.brain.checkMemory(it, MemoryStatus.VALUE_PRESENT) })
|
||||
for (param in params.params) {
|
||||
if (!entity.hasMemoryFromString(param.asString())) {
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
return@put DoubleValue.ONE
|
||||
}
|
||||
map.put("lacks_memory_value") { params ->
|
||||
val memoryTypes = params.params.map {
|
||||
it.asString().asIdentifierDefaultingNamespace()
|
||||
}.map(BuiltInRegistries.MEMORY_MODULE_TYPE::get)
|
||||
return@put DoubleValue(memoryTypes.none { entity.brain.checkMemory(it, MemoryStatus.VALUE_PRESENT) })
|
||||
for (param in params.params) {
|
||||
if (entity.hasMemoryFromString(param.asString())) {
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
return@put DoubleValue.ONE
|
||||
}
|
||||
map.put("is_doing_activity") { params ->
|
||||
for (param in params.params) {
|
||||
if (entity.isDoingActivityFromString(param.asString())) {
|
||||
return@put DoubleValue.ONE
|
||||
}
|
||||
}
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
map.put("can_see") { params ->
|
||||
val target = params.get<MoValue>(0)
|
||||
@@ -1252,15 +1256,6 @@ object MoLangFunctions {
|
||||
map.put("in_battle") { DoubleValue(npc.isInBattle()) }
|
||||
map.put("battles") { ArrayStruct(npc.battleIds.mapNotNull { BattleRegistry.getBattle(it)?.struct }.mapIndexed { index, value -> "$index" to value }.toMap()) }
|
||||
map.put("stop_battles") { _ -> npc.battleIds.forEach { BattleRegistry.getBattle(it)?.stop() } }
|
||||
map.put("is_doing_activity") { params ->
|
||||
val identifiers = params.params.map { it.asString().asIdentifierDefaultingNamespace(namespace = "minecraft") }
|
||||
val activities = identifiers.mapNotNull { identifier -> BuiltInRegistries.ACTIVITY.get(identifier) }
|
||||
if (activities.isNotEmpty()) {
|
||||
return@put DoubleValue(activities.any { activity -> npc.brain.isActive(activity) })
|
||||
} else {
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
map.put("run_script_on_client") { params ->
|
||||
val world = npc.level()
|
||||
if (world is ServerLevel) {
|
||||
@@ -1905,6 +1900,9 @@ object MoLangFunctions {
|
||||
map.put("is_holding_item") { DoubleValue(!pokemonEntity.entityData.get(PokemonEntity.SHOWN_HELD_ITEM).let {
|
||||
it.isEmpty || it.`is`(CobblemonItemTags.WEARABLE_HAT_ITEMS) || it.`is`(CobblemonItemTags.WEARABLE_FACE_ITEMS)
|
||||
}) }
|
||||
map.put("riding_style") {
|
||||
StringValue(pokemonEntity.ifRidingAvailableSupply("") { behaviour, settings, state -> behaviour.getRidingStyle(settings, state).name })
|
||||
}
|
||||
map.put("is_wearing_hat") { DoubleValue(pokemonEntity.entityData.get(PokemonEntity.SHOWN_HELD_ITEM).`is`(CobblemonItemTags.WEARABLE_HAT_ITEMS)) }
|
||||
map.put("is_wearing_face") { DoubleValue(pokemonEntity.entityData.get(PokemonEntity.SHOWN_HELD_ITEM).`is`(CobblemonItemTags.WEARABLE_FACE_ITEMS)) }
|
||||
map.put("is_pastured") {
|
||||
@@ -2657,5 +2655,4 @@ object MoLangFunctions {
|
||||
}
|
||||
}
|
||||
|
||||
fun Either<ResourceLocation, ExpressionLike>.runScript(runtime: MoLangRuntime) = map({ CobblemonScripts.run(it, runtime) }, { it.resolve(runtime) })
|
||||
|
||||
fun Either<ResourceLocation, ExpressionLike>.runScript(runtime: MoLangRuntime) = map({ CobblemonScripts.run(it, runtime) }, { it.resolve(runtime) })
|
||||
@@ -9,8 +9,8 @@
|
||||
package com.cobblemon.mod.common.api.molang
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
@@ -23,11 +23,11 @@ import net.minecraft.resources.ResourceLocation
|
||||
*/
|
||||
class ReferenceExpression(val identifier: ResourceLocation) : ExpressionLike {
|
||||
override fun resolve(runtime: MoLangRuntime, context: Map<String, MoValue>): MoValue {
|
||||
return getScript()?.resolve(runtime, context) ?: DoubleValue.ZERO
|
||||
return getScript()?.resolve(runtime, context) ?: StringValue(identifier.toString())
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return getScript()?.getString() ?: "0"
|
||||
return getScript()?.getString() ?: identifier.toString()
|
||||
}
|
||||
|
||||
fun getScript() = CobblemonScripts.scripts[identifier]
|
||||
|
||||
@@ -33,6 +33,7 @@ object HiddenPowerUtil {
|
||||
ElementalTypes.DARK
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
fun getHiddenPowerType(pokemon: Pokemon?): ElementalType {
|
||||
if (pokemon == null) {
|
||||
return ElementalTypes.NORMAL
|
||||
|
||||
@@ -53,8 +53,7 @@ open class MoveTemplate(
|
||||
val pp: Int,
|
||||
val priority: Int,
|
||||
val critRatio: Double,
|
||||
val effectChances: Array<Double>,
|
||||
val actionEffect: ActionEffectTimeline?
|
||||
val effectChances: Array<Double>
|
||||
) {
|
||||
val struct: MoStruct by lazy {
|
||||
QueryStruct(hashMapOf())
|
||||
@@ -87,8 +86,7 @@ open class MoveTemplate(
|
||||
pp = 5,
|
||||
priority = 0,
|
||||
critRatio = 0.0,
|
||||
effectChances = emptyArray(),
|
||||
actionEffect = null
|
||||
effectChances = emptyArray()
|
||||
)
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -92,18 +92,7 @@ object Moves : DataRegistry {
|
||||
effectChances += secondaryMember.get("chance").asDouble
|
||||
}
|
||||
}
|
||||
val actionEffect = ActionEffects.actionEffects[id.asIdentifierDefaultingNamespace()]
|
||||
?: run {
|
||||
ActionEffects.actionEffects["generic_move".asIdentifierDefaultingNamespace()]
|
||||
// if (damageCategory == DamageCategories.STATUS) {
|
||||
// ActionEffects.actionEffects[cobblemonResource("status")]
|
||||
// } else {
|
||||
// val type = elementalType.name.lowercase()
|
||||
// val category = damageCategory.name.lowercase()
|
||||
// ActionEffects.actionEffects["${category}_$type".asIdentifierDefaultingNamespace()]
|
||||
// }
|
||||
}
|
||||
val move = MoveTemplate(id, num, elementalType, damageCategory, power, target, accuracy, pp, priority, critRatio, effectChances.toTypedArray(), actionEffect)
|
||||
val move = MoveTemplate(id, num, elementalType, damageCategory, power, target, accuracy, pp, priority, critRatio, effectChances.toTypedArray())
|
||||
this.register(move)
|
||||
} catch (e: Exception) {
|
||||
Cobblemon.LOGGER.error("Caught exception trying to resolve the move '{}'", id, e)
|
||||
@@ -117,12 +106,19 @@ object Moves : DataRegistry {
|
||||
MovesRegistrySyncPacket(all()).sendToPlayer(player)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getByName(name: String) = allMoves[name.lowercase()]
|
||||
@JvmStatic
|
||||
fun getByNumericalId(id: Int) = idMapping[id]
|
||||
@JvmStatic
|
||||
fun getByNameOrDummy(name: String) = allMoves[name.lowercase()] ?: MoveTemplate.dummy(name.lowercase())
|
||||
@JvmStatic
|
||||
fun getExceptional() = getByName("tackle") ?: allMoves.values.random()
|
||||
@JvmStatic
|
||||
fun count() = allMoves.size
|
||||
@JvmStatic
|
||||
fun names(): Collection<String> = this.allMoves.keys.toSet()
|
||||
@JvmStatic
|
||||
fun all() = this.allMoves.values.toList()
|
||||
|
||||
internal fun receiveSyncPacket(moves: Collection<MoveTemplate>) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.moves.animations.keyframes.*
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stat
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.pokemon.adapters.CobblemonStatTypeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.*
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
@@ -91,5 +92,11 @@ object ActionEffects : JsonDataRegistry<ActionEffectTimeline> {
|
||||
observable.emit(this)
|
||||
}
|
||||
|
||||
fun getEffectWithBattleContext(id: ResourceLocation, pokemon: BattlePokemon): ActionEffectTimeline? {
|
||||
val species = pokemon.entity?.exposedSpecies ?: pokemon.effectedPokemon.species
|
||||
val contextedEffect = actionEffects[ResourceLocation.fromNamespaceAndPath(id.namespace, id.path + "_" + species)]
|
||||
return contextedEffect ?: actionEffects[id]
|
||||
}
|
||||
|
||||
override fun sync(player: ServerPlayer) {}
|
||||
}
|
||||
@@ -97,6 +97,7 @@ object NPCClasses : JsonDataRegistry<NPCClass> {
|
||||
override val observable = SimpleObservable<NPCClasses>()
|
||||
private val npcClassesByIdentifier = hashMapOf<ResourceLocation, NPCClass>()
|
||||
|
||||
@JvmStatic
|
||||
val classes: Collection<NPCClass>
|
||||
get() = this.npcClassesByIdentifier.values
|
||||
|
||||
@@ -116,6 +117,7 @@ object NPCClasses : JsonDataRegistry<NPCClass> {
|
||||
* @param identifier The unique [NPCClass.id] of the [NPCClass].
|
||||
* @return The [NPCClass] if existing.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getByIdentifier(identifier: ResourceLocation) = this.npcClassesByIdentifier[identifier]
|
||||
|
||||
/**
|
||||
@@ -123,6 +125,7 @@ object NPCClasses : JsonDataRegistry<NPCClass> {
|
||||
*
|
||||
* @return The loaded NPC class amount.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun count() = this.npcClassesByIdentifier.size
|
||||
|
||||
/**
|
||||
@@ -132,6 +135,7 @@ object NPCClasses : JsonDataRegistry<NPCClass> {
|
||||
*
|
||||
* @return A randomly selected [Species].
|
||||
*/
|
||||
@JvmStatic
|
||||
fun random(): NPCClass = this.npcClassesByIdentifier.values.random()
|
||||
|
||||
fun dummy(): NPCClass {
|
||||
|
||||
@@ -102,6 +102,7 @@ object NPCPresets : JsonDataRegistry<NPCPreset> {
|
||||
observable.emit(this)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getPreset(identifier: ResourceLocation): NPCPreset? {
|
||||
return npcPresetsByIdentifier[identifier]
|
||||
}
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@ open class OrientationController(val entity: LivingEntity) {
|
||||
}
|
||||
|
||||
fun getRenderOrientation(delta: Float): Quaternionf {
|
||||
val old = renderOrientationO ?: renderOrientation ?: orientation
|
||||
val old = renderOrientationO ?: renderOrientation ?: orientation ?: Matrix3f()
|
||||
val new = renderOrientation ?: old
|
||||
val oldQuat = Quaternionf().setFromUnnormalized(old)
|
||||
val newQuat = Quaternionf().setFromUnnormalized(new)
|
||||
|
||||
@@ -23,11 +23,14 @@ object PastureLinkManager {
|
||||
// Maps player UUID
|
||||
val links = mutableMapOf<UUID, PastureLink>()
|
||||
|
||||
@JvmStatic
|
||||
fun getLinkByPlayerId(playerId: UUID) = links[playerId]
|
||||
@JvmStatic
|
||||
fun createLink(playerId: UUID, link: PastureLink) {
|
||||
links[playerId] = link
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getLinkByPlayer(player: ServerPlayer): PastureLink? {
|
||||
val link = getLinkByPlayerId(player.uuid)
|
||||
if (link != null) {
|
||||
@@ -40,6 +43,7 @@ object PastureLinkManager {
|
||||
return link
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun removeAt(world: ServerLevel, pos: BlockPos) {
|
||||
links.removeIf { (uuid, pastureLink) ->
|
||||
val shouldRemove = world.dimensionTypeRegistration().`is`(pastureLink.dimension) && pastureLink.pos == pos
|
||||
|
||||
+1
@@ -28,6 +28,7 @@ import net.minecraft.server.level.ServerPlayer
|
||||
object PasturePermissionControllers {
|
||||
val controllers = PrioritizedList<PasturePermissionController>()
|
||||
|
||||
@JvmStatic
|
||||
fun permit(player: ServerPlayer, pastureBlockEntity: PokemonPastureBlockEntity): PasturePermissions {
|
||||
return controllers.firstNotNullOfOrNull { it.permit(player, pastureBlockEntity) }
|
||||
?: PasturePermissions(
|
||||
|
||||
@@ -147,6 +147,7 @@ object CobblemonPermissions {
|
||||
@JvmStatic
|
||||
val SEE_HIDDEN_NPCS = this.create("seehiddennpcs", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
|
||||
@JvmStatic
|
||||
fun all(): Iterable<Permission> = this.permissions
|
||||
|
||||
private fun create(node: String, level: PermissionLevel): Permission {
|
||||
|
||||
@@ -53,100 +53,196 @@ object PokeBalls : JsonDataRegistry<PokeBall> {
|
||||
// ToDo datapack pokeball type here instead
|
||||
private val custom = hashMapOf<ResourceLocation, PokeBall>()
|
||||
|
||||
@JvmStatic
|
||||
@get:JvmName("getPokeBall")
|
||||
val POKE_BALL
|
||||
get() = this.byName("poke_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getSlateBall")
|
||||
val SLATE_BALL
|
||||
get() = this.byName("slate_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAzureBall")
|
||||
val AZURE_BALL
|
||||
get() = this.byName("azure_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getVerdantBall")
|
||||
val VERDANT_BALL
|
||||
get() = this.byName("verdant_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getRoseateBall")
|
||||
val ROSEATE_BALL
|
||||
get() = this.byName("roseate_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getCitrineBall")
|
||||
val CITRINE_BALL
|
||||
get() = this.byName("citrine_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getGreatBall")
|
||||
val GREAT_BALL
|
||||
get() = this.byName("great_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getUltraBall")
|
||||
val ULTRA_BALL
|
||||
get() = this.byName("ultra_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getMasterBall")
|
||||
val MASTER_BALL
|
||||
get() = this.byName("master_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getSafariBall")
|
||||
val SAFARI_BALL
|
||||
get() = this.byName("safari_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getFastBall")
|
||||
val FAST_BALL
|
||||
get() = this.byName("fast_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getLevelBall")
|
||||
val LEVEL_BALL
|
||||
get() = this.byName("level_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getLureBall")
|
||||
val LURE_BALL
|
||||
get() = this.byName("lure_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getHeavyBall")
|
||||
val HEAVY_BALL
|
||||
get() = this.byName("heavy_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getLoveBall")
|
||||
val LOVE_BALL
|
||||
get() = this.byName("love_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getFriendBall")
|
||||
val FRIEND_BALL
|
||||
get() = this.byName("friend_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getMoonBall")
|
||||
val MOON_BALL
|
||||
get() = this.byName("moon_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getSportBall")
|
||||
val SPORT_BALL
|
||||
get() = this.byName("sport_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getNetBall")
|
||||
val NET_BALL
|
||||
get() = this.byName("net_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getDiveBall")
|
||||
val DIVE_BALL
|
||||
get() = this.byName("dive_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getNestBall")
|
||||
val NEST_BALL
|
||||
get() = this.byName("nest_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getRepeatBall")
|
||||
val REPEAT_BALL
|
||||
get() = this.byName("repeat_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getTimerBall")
|
||||
val TIMER_BALL
|
||||
get() = this.byName("timer_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getLuxuryBall")
|
||||
val LUXURY_BALL
|
||||
get() = this.byName("luxury_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getPremierBall")
|
||||
val PREMIER_BALL
|
||||
get() = this.byName("premier_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getDuskBall")
|
||||
val DUSK_BALL
|
||||
get() = this.byName("dusk_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getHealBall")
|
||||
val HEAL_BALL
|
||||
get() = this.byName("heal_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getQuickBall")
|
||||
val QUICK_BALL
|
||||
get() = this.byName("quick_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getCherishBall")
|
||||
val CHERISH_BALL
|
||||
get() = this.byName("cherish_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getParkBall")
|
||||
val PARK_BALL
|
||||
get() = this.byName("park_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getDreamBall")
|
||||
val DREAM_BALL
|
||||
get() = this.byName("dream_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getBeastBall")
|
||||
val BEAST_BALL
|
||||
get() = this.byName("beast_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientPokeBall")
|
||||
val ANCIENT_POKE_BALL
|
||||
get() = this.byName("ancient_poke_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientCitrineBall")
|
||||
val ANCIENT_CITRINE_BALL
|
||||
get() = this.byName("ancient_citrine_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientVerdantBall")
|
||||
val ANCIENT_VERDANT_BALL
|
||||
get() = this.byName("ancient_verdant_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientAzureBall")
|
||||
val ANCIENT_AZURE_BALL
|
||||
get() = this.byName("ancient_azure_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientRoseateBall")
|
||||
val ANCIENT_ROSEATE_BALL
|
||||
get() = this.byName("ancient_roseate_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientSlateBall")
|
||||
val ANCIENT_SLATE_BALL
|
||||
get() = this.byName("ancient_slate_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientIvoryBall")
|
||||
val ANCIENT_IVORY_BALL
|
||||
get() = this.byName("ancient_ivory_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientGreatBall")
|
||||
val ANCIENT_GREAT_BALL
|
||||
get() = this.byName("ancient_great_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientUltraBall")
|
||||
val ANCIENT_ULTRA_BALL
|
||||
get() = this.byName("ancient_ultra_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientHeavyBall")
|
||||
val ANCIENT_HEAVY_BALL
|
||||
get() = this.byName("ancient_heavy_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientLeadenBall")
|
||||
val ANCIENT_LEADEN_BALL
|
||||
get() = this.byName("ancient_leaden_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientGigatonBall")
|
||||
val ANCIENT_GIGATON_BALL
|
||||
get() = this.byName("ancient_gigaton_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientFeatherBall")
|
||||
val ANCIENT_FEATHER_BALL
|
||||
get() = this.byName("ancient_feather_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientWingBall")
|
||||
val ANCIENT_WING_BALL
|
||||
get() = this.byName("ancient_wing_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientJetBall")
|
||||
val ANCIENT_JET_BALL
|
||||
get() = this.byName("ancient_jet_ball")
|
||||
@JvmStatic
|
||||
@get:JvmName("getAncientOriginBall")
|
||||
val ANCIENT_ORIGIN_BALL
|
||||
get() = this.byName("ancient_origin_ball")
|
||||
|
||||
@@ -225,8 +321,10 @@ object PokeBalls : JsonDataRegistry<PokeBall> {
|
||||
* Gets a Pokeball from registry name.
|
||||
* @return the pokeball object if found otherwise null.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getPokeBall(name : ResourceLocation): PokeBall? = this.custom[name] ?: this.defaults[name]
|
||||
|
||||
@JvmStatic
|
||||
fun all() = this.defaults.filterKeys { !this.custom.containsKey(it) }.values + this.custom.values
|
||||
|
||||
private fun createDefault(
|
||||
@@ -250,4 +348,196 @@ object PokeBalls : JsonDataRegistry<PokeBall> {
|
||||
val identifier = cobblemonResource(name)
|
||||
return this.custom[identifier] ?: this.defaults[identifier]!!
|
||||
}
|
||||
|
||||
/**
|
||||
* Backwards compatibility getters
|
||||
*/
|
||||
@JvmName("getPOKE_BALL")
|
||||
@Deprecated("Use PokeBalls.getPokeBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getPOKE_BALL() = POKE_BALL
|
||||
|
||||
@JvmName("getSLATE_BALL")
|
||||
@Deprecated("Use PokeBalls.getSlateBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getSLATE_BALL() = SLATE_BALL
|
||||
|
||||
@JvmName("getAZURE_BALL")
|
||||
@Deprecated("Use PokeBalls.getAzureBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getAZURE_BALL() = AZURE_BALL
|
||||
|
||||
@JvmName("getVERDANT_BALL")
|
||||
@Deprecated("Use PokeBalls.getVerdantBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getVERDANT_BALL() = VERDANT_BALL
|
||||
|
||||
@JvmName("getROSEATE_BALL")
|
||||
@Deprecated("Use PokeBalls.getRoseateBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getROSEATE_BALL() = ROSEATE_BALL
|
||||
|
||||
@JvmName("getCITRINE_BALL")
|
||||
@Deprecated("Use PokeBalls.getCitrineBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getCITRINE_BALL() = CITRINE_BALL
|
||||
|
||||
@JvmName("getGREAT_BALL")
|
||||
@Deprecated("Use PokeBalls.getGreatBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getGREAT_BALL() = GREAT_BALL
|
||||
|
||||
@JvmName("getULTRA_BALL")
|
||||
@Deprecated("Use PokeBalls.getUltraBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getULTRA_BALL() = ULTRA_BALL
|
||||
|
||||
@JvmName("getMASTER_BALL")
|
||||
@Deprecated("Use PokeBalls.getMasterBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getMASTER_BALL() = MASTER_BALL
|
||||
|
||||
@JvmName("getSAFARI_BALL")
|
||||
@Deprecated("Use PokeBalls.getSafariBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getSAFARI_BALL() = SAFARI_BALL
|
||||
|
||||
@JvmName("getFAST_BALL")
|
||||
@Deprecated("Use PokeBalls.getFastBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getFAST_BALL() = FAST_BALL
|
||||
|
||||
@JvmName("getLEVEL_BALL")
|
||||
@Deprecated("Use PokeBalls.getLevelBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getLEVEL_BALL() = LEVEL_BALL
|
||||
|
||||
@JvmName("getLURE_BALL")
|
||||
@Deprecated("Use PokeBalls.getLureBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getLURE_BALL() = LURE_BALL
|
||||
|
||||
@JvmName("getHEAVY_BALL")
|
||||
@Deprecated("Use PokeBalls.getHeavyBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getHEAVY_BALL() = HEAVY_BALL
|
||||
|
||||
@JvmName("getLOVE_BALL")
|
||||
@Deprecated("Use PokeBalls.getLoveBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getLOVE_BALL() = LOVE_BALL
|
||||
|
||||
@JvmName("getFRIEND_BALL")
|
||||
@Deprecated("Use PokeBalls.getFriendBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getFRIEND_BALL() = FRIEND_BALL
|
||||
|
||||
@JvmName("getMOON_BALL")
|
||||
@Deprecated("Use PokeBalls.getMoonBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getMOON_BALL() = MOON_BALL
|
||||
|
||||
@JvmName("getSPORT_BALL")
|
||||
@Deprecated("Use PokeBalls.getSportBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getSPORT_BALL() = SPORT_BALL
|
||||
|
||||
@JvmName("getNET_BALL")
|
||||
@Deprecated("Use PokeBalls.getNetBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getNET_BALL() = NET_BALL
|
||||
|
||||
@JvmName("getNEST_BALL")
|
||||
@Deprecated("Use PokeBalls.getNestBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getNEST_BALL() = NEST_BALL
|
||||
|
||||
@JvmName("getREPEAT_BALL")
|
||||
@Deprecated("Use PokeBalls.getRepeatBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getREPEAT_BALL() = REPEAT_BALL
|
||||
|
||||
@JvmName("getTIMER_BALL")
|
||||
@Deprecated("Use PokeBalls.getTimerBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getTIMER_BALL() = TIMER_BALL
|
||||
|
||||
@JvmName("getLUXURY_BALL")
|
||||
@Deprecated("Use PokeBalls.getLuxuryBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getLUXURY_BALL() = LUXURY_BALL
|
||||
|
||||
@JvmName("getPREMIER_BALL")
|
||||
@Deprecated("Use PokeBalls.getPremierBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getPREMIER_BALL() = PREMIER_BALL
|
||||
|
||||
@JvmName("getDUSK_BALL")
|
||||
@Deprecated("Use PokeBalls.getDuskBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getDUSK_BALL() = DUSK_BALL
|
||||
|
||||
@JvmName("getHEAL_BALL")
|
||||
@Deprecated("Use PokeBalls.getHealBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getHEAL_BALL() = HEAL_BALL
|
||||
|
||||
@JvmName("getQUICK_BALL")
|
||||
@Deprecated("Use PokeBalls.getQuickBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getQUICK_BALL() = QUICK_BALL
|
||||
|
||||
@JvmName("getCHERISH_BALL")
|
||||
@Deprecated("Use PokeBalls.getCherishBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getCHERISH_BALL() = CHERISH_BALL
|
||||
|
||||
@JvmName("getPARK_BALL")
|
||||
@Deprecated("Use PokeBalls.getParkBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getPARK_BALL() = PARK_BALL
|
||||
|
||||
@JvmName("getDREAM_BALL")
|
||||
@Deprecated("Use PokeBalls.getDreamBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getDREAM_BALL() = DREAM_BALL
|
||||
|
||||
@JvmName("getBEAST_BALL")
|
||||
@Deprecated("Use PokeBalls.getBeastBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getBEAST_BALL() = BEAST_BALL
|
||||
|
||||
@JvmName("getANCIENT_POKE_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientPokeBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_POKE_BALL() = ANCIENT_POKE_BALL
|
||||
|
||||
@JvmName("getANCIENT_CITRINE_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientCitrineBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_CITRINE_BALL() = ANCIENT_CITRINE_BALL
|
||||
|
||||
@JvmName("getANCIENT_VERDANT_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientVerdantBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_VERDANT_BALL() = ANCIENT_VERDANT_BALL
|
||||
|
||||
@JvmName("getANCIENT_AZURE_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientAzureBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_AZURE_BALL() = ANCIENT_AZURE_BALL
|
||||
|
||||
@JvmName("getANCIENT_ROSEATE_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientRoseateBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_ROSEATE_BALL() = ANCIENT_ROSEATE_BALL
|
||||
|
||||
@JvmName("getANCIENT_SLATE_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientSlateBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_SLATE_BALL() = ANCIENT_SLATE_BALL
|
||||
|
||||
@JvmName("getANCIENT_IVORY_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientIvoryBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_IVORY_BALL() = ANCIENT_IVORY_BALL
|
||||
|
||||
@JvmName("getANCIENT_GREAT_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientGreatBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_GREAT_BALL() = ANCIENT_GREAT_BALL
|
||||
|
||||
@JvmName("getANCIENT_ULTRA_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientUltraBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_ULTRA_BALL() = ANCIENT_ULTRA_BALL
|
||||
|
||||
@JvmName("getANCIENT_HEAVY_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientHeavyBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_HEAVY_BALL() = ANCIENT_HEAVY_BALL
|
||||
|
||||
@JvmName("getANCIENT_LEADEN_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientLeadenBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_LEADEN_BALL() = ANCIENT_LEADEN_BALL
|
||||
|
||||
@JvmName("getANCIENT_GIGATON_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientGigatonBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_GIGATON_BALL() = ANCIENT_GIGATON_BALL
|
||||
|
||||
@JvmName("getANCIENT_FEATHER_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientFeatherBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_FEATHER_BALL() = ANCIENT_FEATHER_BALL
|
||||
|
||||
@JvmName("getANCIENT_WING_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientWingBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_WING_BALL() = ANCIENT_WING_BALL
|
||||
|
||||
@JvmName("getANCIENT_JET_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientJetBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_JET_BALL() = ANCIENT_JET_BALL
|
||||
|
||||
@JvmName("getANCIENT_ORIGIN_BALL")
|
||||
@Deprecated("Use PokeBalls.getAncientOriginBall(), provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getANCIENT_ORIGIN_BALL() = ANCIENT_ORIGIN_BALL
|
||||
|
||||
}
|
||||
@@ -24,126 +24,151 @@ import net.minecraft.resources.ResourceLocation
|
||||
object Natures {
|
||||
private val allNatures = mutableListOf<Nature>()
|
||||
|
||||
@JvmField
|
||||
val HARDY = registerNature(
|
||||
Nature(cobblemonResource("hardy"), "cobblemon.nature.hardy",
|
||||
null, null, null, null)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val LONELY = registerNature(
|
||||
Nature(cobblemonResource("lonely"), "cobblemon.nature.lonely",
|
||||
Stats.ATTACK, Stats.DEFENCE, Flavour.SPICY, Flavour.SOUR)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val BRAVE = registerNature(
|
||||
Nature(cobblemonResource("brave"), "cobblemon.nature.brave",
|
||||
Stats.ATTACK, Stats.SPEED, Flavour.SPICY, Flavour.SWEET)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val ADAMANT = registerNature(
|
||||
Nature(cobblemonResource("adamant"), "cobblemon.nature.adamant",
|
||||
Stats.ATTACK, Stats.SPECIAL_ATTACK, Flavour.SPICY, Flavour.DRY)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val NAUGHTY = registerNature(
|
||||
Nature(cobblemonResource("naughty"), "cobblemon.nature.naughty",
|
||||
Stats.ATTACK, Stats.SPECIAL_DEFENCE, Flavour.SPICY, Flavour.BITTER)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val BOLD = registerNature(
|
||||
Nature(cobblemonResource("bold"), "cobblemon.nature.bold",
|
||||
Stats.DEFENCE, Stats.ATTACK, Flavour.SOUR, Flavour.SPICY)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val DOCILE = registerNature(
|
||||
Nature(cobblemonResource("docile"), "cobblemon.nature.docile",
|
||||
null, null, null, null)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val RELAXED = registerNature(
|
||||
Nature(cobblemonResource("relaxed"), "cobblemon.nature.relaxed",
|
||||
Stats.DEFENCE, Stats.SPEED, Flavour.SOUR, Flavour.SWEET)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val IMPISH = registerNature(
|
||||
Nature(cobblemonResource("impish"), "cobblemon.nature.impish",
|
||||
Stats.DEFENCE, Stats.SPECIAL_ATTACK, Flavour.SOUR, Flavour.DRY)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val LAX = registerNature(
|
||||
Nature(cobblemonResource("lax"), "cobblemon.nature.lax",
|
||||
Stats.DEFENCE, Stats.SPECIAL_DEFENCE, Flavour.SOUR, Flavour.BITTER)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val TIMID = registerNature(
|
||||
Nature(cobblemonResource("timid"), "cobblemon.nature.timid",
|
||||
Stats.SPEED, Stats.ATTACK, Flavour.SWEET, Flavour.SPICY)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val HASTY = registerNature(
|
||||
Nature(cobblemonResource("hasty"), "cobblemon.nature.hasty",
|
||||
Stats.SPEED, Stats.DEFENCE, Flavour.SWEET, Flavour.SOUR)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val SERIOUS = registerNature(
|
||||
Nature(cobblemonResource("serious"), "cobblemon.nature.serious",
|
||||
null, null, null, null)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val JOLLY = registerNature(
|
||||
Nature(cobblemonResource("jolly"), "cobblemon.nature.jolly",
|
||||
Stats.SPEED, Stats.SPECIAL_ATTACK, Flavour.SWEET, Flavour.DRY)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val NAIVE = registerNature(
|
||||
Nature(cobblemonResource("naive"), "cobblemon.nature.naive",
|
||||
Stats.SPEED, Stats.SPECIAL_DEFENCE, Flavour.SWEET, Flavour.BITTER)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val MODEST = registerNature(
|
||||
Nature(cobblemonResource("modest"), "cobblemon.nature.modest",
|
||||
Stats.SPECIAL_ATTACK, Stats.ATTACK, null, null)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val MILD = registerNature(
|
||||
Nature(cobblemonResource("mild"), "cobblemon.nature.mild",
|
||||
Stats.SPECIAL_ATTACK, Stats.DEFENCE, Flavour.DRY, Flavour.SOUR)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val QUIET = registerNature(
|
||||
Nature(cobblemonResource("quiet"), "cobblemon.nature.quiet",
|
||||
Stats.SPECIAL_ATTACK, Stats.SPEED, Flavour.DRY, Flavour.SWEET)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val BASHFUL = registerNature(
|
||||
Nature(cobblemonResource("bashful"), "cobblemon.nature.bashful",
|
||||
null, null, null, null)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val RASH = registerNature(
|
||||
Nature(cobblemonResource("rash"), "cobblemon.nature.rash",
|
||||
Stats.SPECIAL_ATTACK, Stats.SPECIAL_DEFENCE, Flavour.DRY, Flavour.BITTER)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val CALM = registerNature(
|
||||
Nature(cobblemonResource("calm"), "cobblemon.nature.calm",
|
||||
Stats.SPECIAL_DEFENCE, Stats.ATTACK, Flavour.BITTER, Flavour.SPICY)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val GENTLE = registerNature(
|
||||
Nature(cobblemonResource("gentle"), "cobblemon.nature.gentle",
|
||||
Stats.SPECIAL_DEFENCE, Stats.DEFENCE, Flavour.BITTER, Flavour.SOUR)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val SASSY = registerNature(
|
||||
Nature(cobblemonResource("sassy"), "cobblemon.nature.sassy",
|
||||
Stats.SPECIAL_DEFENCE, Stats.SPEED, Flavour.BITTER, Flavour.SWEET)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val CAREFUL = registerNature(
|
||||
Nature(cobblemonResource("careful"), "cobblemon.nature.careful",
|
||||
Stats.SPECIAL_DEFENCE, Stats.SPECIAL_ATTACK, Flavour.BITTER, Flavour.DRY)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val QUIRKY = registerNature(
|
||||
Nature(cobblemonResource("quirky"), "cobblemon.nature.quirky",
|
||||
null, null, null, null)
|
||||
@@ -153,6 +178,7 @@ object Natures {
|
||||
/**
|
||||
* Registers a new nature type
|
||||
*/
|
||||
@JvmStatic
|
||||
fun registerNature(nature: Nature): Nature {
|
||||
allNatures.add(nature)
|
||||
return nature
|
||||
@@ -162,6 +188,7 @@ object Natures {
|
||||
* Gets a nature by registry name
|
||||
* @return a nature type or null
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getNature(name: ResourceLocation): Nature? {
|
||||
return allNatures.find { nature -> nature.name == name }
|
||||
}
|
||||
@@ -170,20 +197,122 @@ object Natures {
|
||||
* Utility method to get a nature by string
|
||||
* @return a nature type or null
|
||||
*/
|
||||
fun getNature(identifier: String): Nature? {
|
||||
val nature = getNature(cobblemonResource(identifier))
|
||||
if(nature != null) return nature
|
||||
return getNature(ResourceLocation.parse(identifier))
|
||||
}
|
||||
@JvmStatic
|
||||
fun getNature(identifier: String) = getNature(cobblemonResource(identifier))
|
||||
?: getNature(ResourceLocation.parse(identifier))
|
||||
|
||||
/**
|
||||
* Helper function for a random Nature
|
||||
* @return a random nature type
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getRandomNature(): Nature {
|
||||
return allNatures.random()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun all(): Collection<Nature> = this.allNatures.toList()
|
||||
|
||||
/**
|
||||
* Backwards compatibility getters
|
||||
*/
|
||||
@JvmName("getHARDY")
|
||||
@Deprecated("Use Natures.HARDY, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getHARDY() = HARDY
|
||||
|
||||
@JvmName("getLONELY")
|
||||
@Deprecated("Use Natures.LONELY, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getLONELY() = LONELY
|
||||
|
||||
@JvmName("getBRAVE")
|
||||
@Deprecated("Use Natures.BRAVE, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getBRAVE() = BRAVE
|
||||
|
||||
@JvmName("getADAMANT")
|
||||
@Deprecated("Use Natures.ADAMANT, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getADAMANT() = ADAMANT
|
||||
|
||||
@JvmName("getNAUGHTY")
|
||||
@Deprecated("Use Natures.NAUGHTY, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getNAUGHTY() = NAUGHTY
|
||||
|
||||
@JvmName("getBOLD")
|
||||
@Deprecated("Use Natures.BOLD, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getBOLD() = BOLD
|
||||
|
||||
@JvmName("getDOCILE")
|
||||
@Deprecated("Use Natures.DOCILE, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getDOCILE() = DOCILE
|
||||
|
||||
@JvmName("getRELAXED")
|
||||
@Deprecated("Use Natures.RELAXED, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getRELAXED() = RELAXED
|
||||
|
||||
@JvmName("getIMPISH")
|
||||
@Deprecated("Use Natures.IMPISH, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getIMPISH() = IMPISH
|
||||
|
||||
@JvmName("getLAX")
|
||||
@Deprecated("Use Natures.LAX, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getLAX() = LAX
|
||||
|
||||
@JvmName("getTIMID")
|
||||
@Deprecated("Use Natures.TIMID, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getTIMID() = TIMID
|
||||
|
||||
@JvmName("getHASTY")
|
||||
@Deprecated("Use Natures.HASTY, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getHASTY() = HASTY
|
||||
|
||||
@JvmName("getSERIOUS")
|
||||
@Deprecated("Use Natures.SERIOUS, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getSERIOUS() = SERIOUS
|
||||
|
||||
@JvmName("getJOLLY")
|
||||
@Deprecated("Use Natures.JOLLY, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getJOLLY() = JOLLY
|
||||
|
||||
@JvmName("getNAIVE")
|
||||
@Deprecated("Use Natures.NAIVE, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getNAIVE() = NAIVE
|
||||
|
||||
@JvmName("getMODEST")
|
||||
@Deprecated("Use Natures.MODEST, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getMODEST() = MODEST
|
||||
|
||||
@JvmName("getMILD")
|
||||
@Deprecated("Use Natures.MILD, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getMILD() = MILD
|
||||
|
||||
@JvmName("getQUIET")
|
||||
@Deprecated("Use Natures.QUIET, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getQUIET() = QUIET
|
||||
|
||||
@JvmName("getBASHFUL")
|
||||
@Deprecated("Use Natures.BASHFUL, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getBASHFUL() = BASHFUL
|
||||
|
||||
@JvmName("getRASH")
|
||||
@Deprecated("Use Natures.RASH, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getRASH() = RASH
|
||||
|
||||
@JvmName("getCALM")
|
||||
@Deprecated("Use Natures.CALM, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getCALM() = CALM
|
||||
|
||||
@JvmName("getGENTLE")
|
||||
@Deprecated("Use Natures.GENTLE, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getGENTLE() = GENTLE
|
||||
|
||||
@JvmName("getSASSY")
|
||||
@Deprecated("Use Natures.SASSY, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getSASSY() = SASSY
|
||||
|
||||
@JvmName("getCAREFUL")
|
||||
@Deprecated("Use Natures.CAREFUL, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getCAREFUL() = CAREFUL
|
||||
|
||||
@JvmName("getQUIRKY")
|
||||
@Deprecated("Use Natures.QUIRKY, provided for backwards compatibility until Cobblemon 1.8.")
|
||||
fun getQUIRKY() = QUIRKY
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import com.cobblemon.mod.common.api.events.pokemon.ShinyChanceCalculationEvent
|
||||
import com.cobblemon.mod.common.api.moves.Moves
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.api.pokemon.aspect.AspectProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stat
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
|
||||
@@ -31,10 +32,12 @@ import com.cobblemon.mod.common.pokemon.IVs
|
||||
import com.cobblemon.mod.common.pokemon.OriginalTrainerType
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.RenderablePokemon
|
||||
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
|
||||
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.cobblemon.mod.common.util.isDouble
|
||||
import com.cobblemon.mod.common.util.isFloat
|
||||
import com.cobblemon.mod.common.util.isUuid
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import com.cobblemon.mod.common.util.simplify
|
||||
@@ -146,6 +149,8 @@ open class PokemonProperties {
|
||||
props.originalTrainer = parsePlayerProperty(keyPairs, listOf("originaltrainer", "ot"))
|
||||
props.moves = parseString(keyPairs, listOf("moves"))?.split(",")
|
||||
props.heldItem = parseString(keyPairs, listOf("helditem", "held_item"))
|
||||
props.minPerfectIVs = parseIntProperty(keyPairs, listOf("min_perfect_ivs"))?.coerceIn(0, Stats.PERMANENT.size)
|
||||
props.scaleModifier = parseFloatProperty(keyPairs, listOf("scale_modifier"))
|
||||
|
||||
val maybeIVs = IVs()
|
||||
val maybeEVs = EVs()
|
||||
@@ -195,6 +200,16 @@ open class PokemonProperties {
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseFloatProperty(keyPairs: MutableList<Pair<String, String?>>, labels: Iterable<String>): Float? {
|
||||
val matchingKeyPair = getMatchedKeyPair(keyPairs, labels) ?: return null
|
||||
val value = matchingKeyPair.second
|
||||
return if (value == null || !value.isFloat()) {
|
||||
null
|
||||
} else {
|
||||
value.toFloat()
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseIdentifierOfRegistry(keyPairs: MutableList<Pair<String, String?>>, validKeys: List<String>, valueFetcher: (ResourceLocation) -> String?): String? {
|
||||
val matched = getMatchedKeyPair(keyPairs, validKeys) ?: return null
|
||||
val value = matched.second?.lowercase() ?: return null
|
||||
@@ -343,7 +358,9 @@ open class PokemonProperties {
|
||||
var moves: List<String>? = null
|
||||
var heldItem: String? = null
|
||||
var cosmeticItem: String? = null
|
||||
var scaleModifier: Float? = null
|
||||
|
||||
var minPerfectIVs: Int? = null
|
||||
var ivs: IVs? = null
|
||||
var evs: EVs? = null
|
||||
var customProperties = mutableListOf<CustomPokemonProperty>()
|
||||
@@ -413,6 +430,11 @@ open class PokemonProperties {
|
||||
pokemon.hyperTrainIV(stat.key, stat.value)
|
||||
}
|
||||
}
|
||||
minPerfectIVs?.let {
|
||||
CobblemonStatProvider.ofType(Stat.Type.PERMANENT).shuffled().take(it).forEach { stat ->
|
||||
pokemon.setIV(stat, IVs.MAX_VALUE)
|
||||
}
|
||||
}
|
||||
evs?.let { evs ->
|
||||
evs.forEach { stat ->
|
||||
pokemon.setEV(stat.key, stat.value)
|
||||
@@ -469,6 +491,7 @@ open class PokemonProperties {
|
||||
if (stack.isEmpty) return@let
|
||||
pokemon.swapHeldItem(stack, decrement = true, aiCanDrop = false)
|
||||
}
|
||||
scaleModifier?.let { pokemon.scaleModifier = it }
|
||||
pokemon.updateAspects()
|
||||
}
|
||||
|
||||
@@ -512,6 +535,7 @@ open class PokemonProperties {
|
||||
nature?.takeIf { it != pokemon.nature.name.toString() }?.let { return false }
|
||||
ability?.takeIf { it != pokemon.ability.name }?.let { return false }
|
||||
status?.takeIf { it != pokemon.status?.status?.showdownName }?.let { return false }
|
||||
minPerfectIVs?.takeIf { pokemon.ivs.count { stat -> stat.value == IVs.MAX_VALUE } < it }?.let { return false }
|
||||
ivs?.forEach{ stat ->
|
||||
if (stat.value != pokemon.ivs[stat.key]) { return false }
|
||||
}
|
||||
@@ -542,6 +566,7 @@ open class PokemonProperties {
|
||||
|
||||
return@takeIf false
|
||||
}?.let { return false }
|
||||
scaleModifier?.takeIf { it != pokemon.scaleModifier }?.let { return false }
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -570,6 +595,7 @@ open class PokemonProperties {
|
||||
nature?.takeIf { it != properties.nature }?.let { return false }
|
||||
ability?.takeIf { it != properties.ability }?.let { return false }
|
||||
status?.takeIf { it != properties.status }?.let { return false }
|
||||
minPerfectIVs?.takeIf { it != properties.minPerfectIVs }?.let { return false }
|
||||
ivs?.let{ ivs ->
|
||||
ivs.forEach{ stat ->
|
||||
//If the potential subset has IV and the main set does not then it cant be a subset
|
||||
@@ -593,6 +619,7 @@ open class PokemonProperties {
|
||||
originalTrainerType?.takeIf { it != properties.originalTrainerType }?.let{ return false }
|
||||
moves?.takeIf { it.any { move -> properties.moves?.none { it == move } == true } }?.let { return false }
|
||||
fullness?.takeIf { it != properties.fullness }?.let { return false }
|
||||
scaleModifier?.takeIf { it != properties.scaleModifier }?.let { return false }
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -646,6 +673,7 @@ open class PokemonProperties {
|
||||
nature?.let { nbt.putString(DataKeys.POKEMON_NATURE, it) }
|
||||
ability?.let { nbt.putString(DataKeys.POKEMON_ABILITY, it) }
|
||||
status?.let { nbt.putString(DataKeys.POKEMON_STATUS_NAME, it) }
|
||||
minPerfectIVs?.let { nbt.putInt(DataKeys.POKEMON_MIN_PERFECT_IVS, it) }
|
||||
ivs?.let { nbt.put(DataKeys.POKEMON_IVS, IVs.CODEC.encodeStart(NbtOps.INSTANCE, it).result().get()) }
|
||||
evs?.let { nbt.put(DataKeys.POKEMON_EVS, EVs.CODEC.encodeStart(NbtOps.INSTANCE, it).result().get()) }
|
||||
type?.let { nbt.putString(DataKeys.ELEMENTAL_TYPE, it) }
|
||||
@@ -657,6 +685,7 @@ open class PokemonProperties {
|
||||
originalTrainer?.let { nbt.putString(DataKeys.POKEMON_ORIGINAL_TRAINER, it) }
|
||||
moves?.let { nbt.putString(DataKeys.POKEMON_PROPERTIES_MOVES, it.joinToString(separator = ",")) }
|
||||
heldItem?.let {nbt.putString(DataKeys.POKEMON_PROPERTIES_HELDITEM, it)}
|
||||
scaleModifier?.let { nbt.putFloat(DataKeys.POKEMON_SCALE_MODIFIER, it) }
|
||||
val custom = ListTag()
|
||||
customProperties.map { StringTag.valueOf(it.asString()) }.forEach { custom.add(it) }
|
||||
nbt.put(DataKeys.POKEMON_PROPERTIES_CUSTOM, custom)
|
||||
@@ -678,6 +707,7 @@ open class PokemonProperties {
|
||||
nature = if (tag.contains(DataKeys.POKEMON_NATURE)) tag.getString(DataKeys.POKEMON_NATURE) else null
|
||||
ability = if (tag.contains(DataKeys.POKEMON_ABILITY)) tag.getString(DataKeys.POKEMON_ABILITY) else null
|
||||
status = if (tag.contains(DataKeys.POKEMON_STATUS_NAME)) tag.getString(DataKeys.POKEMON_STATUS_NAME) else null
|
||||
minPerfectIVs = if (tag.contains(DataKeys.POKEMON_MIN_PERFECT_IVS)) tag.getInt(DataKeys.POKEMON_MIN_PERFECT_IVS) else null
|
||||
ivs = if (tag.contains(DataKeys.POKEMON_IVS)) IVs.CODEC.decode(NbtOps.INSTANCE, tag.getCompound(DataKeys.POKEMON_IVS)).result().getOrNull()?.first else null
|
||||
evs = if (tag.contains(DataKeys.POKEMON_EVS)) EVs.CODEC.decode(NbtOps.INSTANCE, tag.getCompound(DataKeys.POKEMON_EVS)).result().getOrNull()?.first else null
|
||||
type = if (tag.contains(DataKeys.ELEMENTAL_TYPE)) tag.getString(DataKeys.ELEMENTAL_TYPE) else null
|
||||
@@ -689,6 +719,7 @@ open class PokemonProperties {
|
||||
originalTrainer = if (tag.contains(DataKeys.POKEMON_ORIGINAL_TRAINER)) tag.getString(DataKeys.POKEMON_ORIGINAL_TRAINER) else null
|
||||
moves = if (tag.contains(DataKeys.POKEMON_PROPERTIES_MOVES)) tag.getString(DataKeys.POKEMON_PROPERTIES_MOVES).split(",") else null
|
||||
heldItem = if (tag.contains(DataKeys.POKEMON_PROPERTIES_HELDITEM)) tag.getString(DataKeys.POKEMON_PROPERTIES_HELDITEM) else null
|
||||
scaleModifier = if (tag.contains(DataKeys.POKEMON_SCALE_MODIFIER)) tag.getFloat(DataKeys.POKEMON_SCALE_MODIFIER) else null
|
||||
val custom = tag.getList(DataKeys.POKEMON_PROPERTIES_CUSTOM, Tag.TAG_STRING.toInt())
|
||||
// This is kinda gross
|
||||
custom.forEach { customProperties.addAll(parse(it.asString).customProperties) }
|
||||
@@ -712,6 +743,7 @@ open class PokemonProperties {
|
||||
nature?.let { json.addProperty(DataKeys.POKEMON_NATURE, it) }
|
||||
ability?.let { json.addProperty(DataKeys.POKEMON_ABILITY, it) }
|
||||
status?.let { json.addProperty(DataKeys.POKEMON_STATUS_NAME, it) }
|
||||
minPerfectIVs?.let { json.addProperty(DataKeys.POKEMON_MIN_PERFECT_IVS, it) }
|
||||
ivs?.let { json.add(DataKeys.POKEMON_IVS, IVs.CODEC.encodeStart(JsonOps.INSTANCE, it).result().get()) }
|
||||
evs?.let { json.add(DataKeys.POKEMON_EVS, EVs.CODEC.encodeStart(JsonOps.INSTANCE, it).result().get()) }
|
||||
type?.let { json.addProperty(DataKeys.ELEMENTAL_TYPE, it) }
|
||||
@@ -723,6 +755,7 @@ open class PokemonProperties {
|
||||
originalTrainer?.let { json.addProperty(DataKeys.POKEMON_ORIGINAL_TRAINER, it) }
|
||||
moves?.let { json.addProperty(DataKeys.POKEMON_PROPERTIES_MOVES, it.joinToString(separator = ",")) }
|
||||
heldItem?.let {json.addProperty(DataKeys.POKEMON_PROPERTIES_HELDITEM, it)}
|
||||
scaleModifier?.let { json.addProperty(DataKeys.POKEMON_SCALE_MODIFIER, it) }
|
||||
val custom = JsonArray()
|
||||
customProperties.map { it.asString() }.forEach { custom.add(it) }
|
||||
json.add(DataKeys.POKEMON_PROPERTIES_CUSTOM, custom)
|
||||
@@ -745,6 +778,7 @@ open class PokemonProperties {
|
||||
nature = json.get(DataKeys.POKEMON_NATURE)?.asString
|
||||
ability = json.get(DataKeys.POKEMON_ABILITY)?.asString
|
||||
status = json.get(DataKeys.POKEMON_STATUS_NAME)?.asString
|
||||
minPerfectIVs = json.get(DataKeys.POKEMON_MIN_PERFECT_IVS)?.asInt
|
||||
ivs = json.getAsJsonObject(DataKeys.POKEMON_IVS)?.let { IVs.CODEC.decode(JsonOps.INSTANCE, it).result().getOrNull()?.first }
|
||||
evs = json.getAsJsonObject(DataKeys.POKEMON_EVS)?.let { EVs.CODEC.decode(JsonOps.INSTANCE, it).result().getOrNull()?.first }
|
||||
type = json.get(DataKeys.ELEMENTAL_TYPE)?.asString
|
||||
@@ -756,6 +790,7 @@ open class PokemonProperties {
|
||||
originalTrainer = json.get(DataKeys.POKEMON_ORIGINAL_TRAINER)?.asString
|
||||
moves = json.get(DataKeys.POKEMON_PROPERTIES_MOVES)?.asString?.split(",")
|
||||
heldItem = json.get(DataKeys.POKEMON_PROPERTIES_HELDITEM)?.asString
|
||||
scaleModifier = json.get(DataKeys.POKEMON_SCALE_MODIFIER)?.asFloat
|
||||
val custom = json.get(DataKeys.POKEMON_PROPERTIES_CUSTOM)?.asJsonArray
|
||||
// This is still kinda gross
|
||||
custom?.forEach { customProperties.addAll(parse(it.asString).customProperties) }
|
||||
@@ -777,6 +812,7 @@ open class PokemonProperties {
|
||||
nature?.let { pieces.add("nature=$it") }
|
||||
ability?.let { pieces.add("ability=$it") }
|
||||
status?.let { pieces.add("status=$it") }
|
||||
minPerfectIVs?.let { pieces.add("min_perfect_ivs=$it") }
|
||||
ivs?.forEach{ stat ->
|
||||
pieces.add("${stat.key}_iv=${stat.value}")
|
||||
}
|
||||
@@ -793,6 +829,7 @@ open class PokemonProperties {
|
||||
customProperties.forEach { pieces.add(it.asString()) }
|
||||
moves?.let { pieces.add("moves=${it.joinToString(separator = ",")}") }
|
||||
heldItem?.let {pieces.add("helditem=$it")}
|
||||
scaleModifier?.let { pieces.add("scale_modifier=$it") }
|
||||
return pieces.joinToString(separator)
|
||||
}
|
||||
|
||||
@@ -806,8 +843,8 @@ open class PokemonProperties {
|
||||
return PokemonProperties().loadFromJSON(this.saveToJSON())
|
||||
}
|
||||
|
||||
// If the config value is at least 1, then do 1/x and use that as the property chance
|
||||
private fun Float.checkRate(): Boolean = if (this >= 1) (Random.Default.nextFloat() < 1 / this) else Random.Default.nextFloat() < this
|
||||
// If the config value is at least 0, then do 1/x and use that as the property chance
|
||||
private fun Float.checkRate(): Boolean = this > 0 && (Random.nextFloat() < 1 / this)
|
||||
|
||||
/**
|
||||
* Attempts to find an ability by ID and resolve if it should be forced or if it's legal for the given form.
|
||||
|
||||
@@ -39,7 +39,6 @@ import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.sound.RideSoundSettingsList
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStatDefinition
|
||||
import com.cobblemon.mod.common.api.spawning.TimeRange
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.api.types.adapters.ElementalTypeAdapter
|
||||
@@ -129,7 +128,6 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
.registerTypeAdapter(MobEffect::class.java, RegistryElementAdapter<MobEffect>(BuiltInRegistries::MOB_EFFECT))
|
||||
.registerTypeAdapter(ItemPredicate::class.java, LegacyItemConditionWrapperAdapter)
|
||||
.registerTypeAdapter(RidingBehaviourSettings::class.java, RidingBehaviourSettingsAdapter)
|
||||
.registerTypeAdapter(RidingStatDefinition::class.java, RidingStatDefinitionAdapter)
|
||||
.registerTypeAdapter(RideSoundSettingsList::class.java, RideSoundSettingsListAdapter)
|
||||
.registerTypeAdapter(ObtainableItemCondition::class.java, ObtainableItemConditionAdapter)
|
||||
.disableHtmlEscaping()
|
||||
@@ -144,8 +142,10 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
private val speciesByIdentifier = hashMapOf<ResourceLocation, Species>()
|
||||
private val speciesByDex = HashBasedTable.create<String, Int, Species>()
|
||||
|
||||
@JvmStatic
|
||||
val species: Collection<Species>
|
||||
get() = this.speciesByIdentifier.values
|
||||
@JvmStatic
|
||||
val implemented: List<Species>
|
||||
get() = this.species.filter { it.implemented }
|
||||
|
||||
@@ -171,6 +171,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
* @param name The path of the species asset.
|
||||
* @return The [Species] if existing.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getByName(name: String) = this.getByIdentifier(cobblemonResource(name))
|
||||
|
||||
/**
|
||||
@@ -179,6 +180,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
* @param ndex The [Species.nationalPokedexNumber].
|
||||
* @return The [Species] if existing.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getByPokedexNumber(ndex: Int, namespace: String = Cobblemon.MODID) = this.speciesByDex.get(namespace, ndex)
|
||||
|
||||
/**
|
||||
@@ -187,6 +189,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
* @param identifier The unique [Species.resourceIdentifier] of the [Species].
|
||||
* @return The [Species] if existing.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getByIdentifier(identifier: ResourceLocation) = this.speciesByIdentifier[identifier]
|
||||
|
||||
/**
|
||||
@@ -194,6 +197,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
*
|
||||
* @return The loaded species amount.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun count() = this.speciesByIdentifier.size
|
||||
|
||||
/**
|
||||
@@ -201,6 +205,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
*
|
||||
* @return The dex numbers map to species.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getSpeciesInNamespace(namespace: String = Cobblemon.MODID): MutableMap<Int, Species> = speciesByDex.row(namespace)
|
||||
|
||||
/**
|
||||
@@ -208,6 +213,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
*
|
||||
* @return The list of loaded namespaces.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getNamespaces() = speciesByDex.rowKeySet().toList()
|
||||
|
||||
/**
|
||||
@@ -217,6 +223,7 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
*
|
||||
* @return A randomly selected [Species].
|
||||
*/
|
||||
@JvmStatic
|
||||
fun random(): Species = this.implemented.random()
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, Species>) {
|
||||
@@ -316,4 +323,4 @@ object PokemonSpecies : JsonDataRegistry<Species> {
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -9,8 +9,9 @@
|
||||
package com.cobblemon.mod.common.api.pokemon.aspect
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.api.ai.config.task.PollinateFlowerTaskConfig
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SaccharineLogSlatheredInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.prospecting.LurePokeSnackDetector
|
||||
import com.cobblemon.mod.common.block.entity.PokeSnackBlockEntity
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
|
||||
import net.minecraft.core.particles.BlockParticleOption
|
||||
import net.minecraft.core.particles.ParticleOptions
|
||||
@@ -22,11 +23,12 @@ import net.minecraft.resources.ResourceLocation
|
||||
*/
|
||||
val aspectParticleMap: Map<String, ParticleData> = mapOf(
|
||||
SaccharineLogSlatheredInfluence.HONEY_DRENCHED_ASPECT to ParticleData.MinecraftParticle(ParticleTypes.FALLING_HONEY, 0.075, 1),
|
||||
LurePokeSnackDetector.POKE_SNACK_CRUMBED_ASPECT to ParticleData.MinecraftParticle(
|
||||
PokeSnackBlockEntity.POKE_SNACK_CRUMBED_ASPECT to ParticleData.MinecraftParticle(
|
||||
BlockParticleOption(
|
||||
ParticleTypes.BLOCK,
|
||||
CobblemonBlocks.POKE_SNACK.defaultBlockState()
|
||||
), 0.05, 3),
|
||||
PollinateFlowerTaskConfig.HAS_NECTAR_ASPECT to ParticleData.MinecraftParticle(ParticleTypes.FALLING_NECTAR, 0.075, 1)
|
||||
)
|
||||
|
||||
sealed class ParticleData {
|
||||
|
||||
+4
@@ -36,12 +36,16 @@ object ShoulderEffectRegistry {
|
||||
PlatformEvents.SERVER_PLAYER_LOGIN.subscribe { this.refreshEffects(it.player) }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun register(name: String, effect: Class<out ShoulderEffect>) = effect.also { effects[name] = it }
|
||||
|
||||
@JvmStatic
|
||||
fun unregister(name: String) = effects.remove(name)
|
||||
|
||||
@JvmStatic
|
||||
fun getName(clazz: Class<out ShoulderEffect>) = effects.firstNotNullOf { if (it.value == clazz) it.key else null }
|
||||
|
||||
@JvmStatic
|
||||
fun get(name: String): Class<out ShoulderEffect>? = effects[name]
|
||||
|
||||
// It was removed by a source such as milk, reapply
|
||||
|
||||
+7
@@ -62,10 +62,14 @@ object GlobalSpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
|
||||
data.forEach(this::registerFromAssets)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getCodeFeature(name: String) = codeFeatures[name]
|
||||
@JvmStatic
|
||||
fun getResourceFeature(name: String) = resourceFeatures[name]
|
||||
@JvmStatic
|
||||
fun getFeature(name: String) = getCodeFeature(name) ?: getResourceFeature(name)
|
||||
|
||||
@JvmStatic
|
||||
fun getFeatures() = (resourceFeatures.keys + codeFeatures.keys).mapNotNull(this::getFeature)
|
||||
|
||||
fun loadOnClient(entries: Collection<Map.Entry<String, SpeciesFeatureProvider<*>>>) {
|
||||
@@ -83,7 +87,9 @@ object GlobalSpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
|
||||
mapping[name] = provider
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun register(name: String, provider: SpeciesFeatureProvider<*>) = register(name, provider, isCoded = true)
|
||||
@JvmStatic
|
||||
fun <T : SpeciesFeature> register(name: String, providerLambda: () -> T) {
|
||||
register(name, object : SpeciesFeatureProvider<T> {
|
||||
override fun invoke(pokemon: Pokemon) = providerLambda()
|
||||
@@ -93,6 +99,7 @@ object GlobalSpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
|
||||
}
|
||||
private fun registerFromAssets(identifier: ResourceLocation, provider: SpeciesFeatureProvider<*>) = register(identifier.path, provider, isCoded = false)
|
||||
|
||||
@JvmStatic
|
||||
fun unregister(name: String) {
|
||||
var coded = true
|
||||
val value = getResourceFeature(name)?.also { coded = false } ?: getCodeFeature(name) ?: return
|
||||
|
||||
+1
@@ -60,5 +60,6 @@ object SpeciesFeatureAssignments : JsonDataRegistry<SpeciesFeatureAssignment> {
|
||||
this.assignments.putAll(data)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getFeatures(species: Species) = assignments[species.resourceIdentifier] ?: emptySet()
|
||||
}
|
||||
@@ -68,14 +68,19 @@ object SpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
|
||||
data.forEach(this::registerFromAssets)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getCodeFeature(name: String) = codeFeatures[name]
|
||||
@JvmStatic
|
||||
fun getResourceFeature(name: String) = resourceFeatures[name]
|
||||
@JvmStatic
|
||||
fun getFeature(name: String) = getCodeFeature(name) ?: getResourceFeature(name) ?: GlobalSpeciesFeatures.getFeature(name)
|
||||
fun loadOnClient(entries: Collection<Map.Entry<String, SpeciesFeatureProvider<*>>>) {
|
||||
codeFeatures.putAll(entries.map { it.toPair() })
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getFeatures() = (resourceFeatures.keys + codeFeatures.keys).mapNotNull(this::getFeature)
|
||||
@JvmStatic
|
||||
fun getFeaturesFor(species: Species): List<SpeciesFeatureProvider<*>> {
|
||||
val mentionedFeatures = species.features.mapNotNull(this::getFeature)
|
||||
val globalFeatures = GlobalSpeciesFeatures.getFeatures()
|
||||
@@ -95,9 +100,11 @@ object SpeciesFeatures : JsonDataRegistry<SpeciesFeatureProvider<*>> {
|
||||
mapping[name] = provider
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun register(name: String, provider: SpeciesFeatureProvider<*>) = register(name, provider, isCoded = true)
|
||||
private fun registerFromAssets(identifier: ResourceLocation, provider: SpeciesFeatureProvider<*>) = register(identifier.path, provider, isCoded = false)
|
||||
|
||||
@JvmStatic
|
||||
fun unregister(name: String) {
|
||||
var coded = true
|
||||
val value = getResourceFeature(name)?.also { coded = false } ?: getCodeFeature(name) ?: return
|
||||
|
||||
+7
@@ -29,6 +29,7 @@ object HeldItemProvider {
|
||||
* @param pokemon The [Pokemon] being queried.
|
||||
* @return The [HeldItemManager] that can provide for the given [pokemon], if non match returns the [HeldItemManager.EMPTY].
|
||||
*/
|
||||
@JvmStatic
|
||||
fun provide(pokemon: BattlePokemon): HeldItemManager = this.managers.firstOrNull { manager -> manager.showdownId(pokemon) != null } ?: HeldItemManager.EMPTY
|
||||
|
||||
/**
|
||||
@@ -37,6 +38,7 @@ object HeldItemProvider {
|
||||
* @param pokemon The [Pokemon] being queried.
|
||||
* @return The showdownId string that [pokemon] is holding, otherwise null.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun provideShowdownId(pokemon: BattlePokemon) = this.managers.firstNotNullOfOrNull { manager -> manager.showdownId(pokemon) }
|
||||
|
||||
/**
|
||||
@@ -45,6 +47,8 @@ object HeldItemProvider {
|
||||
* @param manager The [HeldItemManager] being registered.
|
||||
* @param priority The [Priority] to register it under.
|
||||
*/
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun register(manager: HeldItemManager, priority: Priority = Priority.NORMAL) {
|
||||
this.managers.add(priority, manager)
|
||||
}
|
||||
@@ -56,6 +60,8 @@ object HeldItemProvider {
|
||||
* @param priority The [Priority] to specifically remove the instance from, if null it will remove from all.
|
||||
*/
|
||||
@Suppress("unused")
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun unregister(manager: HeldItemManager, priority: Priority? = null) {
|
||||
if (priority != null) {
|
||||
this.managers.remove(priority, manager)
|
||||
@@ -69,6 +75,7 @@ object HeldItemProvider {
|
||||
*
|
||||
* @return The read-only copy of the registered [HeldItemManager]s.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun managers(): List<HeldItemManager> = this.managers.toList()
|
||||
|
||||
}
|
||||
@@ -34,17 +34,24 @@ object Statuses {
|
||||
private val volatileStatuses = mutableListOf<Status>()
|
||||
private val allStatuses = mutableListOf<Status>()
|
||||
|
||||
@JvmField
|
||||
val POISON = registerStatus(PoisonStatus())
|
||||
@JvmField
|
||||
val POISON_BADLY = registerStatus(PoisonBadlyStatus())
|
||||
@JvmField
|
||||
val PARALYSIS = registerStatus(ParalysisStatus())
|
||||
@JvmField
|
||||
val SLEEP = registerStatus(SleepStatus())
|
||||
@JvmField
|
||||
val FROZEN = registerStatus(FrozenStatus())
|
||||
@JvmField
|
||||
val BURN = registerStatus(BurnStatus())
|
||||
@JvmField
|
||||
val ATTRACT = registerStatus(AttractStatus())
|
||||
@JvmField
|
||||
val CONFUSE = registerStatus(ConfuseStatus())
|
||||
|
||||
|
||||
|
||||
@JvmStatic
|
||||
fun <T: Status> registerStatus(status: T) : T {
|
||||
if (status is PersistentStatus) {
|
||||
persistentStatuses.add(status)
|
||||
@@ -56,7 +63,10 @@ object Statuses {
|
||||
return status
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getStatus(name: ResourceLocation) = allStatuses.find { status -> status.name == name }
|
||||
@JvmStatic
|
||||
fun getStatus(showdownName: String) = allStatuses.find { it.showdownName == showdownName }
|
||||
@JvmStatic
|
||||
fun getPersistentStatuses() = persistentStatuses
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import com.cobblemon.mod.common.api.reactive.pipes.StopAfterTransform
|
||||
import com.cobblemon.mod.common.api.reactive.pipes.TakeFirstTransform
|
||||
import java.lang.Thread.sleep
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.function.Consumer
|
||||
|
||||
/**
|
||||
* An object that emits values of the generic type. This can be subscribed to and unsubscribed from, as well as
|
||||
@@ -30,6 +31,8 @@ import java.util.concurrent.CompletableFuture
|
||||
*/
|
||||
interface Observable<T> {
|
||||
fun subscribe(priority: Priority = Priority.NORMAL, handler: (T) -> Unit): ObservableSubscription<T>
|
||||
fun subscribe(handler: Consumer<T>): ObservableSubscription<T> = subscribe(Priority.NORMAL) { handler.accept(it) }
|
||||
fun subscribe(priority: Priority, handler: Consumer<T>): ObservableSubscription<T> = subscribe(priority) { handler.accept(it) }
|
||||
fun unsubscribe(subscription: ObservableSubscription<T>)
|
||||
|
||||
// This isn't pretty, ik
|
||||
|
||||
+12
@@ -103,6 +103,18 @@ interface RidingBehaviour<Settings : RidingBehaviourSettings, State : RidingBeha
|
||||
*/
|
||||
fun damageOnCollision(settings: Settings, state: State, vehicle: PokemonEntity, impactVec: Vec3): Boolean = false
|
||||
|
||||
/**
|
||||
* Called in [com.cobblemon.mod.common.client.render.pokemon.PokemonRenderer] to allow the controller to set rotations
|
||||
* through code using partialTicks and right before rendering.
|
||||
* //TODO: This needs to be further refined. Maybe only the orientationController needs affected? Maybe the rotations set here don't need to be applied to the controller/camera
|
||||
*/
|
||||
fun applyRenderRotation(settings: Settings, state: State, vehicle: PokemonEntity, partialTicks: Float) {}
|
||||
|
||||
/**
|
||||
* Determines if the pair of mouse inputs Pair(mouseX, mouseY) get used to modify the driverRotations or the vehicle rotations themselves.
|
||||
* Driver rotations are the rotations used by passengers or a driver that is freelooking. This does not override the freelook button.
|
||||
*/
|
||||
fun mouseModifiesDriverRotation(settings: Settings, state: State, vehicle: PokemonEntity): Pair<Boolean, Boolean> = Pair(false, false)
|
||||
|
||||
/**
|
||||
* Internal helpers to help behaviour specific calculations
|
||||
|
||||
Loaded 100 of 3352 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user