mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-22 07:06:23 -04:00
Compare commits
513
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09a0cd6c30 | ||
|
|
30f82bbad6 | ||
|
|
1823eb4979 | ||
|
|
ae4af68797 | ||
|
|
da7f4a2682 | ||
|
|
73c4762801 | ||
|
|
43abfa3c17 | ||
|
|
fb87220fe9 | ||
|
|
2a0de32854 | ||
|
|
406097c1ff | ||
|
|
14ec3c00e6 | ||
|
|
18b17b0638 | ||
|
|
59c96fe30d | ||
|
|
565667aa1c | ||
|
|
3955283425 | ||
|
|
beee02033c | ||
|
|
86902b69e1 | ||
|
|
2ac102a3b6 | ||
|
|
a54ff5f0a7 | ||
|
|
edc5ae741c | ||
|
|
70bed4f299 | ||
|
|
e24b20546d | ||
|
|
eb071d4d01 | ||
|
|
625a31e7e8 | ||
|
|
2b14931709 | ||
|
|
2c32b50182 | ||
|
|
b5230a8d3c | ||
|
|
5ff3d163c0 | ||
|
|
82e6e01978 | ||
|
|
a6b5f2d64c | ||
|
|
6408b60dde | ||
|
|
b6308e6c6c | ||
|
|
84a0ceb7e1 | ||
|
|
ccde7ffbb1 | ||
|
|
4e79ed9f7e | ||
|
|
ecefea005d | ||
|
|
4c787f547c | ||
|
|
f0755cc73f | ||
|
|
e215d751c4 | ||
|
|
aac4669ec1 | ||
|
|
7b0b41d192 | ||
|
|
7e38fefa14 | ||
|
|
c1491daf63 | ||
|
|
068b55be7b | ||
|
|
3f6bd52d43 | ||
|
|
4ca3f25ab2 | ||
|
|
70e81f1cbe | ||
|
|
df8abf4ddb | ||
|
|
26dd0b9d42 | ||
|
|
307d8bad1d | ||
|
|
866332e62c | ||
|
|
c54466f6b1 | ||
|
|
fb570404c0 | ||
|
|
d22602dac5 | ||
|
|
63da8fed2d | ||
|
|
2f16ba5470 | ||
|
|
af36d4a365 | ||
|
|
d153ec155b | ||
|
|
7ca7cc089a | ||
|
|
cbdfbc9745 | ||
|
|
ac210e027b | ||
|
|
1fc91a794f | ||
|
|
f78b289171 | ||
|
|
c46461c843 | ||
|
|
386a897295 | ||
|
|
8328f741d8 | ||
|
|
2b19943416 | ||
|
|
5239de2cea | ||
|
|
296355f744 | ||
|
|
e9d9a109c0 | ||
|
|
8a3789fc35 | ||
|
|
05fd7bec36 | ||
|
|
550b99be36 | ||
|
|
8960c6dddc | ||
|
|
bfbee7b1d7 | ||
|
|
bc1f9f8cb4 | ||
|
|
f5d71390dd | ||
|
|
6ff5d3df06 | ||
|
|
988766894a | ||
|
|
34805ea496 | ||
|
|
b670d44e21 | ||
|
|
159905eb3b | ||
|
|
c10213480b | ||
|
|
3d5a365a6e | ||
|
|
4b64b4307a | ||
|
|
382f741db8 | ||
|
|
6d62d911d6 | ||
|
|
a1d40084c5 | ||
|
|
8b1b63e110 | ||
|
|
a7956531ff | ||
|
|
4b0919223b | ||
|
|
baf3cd5f30 | ||
|
|
2327f1aa2c | ||
|
|
62036c0ac6 | ||
|
|
9e2e95e287 | ||
|
|
2db494ff5e | ||
|
|
7fe1415551 | ||
|
|
ca4d4ed3be | ||
|
|
700227be41 | ||
|
|
985a4f65dc | ||
|
|
e117100e34 | ||
|
|
93ea13fa4d | ||
|
|
6694680c50 | ||
|
|
cd14881d17 | ||
|
|
1393cc3ef3 | ||
|
|
23ebd0573a | ||
|
|
6447c2e2eb | ||
|
|
8cafce0a4a | ||
|
|
039a18a2bf | ||
|
|
de271f81b1 | ||
|
|
feb78c5c58 | ||
|
|
8aedac3474 | ||
|
|
71736341f0 | ||
|
|
ca133a20c0 | ||
|
|
acc601d414 | ||
|
|
27d1de8e4e | ||
|
|
e5d052a6bf | ||
|
|
8af62f800b | ||
|
|
a50da47a8e | ||
|
|
f690781b0d | ||
|
|
6a7fc67ae1 | ||
|
|
cf9d794fe1 | ||
|
|
14a3e7afb1 | ||
|
|
7b7acb97d1 | ||
|
|
53af92f254 | ||
|
|
91bce4b153 | ||
|
|
511130d353 | ||
|
|
476c3e54f1 | ||
|
|
4bfe8b808c | ||
|
|
8db943d2a9 | ||
|
|
fdff6ecfa5 | ||
|
|
2eb698969d | ||
|
|
bba60f0098 | ||
|
|
8ee2c95853 | ||
|
|
77db2ce17a | ||
|
|
0ea4641536 | ||
|
|
ff5ea6fa21 | ||
|
|
4820d78416 | ||
|
|
2f417e953c | ||
|
|
8fde0ed4f6 | ||
|
|
6715874a8f | ||
|
|
31f88a1f68 | ||
|
|
f80aa2769a | ||
|
|
20aa4d43b8 | ||
|
|
9bec3e088f | ||
|
|
5b4dbe1957 | ||
|
|
48f248d481 | ||
|
|
d726c4d0ed | ||
|
|
c9c421ba2a | ||
|
|
2436a8ddcc | ||
|
|
3364944c26 | ||
|
|
9e6a6eabc7 | ||
|
|
78def7318e | ||
|
|
fdf062bd4c | ||
|
|
ef5a682adb | ||
|
|
f76d28d29e | ||
|
|
9c70aad64d | ||
|
|
25de1ad180 | ||
|
|
f967d1ec11 | ||
|
|
efd0497de1 | ||
|
|
b30c0a4a9a | ||
|
|
c99b26a44b | ||
|
|
b19bc1e4c7 | ||
|
|
bc5ffda1a5 | ||
|
|
491d6c9fd6 | ||
|
|
ccc6ad77a5 | ||
|
|
00fd9d1278 | ||
|
|
01464f8b71 | ||
|
|
d91fe0b876 | ||
|
|
4de32b8bf4 | ||
|
|
9d6447af9a | ||
|
|
7eb5f93595 | ||
|
|
3b54fa488e | ||
|
|
69e9cb3f22 | ||
|
|
4eb268c4af | ||
|
|
909b5b7f7f | ||
|
|
e2c28ab5a0 | ||
|
|
890d0a2099 | ||
|
|
74075e6be9 | ||
|
|
b8ae6aa889 | ||
|
|
a499e8593a | ||
|
|
3f6faf7796 | ||
|
|
08633c223e | ||
|
|
d5efdeee68 | ||
|
|
57f446260c | ||
|
|
d4cf44f8f0 | ||
|
|
a074ebbcce | ||
|
|
6578ed55e3 | ||
|
|
f567ceadd8 | ||
|
|
5de92f78c6 | ||
|
|
a2402f78e7 | ||
|
|
1ad6d63137 | ||
|
|
39d417c651 | ||
|
|
ce1bf9f4f2 | ||
|
|
a6136906f8 | ||
|
|
37a99b528e | ||
|
|
048b237302 | ||
|
|
131773f9c8 | ||
|
|
22e55b7e77 | ||
|
|
6c288f9cc8 | ||
|
|
b5e86a9460 | ||
|
|
f199e7c1c0 | ||
|
|
4161d96707 | ||
|
|
59927dd701 | ||
|
|
220d8ddc0f | ||
|
|
0dd143e67e | ||
|
|
d83eb62821 | ||
|
|
a716fda023 | ||
|
|
d14aad787c | ||
|
|
2eb7b60dd1 | ||
|
|
bc4699e354 | ||
|
|
c50b149e83 | ||
|
|
d79ffc631b | ||
|
|
63252f4d35 | ||
|
|
1c024f881e | ||
|
|
93f0337399 | ||
|
|
7e8fb07f55 | ||
|
|
7a8856c34c | ||
|
|
63d516953a | ||
|
|
07faf6600f | ||
|
|
08e79d71bf | ||
|
|
9270119675 | ||
|
|
0058906022 | ||
|
|
7cd1870f23 | ||
|
|
6c836663f4 | ||
|
|
eeae26492e | ||
|
|
9e67a82816 | ||
|
|
c09295231c | ||
|
|
6c7d61c9f2 | ||
|
|
01f8a5c6d7 | ||
|
|
14d2a76211 | ||
|
|
7669000962 | ||
|
|
716d1b848e | ||
|
|
4878fc517d | ||
|
|
4d9d543110 | ||
|
|
f11f88c71a | ||
|
|
718a9b922b | ||
|
|
e2a152aeb3 | ||
|
|
3e21226b27 | ||
|
|
c46c5b806c | ||
|
|
3c37d93046 | ||
|
|
8912911800 | ||
|
|
660be08eea | ||
|
|
62ecfaf54a | ||
|
|
6684177236 | ||
|
|
deca5cf55b | ||
|
|
769a9ac845 | ||
|
|
7b2790de50 | ||
|
|
7f2bb84c85 | ||
|
|
0f75797759 | ||
|
|
331e1371d4 | ||
|
|
bdd57ba1a4 | ||
|
|
c194aefce5 | ||
|
|
f4798c8783 | ||
|
|
2178a5f10e | ||
|
|
f5e3945cf6 | ||
|
|
bb121cbee7 | ||
|
|
cee9adc782 | ||
|
|
bc145a56d5 | ||
|
|
670e7e9ca1 | ||
|
|
476ef3bb2f | ||
|
|
460050289b | ||
|
|
0a2e9f6530 | ||
|
|
01fd4dcc68 | ||
|
|
0392eb3b7e | ||
|
|
038a21556e | ||
|
|
493f423a2f | ||
|
|
cbcfa1bbfb | ||
|
|
17a3ff15db | ||
|
|
9c14cccc98 | ||
|
|
57539775e0 | ||
|
|
eb71a20a19 | ||
|
|
850cfbe755 | ||
|
|
28afa6a9e8 | ||
|
|
7a76d95ce7 | ||
|
|
54707d0618 | ||
|
|
307c400e28 | ||
|
|
5c9b3ab25d | ||
|
|
532e991fb2 | ||
|
|
b1bf817329 | ||
|
|
c091f90487 | ||
|
|
a49d4715ff | ||
|
|
652b15532e | ||
|
|
e4064897b0 | ||
|
|
f9ca8222da | ||
|
|
3ae349aea5 | ||
|
|
67480a945f | ||
|
|
e6e811e6e6 | ||
|
|
4635c531b9 | ||
|
|
3bdfac9a46 | ||
|
|
2b7a71cb1c | ||
|
|
d47a500a0e | ||
|
|
13650f98f9 | ||
|
|
d3379557fd | ||
|
|
143c2683fe | ||
|
|
72d64d36e5 | ||
|
|
c0b52c38e3 | ||
|
|
12a0ee309e | ||
|
|
33e6dbb4c1 | ||
|
|
824e37effd | ||
|
|
482c57dd2e | ||
|
|
503c62d78d | ||
|
|
708d0ab6d3 | ||
|
|
19727542bd | ||
|
|
c4e6714a95 | ||
|
|
c116e612c6 | ||
|
|
215a055ce6 | ||
|
|
9c0b6b8d26 | ||
|
|
5c4462ee94 | ||
|
|
04edd6f9e2 | ||
|
|
52821cc051 | ||
|
|
0029deb029 | ||
|
|
c6360e2a36 | ||
|
|
2e77c647b6 | ||
|
|
ee28cf554a | ||
|
|
30dcb9a4da | ||
|
|
ffc9fdfa6d | ||
|
|
c3d3b19788 | ||
|
|
219cd61beb | ||
|
|
207e5a9142 | ||
|
|
4f86c6f322 | ||
|
|
c721fb534d | ||
|
|
dba2622fd7 | ||
|
|
33c8ecd908 | ||
|
|
93367fb0e8 | ||
|
|
694f74be13 | ||
|
|
79d097b17c | ||
|
|
7ef30653bb | ||
|
|
1ecb13f7fc | ||
|
|
da68675133 | ||
|
|
975cdf050f | ||
|
|
9aea5a7daf | ||
|
|
d19878edf6 | ||
|
|
4f98d1e054 | ||
|
|
7b8e07aef3 | ||
|
|
10402575fb | ||
|
|
0f82ade57c | ||
|
|
450b041118 | ||
|
|
770c349ac4 | ||
|
|
f76648b6f2 | ||
|
|
56e60667db | ||
|
|
1442bf5c34 | ||
|
|
2ac37f6c4d | ||
|
|
9795dce227 | ||
|
|
c4a60951c5 | ||
|
|
814eee8125 | ||
|
|
2a9ff3bfbd | ||
|
|
8fe2042127 | ||
|
|
538ad883ab | ||
|
|
136cb86492 | ||
|
|
e4eb1251d1 | ||
|
|
83350cb0db | ||
|
|
778761dbee | ||
|
|
e9881b748a | ||
|
|
d9cf802a9e | ||
|
|
dabaeefa23 | ||
|
|
0e0bec2712 | ||
|
|
48fe160334 | ||
|
|
1bc83d9045 | ||
|
|
7d599e12d0 | ||
|
|
98775ffc1e | ||
|
|
3fbf2595cc | ||
|
|
6665285253 | ||
|
|
61ae29b745 | ||
|
|
a17bf5eeeb | ||
|
|
c71d91a46d | ||
|
|
bbeb3d45f0 | ||
|
|
c86103fd31 | ||
|
|
5190bbe723 | ||
|
|
3663ce2555 | ||
|
|
b5fc52d9b1 | ||
|
|
8fd854f7f7 | ||
|
|
f449cf27c5 | ||
|
|
ca79b70815 | ||
|
|
898c956f17 | ||
|
|
2ce48c9dff | ||
|
|
f64ec12a6a | ||
|
|
474d3f3b55 | ||
|
|
c87e6a391d | ||
|
|
192fd4dba7 | ||
|
|
c26786c644 | ||
|
|
ebb0277d80 | ||
|
|
2a73efa479 | ||
|
|
6e68d22d4a | ||
|
|
dee08e6572 | ||
|
|
2383686e42 | ||
|
|
b8de9c415e | ||
|
|
f0269a3638 | ||
|
|
dbbbd309dc | ||
|
|
b7a905ad79 | ||
|
|
60c8049459 | ||
|
|
8c395b6fee | ||
|
|
e9935a41e3 | ||
|
|
f0ecd4d50d | ||
|
|
c0661022ab | ||
|
|
e7305a3dfb | ||
|
|
86f52f176a | ||
|
|
beb9796e75 | ||
|
|
6bb55adebc | ||
|
|
011bc85d18 | ||
|
|
fad75c498b | ||
|
|
915c69b443 | ||
|
|
05b574543c | ||
|
|
5198b2a709 | ||
|
|
509973a027 | ||
|
|
0253475f50 | ||
|
|
6961c92c8d | ||
|
|
906d7b361d | ||
|
|
54121199b6 | ||
|
|
78b3e0a1aa | ||
|
|
aa45795944 | ||
|
|
353209c72c | ||
|
|
d07eaefdd4 | ||
|
|
2ead9f6f02 | ||
|
|
472a349709 | ||
|
|
9043520364 | ||
|
|
88ea77e2f3 | ||
|
|
a609e2d561 | ||
|
|
6f1c791df4 | ||
|
|
dc41e7b50f | ||
|
|
1b22da8bd9 | ||
|
|
773eb9e1c3 | ||
|
|
87deea9748 | ||
|
|
556636f41e | ||
|
|
daab3dd3dd | ||
|
|
5535390298 | ||
|
|
f54eaf3101 | ||
|
|
1d86ace385 | ||
|
|
4a02a0a67d | ||
|
|
7f193c11e1 | ||
|
|
9f90a08276 | ||
|
|
f49a114f0f | ||
|
|
281fc300a6 | ||
|
|
ea7078b749 | ||
|
|
03aabb55ca | ||
|
|
078da5b213 | ||
|
|
22af77c7e6 | ||
|
|
7ee7a6624f | ||
|
|
85c9fcd28e | ||
|
|
619da2e19a | ||
|
|
c457cdfe5e | ||
|
|
a87c319d10 | ||
|
|
db5bdb0ef1 | ||
|
|
adc79a34d1 | ||
|
|
8776dffed4 | ||
|
|
77f5434b78 | ||
|
|
bf5fd5eed8 | ||
|
|
facead5f0b | ||
|
|
0191373ff5 | ||
|
|
0daf995c70 | ||
|
|
dd9437c663 | ||
|
|
752675ffb0 | ||
|
|
5bcc0fb343 | ||
|
|
2cd726c003 | ||
|
|
f911ad57b9 | ||
|
|
bc2a547b86 | ||
|
|
d5ba9bc3f5 | ||
|
|
3dc8493b76 | ||
|
|
0b991c4ae3 | ||
|
|
1352508070 | ||
|
|
87d467ec67 | ||
|
|
c020deb728 | ||
|
|
d5e15f7bf2 | ||
|
|
59622a1bfb | ||
|
|
1c237503a0 | ||
|
|
138a83c844 | ||
|
|
e8c86f4b4e | ||
|
|
344d2ae3e6 | ||
|
|
19a571147b | ||
|
|
2f369fb6ee | ||
|
|
c1d16f5185 | ||
|
|
2382895a42 | ||
|
|
68adae082b | ||
|
|
eac1b573c9 | ||
|
|
a29a17a28b | ||
|
|
4805659a68 | ||
|
|
fbdcfb20ed | ||
|
|
4a2b186ef7 | ||
|
|
fa41b30a4c | ||
|
|
505282986e | ||
|
|
9e6e74db7c | ||
|
|
cf68e88103 | ||
|
|
84ae73d0d1 | ||
|
|
9bb0f13793 | ||
|
|
912485067b | ||
|
|
128f7c15a6 | ||
|
|
5d67d0fdfc | ||
|
|
3f90d19801 | ||
|
|
897e1651c5 | ||
|
|
9c5bb2fcdb | ||
|
|
8ee8d84c8b | ||
|
|
b25fbf42ab | ||
|
|
f9f3392901 | ||
|
|
35249f5804 | ||
|
|
b32fdeda9c | ||
|
|
1d033701ed | ||
|
|
6422cffde3 | ||
|
|
e8588370e5 | ||
|
|
a96692e5cf | ||
|
|
81c272778f | ||
|
|
31351116b5 | ||
|
|
fd18e4d7f1 | ||
|
|
7eb5364ba7 | ||
|
|
97b679bbe0 | ||
|
|
85dc3ad1d7 | ||
|
|
a90e9544be | ||
|
|
6261163728 | ||
|
|
9288ae8776 | ||
|
|
f887f678f1 | ||
|
|
59ba74606e | ||
|
|
130b1c99db | ||
|
|
adc4b424c5 | ||
|
|
4ad140f7a3 |
@@ -0,0 +1,11 @@
|
||||
### Additions
|
||||
- Added the Campfire Pot, made from apricorns and placed onto campfires.
|
||||
- This pot can be used to make bait for fishing, Poké Cakes, Lure Cakes, local specialties, and potions (less efficiently than a brewing stand).
|
||||
- There is a different pot for each apricorn colour because at this point I think we may have an addiction.
|
||||
- Added Aprijuice, made from the Campfire Pot using apricorns with seasoning to give flavours.
|
||||
- Aprijuice can be fed to ride-able Pokémon to improve their riding characteristics, depending on the flavour and the Pokémon's nature.
|
||||
|
||||
### Datapack and Addon Changes
|
||||
- Renamed the fishing_baits datapack folder to spawn_bait_effects.
|
||||
- Added `seasonings` datapack folder for controlling usable items in the campfire pot and what colour and flavour they apply.
|
||||
- Added campfire pot recipe type, which you could use to make anything work as fishing bait.
|
||||
@@ -6,6 +6,7 @@
|
||||
- Added filter functionality in PC UI, which supports `PokemonProperties` (e.g. `shiny=yes` shows all shiny Pokémon).
|
||||
- Added `/changewallpaper <player> <boxNumber> <wallpaper>` command to change a box wallpaper through commands.
|
||||
- Added `/renamebox <player> <boxNumber> <name>` command to rename a PC box through commands.
|
||||
- Added IVs and EVs stat displays in PC.
|
||||
|
||||
### Developer
|
||||
- Added `RenamePCBoxEvent.Pre` and `RenamePCBoxEvent.Post` events to prevent players from renaming a box or changing their input.
|
||||
|
||||
+38
-1
@@ -17,6 +17,10 @@
|
||||
- Added cosmetics for Gurdurr, Conkeldurr, Squirtle Line, Sneasler, Sandle line, Treecko line, Braixen, Delphox, and Dragonite.
|
||||
- Added `/transformmodelpart (position|rotation|scale) <modelPart> <transform: x y z>` command that can add transformations to a pokemon's model part.
|
||||
- The player executing the command must be facing the target pokemon entity. Transformations are not persistent and will revert when resources are reloaded.
|
||||
- Added lang keys for all moves and abilities up to Generation 9.
|
||||
- Fixed Moon Ball moon phase logic to actually work correctly
|
||||
- Added `translucent_cull` boolean option into resolver's layer to allow for translucent textures with culling
|
||||
- Added [LambDynamicLights](https://modrinth.com/mod/lambdynamiclights) support for items held by Pokémon.
|
||||
|
||||
### Pokémon Added
|
||||
|
||||
@@ -76,6 +80,8 @@
|
||||
- Sneasler
|
||||
- Braixen
|
||||
- Delphox
|
||||
- Cinderace
|
||||
- Kangaskhan
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
- Gyarados
|
||||
@@ -97,18 +103,37 @@
|
||||
- Pidgeot
|
||||
- Nosepass
|
||||
- Probopass
|
||||
- Kangaskhan
|
||||
- Cinderace
|
||||
- Magnezone
|
||||
- Metagross
|
||||
- Added Syrupy Apples.
|
||||
|
||||
### Changes
|
||||
- Renamed `chargeGainedPerTick` config to `secondsToChargeHealingMachine`.
|
||||
- Made Blocks of Gold count as Big Nuggets when held by a Pokémon (for Fling functionality)
|
||||
- Players can now eat Sweet and Tart Apples, Whipped Dreams, and the Alcremie Sweets.
|
||||
- Updated Sweet and Tart Apple sprites
|
||||
- Updated the following recipes: Air Balloon, Assault Vest, Binding Band, Black Belt, Blunder Policy, Choice Band, Choice Scarf, Cleanse Tag, Covert Cloak, Destiny Knot, Eject Button, Expert Belt, Focus Band, Focus Sash, Magnet, Metronome, Muscle Band, Power Anklet, Power Band, Power Belt, Power Bracer, Power Lens, Power Weight, Protective Pads, Protein, Punching Glove, Reaper Cloth, Rocky Helmet, Room Service, Sachet, Safety Goggles, Silk Scarf, Spell Tag, Utility Umbrella, Weakness Policy, Zinc
|
||||
- Added alternate ingredient options to the following recipes: Cell Battery, Charcoal Stick, Dragon Fang, Miracle Seed, Mystic Water, Never Melt Ice, Twisted Spoon, Damp Rock, Heat Rock, Icy Rock, Smooth Rock
|
||||
- Grouped together some recipes within the Recipe Book. Groups include: the seven basic Poké Balls, the seven basic Ancient Poké Balls, Gilded Chests, Pokedexes, and the Weather Rocks.
|
||||
- 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.
|
||||
- Tweaked the Natural Materials Vanilla file to fit with the changes to tags
|
||||
- Substantially optimised spawning checks mainly by front-loading biome filtering.
|
||||
- When using the `cobblemon` or `generation_9` capture calculators a critical capture with a single shake will always play for successful captures when you've already registered the Pokémon as caught in your Pokédex.
|
||||
- Improved the performance of saving Pokédex and player data.
|
||||
- Pokémon hitbox now scales with entity attribute `generic.scale`.
|
||||
- Removed Shulker aspect and replaced it with cosmetic_item-shulker_shell.
|
||||
- Shulker shell Forretress is now a cosmetic rather than a special evo and thus all shulker Forretress will revert back to normal until a shulker shell is put in their cosmetic slot.
|
||||
- Updated `doPokemonSpawning` gamerule to support per-dimension configurations.
|
||||
- The Pokedex now displays a form name of a "normal" Pokémon for when the base form is still a named form.
|
||||
- Improved the zoom functionality of the Pokédex Scanner by giving the levels logarithmic scaling.
|
||||
- Added a subtle rotation effect to the Pokédex Scanner's wheel when zooming.
|
||||
- Improved parity with vanilla mobs' drop behavior; loot and XP drop on death instead of after the entire death sequence finishes.
|
||||
- Quirk animations no longer play in the battle GUI since they were pretty distracting.
|
||||
- A number of Pokemon that float above the ground visually (Gastly, Klingklang, etc.) are no longer considered to be touching the ground
|
||||
|
||||
### Fixes
|
||||
- Fixed Particles sometimes facing the wrong direction (looking at you, Swords Dance)
|
||||
@@ -137,6 +162,9 @@
|
||||
- Fixed Pokémon marked as silent still playing shiny sounds and effects.
|
||||
- Fixed an issue with newer versions of Fabric API where underground Pokémon were spawning in The End.
|
||||
- Fixed spawning not working well when you're at high points surrounded by lower altitude spawning areas, such as flying.
|
||||
- Fixed certain Pokémon with forms not having appropriate stock Pokédex entries.
|
||||
- Fixed issue with Pokédex Scanner that caused the open/close overlay to have the wrong opacity values
|
||||
- Fixed dragon's breath not being usable on the restoration tank when it should be
|
||||
|
||||
### Developer
|
||||
- A finished battle now has winners and losers set inside of `PokemonBattle` instead of them always being empty.
|
||||
@@ -155,7 +183,15 @@
|
||||
- Updated NPCEntity pokeball throw positioning to properly account for the baseScale property.
|
||||
- Fixed `[Pokemon].copyFrom` error causing forms, IVs, and EVs to not be applied properly when using `[Pokemon].loadFromJSON` or `[Pokemon].loadFromNBT`
|
||||
- Added new item class, `WearableItem`. Instances of this class should have a corresponding 3D model. These models render when the items display context is `HEAD`.
|
||||
|
||||
- Pokemon now have a fireImmune attribute in their behaviour that can be set to true to ignore all fire damage (lava, magma blocks, etc.)
|
||||
`JSON
|
||||
{
|
||||
"behaviour": {
|
||||
"fireImmune": true
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
### 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)
|
||||
- The `requiredContext` for an item interaction evolution
|
||||
@@ -173,6 +209,7 @@
|
||||
- Added `pokemon` as an available Molang function for the `battleActor` functions.
|
||||
- Fixed `heldItem` property inside spawn files not working and causing crashes
|
||||
- Fixed `spawn_bedrock_particles` MoLang causing crashes when used in a server environment
|
||||
- The Pokédex form lang key definition now follows `cobblemon.ui.pokedex.info.form.{species}-{formname}` instead of `cobblemon.ui.pokedex.info.form.{formname}`.
|
||||
|
||||
## [1.6.1 (January 26th, 2025)](#1-6-1)
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
|
||||
import utilities.isSnapshot
|
||||
import utilities.version
|
||||
import java.time.OffsetDateTime
|
||||
import java.time.ZoneOffset
|
||||
import java.time.format.DateTimeFormatter
|
||||
import utilities.isSnapshot
|
||||
import utilities.version
|
||||
|
||||
/*
|
||||
*
|
||||
|
||||
@@ -13,10 +13,12 @@ import com.cobblemon.mod.common.client.render.layer.PokemonOnShoulderRenderer;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokemon.FormData;
|
||||
import com.cobblemon.mod.common.pokemon.lighthing.LightingData;
|
||||
import dev.lambdaurora.lambdynlights.LambDynLights;
|
||||
import dev.lambdaurora.lambdynlights.api.DynamicLightHandler;
|
||||
import dev.lambdaurora.lambdynlights.api.DynamicLightHandlers;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -53,15 +55,19 @@ public class LambDynamicLightsCompat {
|
||||
|
||||
private static int resolvedPokemonLightLevel(PokemonEntity pokemon) {
|
||||
var underwater = !pokemon.level().getFluidState(BlockPos.containing(pokemon.getX(), pokemon.getEyeY(), pokemon.getZ())).isEmpty();
|
||||
return extractFormLightLevel(pokemon.getForm(), underwater).orElse(0);
|
||||
|
||||
ItemStack item = pokemon.getShownItem();
|
||||
int itemLightLevel = item.isEmpty()?0:LambDynLights.getLuminanceFromItemStack(item, underwater);
|
||||
int formLightLevel = extractFormLightLevel(pokemon.getForm(), underwater).orElse(0);
|
||||
|
||||
return Math.max(itemLightLevel, formLightLevel);
|
||||
}
|
||||
|
||||
private static int resolvedShoulderLightLevel(Player player) {
|
||||
final var shoulderDataPair = PokemonOnShoulderRenderer.shoulderDataOf(player);
|
||||
var underwater = !player.level().getFluidState(BlockPos.containing(player.getX(), player.getEyeY(), player.getZ())).isEmpty();
|
||||
final Optional<Integer> leftLightLevel = extractShoulderLightLevel(shoulderDataPair.getFirst(), underwater);
|
||||
final Optional<Integer> rightLightLevel = extractShoulderLightLevel(shoulderDataPair.getSecond(), underwater);
|
||||
return Math.max(leftLightLevel.orElse(0), rightLightLevel.orElse(0));
|
||||
final int leftLightLevel = extractShoulderLightLevel(PokemonOnShoulderRenderer.shoulderDataFrom(player.getShoulderEntityLeft()), underwater);
|
||||
final int rightLightLevel = extractShoulderLightLevel(PokemonOnShoulderRenderer.shoulderDataFrom(player.getShoulderEntityRight()), underwater);
|
||||
return Math.max(leftLightLevel, rightLightLevel);
|
||||
}
|
||||
|
||||
private static Optional<Integer> extractFormLightLevel(@NotNull FormData form, boolean underwater) {
|
||||
@@ -71,11 +77,16 @@ public class LambDynamicLightsCompat {
|
||||
return Optional.of(form.getLightingData().getLightLevel());
|
||||
}
|
||||
|
||||
private static Optional<Integer> extractShoulderLightLevel(@Nullable PokemonOnShoulderRenderer.ShoulderData shoulderData, boolean underwater) {
|
||||
private static int extractShoulderLightLevel(@Nullable PokemonOnShoulderRenderer.ShoulderData shoulderData, boolean underwater) {
|
||||
if (shoulderData == null) {
|
||||
return Optional.empty();
|
||||
return 0;
|
||||
}
|
||||
return extractFormLightLevel(shoulderData.getForm(), underwater);
|
||||
|
||||
ItemStack item = shoulderData.getShownItem();
|
||||
int itemLightLevel = item.isEmpty()?0:LambDynLights.getLuminanceFromItemStack(item, underwater);
|
||||
int formLightLevel = extractFormLightLevel(shoulderData.getForm(), underwater).orElse(0);
|
||||
|
||||
return Math.max(itemLightLevel, formLightLevel);
|
||||
}
|
||||
|
||||
private static boolean liquidGlowModeSupport(@NotNull LightingData.LiquidGlowMode liquidGlowMode, boolean underwater) {
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.block.SaccharineLeafBlock;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
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.Desc;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||
import org.spongepowered.asm.mixin.injection.Slice;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
|
||||
@Mixin(targets = "net.minecraft.world.entity.animal.Bee$BeeGrowCropGoal")
|
||||
public abstract class BeeEntityMixin {
|
||||
|
||||
@Unique
|
||||
private BlockState cobblemon$result = null;
|
||||
|
||||
@Inject(method = "tick()V", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/level/block/BonemealableBlock;performBonemeal(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/util/RandomSource;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;)V",
|
||||
shift = At.Shift.BY,
|
||||
by = 2
|
||||
),
|
||||
locals = LocalCapture.CAPTURE_FAILHARD
|
||||
)
|
||||
private void injectCustomGrowth(CallbackInfo ci, int i, BlockPos blockPos, BlockState blockState, Block block) {
|
||||
if (block instanceof SaccharineLeafBlock) {
|
||||
|
||||
int age = blockState.getValue(SaccharineLeafBlock.Companion.getAGE());
|
||||
|
||||
if (age < 2) {
|
||||
this.cobblemon$result = blockState.setValue(SaccharineLeafBlock.Companion.getAGE(), age + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ModifyVariable(method = "tick", at = @At(value = "LOAD", ordinal = 0), index = 5)
|
||||
private BlockState applyCustomBlockState(BlockState before) {
|
||||
if(this.cobblemon$result != null && before == null) {
|
||||
BlockState result = this.cobblemon$result;
|
||||
this.cobblemon$result = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
return before;
|
||||
}
|
||||
}
|
||||
@@ -8,19 +8,46 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.api.riding.Seat;
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate;
|
||||
import com.cobblemon.mod.common.client.render.MatrixWrapper;
|
||||
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.entity.pokemon.PokemonEntity;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import net.minecraft.client.CameraType;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.ClipContext;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Vector3f;
|
||||
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.CallbackInfoReturnable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(LocalPlayer.class)
|
||||
public abstract class LocalPlayerMixin {
|
||||
public abstract class LocalPlayerMixin extends AbstractClientPlayer implements OrientationControllable {
|
||||
@Shadow
|
||||
private float jumpRidingScale;
|
||||
|
||||
public LocalPlayerMixin(ClientLevel clientLevel, GameProfile gameProfile) {
|
||||
super(clientLevel, gameProfile);
|
||||
}
|
||||
|
||||
@Inject(method = "getJumpRidingScale", at = @At("HEAD"), cancellable = true)
|
||||
public void modifyJumpRidingScale(CallbackInfoReturnable<Float> cir) {
|
||||
LocalPlayer player = (LocalPlayer) (Object) this;
|
||||
@@ -34,4 +61,59 @@ public abstract class LocalPlayerMixin {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HitResult pick(double hitDistance, float partialTicks, boolean hitFluids) {
|
||||
Entity vehicle = this.getVehicle();
|
||||
if (vehicle instanceof PokemonEntity pokemonEntity) {
|
||||
int seatIndex = pokemonEntity.getPassengers().indexOf(this);
|
||||
Seat seat = pokemonEntity.getSeats().get(seatIndex);
|
||||
|
||||
PokemonClientDelegate delegate = (PokemonClientDelegate) pokemonEntity.getDelegate();
|
||||
MatrixWrapper locator = delegate.getLocatorStates().get(seat.getLocator());
|
||||
|
||||
if (locator == null) {
|
||||
super.pick(hitDistance, partialTicks, hitFluids);
|
||||
}
|
||||
|
||||
Vec3 locatorOffset = new Vec3(locator.getMatrix().getTranslation(new Vector3f()));
|
||||
|
||||
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, seat));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
Vec3 viewVector = this.getViewVector(partialTicks);
|
||||
Vec3 viewDistanceVector = eyePosition.add(viewVector.x * hitDistance, viewVector.y * hitDistance, viewVector.z * hitDistance);
|
||||
return this.level()
|
||||
.clip(
|
||||
new ClipContext(
|
||||
eyePosition, viewDistanceVector, ClipContext.Block.OUTLINE, hitFluids ? net.minecraft.world.level.ClipContext.Fluid.ANY : net.minecraft.world.level.ClipContext.Fluid.NONE, this
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return super.pick(hitDistance, partialTicks, hitFluids);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private static @NotNull Vector3f cobblemon$getFirstPersonOffset(PosableModel model, Seat seat) {
|
||||
Map<String, Vec3> cameraOffsets = model.getFirstPersonCameraOffset();
|
||||
|
||||
if (cameraOffsets.containsKey(seat.getLocator())) {
|
||||
return cameraOffsets.get(seat.getLocator()).toVector3f();
|
||||
} else {
|
||||
return new Vector3f(0f, 0f, 0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,12 +15,9 @@ import com.cobblemon.mod.common.api.events.CobblemonEvents;
|
||||
import com.cobblemon.mod.common.api.events.item.LeftoversCreatedEvent;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies;
|
||||
import com.cobblemon.mod.common.api.riding.Seat;
|
||||
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.client.entity.PokemonClientDelegate;
|
||||
import com.cobblemon.mod.common.client.render.MatrixWrapper;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.PokedexEntityData;
|
||||
import com.cobblemon.mod.common.pokedex.scanner.ScannableEntity;
|
||||
@@ -40,18 +37,16 @@ import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.entity.*;
|
||||
import net.minecraft.world.entity.EntityDimensions;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.Pose;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.food.FoodProperties;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
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.Nullable;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Vector3f;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
@@ -284,41 +279,4 @@ public abstract class PlayerMixin extends LivingEntity implements ScannableEntit
|
||||
public OrientationController getOrientationController() {
|
||||
return cobblemon$orientationController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HitResult pick(double hitDistance, float partialTicks, boolean hitFluids) {
|
||||
Entity vehicle = this.getVehicle();
|
||||
if (vehicle instanceof PokemonEntity pokemonEntity) {
|
||||
int seatIndex = pokemonEntity.getPassengers().indexOf(this);
|
||||
Seat seat = pokemonEntity.getSeats().get(seatIndex);
|
||||
|
||||
PokemonClientDelegate delegate = (PokemonClientDelegate) pokemonEntity.getDelegate();
|
||||
MatrixWrapper locator = delegate.getLocatorStates().get(seat.getLocator());
|
||||
|
||||
if (locator == null) {
|
||||
super.pick(hitDistance, partialTicks, hitFluids);
|
||||
}
|
||||
|
||||
Vec3 locatorOffset = new Vec3(locator.getMatrix().getTranslation(new Vector3f()));
|
||||
|
||||
OrientationController controller = this.getOrientationController();
|
||||
|
||||
float currEyeHeight = this.getEyeHeight();
|
||||
Matrix3f orientation = controller.isActive() && controller.getOrientation() != null ? controller.getOrientation() : new Matrix3f();
|
||||
Vec3 rotatedEyeHeight = new Vec3(orientation.transform(new Vector3f(0f, currEyeHeight - (this.getBbHeight() / 2), 0f)));
|
||||
|
||||
Vec3 eyePosition = locatorOffset.add(pokemonEntity.position()).add(rotatedEyeHeight);
|
||||
|
||||
Vec3 viewVector = this.getViewVector(partialTicks);
|
||||
Vec3 viewDistanceVector = eyePosition.add(viewVector.x * hitDistance, viewVector.y * hitDistance, viewVector.z * hitDistance);
|
||||
return this.level()
|
||||
.clip(
|
||||
new ClipContext(
|
||||
eyePosition, viewDistanceVector, ClipContext.Block.OUTLINE, hitFluids ? net.minecraft.world.level.ClipContext.Fluid.ANY : net.minecraft.world.level.ClipContext.Fluid.NONE, this
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return super.pick(hitDistance, partialTicks, hitFluids);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import net.minecraft.stats.RecipeBookSettings;
|
||||
import net.minecraft.world.inventory.RecipeBookType;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(RecipeBookSettings.class)
|
||||
public class RecipeBookSettingsMixin {
|
||||
|
||||
|
||||
@Shadow @Final public Map<RecipeBookType, RecipeBookSettings.TypeSettings> states;
|
||||
|
||||
@Inject(method = "<init>", at = @At("TAIL"))
|
||||
private void cobblemon$init(CallbackInfo ci) {
|
||||
states.put(RecipeBookType.valueOf("COOKING_POT"), new RecipeBookSettings.TypeSettings(true, true));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import net.minecraft.world.inventory.RecipeBookType;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(value = RecipeBookType.class)
|
||||
public class RecipeBookTypeMixin {
|
||||
|
||||
@Final
|
||||
@Mutable
|
||||
@Shadow
|
||||
private static RecipeBookType[] $VALUES; // moj
|
||||
|
||||
@Invoker("<init>")
|
||||
private static RecipeBookType cobblemon$createBookType(String name, int ordinal) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "<clinit>",
|
||||
at = @At("TAIL")
|
||||
)
|
||||
private static void cobblemon$addRecipeBookType(CallbackInfo ci) {
|
||||
ArrayList<RecipeBookType> types = new ArrayList<>(List.of($VALUES));
|
||||
types.add(cobblemon$createBookType("COOKING_POT", $VALUES.length));
|
||||
$VALUES = types.toArray(RecipeBookType[]::new);
|
||||
}
|
||||
}
|
||||
@@ -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.mixin.accessor;
|
||||
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(Camera.class)
|
||||
public interface CameraAccessor {
|
||||
@Accessor("level")
|
||||
BlockGetter getLevel();
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.accessor;
|
||||
|
||||
import net.minecraft.client.gui.components.StateSwitchingButton;
|
||||
import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(RecipeBookComponent.class)
|
||||
public interface RecipeBookComponentAccessor {
|
||||
@Accessor("filterButton")
|
||||
StateSwitchingButton getFilterButton();
|
||||
}
|
||||
@@ -10,26 +10,17 @@ 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.api.riding.Seat;
|
||||
import com.cobblemon.mod.common.client.MountedPokemonAnimationRenderController;
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate;
|
||||
import com.cobblemon.mod.common.client.render.MatrixWrapper;
|
||||
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.client.render.camera.MountedCameraRenderer;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
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.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.ClipContext;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.joml.Matrix3f;
|
||||
import org.joml.Quaternionf;
|
||||
@@ -42,39 +33,51 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(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;
|
||||
|
||||
@Shadow private float eyeHeight;
|
||||
@Shadow private float eyeHeightOld;
|
||||
|
||||
@Shadow protected abstract void setPosition(Vec3 pos);
|
||||
@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;
|
||||
|
||||
@Shadow
|
||||
private BlockGetter level;
|
||||
private float eyeHeight;
|
||||
@Shadow
|
||||
private float eyeHeightOld;
|
||||
|
||||
@Shadow private float partialTickTime;
|
||||
@Unique private float returnTimer = 0;
|
||||
@Unique private float rollAngleStart = 0;
|
||||
@Unique Minecraft minecraft = Minecraft.getInstance();
|
||||
@Shadow
|
||||
protected abstract void setPosition(Vec3 pos);
|
||||
|
||||
@Unique boolean disableRollableCameraDebug = false;
|
||||
@Unique
|
||||
private float returnTimer = 0;
|
||||
@Unique
|
||||
private float rollAngleStart = 0;
|
||||
@Unique
|
||||
Minecraft minecraft = Minecraft.getInstance();
|
||||
|
||||
@Unique
|
||||
boolean disableRollableCameraDebug = false;
|
||||
|
||||
@Inject(method = "setRotation", at = @At("HEAD"), cancellable = true)
|
||||
public void cobblemon$setRotation(float f, float g, CallbackInfo ci) {
|
||||
if (!(this.entity instanceof OrientationControllable controllable) || disableRollableCameraDebug) return;
|
||||
var controller = controllable.getOrientationController();
|
||||
if (!controller.isActive() && controller.getOrientation() != null) {
|
||||
if(this.returnTimer < 1) {
|
||||
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(
|
||||
@@ -82,16 +85,17 @@ public abstract class CameraMixin {
|
||||
.rotateY((float) Math.toRadians(180 - this.entity.getYRot()))
|
||||
.rotateX((float) Math.toRadians(-this.entity.getXRot()))
|
||||
);
|
||||
if(rollAngleStart == 0){
|
||||
if (rollAngleStart == 0) {
|
||||
this.returnTimer = 1;
|
||||
controller.reset();
|
||||
return;
|
||||
}
|
||||
controller.getOrientation().rotateZ((float) Math.toRadians(-rollAngleStart*(1-returnTimer)));
|
||||
controller.getOrientation().rotateZ((float) Math.toRadians(-rollAngleStart * (1 - returnTimer)));
|
||||
cobblemon$applyRotation();
|
||||
this.returnTimer += .05F;
|
||||
ci.cancel();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
this.returnTimer = 1;
|
||||
controller.reset();
|
||||
}
|
||||
@@ -105,92 +109,37 @@ public abstract class CameraMixin {
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
//If you want to move this to a delagate you need an AW for position
|
||||
@Inject(method = "setup", at = @At("HEAD"))
|
||||
private void cobblemon$tickAnimationPreRenders(BlockGetter level, Entity entity, boolean detached, boolean thirdPersonReverse, float partialTick, CallbackInfo ci) {
|
||||
MountedPokemonAnimationRenderController.INSTANCE.reset();
|
||||
}
|
||||
|
||||
@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();
|
||||
Entity vehicle = entity.getVehicle();
|
||||
MountedPokemonAnimationRenderController.INSTANCE.reset();
|
||||
|
||||
if(vehicle instanceof Rideable){
|
||||
//RidingCameraDelagate.INSTANCE.positionCamera(instance, x, y, z, original);
|
||||
if (!(vehicle instanceof PokemonEntity pokemon)) {
|
||||
original.call(instance, x, y, z);
|
||||
if (cobblemon$isRidingPokemon(entity)) {
|
||||
Vec3 position = MountedCameraRenderer.INSTANCE.getCameraPosition(instance, entity, entity.getVehicle(), thirdPersonReverse, eyeHeightOld, eyeHeight);
|
||||
if (position != null) {
|
||||
setPosition(position);
|
||||
return;
|
||||
}
|
||||
|
||||
PokemonClientDelegate delegate = (PokemonClientDelegate) pokemon.getDelegate();
|
||||
Vec3 entityPos = new Vec3(
|
||||
Mth.lerp(instance.getPartialTickTime(), pokemon.xOld, pokemon.getX()),
|
||||
Mth.lerp(instance.getPartialTickTime(), pokemon.yOld, pokemon.getY()),
|
||||
Mth.lerp(instance.getPartialTickTime(), pokemon.zOld, pokemon.getZ())
|
||||
);
|
||||
MountedPokemonAnimationRenderController.INSTANCE.setup(pokemon, partialTickTime);
|
||||
int seatIndex = pokemon.getPassengers().indexOf(entity);
|
||||
Seat seat = pokemon.getSeats().get(seatIndex);
|
||||
|
||||
OrientationControllable rollable = (OrientationControllable) entity;
|
||||
OrientationController controller = rollable.getOrientationController();
|
||||
|
||||
if (!instance.isDetached() || Cobblemon.config.getThirdPartyViewBobbing()) {
|
||||
MatrixWrapper locator = delegate.getLocatorStates().get(seat.getLocator());
|
||||
|
||||
if (locator == null) {
|
||||
original.call(instance, x, y, z);
|
||||
return;
|
||||
}
|
||||
|
||||
Vec3 locatorOffset = new Vec3(locator.getMatrix().getTranslation(new Vector3f()));
|
||||
|
||||
float currEyeHeight = Mth.lerp(instance.getPartialTickTime(), eyeHeightOld, eyeHeight);
|
||||
var rotatedEyeHeight = new Vector3f(0f, currEyeHeight - (entity.getBbHeight() / 2), 0f);
|
||||
if (controller.isActive()) {
|
||||
rotatedEyeHeight = controller.getRenderOrientation(partialTickTime).transform(rotatedEyeHeight);
|
||||
}
|
||||
|
||||
Vec3 position = locatorOffset.add(entityPos).add(new Vec3(rotatedEyeHeight));
|
||||
setPosition(position);
|
||||
} else {
|
||||
Vector3f pos = entityPos.add(new Vec3(0, pokemon.getBbHeight() / 2, 0)).toVector3f();
|
||||
|
||||
PosableModel model = VaryingModelRepository.INSTANCE.getPoser(pokemon.getPokemon().getSpecies().getResourceIdentifier(), new FloatingState());
|
||||
Map<String, Vec3> cameraOffsets = model.getSeatToCameraOffset();
|
||||
|
||||
Vec3 cameraOffset;
|
||||
if (thirdPersonReverse && cameraOffsets.containsKey(seat.getLocator() + "_reverse")) {
|
||||
cameraOffset = cameraOffsets.get(seat.getLocator() + "_reverse");
|
||||
} else if (cameraOffsets.containsKey(seat.getLocator())) {
|
||||
cameraOffset = cameraOffsets.get(seat.getLocator());
|
||||
} else {
|
||||
cameraOffset = new Vec3(0f, 2f, 4f);
|
||||
}
|
||||
|
||||
Vector3f offset = cameraOffset.toVector3f();
|
||||
|
||||
if (thirdPersonReverse) offset.z *= -1;
|
||||
float xRot = (float) (-1 * Math.toRadians(instance.getXRot()));
|
||||
|
||||
Matrix3f orientation = controller.isActive() && controller.getOrientation() != null ? controller.getOrientation() : new Matrix3f().rotateY((float) Math.toRadians(180f - instance.getYRot())).rotateX(xRot);
|
||||
Vector3f rotatedOffset = orientation.transform(offset);
|
||||
float offsetDistance = rotatedOffset.length();
|
||||
Vector3f offsetDirection = rotatedOffset.mul(1 / offsetDistance);
|
||||
|
||||
float maxZoom = cobblemon$getMaxZoom(offsetDistance, offsetDirection, pos);
|
||||
|
||||
setPosition(new Vec3(offsetDirection.mul(maxZoom).add(pos)));
|
||||
}
|
||||
} else {
|
||||
original.call(instance, x, y, z);
|
||||
}
|
||||
|
||||
original.call(instance, x, y, z);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private void cobblemon$applyRotation(){
|
||||
if (!(this.entity instanceof OrientationControllable controllable) || controllable.getOrientationController().getOrientation() == null) return;
|
||||
private boolean cobblemon$isRidingPokemon(Entity entity) {
|
||||
return entity.getVehicle() instanceof PokemonEntity;
|
||||
}
|
||||
|
||||
@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));
|
||||
newRotation.rotateY((float) Math.toRadians(180));
|
||||
}
|
||||
this.rotation.set(newRotation);
|
||||
this.xRot = controller.getPitch();
|
||||
@@ -205,30 +154,8 @@ public abstract class CameraMixin {
|
||||
Entity entity = instance.getEntity();
|
||||
Entity vehicle = entity.getVehicle();
|
||||
|
||||
if (!(vehicle instanceof PokemonEntity) || Cobblemon.config.getThirdPartyViewBobbing()) {
|
||||
if (!(vehicle instanceof PokemonEntity) || Cobblemon.config.getViewBobTranslation()) {
|
||||
original.call(instance, zoom, dy, dx);
|
||||
}
|
||||
}
|
||||
|
||||
//Modified vanilla code
|
||||
@Unique
|
||||
private float cobblemon$getMaxZoom(float maxZoom, Vector3f directionVector, Vector3f positionVector) {
|
||||
Vec3 pos = new Vec3(positionVector);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
float g = (float) ((i & 1) * 2 - 1);
|
||||
float h = (float) ((i >> 1 & 1) * 2 - 1);
|
||||
float j = (float) ((i >> 2 & 1) * 2 - 1);
|
||||
Vec3 vec3 = pos.add(g * 0.1F, h * 0.1F, j * 0.1F);
|
||||
Vec3 vec32 = vec3.add(new Vec3(directionVector).scale(maxZoom));
|
||||
HitResult hitResult = this.level.clip(new ClipContext(vec3, vec32, ClipContext.Block.VISUAL, ClipContext.Fluid.NONE, this.entity));
|
||||
if (hitResult.getType() != HitResult.Type.MISS) {
|
||||
float k = (float) hitResult.getLocation().distanceToSqr(pos);
|
||||
if (k < Mth.square(maxZoom)) {
|
||||
maxZoom = Mth.sqrt(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return maxZoom;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.CobblemonRecipeCategories;
|
||||
import com.cobblemon.mod.common.item.crafting.CookingPotBookCategory;
|
||||
import com.cobblemon.mod.common.item.crafting.CookingPotRecipe;
|
||||
import com.cobblemon.mod.common.item.crafting.CookingPotShapelessRecipe;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import net.minecraft.client.ClientRecipeBook;
|
||||
import net.minecraft.client.RecipeBookCategories;
|
||||
import net.minecraft.client.gui.screens.recipebook.RecipeCollection;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
|
||||
import net.minecraft.world.item.crafting.Recipe;
|
||||
import net.minecraft.world.item.crafting.RecipeHolder;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(ClientRecipeBook.class)
|
||||
public abstract class ClientRecipeBookMixin {
|
||||
|
||||
@Shadow
|
||||
protected static Map<RecipeBookCategories, List<List<RecipeHolder<?>>>> categorizeAndGroupRecipes(Iterable<RecipeHolder<?>> recipes) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Shadow private Map<RecipeBookCategories, List<RecipeCollection>> collectionsByTab;
|
||||
|
||||
@Shadow private List<RecipeCollection> allCollections;
|
||||
|
||||
@Inject(method = "getCategory", at = @At(value = "HEAD"), cancellable = true)
|
||||
private static void addCustomCategory(RecipeHolder<?> recipe, CallbackInfoReturnable<RecipeBookCategories> cir) {
|
||||
Recipe<?> recipe2 = recipe.value();
|
||||
if (recipe2 instanceof CookingPotRecipe || recipe2 instanceof CookingPotShapelessRecipe) {
|
||||
CookingPotBookCategory category = recipe2 instanceof CookingPotRecipe
|
||||
? ((CookingPotRecipe) recipe2).getCategory()
|
||||
: ((CookingPotShapelessRecipe) recipe2).category();
|
||||
RecipeBookCategories var7;
|
||||
switch (category) {
|
||||
case MISC -> var7 = CobblemonRecipeCategories.COOKING_POT_MISC.toVanillaCategory();
|
||||
case FOODS -> var7 = CobblemonRecipeCategories.COOKING_POT_FOODS.toVanillaCategory();
|
||||
case MEDICINES -> var7 = CobblemonRecipeCategories.COOKING_POT_MEDICINES.toVanillaCategory();
|
||||
case BAITS -> var7 = CobblemonRecipeCategories.COOKING_POT_BAITS.toVanillaCategory();
|
||||
default -> throw new MatchException(null, null);
|
||||
}
|
||||
cir.setReturnValue(var7);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "setupCollections", at = @At("RETURN"))
|
||||
private void addCustomAggregateCategories(Iterable<RecipeHolder<?>> recipes, RegistryAccess registryAccess, CallbackInfo ci) {
|
||||
Map<RecipeBookCategories, List<List<RecipeHolder<?>>>> map = categorizeAndGroupRecipes(recipes);
|
||||
Map<RecipeBookCategories, List<RecipeCollection>> map2 = Maps.newHashMap();
|
||||
ImmutableList.Builder<RecipeCollection> builder = ImmutableList.builder();
|
||||
|
||||
map.forEach((recipeBookCategories, list) -> {
|
||||
List<RecipeCollection> collections = list.stream()
|
||||
.map(listx -> new RecipeCollection(registryAccess, listx))
|
||||
.peek(builder::add)
|
||||
.collect(ImmutableList.toImmutableList());
|
||||
map2.put(recipeBookCategories, collections);
|
||||
});
|
||||
RecipeBookCategories.AGGREGATE_CATEGORIES.forEach((recipeBookCategories, list) -> map2.put(recipeBookCategories, (List)list.stream().flatMap((recipeBookCategoriesx) -> ((List)map2.getOrDefault(recipeBookCategoriesx, ImmutableList.of())).stream()).collect(ImmutableList.toImmutableList())));
|
||||
CobblemonRecipeCategories.Companion.getCustomAggregateCategories().forEach((recipeBookCategories, list) -> map2.put(recipeBookCategories, (List)list.stream().flatMap((recipeBookCategoriesx) -> ((List)map2.getOrDefault(recipeBookCategoriesx, ImmutableList.of())).stream()).collect(ImmutableList.toImmutableList())));
|
||||
|
||||
this.collectionsByTab = ImmutableMap.copyOf(map2);
|
||||
this.allCollections = builder.build();
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.CobblemonItems;
|
||||
import com.cobblemon.mod.common.CobblemonRecipeCategories;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import net.minecraft.client.RecipeBookCategories;
|
||||
import net.minecraft.world.inventory.RecipeBookType;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Mixin(RecipeBookCategories.class)
|
||||
public class RecipeBookCategoriesMixin {
|
||||
|
||||
@Final
|
||||
@Mutable
|
||||
@Shadow
|
||||
private static RecipeBookCategories[] $VALUES;
|
||||
|
||||
@Invoker("<init>")
|
||||
private static RecipeBookCategories cobblemon$createCategory(String name, int ordinal, ItemStack... icons) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "<clinit>",
|
||||
at = @At("TAIL")
|
||||
)
|
||||
private static void cobblemon$addRecipeBookType(CallbackInfo ci) {
|
||||
ArrayList<RecipeBookCategories> types = new ArrayList<>(List.of($VALUES));
|
||||
types.add(cobblemon$createCategory("COOKING_POT_SEARCH", $VALUES.length, new ItemStack(Items.COMPASS)));
|
||||
types.add(cobblemon$createCategory("COOKING_POT_FOODS", $VALUES.length + 1, new ItemStack(CobblemonItems.ROASTED_LEEK)));
|
||||
types.add(cobblemon$createCategory("COOKING_POT_MEDICINES", $VALUES.length + 2, new ItemStack(CobblemonItems.HP_UP)));
|
||||
types.add(cobblemon$createCategory("COOKING_POT_BAITS", $VALUES.length + 3, new ItemStack(CobblemonItems.PERSIM_BERRY)));
|
||||
types.add(cobblemon$createCategory("COOKING_POT_MISC", $VALUES.length + 4, new ItemStack(CobblemonItems.MIRROR_HERB)));
|
||||
$VALUES = types.toArray(RecipeBookCategories[]::new);
|
||||
}
|
||||
|
||||
@Inject(method = "getCategories", at = @At("HEAD"), cancellable = true)
|
||||
private static void modifyCategories(RecipeBookType recipeBookType, CallbackInfoReturnable<List<RecipeBookCategories>> cir) {
|
||||
if (recipeBookType == RecipeBookType.valueOf("COOKING_POT")) {
|
||||
List var10000 = ImmutableList.of(
|
||||
CobblemonRecipeCategories.COOKING_POT_SEARCH.toVanillaCategory(),
|
||||
CobblemonRecipeCategories.COOKING_POT_FOODS.toVanillaCategory(),
|
||||
CobblemonRecipeCategories.COOKING_POT_MEDICINES.toVanillaCategory(),
|
||||
CobblemonRecipeCategories.COOKING_POT_BAITS.toVanillaCategory(),
|
||||
CobblemonRecipeCategories.COOKING_POT_MISC.toVanillaCategory());
|
||||
cir.setReturnValue(var10000);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.CobblemonRecipeCategories;
|
||||
import net.minecraft.client.ClientRecipeBook;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.RecipeBookCategories;
|
||||
import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent;
|
||||
import net.minecraft.client.gui.screens.recipebook.RecipeBookPage;
|
||||
import net.minecraft.client.gui.screens.recipebook.RecipeBookTabButton;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(RecipeBookComponent.class)
|
||||
public class RecipeBookComponentMixin {
|
||||
|
||||
@Shadow private ClientRecipeBook book;
|
||||
|
||||
@Shadow protected Minecraft minecraft;
|
||||
|
||||
@Shadow private int width;
|
||||
|
||||
@Shadow private int xOffset;
|
||||
|
||||
@Shadow private int height;
|
||||
|
||||
@Shadow @Final private RecipeBookPage recipeBookPage;
|
||||
|
||||
@Inject(method = "updateTabs", at = @At("HEAD"), cancellable = true)
|
||||
private void customUpdateTabs(CallbackInfo ci) {
|
||||
RecipeBookComponent instance = (RecipeBookComponent) (Object) this;
|
||||
int i = (width - 147) / 2 - xOffset - 30;
|
||||
int j = (height - 166) / 2 + 3;
|
||||
int k = 27;
|
||||
int l = 0;
|
||||
|
||||
for (RecipeBookTabButton recipeBookTabButton : instance.tabButtons) {
|
||||
RecipeBookCategories recipeBookCategories = recipeBookTabButton.getCategory();
|
||||
if (recipeBookCategories != RecipeBookCategories.CRAFTING_SEARCH && recipeBookCategories != RecipeBookCategories.FURNACE_SEARCH && recipeBookCategories != CobblemonRecipeCategories.COOKING_POT_SEARCH.toVanillaCategory()) {
|
||||
if (recipeBookTabButton.updateVisibility(book)) {
|
||||
recipeBookTabButton.setPosition(i, j + 27 * l++);
|
||||
recipeBookTabButton.startAnimation(minecraft);
|
||||
}
|
||||
} else {
|
||||
recipeBookTabButton.visible = true;
|
||||
recipeBookTabButton.setPosition(i, j + k * l++);
|
||||
}
|
||||
}
|
||||
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
+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.client;
|
||||
|
||||
import net.minecraft.client.ClientRecipeBook;
|
||||
import net.minecraft.client.gui.screens.recipebook.RecipeBookTabButton;
|
||||
import net.minecraft.client.gui.screens.recipebook.RecipeCollection;
|
||||
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.List;
|
||||
|
||||
@Mixin(RecipeBookTabButton.class)
|
||||
public class RecipeBookTabButtonMixin {
|
||||
|
||||
@Inject(method = "updateVisibility", at = @At("HEAD"), cancellable = true)
|
||||
private void customUpdateVisibility(ClientRecipeBook recipeBook, CallbackInfoReturnable<Boolean> cir) {
|
||||
RecipeBookTabButton instance = (RecipeBookTabButton) (Object) this;
|
||||
List<RecipeCollection> list = recipeBook.getCollection(instance.getCategory());
|
||||
boolean visible = false;
|
||||
if (list != null) {
|
||||
for (RecipeCollection recipeCollection : list) {
|
||||
if (recipeCollection.hasKnownRecipes() && recipeCollection.hasFitting()) {
|
||||
visible = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
instance.visible = visible;
|
||||
cir.setReturnValue(visible);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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 net.minecraft.client.gui.screens.recipebook.RecipeCollection;
|
||||
import net.minecraft.stats.RecipeBook;
|
||||
import net.minecraft.world.entity.player.StackedContents;
|
||||
import net.minecraft.world.item.crafting.RecipeHolder;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Mixin(RecipeCollection.class)
|
||||
public class RecipeCollectionMixin {
|
||||
|
||||
@Shadow @Final private Set<RecipeHolder<?>> fitsDimensions;
|
||||
|
||||
@Shadow @Final private Set<RecipeHolder<?>> craftable;
|
||||
|
||||
@Shadow @Final private List<RecipeHolder<?>> recipes;
|
||||
|
||||
@Inject(method = "canCraft", at = @At("HEAD"), cancellable = true)
|
||||
private void customCanCraft(StackedContents handler, int width, int height, RecipeBook book, CallbackInfo ci) {
|
||||
for (RecipeHolder<?> recipeHolder : recipes) {
|
||||
boolean bl = recipeHolder.value().canCraftInDimensions(width, height) && book.contains(recipeHolder);
|
||||
if (bl) {
|
||||
fitsDimensions.add(recipeHolder);
|
||||
} else {
|
||||
fitsDimensions.remove(recipeHolder);
|
||||
}
|
||||
|
||||
if (bl && handler.canCraft(recipeHolder.value(), null)) {
|
||||
craftable.add(recipeHolder);
|
||||
} else {
|
||||
craftable.remove(recipeHolder);
|
||||
}
|
||||
}
|
||||
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
@@ -128,6 +128,7 @@ import kotlin.reflect.jvm.isAccessible
|
||||
import kotlin.reflect.jvm.javaField
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.commands.synchronization.SingletonArgumentInfo
|
||||
import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.resources.ResourceKey
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
@@ -194,6 +195,8 @@ object Cobblemon {
|
||||
this.LOGGER.info(" - Branch: ${CobblemonBuildDetails.BRANCH}")
|
||||
}
|
||||
|
||||
implementation.registerRecipeSerializers()
|
||||
implementation.registerRecipeTypes()
|
||||
implementation.registerPermissionValidator()
|
||||
implementation.registerSoundEvents()
|
||||
implementation.registerDataComponents()
|
||||
@@ -202,9 +205,11 @@ object Cobblemon {
|
||||
implementation.registerEntityTypes()
|
||||
implementation.registerEntityAttributes()
|
||||
implementation.registerBlockEntityTypes()
|
||||
implementation.registerPoiTypes()
|
||||
implementation.registerVillagers()
|
||||
implementation.registerWorldGenFeatures()
|
||||
implementation.registerParticles()
|
||||
implementation.registerMenu()
|
||||
implementation.registerEntityDataSerializers()
|
||||
implementation.registerCriteria()
|
||||
implementation.registerEntitySubPredicates()
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.block.entity.PokeCakeBlockEntity
|
||||
import com.cobblemon.mod.common.block.entity.BerryBlockEntity
|
||||
import com.cobblemon.mod.common.block.entity.HealingMachineBlockEntity
|
||||
import com.cobblemon.mod.common.block.entity.PCBlockEntity
|
||||
@@ -45,9 +46,9 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
|
||||
@JvmField
|
||||
val PASTURE: BlockEntityType<PokemonPastureBlockEntity> = this.create("pasture", BlockEntityType.Builder.of(::PokemonPastureBlockEntity, CobblemonBlocks.PASTURE).build(null))
|
||||
@JvmField
|
||||
val SIGN: BlockEntityType<CobblemonSignBlockEntity> = this.create("sign", BlockEntityType.Builder.of(::CobblemonSignBlockEntity, CobblemonBlocks.APRICORN_SIGN, CobblemonBlocks.APRICORN_WALL_SIGN).build(null))
|
||||
val SIGN: BlockEntityType<CobblemonSignBlockEntity> = this.create("sign", BlockEntityType.Builder.of(::CobblemonSignBlockEntity, CobblemonBlocks.APRICORN_SIGN, CobblemonBlocks.APRICORN_WALL_SIGN, CobblemonBlocks.SACCHARINE_SIGN, CobblemonBlocks.SACCHARINE_WALL_SIGN).build(null))
|
||||
@JvmField
|
||||
val HANGING_SIGN: BlockEntityType<CobblemonHangingSignBlockEntity> = this.create("hanging_sign", BlockEntityType.Builder.of(::CobblemonHangingSignBlockEntity, CobblemonBlocks.APRICORN_HANGING_SIGN, CobblemonBlocks.APRICORN_WALL_HANGING_SIGN).build(null))
|
||||
val HANGING_SIGN: BlockEntityType<CobblemonHangingSignBlockEntity> = this.create("hanging_sign", BlockEntityType.Builder.of(::CobblemonHangingSignBlockEntity, CobblemonBlocks.APRICORN_HANGING_SIGN, CobblemonBlocks.APRICORN_WALL_HANGING_SIGN, CobblemonBlocks.SACCHARINE_HANGING_SIGN, CobblemonBlocks.SACCHARINE_WALL_HANGING_SIGN).build(null))
|
||||
|
||||
@JvmField
|
||||
val GILDED_CHEST: BlockEntityType<GildedChestBlockEntity> = this.create("chest", BlockEntityType.Builder.of(::GildedChestBlockEntity,
|
||||
@@ -86,4 +87,36 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
|
||||
val DISPLAY_CASE: BlockEntityType<DisplayCaseBlockEntity> = this.create("display_case",
|
||||
BlockEntityType.Builder.of(::DisplayCaseBlockEntity, CobblemonBlocks.DISPLAY_CASE).build(null)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val INCENSE_SWEET: BlockEntityType<SweetIncenseBlockEntity> = this.create("incense_sweet",
|
||||
BlockEntityType.Builder.of(::SweetIncenseBlockEntity, CobblemonBlocks.INCENSE_SWEET).build(null)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val CAMPFIRE: BlockEntityType<CampfireBlockEntity> = this.create("campfire_pot",
|
||||
BlockEntityType.Builder.of(::CampfireBlockEntity, CobblemonBlocks.CAMPFIRE).build(null)
|
||||
)
|
||||
|
||||
/*@JvmField
|
||||
val LURE_CAKE: BlockEntityType<LureCakeBlockEntity> =
|
||||
BlockEntityType.Builder.of({ pos, state -> LureCakeBlockEntity(pos, state) },
|
||||
CobblemonBlocks.LURE_CAKE
|
||||
).build(null)*/
|
||||
|
||||
@JvmField
|
||||
val LURE_CAKE: BlockEntityType<LureCakeBlockEntity> = this.create(
|
||||
"lure_cake",
|
||||
BlockEntityType.Builder.of(::LureCakeBlockEntity, CobblemonBlocks.LURE_CAKE).build(null)
|
||||
)
|
||||
@JvmField
|
||||
val POKE_CAKE: BlockEntityType<PokeCakeBlockEntity> = this.create(
|
||||
"poke_cake",
|
||||
BlockEntityType.Builder.of(::PokeCakeBlockEntity, CobblemonBlocks.POKE_CAKE).build(null)
|
||||
)
|
||||
@JvmField
|
||||
val CANDLE_POKE_CAKE: BlockEntityType<CandlePokeCakeBlockEntity> = this.create(
|
||||
"candle_poke_cake",
|
||||
BlockEntityType.Builder.of(::CandlePokeCakeBlockEntity, CobblemonBlocks.CANDLE_POKE_CAKE).build(null)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -10,8 +10,10 @@ package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.api.apricorn.Apricorn
|
||||
import com.cobblemon.mod.common.block.*
|
||||
import com.cobblemon.mod.common.block.campfirepot.CampfireBlock
|
||||
import com.cobblemon.mod.common.block.LecternBlock
|
||||
import com.cobblemon.mod.common.block.MintBlock.MintType
|
||||
import com.cobblemon.mod.common.block.campfirepot.CampfirePotBlock
|
||||
import com.cobblemon.mod.common.block.chest.GildedChestBlock
|
||||
import com.cobblemon.mod.common.block.sign.CobblemonHangingSignBlock
|
||||
import com.cobblemon.mod.common.block.sign.CobblemonSignBlock
|
||||
@@ -20,6 +22,7 @@ import com.cobblemon.mod.common.block.sign.CobblemonWallSignBlock
|
||||
import com.cobblemon.mod.common.mixin.invoker.*
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Registry
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.core.registries.Registries
|
||||
@@ -27,9 +30,13 @@ import net.minecraft.resources.ResourceKey
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.valueproviders.UniformInt
|
||||
import net.minecraft.world.effect.MobEffects
|
||||
import net.minecraft.world.entity.EntityType
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.block.*
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.properties.BlockSetType
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties.LIT
|
||||
import net.minecraft.world.level.block.state.properties.NoteBlockInstrument
|
||||
import net.minecraft.world.level.block.state.properties.WoodType
|
||||
import net.minecraft.world.level.material.MapColor
|
||||
@@ -43,6 +50,8 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
|
||||
val APRICORN_BLOCK_SET_TYPE = BlockSetType("apricorn")
|
||||
val APRICORN_WOOD_TYPE = WoodType.register(WoodType("apricorn", APRICORN_BLOCK_SET_TYPE))
|
||||
val SACCHARINE_BLOCK_SET_TYPE = BlockSetType("saccharine")
|
||||
val SACCHARINE_WOOD_TYPE = WoodType.register(WoodType("saccharine", SACCHARINE_BLOCK_SET_TYPE))
|
||||
|
||||
// Evolution Ores
|
||||
@JvmField
|
||||
@@ -159,15 +168,80 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
@JvmField
|
||||
val YELLOW_APRICORN_SAPLING = this.create("yellow_apricorn_sapling", ApricornSaplingBlock(PLANT_PROPERTIES, Apricorn.YELLOW))
|
||||
|
||||
// Saccharines
|
||||
@JvmField
|
||||
val SACCHARINE_LOG = this.create("saccharine_log", SaccharineLogBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BLUE).instrument(NoteBlockInstrument.BASS).strength(2.0F).sound(SoundType.WOOD).ignitedByLava()))
|
||||
@JvmField
|
||||
val SACCHARINE_HONEY_LOG = this.create("saccharine_honey_log", SaccharineHoneyLogBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BLUE).instrument(NoteBlockInstrument.BASS).strength(2.0F).sound(SoundType.WOOD).ignitedByLava()))
|
||||
|
||||
@JvmField
|
||||
val STRIPPED_SACCHARINE_LOG = this.create("stripped_saccharine_log", SaccharineStrippedLogBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_LIGHT_BLUE).instrument(NoteBlockInstrument.BASS).strength(2.0F).sound(SoundType.WOOD).ignitedByLava())) //log("stripped_saccharine_log")
|
||||
@JvmField
|
||||
val SACCHARINE_WOOD = log("saccharine_wood")
|
||||
@JvmField
|
||||
val STRIPPED_SACCHARINE_WOOD = this.create("stripped_saccharine_wood", SaccharineStrippedLogBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_LIGHT_BLUE).instrument(NoteBlockInstrument.BASS).strength(2.0F).sound(SoundType.WOOD).ignitedByLava())) //log("stripped_saccharine_log")
|
||||
@JvmField
|
||||
val SACCHARINE_PLANKS = this.create("saccharine_planks", Block(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_LIGHT_BLUE).instrument(NoteBlockInstrument.BASS).strength(2.0f, 3.0f).sound(SoundType.WOOD)))
|
||||
@JvmField
|
||||
val SACCHARINE_LEAVES = this.create("saccharine_leaves", SaccharineLeafBlock(
|
||||
BlockBehaviour.Properties.of().mapColor(
|
||||
MapColor.PLANT
|
||||
).strength(0.2f).randomTicks().sound(SoundType.GRASS).noOcclusion()
|
||||
.isValidSpawn { _: BlockState?, _: BlockGetter?, _: BlockPos?, entity: EntityType<*>? ->
|
||||
entity === EntityType.OCELOT || entity === EntityType.PARROT
|
||||
}.isSuffocating { _: BlockState?, _: BlockGetter?, _: BlockPos? ->
|
||||
false
|
||||
}.isViewBlocking { _: BlockState?, _: BlockGetter?, _: BlockPos? ->
|
||||
false
|
||||
}.ignitedByLava().pushReaction(PushReaction.DESTROY)
|
||||
.isRedstoneConductor { _: BlockState?, _: BlockGetter?, _: BlockPos? ->
|
||||
false
|
||||
}))
|
||||
@JvmField
|
||||
val SACCHARINE_FENCE = this.create("saccharine_fence", FenceBlock(BlockBehaviour.Properties.of().mapColor(SACCHARINE_PLANKS.defaultMapColor()).instrument(NoteBlockInstrument.BASS).strength(2.0f, 3.0f).sound(SoundType.WOOD)))
|
||||
@JvmField
|
||||
val SACCHARINE_FENCE_GATE = this.create("saccharine_fence_gate", FenceGateBlock(SACCHARINE_WOOD_TYPE, BlockBehaviour.Properties.of().mapColor(SACCHARINE_PLANKS.defaultMapColor()).instrument(NoteBlockInstrument.BASS).strength(2.0f, 3.0f).sound(SoundType.WOOD)))
|
||||
|
||||
val SACCHARINE_BUTTON = this.create("saccharine_button", BlocksInvoker.createWoodenButtonBlock(BlockSetType.OAK))
|
||||
@JvmField
|
||||
val SACCHARINE_PRESSURE_PLATE = this.create("saccharine_pressure_plate", PressurePlateBlockInvoker.`cobblemon$create`(SACCHARINE_BLOCK_SET_TYPE, BlockBehaviour.Properties.of().mapColor(SACCHARINE_PLANKS.defaultMapColor()).instrument(NoteBlockInstrument.BASS).noCollission().strength(0.5f).sound(SoundType.WOOD)))
|
||||
@JvmField
|
||||
val SACCHARINE_SIGN = this.create("saccharine_sign", CobblemonSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_SIGN), SACCHARINE_WOOD_TYPE))
|
||||
@JvmField
|
||||
val SACCHARINE_WALL_SIGN = this.create("saccharine_wall_sign", CobblemonWallSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_WALL_SIGN), SACCHARINE_WOOD_TYPE))
|
||||
@JvmField
|
||||
val SACCHARINE_HANGING_SIGN = this.create("saccharine_hanging_sign", CobblemonHangingSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_WALL_HANGING_SIGN), SACCHARINE_WOOD_TYPE))
|
||||
@JvmField
|
||||
val SACCHARINE_WALL_HANGING_SIGN = this.create("saccharine_wall_hanging_sign", CobblemonWallHangingSignBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.OAK_HANGING_SIGN), SACCHARINE_WOOD_TYPE))
|
||||
@JvmField
|
||||
val SACCHARINE_SLAB = this.create("saccharine_slab", SlabBlock(BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).instrument(NoteBlockInstrument.BASS).strength(2.0f, 3.0f).sound(SoundType.WOOD)))
|
||||
@JvmField
|
||||
val SACCHARINE_STAIRS = this.create("saccharine_stairs", StairsBlockInvoker.`cobblemon$create`(SACCHARINE_PLANKS.defaultBlockState(), BlockBehaviour.Properties.ofFullCopy(SACCHARINE_PLANKS)))
|
||||
@JvmField
|
||||
val SACCHARINE_DOOR = this.create("saccharine_door", DoorBlockInvoker.`cobblemon$create`(SACCHARINE_BLOCK_SET_TYPE, BlockBehaviour.Properties.of().mapColor(SACCHARINE_PLANKS.defaultMapColor()).instrument(NoteBlockInstrument.BASS).strength(3.0F).sound(SoundType.WOOD).noOcclusion()))
|
||||
@JvmField
|
||||
val SACCHARINE_TRAPDOOR = this.create("saccharine_trapdoor", TrapdoorBlockInvoker.`cobblemon$create`(SACCHARINE_BLOCK_SET_TYPE, BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).instrument(NoteBlockInstrument.BASS).strength(3.0F).sound(SoundType.WOOD).noOcclusion()))
|
||||
@JvmField
|
||||
val SACCHARINE_SAPLING = this.create("saccharine_sapling", SaccharineSaplingBlock(PLANT_PROPERTIES))
|
||||
|
||||
@JvmField
|
||||
val MEDICINAL_LEEK = this.create("medicinal_leek", MedicinalLeekBlock(BlockBehaviour.Properties.of().pushReaction(PushReaction.DESTROY).ignitedByLava().mapColor(MapColor.CRIMSON_NYLIUM).noCollission().randomTicks().instabreak().sound(CobblemonSounds.MEDICINAL_LEEK_SOUNDS)))
|
||||
@JvmField
|
||||
val BUGWORT = this.create("bugwort", BugwortBlock(BlockBehaviour.Properties.of().pushReaction(PushReaction.DESTROY).ignitedByLava().mapColor(MapColor.COLOR_PURPLE).noCollission().randomTicks().instabreak().sound(CobblemonSounds.MEDICINAL_LEEK_SOUNDS)))
|
||||
@JvmField
|
||||
val ENERGY_ROOT = this.create("energy_root", EnergyRootBlock(BlockBehaviour.Properties.of().pushReaction(PushReaction.DESTROY).ignitedByLava().mapColor(MapColor.DIRT).noCollission().randomTicks().instabreak().sound(CobblemonSounds.ENERGY_ROOT_SOUNDS)))
|
||||
@JvmField
|
||||
val BIG_ROOT = this.create("big_root", BigRootBlock(BlockBehaviour.Properties.of().pushReaction(PushReaction.DESTROY).ignitedByLava().mapColor(MapColor.PLANT).noCollission().randomTicks().instabreak().sound(CobblemonSounds.BIG_ROOT_SOUNDS)))
|
||||
@JvmField
|
||||
val REVIVAL_HERB = this.create("revival_herb", RevivalHerbBlock(BlockBehaviour.Properties.of().pushReaction(PushReaction.DESTROY).mapColor(MapColor.PLANT).ignitedByLava().noCollission().instabreak().sound(CobblemonSounds.REVIVAL_HERB_SOUNDS)))
|
||||
|
||||
@JvmField
|
||||
val LURE_CAKE = this.create("lure_cake", LureCakeBlock(BlockBehaviour.Properties.of().forceSolidOn().strength(0.5F).sound(SoundType.WOOL).pushReaction(PushReaction.DESTROY)))
|
||||
@JvmField
|
||||
val POKE_CAKE = this.create("poke_cake", PokeCakeBlock(BlockBehaviour.Properties.ofFullCopy(LURE_CAKE)))
|
||||
@JvmField
|
||||
val CANDLE_POKE_CAKE = this.create("candle_poke_cake", CandlePokeCakeBlock(BlockBehaviour.Properties.ofFullCopy(LURE_CAKE).lightLevel { blockState -> if (blockState.getValue(LIT) == true) 3 else 0 }))
|
||||
|
||||
@JvmField
|
||||
val TUMBLESTONE_CLUSTER = tumblestoneBlock("tumblestone_cluster", GrowableStoneBlock.STAGE_3, 7, 3, null)
|
||||
@JvmField
|
||||
@@ -319,6 +393,60 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
@JvmField
|
||||
val YELLOW_APRICORN = apricornBlock("yellow_apricorn", Apricorn.YELLOW)
|
||||
|
||||
@JvmField
|
||||
val BLACK_CAMPFIRE_POT = create("campfire_pot_black",
|
||||
CampfirePotBlock(
|
||||
BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BLACK).sound(CobblemonSounds.CAMPFIRE_POT_SOUNDS)
|
||||
.strength(0.5F).pushReaction(PushReaction.BLOCK).noOcclusion()
|
||||
)
|
||||
)
|
||||
@JvmField
|
||||
val BLUE_CAMPFIRE_POT = create("campfire_pot_blue",
|
||||
CampfirePotBlock(
|
||||
BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BLUE).sound(CobblemonSounds.CAMPFIRE_POT_SOUNDS)
|
||||
.strength(0.5F).pushReaction(PushReaction.BLOCK).noOcclusion()
|
||||
)
|
||||
)
|
||||
@JvmField
|
||||
val GREEN_CAMPFIRE_POT = create("campfire_pot_green",
|
||||
CampfirePotBlock(
|
||||
BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_GREEN).sound(CobblemonSounds.CAMPFIRE_POT_SOUNDS)
|
||||
.strength(0.5F).pushReaction(PushReaction.BLOCK).noOcclusion()
|
||||
)
|
||||
)
|
||||
@JvmField
|
||||
val PINK_CAMPFIRE_POT = create("campfire_pot_pink",
|
||||
CampfirePotBlock(
|
||||
BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_PINK).sound(CobblemonSounds.CAMPFIRE_POT_SOUNDS)
|
||||
.strength(0.5F).pushReaction(PushReaction.BLOCK).noOcclusion()
|
||||
)
|
||||
)
|
||||
@JvmField
|
||||
val RED_CAMPFIRE_POT = create("campfire_pot_red",
|
||||
CampfirePotBlock(
|
||||
BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_RED).sound(CobblemonSounds.CAMPFIRE_POT_SOUNDS)
|
||||
.strength(0.5F).pushReaction(PushReaction.BLOCK).noOcclusion()
|
||||
)
|
||||
)
|
||||
@JvmField
|
||||
val WHITE_CAMPFIRE_POT = create("campfire_pot_white",
|
||||
CampfirePotBlock(
|
||||
BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_LIGHT_GRAY)
|
||||
.sound(CobblemonSounds.CAMPFIRE_POT_SOUNDS).strength(0.5F).pushReaction(PushReaction.BLOCK)
|
||||
.noOcclusion()
|
||||
)
|
||||
)
|
||||
@JvmField
|
||||
val YELLOW_CAMPFIRE_POT = create("campfire_pot_yellow",
|
||||
CampfirePotBlock(
|
||||
BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_YELLOW).sound(CobblemonSounds.CAMPFIRE_POT_SOUNDS)
|
||||
.strength(0.5F).pushReaction(PushReaction.BLOCK).noOcclusion()
|
||||
)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val CAMPFIRE = create("campfire", CampfireBlock(BlockBehaviour.Properties.of().sound(SoundType.WOOD).noOcclusion().pushReaction(PushReaction.BLOCK).mapColor(MapColor.PODZOL).strength(2.0F).lightLevel { if ((it.getValue(CampfireBlock.SOUL) as Boolean)) 9 else 14 }))
|
||||
|
||||
@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
|
||||
@@ -360,6 +488,9 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
@JvmField
|
||||
val DISPLAY_CASE = create("display_case", DisplayCaseBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.DISPLAY_CASE_SOUNDS).noOcclusion().pushReaction(PushReaction.BLOCK).mapColor(MapColor.STONE).strength(0.3F)))
|
||||
|
||||
@JvmField
|
||||
val INCENSE_SWEET = create("incense_sweet", SweetIncenseBlock(BlockBehaviour.Properties.of().sound(CobblemonSounds.DISPLAY_CASE_SOUNDS).noOcclusion().pushReaction(PushReaction.BLOCK).mapColor(MapColor.STONE).strength(0.3f)))
|
||||
|
||||
@JvmField
|
||||
val PASTURE = create("pasture", PastureBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BROWN).sound(SoundType.WOOD).strength(2F).noOcclusion().pushReaction(PushReaction.BLOCK).lightLevel { if ((it.getValue(PastureBlock.ON) as Boolean) && (it.getValue(PastureBlock.PART) == PastureBlock.PasturePart.TOP)) 10 else 0 }))
|
||||
|
||||
@@ -381,6 +512,8 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
val PEP_UP_FLOWER = this.create("pep_up_flower", FlowerBlock(MobEffects.LEVITATION, 10F, BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).noCollission().instabreak().sound(SoundType.GRASS).offsetType(BlockBehaviour.OffsetType.XZ).pushReaction(PushReaction.DESTROY)))
|
||||
@JvmField
|
||||
val POTTED_PEP_UP_FLOWER = this.create("potted_pep_up_flower", BlocksInvoker.createFlowerPotBlock(PEP_UP_FLOWER))
|
||||
@JvmField
|
||||
val HEARTY_GRAINS = this.create("hearty_grains", HeartyGrainsBlock(BlockBehaviour.Properties.of().pushReaction(PushReaction.DESTROY).ignitedByLava().mapColor(MapColor.PLANT).noCollission().randomTicks().instabreak().sound(CobblemonSounds.VIVICHOKE_SOUNDS)))
|
||||
|
||||
/**
|
||||
* Returns a map of all the blocks that can be stripped with an axe in the format of input - output.
|
||||
@@ -389,7 +522,10 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
*/
|
||||
fun strippedBlocks(): Map<Block, Block> = mapOf(
|
||||
APRICORN_WOOD to STRIPPED_APRICORN_WOOD,
|
||||
APRICORN_LOG to STRIPPED_APRICORN_LOG
|
||||
APRICORN_LOG to STRIPPED_APRICORN_LOG,
|
||||
SACCHARINE_WOOD to STRIPPED_SACCHARINE_WOOD,
|
||||
SACCHARINE_LOG to STRIPPED_SACCHARINE_LOG,
|
||||
SACCHARINE_HONEY_LOG to STRIPPED_SACCHARINE_LOG
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -94,12 +94,17 @@ interface CobblemonImplementation {
|
||||
*/
|
||||
fun registerBlockEntityTypes()
|
||||
|
||||
fun registerPoiTypes()
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
*/
|
||||
fun registerVillagers()
|
||||
|
||||
fun registerRecipeSerializers()
|
||||
fun registerRecipeTypes()
|
||||
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
@@ -108,6 +113,8 @@ interface CobblemonImplementation {
|
||||
|
||||
fun registerParticles()
|
||||
|
||||
fun registerMenu()
|
||||
|
||||
fun registerEntitySubPredicates()
|
||||
|
||||
|
||||
|
||||
@@ -8,9 +8,13 @@
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.block.PotComponent
|
||||
import com.cobblemon.mod.common.item.components.BaitEffectsComponent
|
||||
import com.cobblemon.mod.common.item.components.FlavourComponent
|
||||
import com.cobblemon.mod.common.item.components.FoodColourComponent
|
||||
import com.cobblemon.mod.common.item.components.HeldItemCapableComponent
|
||||
import com.cobblemon.mod.common.item.components.PokemonItemComponent
|
||||
import com.cobblemon.mod.common.item.RodBaitComponent
|
||||
import com.cobblemon.mod.common.item.components.RodBaitComponent
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import net.minecraft.core.Registry
|
||||
import net.minecraft.core.component.DataComponentType
|
||||
@@ -36,11 +40,34 @@ object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>
|
||||
.networkSynchronized(RodBaitComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
val POT_DATA: DataComponentType<PotComponent> = create("cooking_pot_item", DataComponentType.builder<PotComponent>()
|
||||
.persistent(PotComponent.CODEC)
|
||||
.networkSynchronized(PotComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
val BAIT_EFFECTS: DataComponentType<BaitEffectsComponent> = create("bait_effects", DataComponentType.builder<BaitEffectsComponent>()
|
||||
.persistent(BaitEffectsComponent.CODEC)
|
||||
.networkSynchronized(BaitEffectsComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
val FLAVOUR: DataComponentType<FlavourComponent> = create("flavour", DataComponentType.builder<FlavourComponent>()
|
||||
.persistent(FlavourComponent.CODEC)
|
||||
.networkSynchronized(FlavourComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
val FOOD_COLOUR: DataComponentType<FoodColourComponent> = create("food_colour", DataComponentType.builder<FoodColourComponent>()
|
||||
.persistent(FoodColourComponent.CODEC)
|
||||
.networkSynchronized(FoodColourComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
|
||||
fun register() {
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:pokemon_item"), POKEMON_ITEM)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:bait"), BAIT)
|
||||
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:food_colour"), FOOD_COLOUR)
|
||||
}
|
||||
|
||||
override val registry = BuiltInRegistries.DATA_COMPONENT_TYPE
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.api.apricorn.Apricorn
|
||||
import com.cobblemon.mod.common.api.item.ability.AbilityChanger
|
||||
import com.cobblemon.mod.common.api.mulch.MulchVariant
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
@@ -26,9 +27,14 @@ import com.cobblemon.mod.common.item.armor.CobblemonArmorTrims
|
||||
import com.cobblemon.mod.common.item.battle.DireHitItem
|
||||
import com.cobblemon.mod.common.item.battle.GuardSpecItem
|
||||
import com.cobblemon.mod.common.item.battle.XStatItem
|
||||
import com.cobblemon.mod.common.item.berry.*
|
||||
import com.cobblemon.mod.common.item.berry.BerryItem
|
||||
import com.cobblemon.mod.common.item.berry.FriendshipRaisingBerryItem
|
||||
import com.cobblemon.mod.common.item.berry.HealingBerryItem
|
||||
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.interactive.*
|
||||
import com.cobblemon.mod.common.item.interactive.PotionItem
|
||||
import com.cobblemon.mod.common.item.interactive.ability.AbilityChangeItem
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import com.cobblemon.mod.common.pokeball.PokeBall
|
||||
@@ -44,7 +50,14 @@ import net.minecraft.world.effect.MobEffectInstance
|
||||
import net.minecraft.world.effect.MobEffects
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.food.FoodProperties
|
||||
import net.minecraft.world.item.*
|
||||
import net.minecraft.world.item.BlockItem
|
||||
import net.minecraft.world.item.HangingSignItem
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.item.Rarity
|
||||
import net.minecraft.world.item.SignItem
|
||||
import net.minecraft.world.item.SmithingTemplateItem
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.Block
|
||||
|
||||
@@ -171,6 +184,25 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val POKEDEX_WHITE = pokedexItem(PokedexType.WHITE)
|
||||
|
||||
val campfire_pots = mutableListOf<CampfirePotItem>()
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_BLACK = campfirePotItem(CobblemonBlocks.BLACK_CAMPFIRE_POT, "black")
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_BLUE = campfirePotItem(CobblemonBlocks.BLUE_CAMPFIRE_POT, "blue")
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_GREEN = campfirePotItem(CobblemonBlocks.GREEN_CAMPFIRE_POT, "green")
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_PINK = campfirePotItem(CobblemonBlocks.PINK_CAMPFIRE_POT, "pink")
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_RED = campfirePotItem(CobblemonBlocks.RED_CAMPFIRE_POT, "red")
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_WHITE = campfirePotItem(CobblemonBlocks.WHITE_CAMPFIRE_POT, "white")
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_YELLOW = campfirePotItem(CobblemonBlocks.YELLOW_CAMPFIRE_POT, "yellow")
|
||||
|
||||
@JvmField
|
||||
val Hearty_Grains = compostableItem("hearty_grains", HeartyGrainsItem(CobblemonBlocks.HEARTY_GRAINS))
|
||||
|
||||
@JvmField
|
||||
val VIVICHOKE = compostableItem("vivichoke")
|
||||
|
||||
@@ -261,6 +293,321 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val GIMMIGHOUL_CHEST = this.create("gimmighoul_chest", BlockItem(CobblemonBlocks.GIMMIGHOUL_CHEST, Item.Properties()))
|
||||
|
||||
// Saccharines
|
||||
@JvmField
|
||||
val SACCHARINE_LOG = blockItem("saccharine_log", CobblemonBlocks.SACCHARINE_LOG)
|
||||
@JvmField
|
||||
val SACCHARINE_HONEY_LOG = blockItem("saccharine_honey_log", CobblemonBlocks.SACCHARINE_HONEY_LOG)
|
||||
@JvmField
|
||||
val STRIPPED_SACCHARINE_LOG = blockItem("stripped_saccharine_log", CobblemonBlocks.STRIPPED_SACCHARINE_LOG)
|
||||
@JvmField
|
||||
val SACCHARINE_WOOD = blockItem("saccharine_wood", CobblemonBlocks.SACCHARINE_WOOD)
|
||||
@JvmField
|
||||
val STRIPPED_SACCHARINE_WOOD = blockItem("stripped_saccharine_wood", CobblemonBlocks.STRIPPED_SACCHARINE_WOOD)
|
||||
@JvmField
|
||||
val SACCHARINE_PLANKS = blockItem("saccharine_planks", CobblemonBlocks.SACCHARINE_PLANKS)
|
||||
@JvmField
|
||||
val SACCHARINE_LEAVES = compostableBlockItem("saccharine_leaves", CobblemonBlocks.SACCHARINE_LEAVES)
|
||||
@JvmField
|
||||
val SACCHARINE_BOAT = create("saccharine_boat", CobblemonBoatItem(CobblemonBoatType.SACCHARINE, false, Item.Properties().stacksTo(1)))
|
||||
@JvmField
|
||||
val SACCHARINE_CHEST_BOAT = create("saccharine_chest_boat", CobblemonBoatItem(CobblemonBoatType.SACCHARINE, true, Item.Properties().stacksTo(1)))
|
||||
|
||||
@JvmField
|
||||
val SACCHARINE_DOOR = blockItem("saccharine_door", CobblemonBlocks.SACCHARINE_DOOR)
|
||||
@JvmField
|
||||
val SACCHARINE_TRAPDOOR = blockItem("saccharine_trapdoor", CobblemonBlocks.SACCHARINE_TRAPDOOR)
|
||||
@JvmField
|
||||
val SACCHARINE_FENCE = blockItem("saccharine_fence", CobblemonBlocks.SACCHARINE_FENCE)
|
||||
@JvmField
|
||||
val SACCHARINE_FENCE_GATE = blockItem("saccharine_fence_gate", CobblemonBlocks.SACCHARINE_FENCE_GATE)
|
||||
@JvmField
|
||||
val SACCHARINE_BUTTON = blockItem("saccharine_button", CobblemonBlocks.SACCHARINE_BUTTON)
|
||||
@JvmField
|
||||
val SACCHARINE_PRESSURE_PLATE = blockItem("saccharine_pressure_plate", CobblemonBlocks.SACCHARINE_PRESSURE_PLATE)
|
||||
@JvmField
|
||||
val SACCHARINE_SLAB = blockItem("saccharine_slab", CobblemonBlocks.SACCHARINE_SLAB)
|
||||
@JvmField
|
||||
val SACCHARINE_STAIRS = blockItem("saccharine_stairs", CobblemonBlocks.SACCHARINE_STAIRS)
|
||||
@JvmField
|
||||
val SACCHARINE_SIGN = this.create("saccharine_sign", SignItem(Item.Properties().stacksTo(16), CobblemonBlocks.SACCHARINE_SIGN, CobblemonBlocks.SACCHARINE_WALL_SIGN))
|
||||
@JvmField
|
||||
val SACCHARINE_HANGING_SIGN = this.create("saccharine_hanging_sign", HangingSignItem(CobblemonBlocks.SACCHARINE_HANGING_SIGN, CobblemonBlocks.SACCHARINE_WALL_HANGING_SIGN, Item.Properties().stacksTo(16)))
|
||||
@JvmField
|
||||
val SACCHARINE_SAPLING = saccharineSaplingItem("saccharine_sapling", SaccharineSaplingItem(CobblemonBlocks.SACCHARINE_SAPLING))
|
||||
|
||||
@JvmField
|
||||
val BUGWORT = bugwortItem("bugwort", BugwortItem(CobblemonBlocks.BUGWORT))
|
||||
@JvmField
|
||||
val POKE_BAIT = noSettingsItem("poke_bait")
|
||||
|
||||
@JvmField
|
||||
val LURE_CAKE = blockItem("lure_cake", CobblemonBlocks.LURE_CAKE)
|
||||
@JvmField
|
||||
val POKE_CAKE = blockItem("poke_cake", CobblemonBlocks.POKE_CAKE)
|
||||
|
||||
val aprijuices = mutableListOf<AprijuiceItem>()
|
||||
@JvmField
|
||||
val APRIJUICE_BLACK = aprijuiceItem(Apricorn.BLACK)
|
||||
@JvmField
|
||||
val APRIJUICE_RED = aprijuiceItem(Apricorn.RED)
|
||||
@JvmField
|
||||
val APRIJUICE_BLUE = aprijuiceItem(Apricorn.BLUE)
|
||||
@JvmField
|
||||
val APRIJUICE_GREEN = aprijuiceItem(Apricorn.GREEN)
|
||||
@JvmField
|
||||
val APRIJUICE_YELLOW = aprijuiceItem(Apricorn.YELLOW)
|
||||
@JvmField
|
||||
val APRIJUICE_WHITE = aprijuiceItem(Apricorn.WHITE)
|
||||
@JvmField
|
||||
val APRIJUICE_PINK = aprijuiceItem(Apricorn.PINK)
|
||||
|
||||
@JvmField
|
||||
val POKE_PUFF = noSettingsItem("poke_puff") // todo make a PokePuffItem class for friendship boosting purposes
|
||||
|
||||
// FOODS
|
||||
@JvmField
|
||||
val SWEET_HEART = noSettingsItem("sweet_heart") // todo make a SweetHeartItem class for breeding purposes
|
||||
|
||||
@JvmField
|
||||
val PEWTER_CRUNCHIES = create("pewter_crunchies", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
|
||||
.food(FoodProperties.Builder()
|
||||
.nutrition(10)
|
||||
.saturationModifier(1.2F)
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
|
||||
.alwaysEdible()
|
||||
.build())) {
|
||||
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
|
||||
user.removeAllEffects()
|
||||
return super.finishUsingItem(stack, world, user)
|
||||
}
|
||||
})
|
||||
|
||||
@JvmField
|
||||
val RAGE_CANDY_BAR = create("rage_candy_bar", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
|
||||
.food(FoodProperties.Builder()
|
||||
.nutrition(10)
|
||||
.saturationModifier(1.2F)
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
|
||||
.alwaysEdible()
|
||||
.build())) {
|
||||
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
|
||||
user.removeAllEffects()
|
||||
return super.finishUsingItem(stack, world, user)
|
||||
}
|
||||
})
|
||||
|
||||
@JvmField
|
||||
val LAVA_COOKIE = create("lava_cookie", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
|
||||
.food(FoodProperties.Builder()
|
||||
.nutrition(10)
|
||||
.saturationModifier(1.2F)
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
|
||||
.alwaysEdible()
|
||||
.build())) {
|
||||
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
|
||||
user.removeAllEffects()
|
||||
return super.finishUsingItem(stack, world, user)
|
||||
}
|
||||
})
|
||||
|
||||
@JvmField
|
||||
val OLD_GATEAU = create("old_gateau", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
|
||||
.food(FoodProperties.Builder()
|
||||
.nutrition(10)
|
||||
.saturationModifier(1.2F)
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
|
||||
.alwaysEdible()
|
||||
.build())) {
|
||||
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
|
||||
user.removeAllEffects()
|
||||
return super.finishUsingItem(stack, world, user)
|
||||
}
|
||||
})
|
||||
|
||||
@JvmField
|
||||
val CASTELIACONE = create("casteliacone", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
|
||||
.food(FoodProperties.Builder()
|
||||
.nutrition(10)
|
||||
.saturationModifier(1.2F)
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
|
||||
.alwaysEdible()
|
||||
.build())) {
|
||||
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
|
||||
user.removeAllEffects()
|
||||
return super.finishUsingItem(stack, world, user)
|
||||
}
|
||||
})
|
||||
|
||||
@JvmField
|
||||
val SHALOR_SABLE = create("shalor_sable", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
|
||||
.food(FoodProperties.Builder()
|
||||
.nutrition(10)
|
||||
.saturationModifier(1.2F)
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
|
||||
.alwaysEdible()
|
||||
.build())) {
|
||||
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
|
||||
user.removeAllEffects()
|
||||
return super.finishUsingItem(stack, world, user)
|
||||
}
|
||||
})
|
||||
|
||||
@JvmField
|
||||
val LUMIOSE_GALETTE = create("lumiose_galette", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
|
||||
.food(FoodProperties.Builder()
|
||||
.nutrition(10)
|
||||
.saturationModifier(1.2F)
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
|
||||
.alwaysEdible()
|
||||
.build())) {
|
||||
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
|
||||
user.removeAllEffects()
|
||||
return super.finishUsingItem(stack, world, user)
|
||||
}
|
||||
})
|
||||
|
||||
@JvmField
|
||||
val BIG_MALASADA = create("big_malasada", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
|
||||
.food(FoodProperties.Builder()
|
||||
.nutrition(10)
|
||||
.saturationModifier(1.2F)
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
|
||||
.alwaysEdible()
|
||||
.build())) {
|
||||
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
|
||||
user.removeAllEffects()
|
||||
return super.finishUsingItem(stack, world, user)
|
||||
}
|
||||
})
|
||||
|
||||
/*@JvmField // todo see what we are doing for these (are there different kinds?)
|
||||
val CURRY = create("curry", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
|
||||
.food(FoodProperties.Builder()
|
||||
.nutrition(10)
|
||||
.saturationModifier(1.2F)
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
|
||||
.alwaysEdible()
|
||||
.usingConvertsTo(Items.BOWL)
|
||||
.build())) {
|
||||
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
|
||||
user.removeAllEffects()
|
||||
return super.finishUsingItem(stack, world, user)
|
||||
}
|
||||
})*/
|
||||
|
||||
@JvmField
|
||||
val JUBILIFE_MUFFIN = create("jubilife_muffin", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
|
||||
.food(FoodProperties.Builder()
|
||||
.nutrition(10)
|
||||
.saturationModifier(1.2F)
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
|
||||
.alwaysEdible()
|
||||
.build())) {
|
||||
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
|
||||
user.removeAllEffects()
|
||||
return super.finishUsingItem(stack, world, user)
|
||||
}
|
||||
})
|
||||
|
||||
/*@JvmField // todo see what we are doing for these (are there different kinds?)
|
||||
val SANDWICH = create("sandwich", object : Item(Properties().stacksTo(16) // todo add all the effects and/or an item class for it for special interactions?
|
||||
.food(FoodProperties.Builder()
|
||||
.nutrition(10)
|
||||
.saturationModifier(1.2F)
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
|
||||
.alwaysEdible()
|
||||
.usingConvertsTo(Items.BOWL)
|
||||
.build())) {
|
||||
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
|
||||
user.removeAllEffects()
|
||||
return super.finishUsingItem(stack, world, user)
|
||||
}
|
||||
})*/
|
||||
|
||||
// todo we might need to wait on these for later?
|
||||
/*@JvmField
|
||||
val CHOICE_DUMPLING = noSettingsItem("choice_dumpling") // todo make a ChoiceDumpingItem class for breeding purposes
|
||||
@JvmField
|
||||
val SWAP_SNACK = noSettingsItem("swap_snack") // todo make a SwapSnackItem class for breeding purposes
|
||||
@JvmField
|
||||
val TWICE_SPICED_BEETROOT = noSettingsItem("twice_spiced_beetroot") // todo make a TwiceSpiceBeetrootItem class for breeding purposes
|
||||
*/
|
||||
@JvmField
|
||||
val POTATO_MOCHI = create("potato_mochi", object : Item(Properties().stacksTo(16)
|
||||
.food(FoodProperties.Builder()
|
||||
.nutrition(10)
|
||||
.saturationModifier(1.2F)
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
|
||||
.alwaysEdible()
|
||||
.build())) {
|
||||
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
|
||||
user.removeAllEffects()
|
||||
return super.finishUsingItem(stack, world, user)
|
||||
}
|
||||
})
|
||||
@JvmField
|
||||
val FRIED_RICE = create("fried_rice", object : Item(Properties().stacksTo(16)
|
||||
.food(FoodProperties.Builder()
|
||||
.nutrition(10)
|
||||
.saturationModifier(1.2F)
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
|
||||
.alwaysEdible()
|
||||
.build())) {
|
||||
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
|
||||
user.removeAllEffects()
|
||||
return super.finishUsingItem(stack, world, user)
|
||||
}
|
||||
})
|
||||
@JvmField
|
||||
val CANDIED_APPLE = create("candied_apple", object : Item(Properties().stacksTo(16)
|
||||
.food(FoodProperties.Builder()
|
||||
.nutrition(10)
|
||||
.saturationModifier(1.2F)
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
|
||||
.alwaysEdible()
|
||||
.build())) {
|
||||
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
|
||||
user.removeAllEffects()
|
||||
return super.finishUsingItem(stack, world, user)
|
||||
}
|
||||
})
|
||||
@JvmField
|
||||
val CANDIED_BERRY = create("candied_berry", object : Item(Properties().stacksTo(16)
|
||||
.food(FoodProperties.Builder()
|
||||
.nutrition(10)
|
||||
.saturationModifier(1.2F)
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
|
||||
.alwaysEdible()
|
||||
.build())) {
|
||||
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
|
||||
user.removeAllEffects()
|
||||
return super.finishUsingItem(stack, world, user)
|
||||
}
|
||||
})
|
||||
@JvmField
|
||||
val JELLY_DOUGHNUT = create("jelly_doughnut", object : Item(Properties().stacksTo(16)
|
||||
.food(FoodProperties.Builder()
|
||||
.nutrition(10)
|
||||
.saturationModifier(1.2F)
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
|
||||
.alwaysEdible()
|
||||
.build())) {
|
||||
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
|
||||
user.removeAllEffects()
|
||||
return super.finishUsingItem(stack, world, user)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
// todo etc?
|
||||
|
||||
//@JvmField
|
||||
//val SCATTER_BANG = this.create("scatter_bang", ScatterBangItem(Item.Settings()))
|
||||
//@JvmField
|
||||
//val STICKY_GLOB = this.create("sticky_glob", StickyGlobItem(Item.Settings()))
|
||||
|
||||
@JvmField
|
||||
val RESTORATION_TANK = blockItem("restoration_tank", CobblemonBlocks.RESTORATION_TANK)
|
||||
@JvmField
|
||||
@@ -276,7 +623,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val DISPLAY_CASE = blockItem("display_case", CobblemonBlocks.DISPLAY_CASE)
|
||||
@JvmField
|
||||
val LECTERN = blockItem("lectern", CobblemonBlocks.LECTERN)
|
||||
val INCENSE_SWEET = blockItem("incense_sweet", CobblemonBlocks.INCENSE_SWEET)
|
||||
|
||||
|
||||
// Evolution items
|
||||
@JvmField val LINK_CABLE = create("link_cable", LinkCableItem())
|
||||
@@ -293,20 +641,21 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField val REAPER_CLOTH = noSettingsItem("reaper_cloth")
|
||||
@JvmField val PRISM_SCALE = noSettingsItem("prism_scale")
|
||||
@JvmField val SACHET = noSettingsItem("sachet")
|
||||
@JvmField val WHIPPED_DREAM = noSettingsItem("whipped_dream")
|
||||
@JvmField val STRAWBERRY_SWEET = noSettingsItem("strawberry_sweet")
|
||||
@JvmField val LOVE_SWEET = noSettingsItem("love_sweet")
|
||||
@JvmField val BERRY_SWEET = noSettingsItem("berry_sweet")
|
||||
@JvmField val CLOVER_SWEET = noSettingsItem("clover_sweet")
|
||||
@JvmField val FLOWER_SWEET = noSettingsItem("flower_sweet")
|
||||
@JvmField val STAR_SWEET = noSettingsItem("star_sweet")
|
||||
@JvmField val RIBBON_SWEET = noSettingsItem("ribbon_sweet")
|
||||
@JvmField val WHIPPED_DREAM = create("whipped_dream", foodItem(8, 0.3f))
|
||||
@JvmField val STRAWBERRY_SWEET = create("strawberry_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val LOVE_SWEET = create("love_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val BERRY_SWEET = create("berry_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val CLOVER_SWEET = create("clover_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val FLOWER_SWEET = create("flower_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val STAR_SWEET = create("star_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val RIBBON_SWEET = create("ribbon_sweet", foodItem(6, 0.125f))
|
||||
@JvmField val CHIPPED_POT = noSettingsItem("chipped_pot")
|
||||
@JvmField val CRACKED_POT = noSettingsItem("cracked_pot")
|
||||
@JvmField val MASTERPIECE_TEACUP = noSettingsItem("masterpiece_teacup")
|
||||
@JvmField val UNREMARKABLE_TEACUP = noSettingsItem("unremarkable_teacup")
|
||||
@JvmField val SWEET_APPLE = noSettingsItem("sweet_apple")
|
||||
@JvmField val TART_APPLE = noSettingsItem("tart_apple")
|
||||
@JvmField val SWEET_APPLE = create("sweet_apple", foodItem(4, 0.3f))
|
||||
@JvmField val TART_APPLE = create("tart_apple", foodItem(4, 0.3f))
|
||||
@JvmField val SYRUPY_APPLE = create("syrupy_apple", foodItem(4, 0.3f))
|
||||
@JvmField val GALARICA_CUFF = noSettingsItem("galarica_cuff")
|
||||
@JvmField val GALARICA_WREATH = noSettingsItem("galarica_wreath")
|
||||
@JvmField val BLACK_AUGURITE = noSettingsItem("black_augurite")
|
||||
@@ -420,6 +769,20 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val ZINC = create("zinc", VitaminItem(Stats.SPECIAL_DEFENCE))
|
||||
@JvmField
|
||||
val HEALTH_MOCHI = create("health_mochi", MochiItem(Stats.HP))
|
||||
@JvmField
|
||||
val MUSCLE_MOCHI = create("muscle_mochi", MochiItem(Stats.ATTACK))
|
||||
@JvmField
|
||||
val RESIST_MOCHI = create("resist_mochi", MochiItem(Stats.DEFENCE))
|
||||
@JvmField
|
||||
val GENIUS_MOCHI = create("genius_mochi", MochiItem(Stats.SPECIAL_ATTACK))
|
||||
@JvmField
|
||||
val CLEVER_MOCHI = create("clever_mochi", MochiItem(Stats.SPECIAL_DEFENCE))
|
||||
@JvmField
|
||||
val SWIFT_MOCHI = create("swift_mochi", MochiItem(Stats.SPEED))
|
||||
@JvmField
|
||||
val FRESH_START_MOCHI = create("fresh_start_mochi", FreshStartMochiItem())
|
||||
@JvmField
|
||||
val GENIUS_FEATHER = create("genius_feather", FeatherItem(Stats.SPECIAL_ATTACK))
|
||||
@JvmField
|
||||
val SWIFT_FEATHER = create("swift_feather", FeatherItem(Stats.SPEED))
|
||||
@@ -1267,6 +1630,18 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
}
|
||||
)
|
||||
|
||||
private fun campfirePotItem(block: Block, type: String): CampfirePotItem {
|
||||
val item = create("campfire_pot_${type}", CampfirePotItem(block))
|
||||
campfire_pots.add(item)
|
||||
return item
|
||||
}
|
||||
|
||||
private fun aprijuiceItem(type: Apricorn): AprijuiceItem {
|
||||
val item = create("aprijuice_${type.name.lowercase()}", AprijuiceItem(type))
|
||||
aprijuices.add(item)
|
||||
return item
|
||||
}
|
||||
|
||||
private fun heldItem(name: String, remappedName: String? = null): CobblemonItem = create(
|
||||
name,
|
||||
CobblemonItem(Item.Properties()).also {
|
||||
@@ -1326,6 +1701,21 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
return item
|
||||
}
|
||||
|
||||
private fun saccharineSaplingItem(name: String, saccharineSaplingItem: SaccharineSaplingItem): SaccharineSaplingItem {
|
||||
val finalName = "saccharine_sapling"
|
||||
val item = this.create(finalName, saccharineSaplingItem)
|
||||
compostable(item, .65f)
|
||||
return item
|
||||
}
|
||||
|
||||
private fun bugwortItem(name: String, bugwortItem: BugwortItem): BugwortItem {
|
||||
val finalName = "bugwort"
|
||||
val item = this.create(finalName, bugwortItem)
|
||||
compostable(item, .65f)
|
||||
return item
|
||||
}
|
||||
|
||||
|
||||
private fun mintSeed(name: String, mintBlock: MintBlock): Item {
|
||||
val finalName = "${name}_mint_seeds"
|
||||
val item = this.blockItem(finalName, mintBlock)
|
||||
@@ -1358,4 +1748,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
return createdItem
|
||||
}
|
||||
|
||||
private fun foodItem(nutrition: Int, saturationModifier: Float): Item {
|
||||
return Item(Item.Properties().food(FoodProperties.Builder().nutrition(nutrition).saturationModifier(saturationModifier).build()))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
|
||||
import com.cobblemon.mod.common.block.campfirepot.CookingPotMenu
|
||||
import com.cobblemon.mod.common.client.gui.cookingpot.CookingPotScreen
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import net.minecraft.client.gui.screens.MenuScreens
|
||||
import net.minecraft.core.Registry
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.resources.ResourceKey
|
||||
import net.minecraft.world.inventory.MenuType
|
||||
|
||||
object CobblemonMenuType : PlatformRegistry<Registry<MenuType<*>>, ResourceKey<Registry<MenuType<*>>>, MenuType<*>>() {
|
||||
|
||||
val COOKING_POT = MenuType.register("cooking_pot", ::CookingPotMenu)
|
||||
|
||||
override val registry: Registry<MenuType<*>>
|
||||
get() = BuiltInRegistries.MENU
|
||||
override val resourceKey: ResourceKey<Registry<MenuType<*>>>
|
||||
get() = Registries.MENU
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import com.cobblemon.mod.common.client.net.battle.*
|
||||
import com.cobblemon.mod.common.client.net.callback.move.OpenMoveCallbackHandler
|
||||
import com.cobblemon.mod.common.client.net.callback.party.OpenPartyCallbackHandler
|
||||
import com.cobblemon.mod.common.client.net.callback.partymove.OpenPartyMoveCallbackHandler
|
||||
import com.cobblemon.mod.common.client.net.cooking.ToggleCookingPotLidHandler
|
||||
import com.cobblemon.mod.common.client.net.data.DataRegistrySyncPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.data.UnlockReloadPacketHandler
|
||||
import com.cobblemon.mod.common.client.net.dialogue.DialogueClosedHandler
|
||||
@@ -67,6 +68,8 @@ import com.cobblemon.mod.common.net.messages.client.battle.*
|
||||
import com.cobblemon.mod.common.net.messages.client.callback.OpenMoveCallbackPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyCallbackPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.callback.OpenPartyMoveCallbackPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.cooking.SeasoningRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.cooking.ToggleCookingPotLidPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.data.*
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueClosedPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.dialogue.DialogueOpenedPacket
|
||||
@@ -142,6 +145,8 @@ import com.cobblemon.mod.common.net.messages.server.callback.party.PartyPokemonS
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.party.PartySelectCancelledPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.partymove.PartyMoveSelectCancelledPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.partymove.PartyPokemonMoveSelectedPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.debug.ServerboundUpdateRidingStatRangePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.debug.ServerboundUpdateRidingStatsPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.dialogue.EscapeDialoguePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.dialogue.InputToDialoguePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.npc.SaveNPCPacket
|
||||
@@ -186,6 +191,8 @@ import com.cobblemon.mod.common.net.serverhandling.callback.party.PartyPokemonSe
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.party.PartySelectCancelledHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.partymove.PartyMoveSelectCancelledHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.partymove.PartyPokemonMoveSelectedHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.debug.ServerboundUpdateRidingStatRangeHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.debug.ServerboundUpdateRidingStatsHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.dialogue.EscapeDialogueHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.dialogue.InputToDialogueHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.evolution.AcceptEvolutionHandler
|
||||
@@ -281,6 +288,7 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(MarksUpdatePacket.ID, MarksUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarksPotentialUpdatePacket.ID, MarksPotentialUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarkingsUpdatePacket.ID, MarkingsUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(RideBoostsUpdatePacket.ID, RideBoostsUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
|
||||
// Evolution start
|
||||
list.add(PacketRegisterInfo(AddEvolutionPacket.ID, AddEvolutionPacket::decode, PokemonUpdatePacketHandler()))
|
||||
@@ -370,7 +378,8 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(ScriptRegistrySyncPacket.ID, ScriptRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(PokedexDexSyncPacket.ID, PokedexDexSyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(DexEntrySyncPacket.ID, DexEntrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(FishingBaitRegistrySyncPacket.ID, FishingBaitRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(SpawnBaitRegistrySyncPacket.ID, SpawnBaitRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(SeasoningRegistrySyncPacket.ID, SeasoningRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(FlowRegistrySyncPacket.ID, FlowRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(CosmeticItemAssignmentSyncPacket.ID, CosmeticItemAssignmentSyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarkRegistrySyncPacket.ID, MarkRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
@@ -536,6 +545,11 @@ object CobblemonNetwork {
|
||||
// Riding packet(s)
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateOrientationPacket.ID, ServerboundUpdateOrientationPacket::decode, OrientationPacketHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatePacket.ID, ServerboundUpdateRidingStatePacket::decode, ServerboundUpdateRidingStateHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatsPacket.ID, ServerboundUpdateRidingStatsPacket::decode, ServerboundUpdateRidingStatsHandler))
|
||||
list.add(PacketRegisterInfo(ServerboundUpdateRidingStatRangePacket.ID, ServerboundUpdateRidingStatRangePacket::decode, ServerboundUpdateRidingStatRangeHandler))
|
||||
|
||||
// Cooking
|
||||
list.add(PacketRegisterInfo(ToggleCookingPotLidPacket.ID, ToggleCookingPotLidPacket::decode, ToggleCookingPotLidHandler))
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
+14
-2
@@ -19,7 +19,7 @@ import net.minecraft.world.entity.ai.village.poi.PoiType
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
|
||||
object CobblemonVillagerPoiTypes: PlatformRegistry<Registry<PoiType>, ResourceKey<Registry<PoiType>>, PoiType>() {
|
||||
object CobblemonPoiTypes: PlatformRegistry<Registry<PoiType>, ResourceKey<Registry<PoiType>>, PoiType>() {
|
||||
override val registry: Registry<PoiType> = BuiltInRegistries.POINT_OF_INTEREST_TYPE
|
||||
override val resourceKey: ResourceKey<Registry<PoiType>> = Registries.POINT_OF_INTEREST_TYPE
|
||||
|
||||
@@ -27,8 +27,20 @@ object CobblemonVillagerPoiTypes: PlatformRegistry<Registry<PoiType>, ResourceKe
|
||||
val NURSE_KEY: ResourceKey<PoiType> = createKey("nurse")
|
||||
@JvmField
|
||||
val NURSE = create(NURSE_KEY.location().path, PoiType(getBlockStates(CobblemonBlocks.HEALING_MACHINE), 1, 1))
|
||||
@JvmField
|
||||
val LURE_CAKE_KEY: ResourceKey<PoiType> = createKey("lure_cake")
|
||||
@JvmField
|
||||
val LURE_CAKE = create(LURE_CAKE_KEY.location().path, PoiType(getBlockStates(CobblemonBlocks.LURE_CAKE), 0, 1))
|
||||
@JvmField
|
||||
val SACCHARINE_HONEY_LOG_KEY: ResourceKey<PoiType> = createKey("saccharine_honey_log")
|
||||
@JvmField
|
||||
val SACCHARINE_HONEY_LOG = create(SACCHARINE_HONEY_LOG_KEY.location().path, PoiType(getBlockStates(CobblemonBlocks.SACCHARINE_HONEY_LOG), 0, 1))
|
||||
@JvmField
|
||||
val INCENSE_SWEET_KEY: ResourceKey<PoiType> = createKey("saccharine_honey_log")
|
||||
@JvmField
|
||||
val INCENSE_SWEET = create(INCENSE_SWEET_KEY.location().path, PoiType(getBlockStates(CobblemonBlocks.INCENSE_SWEET), 0, 1))
|
||||
|
||||
private fun createKey(string: String): ResourceKey<PoiType> = ResourceKey.create(Registries.POINT_OF_INTEREST_TYPE, cobblemonResource(string))
|
||||
|
||||
private fun getBlockStates(block: Block): Set<BlockState> = ImmutableSet.copyOf(block.stateDefinition.possibleStates)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
import net.minecraft.client.RecipeBookCategories
|
||||
|
||||
enum class CobblemonRecipeCategories {
|
||||
|
||||
COOKING_POT_SEARCH("COOKING_POT_SEARCH"),
|
||||
COOKING_POT_FOODS("COOKING_POT_FOODS"),
|
||||
COOKING_POT_MEDICINES("COOKING_POT_MEDICINES"),
|
||||
COOKING_POT_BAITS("COOKING_POT_BAITS"),
|
||||
COOKING_POT_MISC("COOKING_POT_MISC");
|
||||
|
||||
companion object {
|
||||
val customAggregateCategories: Map<RecipeBookCategories, List<RecipeBookCategories>> = mapOf(
|
||||
COOKING_POT_SEARCH.toVanillaCategory() to listOf(
|
||||
COOKING_POT_FOODS.toVanillaCategory(), COOKING_POT_MISC.toVanillaCategory(), COOKING_POT_MEDICINES.toVanillaCategory(), COOKING_POT_BAITS.toVanillaCategory()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
var id: String
|
||||
|
||||
constructor(id: String) {
|
||||
this.id = id
|
||||
}
|
||||
|
||||
fun toVanillaCategory(): RecipeBookCategories {
|
||||
return RecipeBookCategories.valueOf(this.id)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
|
||||
import com.cobblemon.mod.common.item.crafting.CookingPotRecipe
|
||||
import com.cobblemon.mod.common.item.crafting.CookingPotShapelessRecipe
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import net.minecraft.core.Registry
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.resources.ResourceKey
|
||||
import net.minecraft.world.item.crafting.Recipe
|
||||
import net.minecraft.world.item.crafting.RecipeSerializer
|
||||
|
||||
object CobblemonRecipeSerializers : PlatformRegistry<Registry<RecipeSerializer<*>>, ResourceKey<Registry<RecipeSerializer<*>>>, RecipeSerializer<*>>() {
|
||||
|
||||
val COOKING_POT_COOKING: RecipeSerializer<*> = register("cobblemon:cooking_pot", CookingPotRecipe.Serializer())
|
||||
val COOKING_POT_SHAPELESS: RecipeSerializer<*> = register("cobblemon:cooking_pot_shapeless", CookingPotShapelessRecipe.Serializer())
|
||||
|
||||
override val registry: Registry<RecipeSerializer<*>>
|
||||
get() = BuiltInRegistries.RECIPE_SERIALIZER
|
||||
override val resourceKey: ResourceKey<Registry<RecipeSerializer<*>>>
|
||||
get() = Registries.RECIPE_SERIALIZER
|
||||
|
||||
fun <S : RecipeSerializer<T>, T : Recipe<*>> register(key: String, recipeSerializer: S): S {
|
||||
return Registry.register(BuiltInRegistries.RECIPE_SERIALIZER, key, recipeSerializer) as S
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
|
||||
import com.cobblemon.mod.common.item.crafting.CookingPotRecipe
|
||||
import com.cobblemon.mod.common.item.crafting.CookingPotShapelessRecipe
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import net.minecraft.core.Registry
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.resources.ResourceKey
|
||||
import net.minecraft.world.item.crafting.Recipe
|
||||
import net.minecraft.world.item.crafting.RecipeType
|
||||
|
||||
object CobblemonRecipeTypes : PlatformRegistry<Registry<RecipeType<*>>, ResourceKey<Registry<RecipeType<*>>>, RecipeType<*>>() {
|
||||
|
||||
val COOKING_POT_COOKING: RecipeType<CookingPotRecipe> = register("cobblemon:cooking_pot")
|
||||
val COOKING_POT_SHAPELESS: RecipeType<CookingPotShapelessRecipe> = register("cobblemon:cooking_pot_shapeless")
|
||||
|
||||
override val registry: Registry<RecipeType<*>>
|
||||
get() = BuiltInRegistries.RECIPE_TYPE
|
||||
override val resourceKey: ResourceKey<Registry<RecipeType<*>>>
|
||||
get() = Registries.RECIPE_TYPE
|
||||
|
||||
fun <T : Recipe<*>> register(identifier: String): RecipeType<T> {
|
||||
return Registry.register(
|
||||
BuiltInRegistries.RECIPE_TYPE,
|
||||
identifier,
|
||||
object : RecipeType<T> {
|
||||
override fun toString(): String {
|
||||
return identifier
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -112,6 +112,8 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
val MEDICINE_SPRAY_USE = this.create("item.medicine.spray.use")
|
||||
@JvmField
|
||||
val MEDICINE_FEATHER_USE = this.create("item.medicine.feather.use")
|
||||
@JvmField
|
||||
val MOCHI_USE = this.create("item.medicine.feather.use")
|
||||
|
||||
@JvmField
|
||||
val MULCH_PLACE = this.create("block.mulch.place")
|
||||
@@ -425,5 +427,37 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
DISPLAY_CASE_STEP
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_PLACE_CAMPFIRE = this.create("block.campfire_pot.place_campfire")
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_RETRIEVE = this.create("block.campfire_pot.retrieve")
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_OPEN = this.create("block.campfire_pot.open")
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_CLOSE = this.create("block.campfire_pot.close")
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_USE = this.create("block.campfire_pot.use")
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_COOK = this.create("block.campfire_pot.cook")
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_CRAFT = this.create("block.campfire_pot.craft")
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_PLACE = this.create("block.campfire_pot.place")
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_BREAK = this.create("block.campfire_pot.break")
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_HIT = this.create("block.campfire_pot.hit")
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_STEP = this.create("block.campfire_pot.step")
|
||||
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_SOUNDS = SoundType(1f, 1.1f,
|
||||
CAMPFIRE_POT_BREAK,
|
||||
CAMPFIRE_POT_STEP,
|
||||
CAMPFIRE_POT_PLACE,
|
||||
CAMPFIRE_POT_HIT,
|
||||
CAMPFIRE_POT_STEP
|
||||
)
|
||||
|
||||
private fun create(name: String): SoundEvent = this.create(name, SoundEvent.createVariableRangeEvent(cobblemonResource(name)))
|
||||
}
|
||||
@@ -24,7 +24,7 @@ object CobblemonVillagerProfessions: PlatformRegistry<Registry<VillagerProfessio
|
||||
override val resourceKey: ResourceKey<Registry<VillagerProfession>> = Registries.VILLAGER_PROFESSION
|
||||
|
||||
@JvmField
|
||||
val NURSE = profession(CobblemonVillagerPoiTypes.NURSE_KEY, CobblemonSounds.VILLAGER_WORK_NURSE)
|
||||
val NURSE = profession(CobblemonPoiTypes.NURSE_KEY, CobblemonSounds.VILLAGER_WORK_NURSE)
|
||||
|
||||
/**
|
||||
* Register a villager profession texture override for Cobblemon villagers of the given [VillagerProfession] for specified names.
|
||||
|
||||
+2
-2
@@ -20,8 +20,8 @@ import net.minecraft.resources.ResourceLocation
|
||||
class CastPokeRodContext(val baitId: ResourceLocation)
|
||||
|
||||
class CastPokeRodCriterionCondition(
|
||||
playerCtx: Optional<ContextAwarePredicate>,
|
||||
val baitId: String
|
||||
playerCtx: Optional<ContextAwarePredicate>,
|
||||
val baitId: String
|
||||
): SimpleCriterionCondition<CastPokeRodContext>(playerCtx) {
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -10,6 +10,7 @@ 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
|
||||
@@ -27,15 +28,43 @@ import net.minecraft.world.level.material.MapColor
|
||||
* @author Licious
|
||||
* @since October 29th, 2022
|
||||
*/
|
||||
enum class Apricorn : StringRepresentable {
|
||||
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 {
|
||||
|
||||
BLACK,
|
||||
BLUE,
|
||||
GREEN,
|
||||
PINK,
|
||||
RED,
|
||||
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
|
||||
)
|
||||
),
|
||||
WHITE,
|
||||
YELLOW;
|
||||
YELLOW(
|
||||
mapOf(
|
||||
Flavour.SOUR to true,
|
||||
Flavour.DRY to false
|
||||
)
|
||||
);
|
||||
|
||||
fun item(): ApricornItem = when(this) {
|
||||
BLACK -> CobblemonItems.BLACK_APRICORN
|
||||
|
||||
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.api.berry
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.api.berry.spawncondition.BerrySpawnCondition
|
||||
import com.cobblemon.mod.common.api.cooking.Flavour
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.berry.BerryYieldCalculationEvent
|
||||
import com.cobblemon.mod.common.api.mulch.MulchVariant
|
||||
@@ -20,16 +21,10 @@ import com.cobblemon.mod.common.item.berry.BerryItem
|
||||
import com.cobblemon.mod.common.pokemon.Nature
|
||||
import com.cobblemon.mod.common.util.readBox
|
||||
import com.cobblemon.mod.common.util.readEnumConstant
|
||||
import com.cobblemon.mod.common.util.readEnumSet
|
||||
import com.cobblemon.mod.common.util.readIdentifier
|
||||
import com.cobblemon.mod.common.util.readList
|
||||
import com.cobblemon.mod.common.util.readMap
|
||||
import com.cobblemon.mod.common.util.writeBox
|
||||
import com.cobblemon.mod.common.util.writeCollection
|
||||
import com.cobblemon.mod.common.util.writeEnumConstant
|
||||
import com.cobblemon.mod.common.util.writeEnumSet
|
||||
import com.cobblemon.mod.common.util.writeIdentifier
|
||||
import com.cobblemon.mod.common.util.writeMap
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
@@ -38,6 +33,7 @@ import java.util.EnumSet
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.tags.TagKey
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.item.DyeColor
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.biome.Biome
|
||||
import net.minecraft.world.level.block.Block
|
||||
@@ -61,7 +57,7 @@ import net.minecraft.world.phys.shapes.VoxelShape
|
||||
* @property growthPoints A collection of [GrowthPoint]s for the berry flowers and fruit.
|
||||
* @property sproutShapeBoxes A collection of [Box]es that make up the tree [VoxelShape] during the sprouting stages.
|
||||
* @property matureShapeBoxes A collection of [Box]es that make up the tree [VoxelShape] during the mature stages.
|
||||
* @property flavors The [Flavor] values.
|
||||
* @property flavours The [com.cobblemon.mod.common.api.cooking.Flavour] values.
|
||||
* @property tintIndexes Determines tints at specific indexes if any.
|
||||
* @property flowerModelIdentifier The [ResourceLocation] for the model of the berry in flower form.
|
||||
* @property flowerTexture The [ResourceLocation] for the texture of the berry in flower form. This is resolved into a [ModelPart] on the client.
|
||||
@@ -87,7 +83,10 @@ class Berry(
|
||||
private val sproutShapeBoxes: Collection<AABB>,
|
||||
@SerializedName("matureShape")
|
||||
private val matureShapeBoxes: Collection<AABB>,
|
||||
private val flavors: Map<Flavor, Int>,
|
||||
@SerializedName("flavours", alternate = ["flavor"])
|
||||
val flavours: Map<Flavour, Int>,
|
||||
@SerializedName("colour", alternate = ["color"])
|
||||
val colour: DyeColor,
|
||||
val tintIndexes: Map<Int, Color>,
|
||||
@SerializedName("flowerModel")
|
||||
val flowerModelIdentifier: ResourceLocation,
|
||||
@@ -144,13 +143,13 @@ class Berry(
|
||||
/**
|
||||
* Query the value of a certain flavor.
|
||||
*
|
||||
* @param flavor The [Flavor] being queried.
|
||||
* @param flavour The [Flavour] being queried.
|
||||
* @return The value if any or 0.
|
||||
*/
|
||||
fun flavor(flavor: Flavor): Int = this.flavors[flavor] ?: 0
|
||||
fun flavor(flavour: Flavour): Int = this.flavours[flavour] ?: 0
|
||||
|
||||
fun dislikedBy(nature: Nature): Boolean {
|
||||
val dislikedFlavor = nature.dislikedFlavor ?: return false
|
||||
val dislikedFlavor = nature.dislikedFlavour ?: return false
|
||||
return flavor(dislikedFlavor) > 0
|
||||
}
|
||||
|
||||
@@ -281,7 +280,8 @@ class Berry(
|
||||
buffer.writeCollection(this.matureShapeBoxes) { writer, value ->
|
||||
writer.writeBox(value)
|
||||
}
|
||||
buffer.writeMap(this.flavors, { writer, key -> writer.writeEnumConstant(key) }, { writer, value -> writer.writeInt(value) })
|
||||
buffer.writeMap(this.flavours, { writer, key -> writer.writeEnumConstant(key) }, { writer, value -> writer.writeInt(value) })
|
||||
buffer.writeEnumConstant(colour)
|
||||
buffer.writeMap(this.tintIndexes, { writer, key -> writer.writeInt(key) }, { writer, value -> writer.writeInt(value.rgb) })
|
||||
buffer.writeIdentifier(this.flowerModelIdentifier)
|
||||
buffer.writeIdentifier(this.flowerTexture)
|
||||
@@ -353,7 +353,8 @@ class Berry(
|
||||
val mutations = buffer.readMap({ reader -> reader.readIdentifier() }, { reader -> reader.readIdentifier() })
|
||||
val sproutShapeBoxes = buffer.readList { it.readBox() }
|
||||
val matureShapeBoxes = buffer.readList { it.readBox() }
|
||||
val flavors = buffer.readMap({ reader -> reader.readEnumConstant(Flavor::class.java) }, { reader -> reader.readInt() })
|
||||
val flavors = buffer.readMap({ reader -> reader.readEnumConstant(Flavour::class.java) }, { reader -> reader.readInt() })
|
||||
val colour = buffer.readEnumConstant(DyeColor::class.java)
|
||||
val tintIndexes = buffer.readMap({ reader -> reader.readInt() }, { reader -> Color(reader.readInt()) })
|
||||
val flowerModelIdentifier = buffer.readIdentifier()
|
||||
val flowerTexture = buffer.readIdentifier()
|
||||
@@ -361,7 +362,7 @@ class Berry(
|
||||
val fruitTexture = buffer.readIdentifier()
|
||||
val stageOneYPos = GrowthPoint(Vec3(buffer.readDouble(), buffer.readDouble(), buffer.readDouble()), Vec3(buffer.readDouble(), buffer.readDouble(), buffer.readDouble()))
|
||||
val boneMealChance = buffer.readFloat()
|
||||
return Berry(identifier, baseYield, emptyList(), growthTime, refreshRate, favMulchs, emptySet(), emptyList(), growthPoints, randomizedGrowthPoints, mutations, sproutShapeBoxes, matureShapeBoxes, flavors, tintIndexes, flowerModelIdentifier, flowerTexture, fruitModelIdentifier, fruitTexture, stageOneYPos, 0F, boneMealChance)
|
||||
return Berry(identifier, baseYield, emptyList(), growthTime, refreshRate, favMulchs, emptySet(), emptyList(), growthPoints, randomizedGrowthPoints, mutations, sproutShapeBoxes, matureShapeBoxes, flavors, colour, tintIndexes, flowerModelIdentifier, flowerTexture, fruitModelIdentifier, fruitTexture, stageOneYPos, 0F, boneMealChance)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.berry
|
||||
|
||||
/**
|
||||
* Represents the different flavors associated with berries and other Pokémon consumables.
|
||||
* See the [Bulbapedia](https://bulbapedia.bulbagarden.net/wiki/Flavor) article for more information.
|
||||
*
|
||||
* @author Licious
|
||||
* @since November 28th, 2022
|
||||
*/
|
||||
enum class Flavor(val colour: Int) {
|
||||
SPICY(0x00FF00),
|
||||
DRY(0xFF0000),
|
||||
SWEET(0x0000FF),
|
||||
BITTER(0xFFFF00),
|
||||
SOUR(0xFF00FF);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.cooking
|
||||
|
||||
import net.minecraft.ChatFormatting
|
||||
import net.minecraft.util.StringRepresentable
|
||||
|
||||
/**
|
||||
* Represents the different flavors associated with berries and other Pokémon consumables.
|
||||
* See the [Bulbapedia](https://bulbapedia.bulbagarden.net/wiki/Flavor) article for more information.
|
||||
*
|
||||
* @author Licious
|
||||
* @since November 28th, 2022
|
||||
*/
|
||||
enum class Flavour(val colour: Int, val chatFormatting: ChatFormatting): StringRepresentable {
|
||||
SPICY(0x00FF00, ChatFormatting.RED),
|
||||
DRY(0xFF0000, ChatFormatting.DARK_AQUA),
|
||||
SWEET(0x0000FF, ChatFormatting.LIGHT_PURPLE),
|
||||
BITTER(0xFFFF00, ChatFormatting.GREEN),
|
||||
SOUR(0xFF00FF, ChatFormatting.YELLOW);
|
||||
|
||||
override fun getSerializedName() = name
|
||||
companion object {
|
||||
val CODEC = StringRepresentable.fromEnum<Flavour> { Flavour.entries.toTypedArray() }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.cooking
|
||||
|
||||
import net.minecraft.util.FastColor
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
||||
private val colourMap = mapOf(
|
||||
Flavour.SPICY to 0xFEB37D,
|
||||
Flavour.DRY to 0x8AE9FC,
|
||||
Flavour.SWEET to 0xFFBEED,
|
||||
Flavour.BITTER to 0x9EED8F,
|
||||
Flavour.SOUR to 0xFCF38A
|
||||
)
|
||||
|
||||
private val bubbleColourMap = mapOf(
|
||||
Flavour.SPICY to 0xFFD9AD,
|
||||
Flavour.DRY to 0xBCF8FE,
|
||||
Flavour.SWEET to 0xFEE3F9,
|
||||
Flavour.BITTER to 0xC8F7BC,
|
||||
Flavour.SOUR to 0xFDFAB8
|
||||
)
|
||||
|
||||
fun getColourMixFromSeasonings(seasonings: List<ItemStack>, forBubbles: Boolean = false): Int? {
|
||||
val flavors = seasonings
|
||||
.flatMap { Seasonings.getFlavoursFromItemStack(it).entries }
|
||||
.groupingBy { it.key }
|
||||
.fold(0) { acc, entry -> acc + entry.value }
|
||||
|
||||
val maxFlavorValue = flavors.values.maxOrNull()
|
||||
val dominantFlavors = flavors.filter { it.value == maxFlavorValue }.map { it.key }
|
||||
|
||||
return getColourMixFromFlavours(dominantFlavors, forBubbles)
|
||||
}
|
||||
|
||||
fun getColourMixFromFlavours(dominantFlavours: List<Flavour>, forBubbles: Boolean = false): Int? {
|
||||
val colors =
|
||||
dominantFlavours.mapNotNull { if (forBubbles) bubbleColourMap[it] else colourMap[it] }
|
||||
.map { FastColor.ARGB32.opaque(it) }
|
||||
|
||||
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
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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.cooking
|
||||
|
||||
import com.cobblemon.mod.common.api.conditional.ITEM_REGISTRY_LIKE_CODEC
|
||||
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
|
||||
import com.cobblemon.mod.common.api.conditional.RegistryLikeIdentifierCondition
|
||||
import com.cobblemon.mod.common.api.fishing.SpawnBait
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import io.netty.buffer.ByteBuf
|
||||
import net.minecraft.network.codec.ByteBufCodecs
|
||||
import net.minecraft.network.codec.StreamCodec
|
||||
import net.minecraft.world.item.DyeColor
|
||||
import net.minecraft.world.item.Item
|
||||
|
||||
data class Seasoning(
|
||||
val ingredient: RegistryLikeCondition<Item>,
|
||||
@SerializedName("flavours", alternate = ["flavors"])
|
||||
val flavours: Map<Flavour, Int>,
|
||||
@SerializedName("colour", alternate = ["color"])
|
||||
val colour: DyeColor,
|
||||
@SerializedName("baitEffects")
|
||||
val baitEffects: List<SpawnBait.Effect> = emptyList()
|
||||
) {
|
||||
companion object {
|
||||
val CODEC: Codec<Seasoning> = RecordCodecBuilder.create { builder ->
|
||||
builder.group(
|
||||
ITEM_REGISTRY_LIKE_CODEC.fieldOf("ingredient").forGetter { it.ingredient },
|
||||
Codec.unboundedMap(Flavour.CODEC, Codec.INT).fieldOf("flavours").forGetter { it.flavours }, // Use map codec
|
||||
DyeColor.CODEC.fieldOf("colour").forGetter { it.colour },
|
||||
SpawnBait.Effect.CODEC.listOf().optionalFieldOf("baitEffects", emptyList()).forGetter { it.baitEffects }
|
||||
).apply(builder, ::Seasoning)
|
||||
}
|
||||
|
||||
val STREAM_CODEC: StreamCodec<ByteBuf, Seasoning> = ByteBufCodecs.fromCodec(CODEC)
|
||||
|
||||
val BLANK_SEASONING = Seasoning(
|
||||
ingredient = RegistryLikeIdentifierCondition<Item>(cobblemonResource("blank")),
|
||||
flavours = Flavour.entries.associate { it to 0 },
|
||||
colour = DyeColor.WHITE,
|
||||
baitEffects = emptyList()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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.cooking
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonItemComponents
|
||||
import com.cobblemon.mod.common.api.berry.Berries
|
||||
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
|
||||
import com.cobblemon.mod.common.api.conditional.RegistryLikeIdentifierCondition
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.fishing.SpawnBait
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.net.messages.client.cooking.SeasoningRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ItemLikeConditionAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.server.packs.PackType
|
||||
import net.minecraft.world.item.DyeColor
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
||||
object Seasonings : JsonDataRegistry<Seasoning> {
|
||||
override val id = cobblemonResource("seasonings")
|
||||
override val type = PackType.SERVER_DATA
|
||||
override val observable = SimpleObservable<Seasonings>()
|
||||
override val typeToken: TypeToken<Seasoning> = TypeToken.get(Seasoning::class.java)
|
||||
override val resourcePath = "seasonings"
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Item::class.java).type, ItemLikeConditionAdapter)
|
||||
.setPrettyPrinting()
|
||||
.create()
|
||||
|
||||
val seasonings = mutableListOf<Seasoning>()
|
||||
|
||||
val BLANK_SEASONING = Seasoning(
|
||||
ingredient = RegistryLikeIdentifierCondition<Item>(cobblemonResource("blank")),
|
||||
flavours = emptyMap(),
|
||||
colour = DyeColor.WHITE
|
||||
)
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
SeasoningRegistrySyncPacket(seasonings.toList()).sendToPlayer(player)
|
||||
}
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, Seasoning>) {
|
||||
// this needs to sideload the berry data so we don't get duplicate JSONs.
|
||||
val finalData = Berries.all().associate {
|
||||
it.identifier to Seasoning(
|
||||
ingredient = RegistryLikeIdentifierCondition(it.identifier),
|
||||
flavours = it.flavours.toMap(),
|
||||
colour = it.colour
|
||||
)
|
||||
}.toMutableMap()
|
||||
finalData.putAll(data)
|
||||
seasonings.addAll(finalData.values)
|
||||
}
|
||||
|
||||
fun reloadEntries(seasonings: Collection<Seasoning>) {
|
||||
this.seasonings.clear()
|
||||
this.seasonings.addAll(seasonings)
|
||||
}
|
||||
|
||||
fun getFlavoursFromItemStack(stack: ItemStack): Map<Flavour, Int> {
|
||||
val holder = stack.itemHolder
|
||||
val seasoning = seasonings.find { it.ingredient.fits(holder) } ?: BLANK_SEASONING
|
||||
val inherentFlavours = stack.get(CobblemonItemComponents.FLAVOUR)?.flavours ?: emptyMap()
|
||||
|
||||
return seasoning.flavours.mapValues { (flavour, value) -> inherentFlavours.getOrDefault(flavour, 0) + value }
|
||||
}
|
||||
|
||||
fun getBaitEffectsFromItemStack(stack: ItemStack): List<SpawnBait.Effect> {
|
||||
return getFromItemStack(stack)?.baitEffects ?: emptyList()
|
||||
}
|
||||
|
||||
fun getFromItemStack(stack: ItemStack): Seasoning? {
|
||||
val holder = stack.itemHolder
|
||||
return seasonings.find { it.ingredient.fits(holder) }
|
||||
}
|
||||
|
||||
fun isSeasoning(stack: ItemStack) = getFromItemStack(stack) != null
|
||||
}
|
||||
@@ -255,6 +255,11 @@ object CobblemonEvents {
|
||||
@JvmField
|
||||
val BAIT_EFFECT_REGISTRATION = EventObservable<BaitEffectFunctionRegistryEvent>()
|
||||
|
||||
// Baits and Lures
|
||||
@JvmField
|
||||
val BAIT_SPAWN_POKEMON_MODIFY = EventObservable<BaitSpawnPokemonEvent.Modify>()
|
||||
|
||||
|
||||
@JvmField
|
||||
val COLLECT_EGG = CancelableObservable<CollectEggEvent>()
|
||||
@JvmField
|
||||
|
||||
+5
-5
@@ -8,19 +8,19 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.events.fishing
|
||||
|
||||
import com.cobblemon.mod.common.api.fishing.FishingBait
|
||||
import com.cobblemon.mod.common.api.fishing.SpawnBait
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
/**
|
||||
* Event to register code-based functions for bait effects.
|
||||
* @see FishingBait.Effect
|
||||
* @see FishingBait.Effects
|
||||
* @see SpawnBait.Effect
|
||||
* @see SpawnBait.Effects
|
||||
*/
|
||||
class BaitEffectFunctionRegistryEvent {
|
||||
val functions = mutableMapOf<ResourceLocation, (PokemonEntity, FishingBait.Effect) -> Unit>()
|
||||
val functions = mutableMapOf<ResourceLocation, (PokemonEntity, SpawnBait.Effect) -> Unit>()
|
||||
|
||||
fun registerFunction(id: ResourceLocation, function: (PokemonEntity, FishingBait.Effect) -> Unit) {
|
||||
fun registerFunction(id: ResourceLocation, function: (PokemonEntity, SpawnBait.Effect) -> Unit) {
|
||||
functions[id] = function
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.fishing
|
||||
|
||||
import com.cobblemon.mod.common.api.events.Cancelable
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.entity.fishing.PokeRodFishingBobberEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
||||
/**
|
||||
* Event that is fired when a Pokemon is spawned by a bobber.
|
||||
*/
|
||||
interface BaitSpawnPokemonEvent {
|
||||
|
||||
/**
|
||||
* Event that is fired before a Pokemon is spawned by a bobber.
|
||||
* @param bobber The PokeRodFishingBobberEntity that is spawning the Pokemon.
|
||||
* @param chosenBucket The bucket that is chosen.
|
||||
* @param rod The ItemStack of the rod that the bobber is attached to.
|
||||
*/
|
||||
data class Pre(
|
||||
val bobber: PokeRodFishingBobberEntity, // todo replace this with the bait entity
|
||||
val chosenBucket: SpawnBucket,
|
||||
val rod: ItemStack
|
||||
) : Cancelable(), BobberSpawnPokemonEvent
|
||||
|
||||
/**
|
||||
* Event that is fired when a Pokemon is modified before it is spawned by a bobber.
|
||||
* @param chosenBucket The bucket that is chosen.
|
||||
* @param rod The ItemStack of the rod that the bobber is attached to.
|
||||
* @param pokemon The Pokemon that is modified.
|
||||
*/
|
||||
data class Modify(
|
||||
val chosenBucket: SpawnBucket,
|
||||
val rod: ItemStack,
|
||||
val pokemon: PokemonEntity
|
||||
) : BobberSpawnPokemonEvent
|
||||
|
||||
/**
|
||||
* Event that is fired after a Pokemon is spawned by a bobber.
|
||||
* @param bobber The PokeRodFishingBobberEntity that is spawning the Pokemon.
|
||||
* @param chosenBucket The bucket that is chosen.
|
||||
* @param bait The ItemStack of the bait that is set on the rod.
|
||||
* @param pokemon The Pokemon that is spawned.
|
||||
*/
|
||||
data class Post(
|
||||
val bobber: PokeRodFishingBobberEntity,
|
||||
val chosenBucket: SpawnBucket,
|
||||
val bait: ItemStack,
|
||||
val pokemon: PokemonEntity
|
||||
) : BobberSpawnPokemonEvent
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.fishing
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonItemComponents
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.net.messages.client.data.FishingBaitRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.server.packs.PackType
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
||||
object FishingBaits : JsonDataRegistry<FishingBait>{
|
||||
override val id = cobblemonResource("fishing_baits")
|
||||
override val type = PackType.SERVER_DATA
|
||||
override val observable = SimpleObservable<FishingBaits>()
|
||||
override val typeToken: TypeToken<FishingBait> = TypeToken.get(FishingBait::class.java)
|
||||
override val resourcePath = "fishing_baits"
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
|
||||
.setPrettyPrinting()
|
||||
.create()
|
||||
|
||||
private val itemMap = mutableMapOf<ResourceLocation, FishingBait>()
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
FishingBaitRegistrySyncPacket(this.itemMap.values.toList()).sendToPlayer(player)
|
||||
}
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, FishingBait>) {
|
||||
itemMap.clear()
|
||||
data.forEach { id, bait ->
|
||||
itemMap[bait.item] = bait
|
||||
}
|
||||
}
|
||||
|
||||
fun getFromRodItemStack(stack: ItemStack): FishingBait? {
|
||||
return stack.components.get(CobblemonItemComponents.BAIT)?.bait
|
||||
}
|
||||
|
||||
fun getFromBaitItemStack(stack: ItemStack): FishingBait? {
|
||||
return getFromIdentifier(BuiltInRegistries.ITEM.getKey(stack.item))
|
||||
}
|
||||
|
||||
fun getFromIdentifier(identifier: ResourceLocation): FishingBait? {
|
||||
return itemMap[identifier]
|
||||
}
|
||||
|
||||
fun isFishingBait(stack: ItemStack) = itemMap.containsKey(BuiltInRegistries.ITEM.getKey(stack.item))
|
||||
|
||||
//
|
||||
//
|
||||
// fun getBaitSubcategory(item: ItemStack): String? {
|
||||
// val itemId = Registries.ITEM.getId(item.item)
|
||||
// if (itemId in itemMap.keys) {
|
||||
// return itemMap[itemId]?.subcategory
|
||||
// }
|
||||
// val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
|
||||
// if (tag != null) {
|
||||
// return tagMap[tag]?.subcategory
|
||||
// }
|
||||
// return null
|
||||
// }
|
||||
//
|
||||
// fun getBaitSuccessChance(item: ItemStack): Double? {
|
||||
// val itemId = Registries.ITEM.getId(item.item)
|
||||
// if (itemId in itemMap.keys) {
|
||||
// return itemMap[itemId]?.chance
|
||||
// }
|
||||
// val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
|
||||
// if (tag != null) {
|
||||
// return tagMap[tag]?.chance
|
||||
// }
|
||||
// return null
|
||||
// }
|
||||
//
|
||||
// fun getBaitEffectValue(item: ItemStack): Double? {
|
||||
// val itemId = Registries.ITEM.getId(item.item)
|
||||
// if (itemId in itemMap.keys) {
|
||||
// return itemMap[itemId]?.value
|
||||
// }
|
||||
// val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
|
||||
// if (tag != null) {
|
||||
// return tagMap[tag]?.value
|
||||
// }
|
||||
// return null
|
||||
// }
|
||||
//
|
||||
//
|
||||
// fun getBaitNote(item: ItemStack): String? {
|
||||
// val itemId = Registries.ITEM.getId(item.item)
|
||||
// if (itemId in itemMap.keys) {
|
||||
// return itemMap[itemId]?.note
|
||||
// }
|
||||
// val tag = tagMap.keys.firstOrNull { it.fits(item.item, Registries.ITEM) }
|
||||
// if (tag != null) {
|
||||
// return tagMap[tag]?.note
|
||||
// }
|
||||
// return null
|
||||
// }
|
||||
}
|
||||
+16
-23
@@ -8,6 +8,8 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.fishing
|
||||
|
||||
import com.cobblemon.mod.common.api.conditional.ITEM_REGISTRY_LIKE_CODEC
|
||||
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.fishing.BaitEffectFunctionRegistryEvent
|
||||
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawnCause
|
||||
@@ -16,18 +18,14 @@ import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import java.util.Optional
|
||||
import net.minecraft.core.Registry
|
||||
import net.minecraft.network.codec.ByteBufCodecs
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
||||
data class FishingBait(
|
||||
val item: ResourceLocation,
|
||||
class SpawnBait(
|
||||
val item: RegistryLikeCondition<Item>,
|
||||
val effects: List<Effect>,
|
||||
) {
|
||||
fun toItemStack(itemRegistry: Registry<Item>) = item.let(itemRegistry::get)?.let { ItemStack(it) } ?: ItemStack.EMPTY
|
||||
|
||||
data class Effect(
|
||||
val type: ResourceLocation,
|
||||
val subcategory: ResourceLocation?,
|
||||
@@ -49,19 +47,14 @@ data class FishingBait(
|
||||
}
|
||||
|
||||
companion object {
|
||||
val CODEC = RecordCodecBuilder.create<FishingBait> { instance ->
|
||||
val CODEC = RecordCodecBuilder.create<SpawnBait> { instance ->
|
||||
instance.group(
|
||||
ResourceLocation.CODEC.fieldOf("item").forGetter { it.item },
|
||||
ITEM_REGISTRY_LIKE_CODEC.fieldOf("item").forGetter { it.item },
|
||||
Effect.CODEC.listOf().fieldOf("effects").forGetter {it.effects}
|
||||
).apply(instance, ::FishingBait)
|
||||
).apply(instance, ::SpawnBait)
|
||||
}
|
||||
|
||||
val STREAM_CODEC = ByteBufCodecs.fromCodec(CODEC)
|
||||
|
||||
val BLANK_BAIT = FishingBait(
|
||||
cobblemonResource("blank"),
|
||||
emptyList()
|
||||
)
|
||||
}
|
||||
|
||||
object Effects {
|
||||
@@ -78,7 +71,7 @@ data class FishingBait(
|
||||
val HIDDEN_ABILITY_CHANCE = cobblemonResource("ha_chance")
|
||||
val POKEMON_CHANCE = cobblemonResource("pokemon_chance")
|
||||
val FRIENDSHIP = cobblemonResource("friendship")
|
||||
val INERT = cobblemonResource("inert")
|
||||
val RARITY_BUCKET = cobblemonResource("rarity_bucket")
|
||||
|
||||
fun registerEffect(type: ResourceLocation, effect: (PokemonEntity, Effect) -> Unit) {
|
||||
EFFECT_FUNCTIONS[type] = effect
|
||||
@@ -89,15 +82,15 @@ data class FishingBait(
|
||||
}
|
||||
|
||||
fun setupEffects() {
|
||||
EFFECT_FUNCTIONS[NATURE] = { entity, effect -> FishingSpawnCause.alterNatureAttempt(entity, effect) }
|
||||
EFFECT_FUNCTIONS[IV] = { entity, effect -> FishingSpawnCause.alterIVAttempt(entity, effect) }
|
||||
EFFECT_FUNCTIONS[SHINY_REROLL] = { entity, effect -> FishingSpawnCause.shinyReroll(entity, effect) }
|
||||
EFFECT_FUNCTIONS[GENDER_CHANCE] = { entity, effect -> FishingSpawnCause.alterGenderAttempt(entity, effect) }
|
||||
EFFECT_FUNCTIONS[LEVEL_RAISE] = { entity, effect -> FishingSpawnCause.alterLevelAttempt(entity, effect) }
|
||||
EFFECT_FUNCTIONS[HIDDEN_ABILITY_CHANCE] = { entity, _ -> FishingSpawnCause.alterHAAttempt(entity) }
|
||||
EFFECT_FUNCTIONS[FRIENDSHIP] = { entity, effect -> FishingSpawnCause.alterFriendshipAttempt(entity, effect) }
|
||||
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(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) }
|
||||
registerEffect(FRIENDSHIP) { entity, effect -> FishingSpawnCause.alterFriendshipAttempt(entity, effect) }
|
||||
CobblemonEvents.BAIT_EFFECT_REGISTRATION.post(BaitEffectFunctionRegistryEvent()) { event ->
|
||||
EFFECT_FUNCTIONS.putAll(event.functions)
|
||||
event.functions.forEach { (type, function) -> registerEffect(type, function) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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.fishing
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonItemComponents
|
||||
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
|
||||
import com.cobblemon.mod.common.api.conditional.RegistryLikeIdentifierCondition
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.net.messages.client.data.SpawnBaitRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ItemLikeConditionAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import net.minecraft.core.Holder
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.server.packs.PackType
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
||||
object SpawnBaitEffects : JsonDataRegistry<SpawnBait> {
|
||||
override val id = cobblemonResource("spawn_bait_effects")
|
||||
override val type = PackType.SERVER_DATA
|
||||
override val observable = SimpleObservable<SpawnBaitEffects>()
|
||||
override val typeToken: TypeToken<SpawnBait> = TypeToken.get(SpawnBait::class.java)
|
||||
override val resourcePath = "spawn_bait_effects"
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
|
||||
.registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Item::class.java).type, ItemLikeConditionAdapter)
|
||||
.setPrettyPrinting()
|
||||
.create()
|
||||
|
||||
private val effectsMap = mutableMapOf<ResourceLocation, SpawnBait>()
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
SpawnBaitRegistrySyncPacket(this.effectsMap.toMap()).sendToPlayer(player)
|
||||
}
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, SpawnBait>) {
|
||||
effectsMap.clear()
|
||||
data.forEach { id, bait ->
|
||||
effectsMap[id] = bait
|
||||
}
|
||||
}
|
||||
|
||||
fun getEffectsFromRodItemStack(stack: ItemStack): List<SpawnBait.Effect> {
|
||||
return getEffectsFromItemStack(stack.components.get(CobblemonItemComponents.BAIT)?.stack ?: ItemStack.EMPTY)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
fun getBaitIdentifiersFromItem(holder: Holder<Item>): List<ResourceLocation> {
|
||||
return effectsMap.entries.filter { it.value.item.fits(holder) }.map { it.key }
|
||||
}
|
||||
|
||||
fun getBaitFromItemStack(holder: Holder<Item>): List<SpawnBait> {
|
||||
return effectsMap.values.filter { it.item.fits(holder) }
|
||||
}
|
||||
|
||||
private fun getEffectsFromItem(holder: Holder<Item>): List<SpawnBait.Effect> {
|
||||
return getBaitFromItemStack(holder).flatMap { it.effects }
|
||||
}
|
||||
|
||||
fun getFromIdentifier(identifier: ResourceLocation): SpawnBait? {
|
||||
// Check normal spawn bait registry
|
||||
effectsMap[identifier]?.let { return it }
|
||||
|
||||
// check seasoning spawn bait registry
|
||||
if (identifier.namespace == "seasonings") {
|
||||
val seasoning = com.cobblemon.mod.common.api.cooking.Seasonings.seasonings.find {
|
||||
it.ingredient is RegistryLikeIdentifierCondition &&
|
||||
(it.ingredient as RegistryLikeIdentifierCondition<Item>).identifier.path == identifier.path
|
||||
}
|
||||
|
||||
if (seasoning != null && seasoning.baitEffects.isNotEmpty()) {
|
||||
return SpawnBait(
|
||||
item = seasoning.ingredient,
|
||||
effects = seasoning.baitEffects
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun isFishingBait(stack: ItemStack): Boolean {
|
||||
val holder = stack.itemHolder
|
||||
return stack.has(CobblemonItemComponents.BAIT_EFFECTS) || effectsMap.values.any { it.item.fits(holder) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.fishing
|
||||
|
||||
object SpawnBaitUtils {
|
||||
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
|
||||
|
||||
if (type == SpawnBait.Effects.RARITY_BUCKET) {
|
||||
// we want to keep the highest rarity bucket effect instead of merging them
|
||||
groupEffects.maxByOrNull { it.value }!!
|
||||
} else {
|
||||
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.9
|
||||
else -> 1.0
|
||||
}
|
||||
|
||||
val adjustedChance = (totalChance * multiplier).coerceAtMost(1.0)
|
||||
val adjustedValue = totalValue * multiplier
|
||||
|
||||
SpawnBait.Effect(type, subcategory, adjustedChance, adjustedValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -215,6 +215,7 @@ fun drawPosablePortrait(
|
||||
ageInTicks: Float = 0F,
|
||||
headYaw: Float = 0F,
|
||||
headPitch: Float = 0F,
|
||||
doQuirks: Boolean = true,
|
||||
r: Float = 1F,
|
||||
g: Float = 1F,
|
||||
b: Float = 1F,
|
||||
@@ -240,6 +241,7 @@ fun drawPosablePortrait(
|
||||
context.put(RenderContext.SPECIES, identifier)
|
||||
context.put(RenderContext.ASPECTS, state.currentAspects)
|
||||
context.put(RenderContext.POSABLE_STATE, state)
|
||||
context.put(RenderContext.DO_QUIRKS, doQuirks)
|
||||
|
||||
val renderType = RenderType.entityCutout(texture)
|
||||
|
||||
|
||||
+12
-12
@@ -82,7 +82,7 @@ interface PokemonAndMoveSelectingItem {
|
||||
val bagItem = bagItem
|
||||
if (!battlePokemon.actor.canFitForcedAction()) {
|
||||
player.sendSystemMessage(battleLang("bagitem.cannot").red())
|
||||
} else if (!bagItem!!.canUse(battle, battlePokemon)) {
|
||||
} else if (!bagItem!!.canUse(stack, battle, battlePokemon)) {
|
||||
player.sendSystemMessage(battleLang("bagitem.invalid").red())
|
||||
} else {
|
||||
battlePokemon.actor.forceChoose(BagItemActionResponse(bagItem, battlePokemon, move.template.name))
|
||||
@@ -92,10 +92,10 @@ interface PokemonAndMoveSelectingItem {
|
||||
}
|
||||
}
|
||||
|
||||
fun canUseOnPokemon(pokemon: Pokemon): Boolean
|
||||
fun canUseOnBattlePokemon(battlePokemon: BattlePokemon): Boolean = bagItem!!.canUse(battlePokemon.actor.battle, battlePokemon)
|
||||
fun canUseOnMove(pokemon: Pokemon, move: Move): Boolean = canUseOnMove(move)
|
||||
fun canUseOnMove(move: Move): Boolean
|
||||
fun canUseOnPokemon(stack: ItemStack, pokemon: Pokemon): Boolean
|
||||
fun canUseOnBattlePokemon(stack: ItemStack, battlePokemon: BattlePokemon): Boolean = bagItem!!.canUse(stack, battlePokemon.actor.battle, battlePokemon)
|
||||
fun canUseOnMove(stack: ItemStack, pokemon: Pokemon, move: Move): Boolean = canUseOnMove(stack, move)
|
||||
fun canUseOnMove(stack: ItemStack, move: Move): Boolean
|
||||
|
||||
fun interactWithSpecific(player: ServerPlayer, stack: ItemStack, pokemon: Pokemon): InteractionResultHolder<ItemStack>? {
|
||||
|
||||
@@ -106,18 +106,18 @@ interface PokemonAndMoveSelectingItem {
|
||||
MoveSelectCallbacks.create(
|
||||
player = player,
|
||||
moves = pokemon.moveSet.toList(),
|
||||
canSelect = ::canUseOnMove,
|
||||
canSelect = { canUseOnMove(stack, it)},
|
||||
handler = { move -> if (stack.isHeld(player)) applyToPokemon(player, stack, pokemon, move) }
|
||||
)
|
||||
return InteractionResultHolder.success(stack)
|
||||
}
|
||||
|
||||
fun interactWithSpecificBattle(player: ServerPlayer, stack: ItemStack, battlePokemon: BattlePokemon): InteractionResultHolder<ItemStack>? {
|
||||
return if (canUseOnBattlePokemon(battlePokemon)) {
|
||||
return if (canUseOnBattlePokemon(stack, battlePokemon)) {
|
||||
MoveSelectCallbacks.create(
|
||||
player = player,
|
||||
moves = battlePokemon.moveSet.getMoves(),
|
||||
canSelect = ::canUseOnMove,
|
||||
canSelect = { canUseOnMove(stack, it) },
|
||||
handler = { applyToBattlePokemon(player, stack, battlePokemon, it) }
|
||||
)
|
||||
InteractionResultHolder.success(stack)
|
||||
@@ -131,8 +131,8 @@ interface PokemonAndMoveSelectingItem {
|
||||
PartyMoveSelectCallbacks.createFromPokemon(
|
||||
player = player,
|
||||
pokemon = player.party().toList(),
|
||||
canSelectPokemon = ::canUseOnPokemon,
|
||||
canSelectMove = ::canUseOnMove,
|
||||
canSelectPokemon = { canUseOnPokemon(stack, it) },
|
||||
canSelectMove = { pokemon, move -> canUseOnMove(stack, pokemon, move) },
|
||||
handler = { pk, mv -> if (stack.isHeld(player)) applyToPokemon(player, stack, pk, mv) }
|
||||
)
|
||||
|
||||
@@ -144,8 +144,8 @@ interface PokemonAndMoveSelectingItem {
|
||||
player = player,
|
||||
pokemon = actor.pokemonList.map { it.effectedPokemon },
|
||||
moves = { pk -> actor.pokemonList.find { it.effectedPokemon == pk }!!.moveSet.getMoves() },
|
||||
canSelectPokemon = { pk -> canUseOnBattlePokemon(actor.pokemonList.find { it.effectedPokemon == pk }!!) },
|
||||
canSelectMove = ::canUseOnMove,
|
||||
canSelectPokemon = { pk -> canUseOnBattlePokemon(stack, actor.pokemonList.find { it.effectedPokemon == pk }!!) },
|
||||
canSelectMove = { pokemon, move -> canUseOnMove(stack, pokemon, move) },
|
||||
handler = { pk, mv -> applyToBattlePokemon(player, stack, actor.pokemonList.find { it.effectedPokemon == pk }!!, mv) }
|
||||
)
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ interface PokemonSelectingItem {
|
||||
val bagItem = bagItem
|
||||
if (!battlePokemon.actor.canFitForcedAction()) {
|
||||
player.sendSystemMessage(battleLang("bagitem.cannot").red())
|
||||
} else if (!bagItem!!.canUse(battle, battlePokemon)) {
|
||||
} else if (!bagItem!!.canUse(stack, battle, battlePokemon)) {
|
||||
player.sendSystemMessage(battleLang("bagitem.invalid").red())
|
||||
} else {
|
||||
battlePokemon.actor.forceChoose(BagItemActionResponse(bagItem, battlePokemon))
|
||||
@@ -105,11 +105,11 @@ interface PokemonSelectingItem {
|
||||
}
|
||||
}
|
||||
|
||||
fun canUseOnPokemon(pokemon: Pokemon): Boolean
|
||||
fun canUseOnBattlePokemon(battlePokemon: BattlePokemon): Boolean = bagItem!!.canUse(battlePokemon.actor.battle, battlePokemon)
|
||||
fun canUseOnPokemon(stack: ItemStack, pokemon: Pokemon): Boolean
|
||||
fun canUseOnBattlePokemon(stack: ItemStack, battlePokemon: BattlePokemon): Boolean = bagItem!!.canUse(stack, battlePokemon.actor.battle, battlePokemon)
|
||||
|
||||
fun interactWithSpecificBattle(player: ServerPlayer, stack: ItemStack, battlePokemon: BattlePokemon): InteractionResultHolder<ItemStack> {
|
||||
return if (canUseOnBattlePokemon(battlePokemon)) {
|
||||
return if (canUseOnBattlePokemon(stack, battlePokemon)) {
|
||||
applyToBattlePokemon(player, stack, battlePokemon)
|
||||
InteractionResultHolder.success(stack)
|
||||
} else {
|
||||
@@ -127,7 +127,7 @@ interface PokemonSelectingItem {
|
||||
PartySelectCallbacks.createFromPokemon(
|
||||
player = player,
|
||||
pokemon = party,
|
||||
canSelect = ::canUseOnPokemon,
|
||||
canSelect = { pk -> canUseOnPokemon(stack, pk) },
|
||||
handler = { pk ->
|
||||
if (stack.isHeld(player)) {
|
||||
applyToPokemon(player, stack, pk)
|
||||
@@ -143,7 +143,7 @@ interface PokemonSelectingItem {
|
||||
PartySelectCallbacks.createBattleSelect(
|
||||
player = player,
|
||||
pokemon = actor.pokemonList,
|
||||
canSelect = { pk -> canUseOnBattlePokemon(actor.pokemonList.find { it.effectedPokemon == pk.effectedPokemon }!!) },
|
||||
canSelect = { pk -> canUseOnBattlePokemon(stack, actor.pokemonList.find { it.effectedPokemon == pk.effectedPokemon }!!) },
|
||||
handler = { pk -> applyToBattlePokemon(player, stack, actor.pokemonList.find { it.effectedPokemon == pk.effectedPokemon }!!) }
|
||||
)
|
||||
|
||||
|
||||
@@ -831,7 +831,11 @@ object MoLangFunctions {
|
||||
map.put("in_battle") { DoubleValue(pokemonEntity.isBattling) }
|
||||
map.put("is_moving") { DoubleValue((pokemonEntity.moveControl as? PokemonMoveControl)?.hasWanted() == true) }
|
||||
map.put("is_flying") { DoubleValue(pokemonEntity.getBehaviourFlag(PokemonBehaviourFlag.FLYING)) }
|
||||
map.put("is_gliding") { DoubleValue(pokemonEntity.useRidingAltPose()) }
|
||||
map.put("is_flying") { DoubleValue(pokemonEntity.getBehaviourFlag(PokemonBehaviourFlag.FLYING)) }
|
||||
map.put("get_alt_pose") { StringValue(pokemonEntity.getAltPose()) }
|
||||
map.put("is_gliding") { DoubleValue(pokemonEntity.isUsingAltPose(cobblemonResource("gliding"))) }
|
||||
map.put("is_sprinting") { DoubleValue(pokemonEntity.isUsingAltPose(cobblemonResource("sprinting"))) }
|
||||
map.put("in_air") { DoubleValue(pokemonEntity.isUsingAltPose(cobblemonResource("in_air"))) }
|
||||
map.put("is_ridden") { DoubleValue(pokemonEntity.hasControllingPassenger()) }
|
||||
map.put("has_aspect") { DoubleValue(it.getString(0) in pokemonEntity.aspects) }
|
||||
map.put("is_pokemon") { DoubleValue.ONE }
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.net.serializers
|
||||
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.readString
|
||||
import com.cobblemon.mod.common.util.writeString
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.network.codec.StreamCodec
|
||||
import net.minecraft.network.syncher.EntityDataSerializer
|
||||
|
||||
object RideBoostsDataSerializer : EntityDataSerializer<Map<RidingStat, Float>> {
|
||||
val ID = cobblemonResource("ride_boosts")
|
||||
fun read(buf: RegistryFriendlyByteBuf): Map<RidingStat, Float> {
|
||||
return buf.readMap(
|
||||
{ RidingStat.valueOf(it.readString()) },
|
||||
{ it.readFloat() }
|
||||
)
|
||||
}
|
||||
override fun copy(value: Map<RidingStat, Float>) = value.toMap()
|
||||
fun write(buf: RegistryFriendlyByteBuf, value: Map<RidingStat, Float>) {
|
||||
buf.writeMap(
|
||||
value,
|
||||
{ _, it -> buf.writeString(it.name) },
|
||||
{ _, it -> buf.writeFloat(it) }
|
||||
)
|
||||
}
|
||||
|
||||
override fun codec() = StreamCodec.of(::write, ::read)
|
||||
}
|
||||
+9
-14
@@ -17,6 +17,7 @@ import org.joml.Matrix3f
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Vector3f
|
||||
import kotlin.math.asin
|
||||
import kotlin.math.sign
|
||||
|
||||
open class OrientationController(val entity: LivingEntity) {
|
||||
|
||||
@@ -108,21 +109,15 @@ open class OrientationController(val entity: LivingEntity) {
|
||||
get() = Mth.wrapDegrees(-upVector.angleSigned(UP, forwardVector).toDegrees())
|
||||
|
||||
fun applyGlobalYaw(deltaYawDegrees: Float) = updateOrientation { original ->
|
||||
val euler = Vector3f()
|
||||
original.getEulerAnglesXYZ(euler)
|
||||
val pitch0 = euler.x
|
||||
val roll0 = euler.z
|
||||
return@updateOrientation original.rotateLocalY(-deltaYawDegrees.toRadians())
|
||||
}
|
||||
|
||||
val unroll = Matrix3f().rotateZ(-roll0)
|
||||
val unpitch = Matrix3f().rotateX(-pitch0)
|
||||
val flattened = Matrix3f(original).mul(unroll).mul(unpitch)
|
||||
|
||||
//Flip to reflect current acceptance of what direction is pos for yaw
|
||||
val globalYaw = Matrix3f().rotationY(-1.0f * deltaYawDegrees.toRadians())
|
||||
val rePitch = Matrix3f().rotateX(pitch0)
|
||||
val reRoll = Matrix3f().rotateZ(roll0)
|
||||
|
||||
return@updateOrientation Matrix3f(globalYaw).mul(flattened).mul(rePitch).mul(reRoll)
|
||||
fun applyGlobalPitch(deltaPitchDegrees: Float) = updateOrientation { original ->
|
||||
val currQuat = Quaternionf().setFromUnnormalized(original)
|
||||
val horzLeftVector = Vector3f(this.leftVector.x, 0.0f, this.leftVector.z)
|
||||
val globalPitch = Quaternionf().fromAxisAngleRad(horzLeftVector.normalize(), -deltaPitchDegrees.toRadians())
|
||||
val resultQuat = globalPitch.mul(currQuat)
|
||||
return@updateOrientation Matrix3f().set(resultQuat)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-6
@@ -77,18 +77,18 @@ object CatchRateModifiers {
|
||||
|
||||
/**
|
||||
* Used by [PokeBalls.MOON_BALL].
|
||||
* Boosts the catch rate 1.5× during Moon Phases 3 and 7 between the times of 12000 – 24000.
|
||||
* 2.5× during Moon Phases 2 and 8 between the times of 12000 – 24000.
|
||||
* 4× during Moon Phase 1 between the times of 12000 – 24000.
|
||||
* Boosts the catch rate 1.5× during Moon Phases 2 and 6 between the times of 12000 – 24000.
|
||||
* 2.5× during Moon Phases 1 and 7 between the times of 12000 – 24000.
|
||||
* 4× during Moon Phase 0 between the times of 12000 – 24000.
|
||||
* 1× otherwise.
|
||||
*/
|
||||
val MOON_PHASES: CatchRateModifier = WorldStateModifier { _, entity ->
|
||||
if (entity.level().gameTime in 12000..24000)
|
||||
return@WorldStateModifier 1F
|
||||
when (entity.level().moonPhase) {
|
||||
3, 7 -> 1.5F
|
||||
2, 8 -> 2.5F
|
||||
1 -> 4F
|
||||
2, 6 -> 1.5F
|
||||
1, 7 -> 2.5F
|
||||
0 -> 4F
|
||||
else -> 1F
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon
|
||||
|
||||
import com.cobblemon.mod.common.api.berry.Flavor
|
||||
import com.cobblemon.mod.common.api.cooking.Flavour
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.pokemon.Nature
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
@@ -31,27 +31,27 @@ object Natures {
|
||||
|
||||
val LONELY = registerNature(
|
||||
Nature(cobblemonResource("lonely"), "cobblemon.nature.lonely",
|
||||
Stats.ATTACK, Stats.DEFENCE, Flavor.SPICY, Flavor.SOUR)
|
||||
Stats.ATTACK, Stats.DEFENCE, Flavour.SPICY, Flavour.SOUR)
|
||||
)
|
||||
|
||||
val BRAVE = registerNature(
|
||||
Nature(cobblemonResource("brave"), "cobblemon.nature.brave",
|
||||
Stats.ATTACK, Stats.SPEED, Flavor.SPICY, Flavor.SWEET)
|
||||
Stats.ATTACK, Stats.SPEED, Flavour.SPICY, Flavour.SWEET)
|
||||
)
|
||||
|
||||
val ADAMANT = registerNature(
|
||||
Nature(cobblemonResource("adamant"), "cobblemon.nature.adamant",
|
||||
Stats.ATTACK, Stats.SPECIAL_ATTACK, Flavor.SPICY, Flavor.DRY)
|
||||
Stats.ATTACK, Stats.SPECIAL_ATTACK, Flavour.SPICY, Flavour.DRY)
|
||||
)
|
||||
|
||||
val NAUGHTY = registerNature(
|
||||
Nature(cobblemonResource("naughty"), "cobblemon.nature.naughty",
|
||||
Stats.ATTACK, Stats.SPECIAL_DEFENCE, Flavor.SPICY, Flavor.BITTER)
|
||||
Stats.ATTACK, Stats.SPECIAL_DEFENCE, Flavour.SPICY, Flavour.BITTER)
|
||||
)
|
||||
|
||||
val BOLD = registerNature(
|
||||
Nature(cobblemonResource("bold"), "cobblemon.nature.bold",
|
||||
Stats.DEFENCE, Stats.ATTACK, Flavor.SOUR, Flavor.SPICY)
|
||||
Stats.DEFENCE, Stats.ATTACK, Flavour.SOUR, Flavour.SPICY)
|
||||
)
|
||||
|
||||
val DOCILE = registerNature(
|
||||
@@ -61,27 +61,27 @@ object Natures {
|
||||
|
||||
val RELAXED = registerNature(
|
||||
Nature(cobblemonResource("relaxed"), "cobblemon.nature.relaxed",
|
||||
Stats.DEFENCE, Stats.SPEED, Flavor.SOUR, Flavor.SWEET)
|
||||
Stats.DEFENCE, Stats.SPEED, Flavour.SOUR, Flavour.SWEET)
|
||||
)
|
||||
|
||||
val IMPISH = registerNature(
|
||||
Nature(cobblemonResource("impish"), "cobblemon.nature.impish",
|
||||
Stats.DEFENCE, Stats.SPECIAL_ATTACK, Flavor.SOUR, Flavor.DRY)
|
||||
Stats.DEFENCE, Stats.SPECIAL_ATTACK, Flavour.SOUR, Flavour.DRY)
|
||||
)
|
||||
|
||||
val LAX = registerNature(
|
||||
Nature(cobblemonResource("lax"), "cobblemon.nature.lax",
|
||||
Stats.DEFENCE, Stats.SPECIAL_DEFENCE, Flavor.SOUR, Flavor.BITTER)
|
||||
Stats.DEFENCE, Stats.SPECIAL_DEFENCE, Flavour.SOUR, Flavour.BITTER)
|
||||
)
|
||||
|
||||
val TIMID = registerNature(
|
||||
Nature(cobblemonResource("timid"), "cobblemon.nature.timid",
|
||||
Stats.SPEED, Stats.ATTACK, Flavor.SWEET, Flavor.SPICY)
|
||||
Stats.SPEED, Stats.ATTACK, Flavour.SWEET, Flavour.SPICY)
|
||||
)
|
||||
|
||||
val HASTY = registerNature(
|
||||
Nature(cobblemonResource("hasty"), "cobblemon.nature.hasty",
|
||||
Stats.SPEED, Stats.DEFENCE, Flavor.SWEET, Flavor.SOUR)
|
||||
Stats.SPEED, Stats.DEFENCE, Flavour.SWEET, Flavour.SOUR)
|
||||
)
|
||||
|
||||
val SERIOUS = registerNature(
|
||||
@@ -91,12 +91,12 @@ object Natures {
|
||||
|
||||
val JOLLY = registerNature(
|
||||
Nature(cobblemonResource("jolly"), "cobblemon.nature.jolly",
|
||||
Stats.SPEED, Stats.SPECIAL_ATTACK, Flavor.SWEET, Flavor.DRY)
|
||||
Stats.SPEED, Stats.SPECIAL_ATTACK, Flavour.SWEET, Flavour.DRY)
|
||||
)
|
||||
|
||||
val NAIVE = registerNature(
|
||||
Nature(cobblemonResource("naive"), "cobblemon.nature.naive",
|
||||
Stats.SPEED, Stats.SPECIAL_DEFENCE, Flavor.SWEET, Flavor.BITTER)
|
||||
Stats.SPEED, Stats.SPECIAL_DEFENCE, Flavour.SWEET, Flavour.BITTER)
|
||||
)
|
||||
|
||||
val MODEST = registerNature(
|
||||
@@ -106,12 +106,12 @@ object Natures {
|
||||
|
||||
val MILD = registerNature(
|
||||
Nature(cobblemonResource("mild"), "cobblemon.nature.mild",
|
||||
Stats.SPECIAL_ATTACK, Stats.DEFENCE, Flavor.DRY, Flavor.SOUR)
|
||||
Stats.SPECIAL_ATTACK, Stats.DEFENCE, Flavour.DRY, Flavour.SOUR)
|
||||
)
|
||||
|
||||
val QUIET = registerNature(
|
||||
Nature(cobblemonResource("quiet"), "cobblemon.nature.quiet",
|
||||
Stats.SPECIAL_ATTACK, Stats.SPEED, Flavor.DRY, Flavor.SWEET)
|
||||
Stats.SPECIAL_ATTACK, Stats.SPEED, Flavour.DRY, Flavour.SWEET)
|
||||
)
|
||||
|
||||
val BASHFUL = registerNature(
|
||||
@@ -121,27 +121,27 @@ object Natures {
|
||||
|
||||
val RASH = registerNature(
|
||||
Nature(cobblemonResource("rash"), "cobblemon.nature.rash",
|
||||
Stats.SPECIAL_ATTACK, Stats.SPECIAL_DEFENCE, Flavor.DRY, Flavor.BITTER)
|
||||
Stats.SPECIAL_ATTACK, Stats.SPECIAL_DEFENCE, Flavour.DRY, Flavour.BITTER)
|
||||
)
|
||||
|
||||
val CALM = registerNature(
|
||||
Nature(cobblemonResource("calm"), "cobblemon.nature.calm",
|
||||
Stats.SPECIAL_DEFENCE, Stats.ATTACK, Flavor.BITTER, Flavor.SPICY)
|
||||
Stats.SPECIAL_DEFENCE, Stats.ATTACK, Flavour.BITTER, Flavour.SPICY)
|
||||
)
|
||||
|
||||
val GENTLE = registerNature(
|
||||
Nature(cobblemonResource("gentle"), "cobblemon.nature.gentle",
|
||||
Stats.SPECIAL_DEFENCE, Stats.DEFENCE, Flavor.BITTER, Flavor.SOUR)
|
||||
Stats.SPECIAL_DEFENCE, Stats.DEFENCE, Flavour.BITTER, Flavour.SOUR)
|
||||
)
|
||||
|
||||
val SASSY = registerNature(
|
||||
Nature(cobblemonResource("sassy"), "cobblemon.nature.sassy",
|
||||
Stats.SPECIAL_DEFENCE, Stats.SPEED, Flavor.BITTER, Flavor.SWEET)
|
||||
Stats.SPECIAL_DEFENCE, Stats.SPEED, Flavour.BITTER, Flavour.SWEET)
|
||||
)
|
||||
|
||||
val CAREFUL = registerNature(
|
||||
Nature(cobblemonResource("careful"), "cobblemon.nature.careful",
|
||||
Stats.SPECIAL_DEFENCE, Stats.SPECIAL_ATTACK, Flavor.BITTER, Flavor.DRY)
|
||||
Stats.SPECIAL_DEFENCE, Stats.SPECIAL_ATTACK, Flavour.BITTER, Flavour.DRY)
|
||||
)
|
||||
|
||||
val QUIRKY = registerNature(
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.api.riding
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStatDefinition
|
||||
@@ -17,17 +18,18 @@ import com.cobblemon.mod.common.util.adapters.RidingBehaviourSettingsAdapter
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
class RidingProperties(
|
||||
val stats: Map<RidingStat, RidingStatDefinition> = mapOf(),
|
||||
val seats: List<Seat> = listOf(),
|
||||
val conditions: List<Expression> = listOf(),
|
||||
val behaviour: RidingBehaviourSettings? = null
|
||||
val stats: MutableMap<RidingStat, RidingStatDefinition> = mutableMapOf(),
|
||||
val seats: List<Seat> = listOf(),
|
||||
val conditions: List<Expression> = listOf(),
|
||||
val behaviour: RidingBehaviourSettings? = null
|
||||
) {
|
||||
|
||||
companion object {
|
||||
fun decode(buffer: RegistryFriendlyByteBuf): RidingProperties {
|
||||
val stats: Map<RidingStat, RidingStatDefinition> = buffer.readMap(
|
||||
{ buffer.readEnum(RidingStat::class.java) },
|
||||
{ RidingStatDefinition.decode(buffer) }
|
||||
)
|
||||
val stats: MutableMap<RidingStat, RidingStatDefinition> = buffer.readMap(
|
||||
{ buffer.readEnum(RidingStat::class.java) },
|
||||
{ RidingStatDefinition.decode(buffer) }
|
||||
).toMutableMap()
|
||||
val seats: List<Seat> = buffer.readList { _ -> Seat.decode(buffer) }
|
||||
val conditions = buffer.readList { buffer.readString().asExpression() }
|
||||
val behaviour = buffer.readNullable { _ ->
|
||||
@@ -41,11 +43,19 @@ class RidingProperties(
|
||||
}
|
||||
}
|
||||
|
||||
internal fun updateStatRange(stat: RidingStat, style: RidingStyle, min: Int, max: Int) {
|
||||
if (!Cobblemon.config.enableDebugKeys) return
|
||||
if (stats[stat] == null) {
|
||||
stats[stat] = RidingStatDefinition()
|
||||
}
|
||||
stats[stat]!!.ranges[style] = min..max
|
||||
}
|
||||
|
||||
fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeMap(
|
||||
stats,
|
||||
{ _, stat -> buffer.writeEnum(stat) },
|
||||
{ _, stat -> stat.encode(buffer) }
|
||||
stats,
|
||||
{ _, stat -> buffer.writeEnum(stat) },
|
||||
{ _, stat -> stat.encode(buffer) }
|
||||
)
|
||||
buffer.writeCollection(seats) { _, seat -> seat.encode(buffer) }
|
||||
buffer.writeCollection(conditions) { _, condition -> buffer.writeString(condition.getString()) }
|
||||
@@ -62,4 +72,4 @@ class RidingProperties(
|
||||
fun hasStat(stat: RidingStat, style: RidingStyle): Boolean {
|
||||
return stats[stat]?.ranges?.containsKey(style) == true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,5 @@ package com.cobblemon.mod.common.api.riding
|
||||
enum class RidingStyle {
|
||||
LAND,
|
||||
LIQUID,
|
||||
AIR,
|
||||
COMPOSITE
|
||||
AIR
|
||||
}
|
||||
|
||||
+3
-2
@@ -28,7 +28,8 @@ import net.minecraft.world.phys.Vec3
|
||||
*/
|
||||
interface RidingBehaviour<Settings : RidingBehaviourSettings, State : RidingBehaviourState> {
|
||||
val key: ResourceLocation
|
||||
val style: RidingStyle
|
||||
|
||||
fun getRidingStyle(settings: Settings, state: State): RidingStyle
|
||||
|
||||
fun isActive(settings: Settings, state: State, vehicle: PokemonEntity): Boolean
|
||||
|
||||
@@ -73,7 +74,7 @@ interface RidingBehaviour<Settings : RidingBehaviourSettings, State : RidingBeha
|
||||
|
||||
fun useAngVelSmoothing(settings: Settings, state: State, vehicle: PokemonEntity): Boolean
|
||||
|
||||
fun useRidingAltPose(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player): Boolean
|
||||
fun useRidingAltPose(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player): ResourceLocation
|
||||
|
||||
fun inertia(settings: Settings, state: State, vehicle: PokemonEntity): Double
|
||||
|
||||
|
||||
+8
-3
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.api.riding.behaviour
|
||||
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.SmoothDouble
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
@@ -25,7 +26,10 @@ import net.minecraft.world.phys.Vec3
|
||||
class RidingController<Settings : RidingBehaviourSettings, State : RidingBehaviourState>(val behaviour: RidingBehaviour<Settings, State>) : RidingBehaviour<Settings, State> {
|
||||
|
||||
override val key = behaviour.key
|
||||
override val style = behaviour.style
|
||||
|
||||
override fun getRidingStyle(settings: Settings, state: State): RidingStyle {
|
||||
return behaviour.getRidingStyle(settings, state)
|
||||
}
|
||||
|
||||
override fun isActive(settings: Settings, state: State, vehicle: PokemonEntity) =
|
||||
behaviour.isActive(settings, state, vehicle)
|
||||
@@ -135,8 +139,8 @@ class RidingController<Settings : RidingBehaviourSettings, State : RidingBehavio
|
||||
return behaviour.inertia(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player): Boolean {
|
||||
if (!isActive(settings, state, vehicle)) return false
|
||||
override fun useRidingAltPose(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player): ResourceLocation {
|
||||
if (!isActive(settings, state, vehicle)) return cobblemonResource("no_pose")
|
||||
return behaviour.useRidingAltPose(settings, state, vehicle, driver)
|
||||
}
|
||||
|
||||
@@ -175,4 +179,5 @@ class RidingController<Settings : RidingBehaviourSettings, State : RidingBehavio
|
||||
return behaviour.createDefaultState(settings)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+39
-45
@@ -18,7 +18,10 @@ import com.cobblemon.mod.common.api.riding.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
@@ -27,8 +30,6 @@ import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import org.joml.Matrix3f
|
||||
import org.joml.Quaternionf
|
||||
import org.joml.Vector3f
|
||||
import kotlin.math.*
|
||||
|
||||
@@ -38,7 +39,10 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
}
|
||||
|
||||
override val key: ResourceLocation = KEY
|
||||
override val style = RidingStyle.AIR
|
||||
|
||||
override fun getRidingStyle(settings: BirdAirSettings, state: BirdAirState): RidingStyle {
|
||||
return RidingStyle.AIR
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<BirdAirSettings, BirdAirState>(PoseType.HOVER)
|
||||
.with(PoseOption(PoseType.FLY) { _, state, _ -> state.rideVelocity.get().z > 0.2 })
|
||||
@@ -110,6 +114,7 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
upForce = if (vehicle.y >= altitudeLimit && upForce > 0) 0.0 else upForce
|
||||
}
|
||||
|
||||
|
||||
val velocity = Vec3(state.rideVelocity.get().x , upForce, forwardForce)
|
||||
return velocity
|
||||
}
|
||||
@@ -154,7 +159,7 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
if (controller != null) {
|
||||
//Base glide speed change on current pitch of the ride.
|
||||
glideSpeedChange = sin(Math.toRadians(controller.pitch.toDouble()))
|
||||
glideSpeedChange = glideSpeedChange.pow(3) * 0.5
|
||||
glideSpeedChange = glideSpeedChange * 0.25
|
||||
|
||||
//TODO: Possibly create a deadzone around parallel where glide doesn't affect speed?
|
||||
if (glideSpeedChange <= 0.0) {
|
||||
@@ -181,22 +186,6 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
}
|
||||
}
|
||||
|
||||
//Lateral movement based on driver input.
|
||||
// val latTopSpeed = topSpeed / 2.0
|
||||
// if (driver.xxa != 0.0f && state.stamina.get() > 0.0) {
|
||||
// newVelocity = Vec3(
|
||||
// (newVelocity.x + (accel * driver.xxa)).coerceIn(-latTopSpeed, latTopSpeed),
|
||||
// newVelocity.y,
|
||||
// newVelocity.z)
|
||||
// activeInput = true
|
||||
// }
|
||||
// else {
|
||||
// newVelocity = Vec3(
|
||||
// lerp(newVelocity.x, 0.0, latTopSpeed / 20.0),
|
||||
// newVelocity.y,
|
||||
// newVelocity.z)
|
||||
// }
|
||||
|
||||
//Vertical movement based on driver input.
|
||||
val vertTopSpeed = topSpeed / 2.0
|
||||
val vertInput = when {
|
||||
@@ -269,33 +258,21 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
val rotMin = 15.0
|
||||
val rotLimit = max(handling * sqrt(normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed)), rotMin)
|
||||
|
||||
|
||||
val rotationChangeRate = 100.0
|
||||
|
||||
var yawForce = rotationChangeRate * sin(Math.toRadians(controller.roll.toDouble()))
|
||||
//for a bit of correction on the rolls limit it to a quarter the amount
|
||||
var pitchForce = -0.35 * rotationChangeRate * abs(sin(Math.toRadians(controller.roll.toDouble())))
|
||||
|
||||
//limit rotation modulation when pitched up heavily or pitched down heavily
|
||||
yawForce *= abs(cos(Math.toRadians(controller.pitch.toDouble())))
|
||||
pitchForce *= abs(cos(Math.toRadians(controller.pitch.toDouble()))) * 1.5
|
||||
|
||||
var yawDeltaDeg = deltaTime * rotationChangeRate * sin(Math.toRadians(controller.roll.toDouble())) //sin(Math.toRadians(controller.roll.toDouble())) * abs(cos(Math.toRadians(controller.pitch.toDouble())))
|
||||
var yawDeltaDeg = deltaTime * handling * sin(Math.toRadians(controller.roll.toDouble())) //sin(Math.toRadians(controller.roll.toDouble())) * abs(cos(Math.toRadians(controller.pitch.toDouble())))
|
||||
val trueYawDelt = yawDeltaDeg * abs(cos(Math.toRadians(controller.pitch.toDouble())))
|
||||
//val pitchedYawDelt = yawDeltaDeg - trueYawDelt
|
||||
|
||||
controller.applyGlobalYaw(trueYawDelt.toFloat())
|
||||
|
||||
val correctionRate = 5.0
|
||||
//Calculate correcting roll force.
|
||||
if(abs(controller.roll) > rotLimit) {
|
||||
val correctionRate = 5.0
|
||||
if(abs(controller.roll) > rotLimit && state.rideVelocity.get().length() < 0.2) {
|
||||
state.currRollCorrectionForce.set(
|
||||
state.currRollCorrectionForce.get() + ((abs(controller.roll) - rotLimit) / 180 - rotLimit) * controller.roll.sign * correctionRate * deltaTime * 0.01
|
||||
)
|
||||
} else {
|
||||
state.currRollCorrectionForce.set(
|
||||
//reduce rollCorrection gradually and make sure to
|
||||
//state.currRollCorrectionForce.get() - max(correctionRate * deltaTime * 0.04, abs(state.currRollCorrectionForce.get())) * state.currRollCorrectionForce.get().sign
|
||||
//reduce rollCorrection gradually
|
||||
lerp(state.currRollCorrectionForce.get(), 0.0, deltaTime * 0.98)
|
||||
)
|
||||
}
|
||||
@@ -335,7 +312,7 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
//modulated by speed so that when flapping idle in air you are ont wobbling around to look around
|
||||
val rotMin = 15.0
|
||||
var rollForce = xInput
|
||||
val rotLimit = max(handling * sqrt(normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed)), rotMin)
|
||||
val rotLimit = max(90 * sqrt(normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed)), rotMin)
|
||||
|
||||
//Limit roll by non linearly decreasing inputs towards
|
||||
// a rotation limit based on the current distance from
|
||||
@@ -346,12 +323,12 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
val d = abs(abs(controller.roll) - rotLimit)
|
||||
rollForce *= (d.pow(2)) / (rotLimit.pow(2))
|
||||
}
|
||||
} else if (sign(rollForce) == sign(controller.roll).toDouble()) {
|
||||
rollForce = 0.0
|
||||
} else { //if (sign(rollForce) == sign(controller.roll).toDouble()) {
|
||||
rollForce *= max(abs(sin(controller.pitch.toRadians())),0.1f)
|
||||
}
|
||||
|
||||
//Give the ability to yaw with x mouse input when at low speeds.
|
||||
val yawForce = xInput * ( 1.0 - sqrt(normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed)))
|
||||
val yawForce = xInput * ( 1.0 - sqrt(normalizeVal(state.rideVelocity.get().length(), 0.0, topSpeed)))
|
||||
|
||||
//Yaw locally a bit when up or down so that its more intuitive to make it out of a dive or a straight vertical
|
||||
//climb
|
||||
@@ -359,10 +336,24 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
|
||||
|
||||
//Apply yaw globally as we don't want roll or pitch changes due to local yaw when looking up or down.
|
||||
controller.applyGlobalYaw(yawForce.toFloat())
|
||||
if (controller.upVector.dot(Vector3f(0f,1f,0f)) > 0) {
|
||||
controller.applyGlobalYaw(yawForce.toFloat())
|
||||
}
|
||||
|
||||
|
||||
// Pitch up globally
|
||||
controller.applyGlobalPitch(-1 * yInput.toFloat())
|
||||
// roll to 0 if pitching and not upside down. This is to prevent odd back and forth wobbling when
|
||||
// pitching globally and experiencing axis changes
|
||||
if (controller.upVector.dot(Vector3f(0f,1f,0f)) > 0) {
|
||||
// correct roll equal to the amount the ride is pitching (yInput)
|
||||
// correct roll only when near to horizontal (cos(pitch))
|
||||
// correct roll proportional to how rolled the ride currently is
|
||||
rollForce += controller.roll * -0.01 * abs(yInput) * abs(cos(controller.pitch.toRadians())) * abs(sin(controller.roll.toRadians()))
|
||||
}
|
||||
|
||||
//yaw, pitch, roll
|
||||
return Vec3(yawForcePitched, yInput, rollForce)
|
||||
return Vec3(0.0, 0.0, rollForce)
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -441,8 +432,11 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
state: BirdAirState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return state.gliding.get()
|
||||
): ResourceLocation {
|
||||
if (state.gliding.get()) {
|
||||
return cobblemonResource("gliding")
|
||||
}
|
||||
return cobblemonResource("no_pose")
|
||||
}
|
||||
|
||||
override fun inertia(settings: BirdAirSettings, state: BirdAirState, vehicle: PokemonEntity): Double {
|
||||
@@ -474,7 +468,7 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
state: BirdAirState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
override fun createDefaultState(settings: BirdAirSettings) = BirdAirState()
|
||||
|
||||
+7
-3
@@ -19,6 +19,7 @@ import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.SmoothDouble
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
@@ -35,7 +36,10 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
override val style = RidingStyle.LIQUID
|
||||
|
||||
override fun getRidingStyle(settings: DolphinSettings, state: DolphinState): RidingStyle {
|
||||
return RidingStyle.LIQUID
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<DolphinSettings, DolphinState>(PoseType.FLOAT)
|
||||
.with(PoseOption(PoseType.SWIM) { _, _, entity -> entity.entityData.get(PokemonEntity.MOVING) })
|
||||
@@ -221,8 +225,8 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
state: DolphinState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
): ResourceLocation {
|
||||
return cobblemonResource("no_pose")
|
||||
}
|
||||
|
||||
override fun inertia(settings: DolphinSettings, state: DolphinState, vehicle: PokemonEntity): Double {
|
||||
|
||||
+88
-38
@@ -9,7 +9,6 @@
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangMath.lerp
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.*
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseOption
|
||||
@@ -17,10 +16,14 @@ import com.cobblemon.mod.common.api.riding.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.util.SmoothDouble
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.attributes.Attributes
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
@@ -33,11 +36,14 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
override val style = RidingStyle.LAND
|
||||
|
||||
override fun getRidingStyle(settings: GenericLandSettings, state: GenericLandState): RidingStyle {
|
||||
return RidingStyle.LAND
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<GenericLandSettings, GenericLandState>(PoseType.STAND)
|
||||
.with(PoseOption(PoseType.WALK) { _, state, _ ->
|
||||
return@PoseOption abs(state.rideVelocity.get().z) > 0.2
|
||||
return@PoseOption abs(state.rideVelocity.get().z) > 0.0
|
||||
})
|
||||
|
||||
override fun isActive(
|
||||
@@ -73,6 +79,25 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
|
||||
// Use this as a "tick" function and calculate sprinting and inAir state here
|
||||
state.sprinting.set(driver.isSprinting)
|
||||
|
||||
// Check both vertical movement and if there are blocks below.
|
||||
val posBelow = vehicle.blockPosition().below()
|
||||
val blockStateBelow = vehicle.level().getBlockState(posBelow)
|
||||
val isAirOrLiquid = blockStateBelow.isAir || !blockStateBelow.fluidState.isEmpty
|
||||
|
||||
val canSupportEntity = blockStateBelow.isFaceSturdy(vehicle.level(), posBelow, Direction.UP)
|
||||
val standingOnSolid = canSupportEntity && !isAirOrLiquid
|
||||
|
||||
// val level = vehicle.level()
|
||||
// val toesBox = vehicle.boundingBox.move(0.0, -0.1, 0.0)
|
||||
|
||||
// inAir if not on the ground
|
||||
val inAir = !(vehicle.deltaMovement.y == 0.0 || standingOnSolid)
|
||||
state.inAir.set(inAir)
|
||||
|
||||
return state.rideVelocity.get().length().toFloat()
|
||||
}
|
||||
|
||||
@@ -142,8 +167,11 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
driver: LivingEntity
|
||||
): Float {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
|
||||
//In degrees per second
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr)
|
||||
val walkHandling = 140.0 * 2
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr) * 2
|
||||
|
||||
val maxYawDiff = 90.0f
|
||||
|
||||
//Normalize the current rotation diff
|
||||
@@ -158,8 +186,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
//Take the inverse so that you turn less at higher speeds
|
||||
val normSpeed = 1.0f // = 1.0f - 0.5f*normalizeVal(state.rideVelocityocity.length(), 0.0, topSpeed).toFloat()
|
||||
|
||||
// TODO: This needs to be tweaked with in game results and testing
|
||||
val turnRate = (handling.toFloat() / 20.0f) * 2
|
||||
// TurnRate should always be quick if not sprinting
|
||||
val turnRate = if(state.sprinting.get()) (handling.toFloat() / 20.0f) else (walkHandling.toFloat() / 20.0f)
|
||||
|
||||
//Ensure you only ever rotate as much difference as there is between the angles.
|
||||
val turnSpeed = turnRate * rotDiffMod * normSpeed
|
||||
@@ -176,26 +204,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
//Limit horizontal velocity that may have accumulated through alternate behaviour
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val currVel = state.rideVelocity.get()
|
||||
// state.rideVelocity.set(Vec3(
|
||||
// max(currVel.x, topSpeed),
|
||||
// currVel.y,
|
||||
// max(currVel.z, topSpeed)
|
||||
// ))
|
||||
|
||||
state.rideVelocity.set(calculateRideSpaceVel(settings, state, vehicle, driver))
|
||||
|
||||
//This is cheap.
|
||||
//Also make it stop quicker the slower it is.
|
||||
val maxSpeed = 1.0
|
||||
//state.currVel = state.currVel.lerp( Vec3(0.0, state.currVel.y, 0.0), 1.0/20.0 )
|
||||
|
||||
|
||||
//entity.deltaMovement = entity.deltaMovement.lerp(velocity, 1.0)
|
||||
//state.currVel = state.currVel.add( f.toDouble() / 20.0, gravity / 20.0 , g.toDouble() / 20.0)
|
||||
return state.rideVelocity.get()
|
||||
state.rideVelocity.set(calculateRideSpaceVel(settings, state, vehicle, driver))
|
||||
return state.rideVelocity.get()
|
||||
}
|
||||
|
||||
private fun calculateRideSpaceVel(
|
||||
@@ -204,9 +214,13 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Vec3 {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
|
||||
// Check to see if the ride should be walking or sprinting
|
||||
val walkSpeed = getWalkSpeed(vehicle)
|
||||
val rideTopSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val topSpeed = if(state.sprinting.get()) rideTopSpeed else walkSpeed
|
||||
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr)
|
||||
val speed = state.rideVelocity.get().length()
|
||||
|
||||
//Flag for determining if player is actively inputting
|
||||
var activeInput = false
|
||||
@@ -243,18 +257,19 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
}
|
||||
|
||||
//ground Friction
|
||||
if( abs(newVelocity.z) > 0 && vehicle.onGround() && !activeInput) {
|
||||
if( (newVelocity.horizontalDistance() > 0 && vehicle.onGround() && !activeInput) || newVelocity.horizontalDistance() > topSpeed) {
|
||||
newVelocity = newVelocity.subtract(0.0, 0.0, min(0.03 * newVelocity.z.sign, newVelocity.z))
|
||||
}
|
||||
|
||||
//Jump the thang!
|
||||
if (driver.jumping && vehicle.onGround()) {
|
||||
val jumpVel = 1.0
|
||||
newVelocity = newVelocity.add(0.0, 1.0, 0.0)
|
||||
val jumpForce = 1.0
|
||||
val horz = state.rideVelocity.get().horizontalDistance()
|
||||
newVelocity = newVelocity.add(0.0, jumpForce, 0.0)
|
||||
|
||||
//Ensure this doesn't add unwanted forward velocity
|
||||
val mag = if(newVelocity.length() < topSpeed) newVelocity.length() else topSpeed
|
||||
newVelocity = newVelocity.normalize().scale(mag)
|
||||
//val mag = if(newVelocity.length() < rideTopSpeed) newVelocity.length() else rideTopSpeed
|
||||
//newVelocity = newVelocity.normalize().scale(mag)
|
||||
}
|
||||
|
||||
return newVelocity
|
||||
@@ -269,6 +284,14 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
return ((currSpeed - minSpeed) / (maxSpeed - minSpeed)).coerceIn(0.0, 1.0)
|
||||
}
|
||||
|
||||
private fun getWalkSpeed( vehicle: PokemonEntity ): Double {
|
||||
val walkspeed = vehicle.runtime.resolveDouble(vehicle.behaviour.moving.walk.walkSpeed)
|
||||
val movementSpeed = vehicle.attributes.getValue(Attributes.MOVEMENT_SPEED)
|
||||
val speedModifier = 1.2 * 0.35
|
||||
return walkspeed * movementSpeed * speedModifier
|
||||
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
@@ -360,8 +383,12 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
): ResourceLocation {
|
||||
when {
|
||||
state.inAir.get() -> cobblemonResource("in_air")
|
||||
state.sprinting.get() -> return cobblemonResource("sprinting")
|
||||
}
|
||||
return cobblemonResource("no_pose")
|
||||
}
|
||||
|
||||
override fun inertia(
|
||||
@@ -369,7 +396,7 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity
|
||||
): Double {
|
||||
return 0.5
|
||||
return 1.0
|
||||
}
|
||||
|
||||
override fun shouldRoll(
|
||||
@@ -409,7 +436,7 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
state: GenericLandState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
override fun createDefaultState(settings: GenericLandSettings) = GenericLandState()
|
||||
@@ -460,15 +487,38 @@ class GenericLandSettings : RidingBehaviourSettings {
|
||||
}
|
||||
|
||||
class GenericLandState : RidingBehaviourState() {
|
||||
var currSpeed = ridingState(0.0, Side.BOTH)
|
||||
var sprinting = ridingState(false, Side.CLIENT)
|
||||
var inAir = ridingState(false, Side.CLIENT)
|
||||
|
||||
override fun encode(buffer: FriendlyByteBuf) {
|
||||
super.encode(buffer)
|
||||
buffer.writeBoolean(sprinting.get())
|
||||
buffer.writeBoolean(inAir.get())
|
||||
}
|
||||
|
||||
override fun decode(buffer: FriendlyByteBuf) {
|
||||
super.decode(buffer)
|
||||
sprinting.set(buffer.readBoolean(), forced = true)
|
||||
inAir.set(buffer.readBoolean(), forced = true)
|
||||
}
|
||||
|
||||
override fun reset() {
|
||||
super.reset()
|
||||
sprinting.set(false, forced = true)
|
||||
inAir.set(false, forced = true)
|
||||
}
|
||||
|
||||
override fun copy() = GenericLandState().also {
|
||||
it.rideVelocity.set(this.rideVelocity.get(), forced = true)
|
||||
it.stamina.set(this.stamina.get(), forced = true)
|
||||
it.sprinting.set(this.sprinting.get(), forced = true)
|
||||
it.inAir.set(this.inAir.get(), forced = true)
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
if (previous !is GenericLandState) return false
|
||||
if (previous.sprinting.get() != sprinting.get()) return true
|
||||
if (previous.inAir.get() != inAir.get()) return true
|
||||
return super.shouldSync(previous)
|
||||
}
|
||||
}
|
||||
|
||||
+6
-3
@@ -35,7 +35,10 @@ class GenericSwimBehaviour : RidingBehaviour<GenericSwimSettings, RidingBehaviou
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
override val style = RidingStyle.LIQUID
|
||||
|
||||
override fun getRidingStyle(settings: GenericSwimSettings, state: RidingBehaviourState): RidingStyle {
|
||||
return RidingStyle.LIQUID
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<GenericSwimSettings, RidingBehaviourState>(PoseType.FLOAT)
|
||||
.with(PoseOption(PoseType.SWIM) { _, _, entity -> entity.isSwimming && entity.entityData.get(PokemonEntity.MOVING) })
|
||||
@@ -176,8 +179,8 @@ class GenericSwimBehaviour : RidingBehaviour<GenericSwimSettings, RidingBehaviou
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
): ResourceLocation {
|
||||
return cobblemonResource("no_pose")
|
||||
}
|
||||
|
||||
override fun inertia(settings: GenericSwimSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Double {
|
||||
|
||||
+48
-45
@@ -35,10 +35,13 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
override val style = RidingStyle.AIR
|
||||
|
||||
override fun getRidingStyle(settings: GliderAirSettings, state: RidingBehaviourState): RidingStyle {
|
||||
return RidingStyle.AIR
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<GliderAirSettings, RidingBehaviourState>(PoseType.HOVER)
|
||||
.with(PoseOption(PoseType.FLY) { _, _, entity -> entity.entityData.get(PokemonEntity.MOVING) })
|
||||
.with(PoseOption(PoseType.FLY) { _, _, entity -> entity.entityData.get(PokemonEntity.MOVING) })
|
||||
|
||||
override fun isActive(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
|
||||
return true
|
||||
@@ -53,20 +56,20 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
settings: GliderAirSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
settings: GliderAirSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
return Vec2(driver.xRot, driver.yRot)
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: GliderAirSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
settings: GliderAirSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
val xVector = if (vehicle.runtime.resolveBoolean(settings.canStrafe)) driver.xxa.toDouble() else 0.0
|
||||
val yVector = -vehicle.runtime.resolveDouble(settings.glideSpeed)
|
||||
@@ -77,26 +80,26 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: GliderAirSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
settings: GliderAirSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: GliderAirSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
settings: GliderAirSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
|
||||
@@ -111,38 +114,38 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: GliderAirSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
settings: GliderAirSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return 0.0f
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: GliderAirSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
settings: GliderAirSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: GliderAirSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
settings: GliderAirSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: GliderAirSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
settings: GliderAirSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return 1.0f
|
||||
}
|
||||
@@ -156,8 +159,8 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
): ResourceLocation {
|
||||
return cobblemonResource("no_pose")
|
||||
}
|
||||
|
||||
override fun inertia(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Double {
|
||||
|
||||
+6
-3
@@ -39,7 +39,10 @@ class HelicopterBehaviour : RidingBehaviour<HelicopterSettings, RidingBehaviourS
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
override val style = RidingStyle.AIR
|
||||
|
||||
override fun getRidingStyle(settings: HelicopterSettings, state: RidingBehaviourState): RidingStyle {
|
||||
return RidingStyle.AIR
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<HelicopterSettings, RidingBehaviourState>(PoseType.HOVER)
|
||||
.with(PoseOption(PoseType.FLY) { _, _, entity -> entity.entityData.get(PokemonEntity.MOVING) })
|
||||
@@ -237,8 +240,8 @@ class HelicopterBehaviour : RidingBehaviour<HelicopterSettings, RidingBehaviourS
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
): ResourceLocation {
|
||||
return cobblemonResource("no_pose")
|
||||
}
|
||||
|
||||
override fun inertia(settings: HelicopterSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Double {
|
||||
|
||||
+83
-41
@@ -9,7 +9,6 @@
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangMath.lerp
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.*
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseOption
|
||||
@@ -17,14 +16,20 @@ import com.cobblemon.mod.common.api.riding.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import net.fabricmc.loader.impl.lib.sat4j.core.Vec
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.util.SmoothDouble
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import org.joml.Matrix3f
|
||||
import org.joml.Vector3f
|
||||
import kotlin.math.*
|
||||
|
||||
class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
|
||||
@@ -33,7 +38,10 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
override val style = RidingStyle.AIR
|
||||
|
||||
override fun getRidingStyle(settings: HoverSettings, state: HoverState): RidingStyle {
|
||||
return RidingStyle.AIR
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<HoverSettings, HoverState>(PoseType.STAND)
|
||||
.with(PoseOption(PoseType.WALK) { _, state, _ ->
|
||||
@@ -143,7 +151,7 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
|
||||
): Float {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
//In degrees per second
|
||||
val handling = vehicle.runtime.resolveDouble(settings.handlingExpr)
|
||||
val handling = 220.0
|
||||
val maxYawDiff = 90.0f
|
||||
|
||||
//Normalize the current rotation diff
|
||||
@@ -158,8 +166,7 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
|
||||
//Take the inverse so that you turn less at higher speeds
|
||||
val normSpeed = 1.0f // = 1.0f - 0.5f*normalizeVal(state.rideVelocityocity.length(), 0.0, topSpeed).toFloat()
|
||||
|
||||
// TODO: This needs to be tweaked with in game results and testing
|
||||
val turnRate = (handling.toFloat() / 20.0f) * 2
|
||||
val turnRate = (handling.toFloat() / 20.0f)
|
||||
|
||||
//Ensure you only ever rotate as much difference as there is between the angles.
|
||||
val turnSpeed = turnRate * rotDiffMod * normSpeed
|
||||
@@ -168,7 +175,6 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
|
||||
return rotAmount
|
||||
}
|
||||
|
||||
|
||||
override fun velocity(
|
||||
settings: HoverSettings,
|
||||
state: HoverState,
|
||||
@@ -177,14 +183,35 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
|
||||
val strafeFactor = 0.2
|
||||
val f = driver.xxa * strafeFactor
|
||||
var g = driver.zza
|
||||
if (g <= 0.0f) {
|
||||
g *= -1.0f
|
||||
}
|
||||
// if (Minecraft.getInstance().options.keySprint.isDown) {
|
||||
// val belowBox = vehicle.boundingBox.expandTowards(0.0,-1.5, 0.0).inflate(5.0, 10.0,5.0)
|
||||
//
|
||||
// val level = vehicle.level()
|
||||
// val toBeSucked = level.getEntities(vehicle, belowBox)
|
||||
// for (suckee in toBeSucked) {
|
||||
// if (suckee != null) {
|
||||
// abductify(suckee, vehicle.position().add(0.0,-2.0,0.0))
|
||||
// suckee.deltaMovement = suckee.deltaMovement.add(0.0, 0.5,0.0)
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
return calculateRideSpaceVel(settings, state, vehicle, driver).scale(10.0)
|
||||
//
|
||||
// if (firstEntity != null) {
|
||||
// // Example action: print the entity name
|
||||
// println("Found nearby entity: ${firstEntity.name.string}")
|
||||
//
|
||||
// firstEntity.deltaMovement = firstEntity.deltaMovement.add(0.0, 0.1,0.0)
|
||||
// }
|
||||
val retVel = calculateRideSpaceVel(settings, state, vehicle, driver)
|
||||
//state.rideVelocity.set(retVel)
|
||||
return retVel
|
||||
}
|
||||
|
||||
private fun abductify(abductee: Entity, pos: Vec3) {
|
||||
val diff = pos.subtract(abductee.position()).scale(1.0)
|
||||
abductee.deltaMovement = abductee.deltaMovement.add(diff)
|
||||
}
|
||||
|
||||
private fun calculateRideSpaceVel(
|
||||
@@ -195,24 +222,27 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
|
||||
): Vec3 {
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val accel = vehicle.runtime.resolveDouble(settings.accelerationExpr)
|
||||
val speed = state.rideVelocity.get().length()
|
||||
val speed = vehicle.deltaMovement.length()
|
||||
|
||||
//Flag for determining if player is actively inputting
|
||||
var activeInput = false
|
||||
|
||||
val minSpeed = 0.0
|
||||
|
||||
var newVelocity = Vec3(state.rideVelocity.get().x, state.rideVelocity.get().y, state.rideVelocity.get().z)
|
||||
var newVelocity = vehicle.deltaMovement
|
||||
|
||||
var jumpVec = Vec3.ZERO
|
||||
val yawAligned = Matrix3f().rotateY(vehicle.yRot.toRadians())
|
||||
newVelocity = (newVelocity.toVector3f().mul(yawAligned)).toVec3d()
|
||||
|
||||
//air Resistance
|
||||
//newVelocity = newVelocity.lerp(Vec3.ZERO,(((topSpeed - speed) / topSpeed))*0.001)
|
||||
|
||||
|
||||
//speed up and slow down based on input
|
||||
if (driver.zza != 0.0f && state.stamina.get() > 0.0) {
|
||||
//make sure it can't exceed top speed
|
||||
val forwardInput = when {
|
||||
driver.zza > 0 && newVelocity.z > topSpeed -> 0.0
|
||||
driver.zza < 0 && newVelocity.z < (-topSpeed / 3.0) -> 0.0
|
||||
speed > topSpeed && (driver.zza.sign == newVelocity.z.sign.toFloat()) -> 0.0
|
||||
else -> driver.zza.sign
|
||||
}
|
||||
|
||||
@@ -221,48 +251,60 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
|
||||
newVelocity.y,
|
||||
(newVelocity.z + (accel * forwardInput.toDouble())))
|
||||
|
||||
activeInput = true
|
||||
jumpVec = jumpVec.add(0.0, 0.0, forwardInput.toDouble())
|
||||
} else {
|
||||
// newVelocity = Vec3(
|
||||
// newVelocity.x,
|
||||
// newVelocity.y,
|
||||
// newVelocity.z - (((topSpeed - speed) / topSpeed)*0.001)
|
||||
// )
|
||||
}
|
||||
|
||||
//speed up and slow down based on input
|
||||
if (driver.xxa != 0.0f && state.stamina.get() > 0.0) {
|
||||
//make sure it can't exceed top speed
|
||||
val forwardInput = when {
|
||||
driver.xxa > 0 && newVelocity.x > topSpeed -> 0.0
|
||||
driver.xxa < 0 && newVelocity.x < (-topSpeed / 3.0) -> 0.0
|
||||
val lateralInput = when {
|
||||
speed > topSpeed && (driver.xxa.sign == newVelocity.x.sign.toFloat()) -> 0.0
|
||||
else -> driver.xxa.sign
|
||||
}
|
||||
|
||||
newVelocity = Vec3(
|
||||
newVelocity.x + (accel * forwardInput.toDouble()),
|
||||
newVelocity.x + (accel * lateralInput.toDouble()),
|
||||
newVelocity.y,
|
||||
(newVelocity.z ))
|
||||
|
||||
activeInput = true
|
||||
//air resistance
|
||||
// if (lateralInput == 0.0) {
|
||||
// newVelocity = Vec3(
|
||||
// newVelocity.x - (((topSpeed - speed) / topSpeed)*0.001),
|
||||
// newVelocity.y,
|
||||
// newVelocity.z
|
||||
// )
|
||||
// }
|
||||
}
|
||||
|
||||
//Vertical movement based on driver input.
|
||||
val vertTopSpeed = topSpeed / 2.0
|
||||
val vertInput = when {
|
||||
driver.jumping -> 1.0
|
||||
driver.isShiftKeyDown -> -1.0
|
||||
driver.jumping && !(speed > topSpeed && (newVelocity.y.sign.toFloat() > 0.0))-> 1.0
|
||||
driver.isShiftKeyDown && !(speed > topSpeed && (newVelocity.y.sign.toFloat() < 0.0))-> -1.0
|
||||
else -> 0.0
|
||||
}
|
||||
|
||||
if (vertInput != 0.0 && state.stamina.get() > 0.0) {
|
||||
//air resistance
|
||||
// if (vertInput == 0.0) {
|
||||
// newVelocity = Vec3(
|
||||
// newVelocity.x,
|
||||
// newVelocity.y - (((topSpeed - speed) / topSpeed)*0.001),
|
||||
// newVelocity.z
|
||||
// )
|
||||
// }
|
||||
|
||||
if (state.stamina.get() > 0.0) {
|
||||
newVelocity = Vec3(
|
||||
newVelocity.x,
|
||||
(newVelocity.y + (accel * vertInput)).coerceIn(-vertTopSpeed, vertTopSpeed),
|
||||
(newVelocity.y + (accel * vertInput)), //.coerceIn(-vertTopSpeed, vertTopSpeed),
|
||||
newVelocity.z)
|
||||
activeInput = true
|
||||
}
|
||||
|
||||
|
||||
//air Friction
|
||||
|
||||
|
||||
|
||||
return newVelocity
|
||||
}
|
||||
|
||||
@@ -366,8 +408,8 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
): ResourceLocation {
|
||||
return cobblemonResource("no_pose")
|
||||
}
|
||||
|
||||
override fun inertia(
|
||||
@@ -375,7 +417,7 @@ class HoverBehaviour : RidingBehaviour<HoverSettings, HoverState> {
|
||||
state: HoverState,
|
||||
vehicle: PokemonEntity
|
||||
): Double {
|
||||
return 0.05
|
||||
return 1.0
|
||||
}
|
||||
|
||||
override fun shouldRoll(
|
||||
@@ -427,12 +469,12 @@ class HoverSettings : RidingBehaviourSettings {
|
||||
var canJump = "true".asExpression()
|
||||
private set
|
||||
|
||||
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 1.0, 0.3)".asExpression()
|
||||
var speedExpr: Expression = "q.get_ride_stats('SPEED', 'AIR', 0.65, 0.3)".asExpression()
|
||||
private set
|
||||
|
||||
// Max accel is a whole 1.0 in 1 second. The conversion in the function below is to convert seconds to ticks
|
||||
var accelerationExpr: Expression =
|
||||
"q.get_ride_stats('ACCELERATION', 'AIR', (1.0 / (20.0 * 0.5)), (1.0 / (20.0 * 5.0)))".asExpression()
|
||||
"q.get_ride_stats('ACCELERATION', 'AIR', (1.0 / (20.0 * 1.5)), (1.0 / (20.0 * 3.0)))".asExpression()
|
||||
private set
|
||||
|
||||
// Between 30 seconds and 10 seconds at the lowest when at full speed.
|
||||
|
||||
+28
-17
@@ -20,6 +20,7 @@ import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import com.bedrockk.molang.runtime.MoLangMath.lerp
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.SmoothDouble
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
@@ -35,7 +36,10 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
override val style = RidingStyle.AIR
|
||||
|
||||
override fun getRidingStyle(settings: JetAirSettings, state: JetAirState): RidingStyle {
|
||||
return RidingStyle.AIR
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<JetAirSettings, JetAirState>(PoseType.HOVER)
|
||||
.with(PoseOption(PoseType.FLY) { _, state, _ -> state.rideVelocity.get().z > 0.1 })
|
||||
@@ -174,7 +178,7 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
|
||||
state.rideVelocity.set(Vec3(state.rideVelocity.get().x, state.rideVelocity.get().y, max(state.rideVelocity.get().z - ((accel) / 4), minSpeed)))
|
||||
} else if (driver.zza < 0.0 && speed > minSpeed) {
|
||||
//modify deccel to be slower when at closer speeds to minimum speed
|
||||
val deccelMod = max((normalizeSpeed(speed, minSpeed, topSpeed) - 1).pow(2) * 8, 0.1)
|
||||
val deccelMod = max((normalizeSpeed(speed, minSpeed, topSpeed) - 1).pow(2) * 4, 0.1)
|
||||
|
||||
//Decelerate currently always a constant half of max acceleration.
|
||||
state.rideVelocity.set(Vec3(state.rideVelocity.get().x, state.rideVelocity.get().y, max(state.rideVelocity.get().z - ((accel * deccelMod) / 2), minSpeed)))
|
||||
@@ -226,13 +230,8 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
|
||||
val invertRoll = if (Cobblemon.config.invertRoll) -1 else 1
|
||||
val invertPitch = if (Cobblemon.config.invertPitch) -1 else 1
|
||||
|
||||
// Smooth out and accumulate roll input
|
||||
val smoothingSpeed = 4.0
|
||||
val mouseXc = (mouseX).coerceIn(-60.0, 60.0)
|
||||
val xInput = mouseXSmoother.getNewDeltaValue(mouseXc * 0.1 * invertRoll, deltaTime * smoothingSpeed);
|
||||
|
||||
// Accumulate the y mouse input for pitch
|
||||
//state.currMouseXForce.set((state.currMouseXForce.get() + (0.0015 * mouseX * invertRoll)).coerceIn(-1.0, 1.0))
|
||||
// Accumulate the mouse input
|
||||
state.currMouseXForce.set((state.currMouseXForce.get() + (0.0015 * mouseX * invertRoll)).coerceIn(-1.0, 1.0))
|
||||
state.currMouseYForce.set((state.currMouseYForce.get() + (0.0015 * mouseY * invertPitch)).coerceIn(-1.0, 1.0))
|
||||
|
||||
//Get handling in degrees per second
|
||||
@@ -253,12 +252,24 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
|
||||
|
||||
val pitchRot = handling * state.currMouseYForce.get()
|
||||
|
||||
//Roll is 1.5 times as fast as pitch
|
||||
// Roll
|
||||
val rollRot = handling * 1.5 * state.currMouseXForce.get()
|
||||
|
||||
val mouseRotation = Vec3(0.0, pitchRot, rollRot)
|
||||
|
||||
// Have accumulated input begin decay when no input detected
|
||||
if(abs(mouseX) == 0.0) {
|
||||
// Have decay on roll be much stronger.
|
||||
state.currMouseXForce.set(lerp( state.currMouseXForce.get(), 0.0, 0.02 ))
|
||||
}
|
||||
if(mouseY == 0.0) {
|
||||
state.currMouseYForce.set(lerp(state.currMouseYForce.get(), 0.0, 0.005 ))
|
||||
}
|
||||
|
||||
|
||||
|
||||
//val rollRot = handling * 1.5 * state.currMouseXForce.get()
|
||||
val rollRot = handling * 1.5 * xInput.coerceIn(-1.0,1.0)
|
||||
//yaw, pitch, roll
|
||||
return Vec3(0.0, pitchRot, rollRot)
|
||||
return mouseRotation
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
@@ -324,12 +335,12 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
|
||||
state: JetAirState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
): ResourceLocation {
|
||||
return cobblemonResource("no_pose")
|
||||
}
|
||||
|
||||
override fun inertia(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Double {
|
||||
return 0.5
|
||||
return 1.0
|
||||
}
|
||||
|
||||
override fun shouldRoll(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Boolean {
|
||||
@@ -365,7 +376,7 @@ class JetAirSettings : RidingBehaviourSettings {
|
||||
var gravity: Expression = "0".asExpression()
|
||||
private set
|
||||
|
||||
var minSpeed: Expression = "0.8".asExpression()
|
||||
var minSpeed: Expression = "1.2".asExpression()
|
||||
private set
|
||||
|
||||
var handlingYawExpr: Expression = "q.get_ride_stats('SKILL', 'AIR', 50.0, 25.0)".asExpression()
|
||||
|
||||
+6
-3
@@ -34,7 +34,10 @@ class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
override val style = RidingStyle.LIQUID
|
||||
|
||||
override fun getRidingStyle(settings: SwimDashSettings, state: SwimDashState): RidingStyle {
|
||||
return RidingStyle.LIQUID
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<SwimDashSettings, SwimDashState>(PoseType.FLOAT)
|
||||
.with(PoseOption(PoseType.SWIM) { _, _, entity -> entity.isSwimming && entity.entityData.get(PokemonEntity.MOVING) })
|
||||
@@ -183,8 +186,8 @@ class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
|
||||
state: SwimDashState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
): ResourceLocation {
|
||||
return cobblemonResource("no_pose")
|
||||
}
|
||||
|
||||
override fun inertia(settings: SwimDashSettings, state: SwimDashState, vehicle: PokemonEntity): Double {
|
||||
|
||||
+6
-3
@@ -53,7 +53,10 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
override val style = RidingStyle.LAND
|
||||
|
||||
override fun getRidingStyle(settings: VehicleLandSettings, state: VehicleLandState): RidingStyle {
|
||||
return RidingStyle.LAND
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<VehicleLandSettings, VehicleLandState>(PoseType.STAND)
|
||||
.with(PoseOption(PoseType.WALK) { _, _, entity -> entity.entityData.get(PokemonEntity.MOVING) })
|
||||
@@ -222,8 +225,8 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
|
||||
state: VehicleLandState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
): ResourceLocation {
|
||||
return cobblemonResource("no_pose")
|
||||
}
|
||||
|
||||
override fun inertia(settings: VehicleLandSettings, state: VehicleLandState, vehicle: PokemonEntity): Double {
|
||||
|
||||
+19
-13
@@ -30,8 +30,14 @@ class CompositeBehaviour : RidingBehaviour<CompositeSettings, CompositeState> {
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
override val style = RidingStyle.COMPOSITE
|
||||
|
||||
override fun getRidingStyle(settings: CompositeSettings, state: CompositeState): RidingStyle {
|
||||
return chooseBehaviour(settings, state) {
|
||||
behaviour, behaviourSettings, behaviourState ->
|
||||
behaviour.getRidingStyle(behaviourSettings, behaviourState)
|
||||
}
|
||||
}
|
||||
|
||||
override fun createDefaultState(settings: CompositeSettings): CompositeState {
|
||||
val defaultBehaviour = RidingBehaviours.get(settings.defaultBehaviour.key)
|
||||
val defaultState = defaultBehaviour.createDefaultState(settings.defaultBehaviour)
|
||||
@@ -51,7 +57,7 @@ class CompositeBehaviour : RidingBehaviour<CompositeSettings, CompositeState> {
|
||||
): T {
|
||||
val defaultBehaviour = RidingBehaviours.get(settings.defaultBehaviour.key)
|
||||
val alternativeBehaviour = RidingBehaviours.get(settings.alternateBehaviour.key)
|
||||
return when (state.activeController.get()) {
|
||||
return when (state.activeBehaviour.get()) {
|
||||
settings.defaultBehaviour.key -> action(
|
||||
defaultBehaviour,
|
||||
settings.defaultBehaviour,
|
||||
@@ -63,7 +69,7 @@ class CompositeBehaviour : RidingBehaviour<CompositeSettings, CompositeState> {
|
||||
state.alternateBehaviourState
|
||||
)
|
||||
|
||||
else -> error("Invalid controller: ${state.activeController.get()}")
|
||||
else -> error("Invalid controller: ${state.activeBehaviour.get()}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +171,7 @@ class CompositeBehaviour : RidingBehaviour<CompositeSettings, CompositeState> {
|
||||
state: CompositeState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
): ResourceLocation {
|
||||
return chooseBehaviour(settings, state) { behaviour, behaviourSettings, behaviourState ->
|
||||
behaviour.useRidingAltPose(behaviourSettings, behaviourState, vehicle, driver)
|
||||
}
|
||||
@@ -364,28 +370,28 @@ open class CompositeSettings : RidingBehaviourSettings {
|
||||
}
|
||||
|
||||
class CompositeState(
|
||||
private val defaultBehaviour: ResourceLocation,
|
||||
val defaultBehaviour: ResourceLocation,
|
||||
val defaultBehaviourState: RidingBehaviourState,
|
||||
val alternateBehaviourState: RidingBehaviourState
|
||||
) : RidingBehaviourState() {
|
||||
var activeController = ridingState(defaultBehaviour, Side.CLIENT)
|
||||
var activeBehaviour = ridingState(defaultBehaviour, Side.CLIENT)
|
||||
var lastTransition = ridingState(-100L, Side.BOTH)
|
||||
|
||||
override val rideVelocity: SidedRidingState<Vec3>
|
||||
get() = when (activeController.get()) {
|
||||
get() = when (activeBehaviour.get()) {
|
||||
defaultBehaviour -> defaultBehaviourState.rideVelocity
|
||||
else -> alternateBehaviourState.rideVelocity
|
||||
}
|
||||
|
||||
override val stamina: SidedRidingState<Float>
|
||||
get() = when (activeController.get()) {
|
||||
get() = when (activeBehaviour.get()) {
|
||||
defaultBehaviour -> defaultBehaviourState.stamina
|
||||
else -> alternateBehaviourState.stamina
|
||||
}
|
||||
|
||||
override fun reset() {
|
||||
super.reset()
|
||||
activeController.set(defaultBehaviour, forced = true)
|
||||
activeBehaviour.set(defaultBehaviour, forced = true)
|
||||
lastTransition.set(-100L, forced = true)
|
||||
defaultBehaviourState.reset()
|
||||
alternateBehaviourState.reset()
|
||||
@@ -394,7 +400,7 @@ class CompositeState(
|
||||
override fun copy(): CompositeState {
|
||||
val state =
|
||||
CompositeState(defaultBehaviour, defaultBehaviourState.copy(), alternateBehaviourState.copy())
|
||||
state.activeController.set(activeController.get(), forced = true)
|
||||
state.activeBehaviour.set(activeBehaviour.get(), forced = true)
|
||||
state.lastTransition.set(lastTransition.get(), forced = true)
|
||||
state.rideVelocity.set(rideVelocity.get(), forced = true)
|
||||
state.stamina.set(stamina.get(), forced = true)
|
||||
@@ -403,7 +409,7 @@ class CompositeState(
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
if (previous !is CompositeState) return false
|
||||
if (previous.activeController.get() != activeController.get()) return true
|
||||
if (previous.activeBehaviour.get() != activeBehaviour.get()) return true
|
||||
if (defaultBehaviourState.shouldSync(previous.defaultBehaviourState)) return true
|
||||
if (alternateBehaviourState.shouldSync(previous.alternateBehaviourState)) return true
|
||||
return super.shouldSync(previous)
|
||||
@@ -411,14 +417,14 @@ class CompositeState(
|
||||
|
||||
override fun encode(buffer: FriendlyByteBuf) {
|
||||
super.encode(buffer)
|
||||
buffer.writeResourceLocation(activeController.get())
|
||||
buffer.writeResourceLocation(activeBehaviour.get())
|
||||
defaultBehaviourState.encode(buffer)
|
||||
alternateBehaviourState.encode(buffer)
|
||||
}
|
||||
|
||||
override fun decode(buffer: FriendlyByteBuf) {
|
||||
super.decode(buffer)
|
||||
activeController.set(buffer.readResourceLocation(), forced = true)
|
||||
activeBehaviour.set(buffer.readResourceLocation(), forced = true)
|
||||
defaultBehaviourState.decode(buffer)
|
||||
alternateBehaviourState.decode(buffer)
|
||||
}
|
||||
|
||||
+2
-2
@@ -44,10 +44,10 @@ interface CompositeRidingStrategy<T : CompositeSettings> {
|
||||
toState.stamina.set(fromState.stamina.get())
|
||||
toState.rideVelocity.set(fromState.rideVelocity.get())
|
||||
fromState.reset()
|
||||
state.activeController.set(toSettings.key)
|
||||
state.activeBehaviour.set(toSettings.key)
|
||||
state.lastTransition.set(vehicle.level().gameTime)
|
||||
val behaviour = RidingBehaviours.get(toSettings.key)
|
||||
vehicle.setBehaviourFlag(PokemonBehaviourFlag.FLYING, behaviour.style == RidingStyle.AIR)
|
||||
vehicle.setBehaviourFlag(PokemonBehaviourFlag.FLYING, behaviour.getRidingStyle(toSettings, toState) == RidingStyle.AIR)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-4
@@ -9,13 +9,11 @@
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types.composite.strategies
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviours
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.composite.CompositeSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.composite.CompositeState
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonBehaviourFlag
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
@@ -47,7 +45,7 @@ object FallStrategy : CompositeRidingStrategy<FallCompositeSettings> {
|
||||
defaultSettings: RidingBehaviourSettings,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
if (state.activeController.get() == defaultSettings.key) return false
|
||||
if (state.activeBehaviour.get() == defaultSettings.key) return false
|
||||
if (state.lastTransition.get() + 20 >= vehicle.level().gameTime) return false
|
||||
if (!vehicle.onGround()) return false
|
||||
val defaultBehaviour = RidingBehaviours.get(defaultSettings.key)
|
||||
@@ -61,7 +59,7 @@ object FallStrategy : CompositeRidingStrategy<FallCompositeSettings> {
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
if (state.activeController.get() == alternateSettings.key) return false
|
||||
if (state.activeBehaviour.get() == alternateSettings.key) return false
|
||||
if (!driver.jumping) return false
|
||||
if (state.lastTransition.get() + 20 >= vehicle.level().gameTime) return false
|
||||
|
||||
|
||||
+2
-4
@@ -8,13 +8,11 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types.composite.strategies
|
||||
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviours
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.composite.CompositeSettings
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.composite.CompositeState
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonBehaviourFlag
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.world.entity.player.Player
|
||||
@@ -45,7 +43,7 @@ object JumpStrategy : CompositeRidingStrategy<CompositeSettings> {
|
||||
defaultSettings: RidingBehaviourSettings,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
if (state.activeController.get() == defaultSettings.key) return false
|
||||
if (state.activeBehaviour.get() == defaultSettings.key) return false
|
||||
if (!vehicle.onGround()) return false
|
||||
if (state.lastTransition.get() + 20 >= vehicle.level().gameTime) return false
|
||||
val defaultBehaviour = RidingBehaviours.get(defaultSettings.key)
|
||||
@@ -58,7 +56,7 @@ object JumpStrategy : CompositeRidingStrategy<CompositeSettings> {
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
if (state.activeController.get() == alternativeSettings.key) return false
|
||||
if (state.activeBehaviour.get() == alternativeSettings.key) return false
|
||||
if (!driver.jumping) return false
|
||||
if (state.lastTransition.get() + 20 >= vehicle.level().gameTime) return false
|
||||
val alternativeBehaviour = RidingBehaviours.get(alternativeSettings.key)
|
||||
|
||||
+2
-2
@@ -45,7 +45,7 @@ object RunStrategy : CompositeRidingStrategy<CompositeSettings> {
|
||||
entity: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
if (state.activeController.get() == defaultSettings.key) return false
|
||||
if (state.activeBehaviour.get() == defaultSettings.key) return false
|
||||
if (!entity.onGround()) return false
|
||||
if (state.lastTransition.get() + 20 >= entity.level().gameTime) return false
|
||||
val defaultBehaviour = RidingBehaviours.get(defaultSettings.key)
|
||||
@@ -60,7 +60,7 @@ object RunStrategy : CompositeRidingStrategy<CompositeSettings> {
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Boolean {
|
||||
if (state.activeController.get() == alternativeSettings.key) return false
|
||||
if (state.activeBehaviour.get() == alternativeSettings.key) return false
|
||||
if (state.lastTransition.get() + 20 >= entity.level().gameTime) return false
|
||||
val alternativeBehaviour = RidingBehaviours.get(alternativeSettings.key)
|
||||
return driver.isSprinting && input.z > 0.5 && alternativeBehaviour.isActive(alternativeSettings, state.alternateBehaviourState, entity)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.stats
|
||||
|
||||
import com.cobblemon.mod.common.api.berry.Flavor
|
||||
import com.cobblemon.mod.common.api.cooking.Flavour
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import net.minecraft.network.chat.Component
|
||||
|
||||
@@ -19,13 +19,13 @@ import net.minecraft.network.chat.Component
|
||||
* @since February 17th, 2025
|
||||
*/
|
||||
enum class RidingStat(
|
||||
val flavour: Flavor
|
||||
val flavour: Flavour
|
||||
) {
|
||||
SPEED(Flavor.SWEET),
|
||||
ACCELERATION(Flavor.SPICY),
|
||||
SKILL(Flavor.DRY),
|
||||
JUMP(Flavor.BITTER),
|
||||
STAMINA(Flavor.SOUR);
|
||||
SPEED(Flavour.SWEET),
|
||||
ACCELERATION(Flavour.SPICY),
|
||||
SKILL(Flavour.DRY),
|
||||
JUMP(Flavour.BITTER),
|
||||
STAMINA(Flavour.SOUR);
|
||||
|
||||
companion object {
|
||||
fun getByName(name: String) = RidingStat.entries.firstOrNull { it.name.equals(name, ignoreCase = true) }
|
||||
|
||||
+8
-8
@@ -43,12 +43,12 @@ class RidingStatDefinition {
|
||||
buffer.writeNullable(displayName) { _, it -> buffer.writeText(it) }
|
||||
buffer.writeNullable(description) { _, it -> buffer.writeText(it) }
|
||||
buffer.writeMap(
|
||||
ranges,
|
||||
{ _, it -> buffer.writeEnum(it) },
|
||||
{ _, it ->
|
||||
buffer.writeSizedInt(IntSize.U_BYTE, it.first)
|
||||
buffer.writeSizedInt(IntSize.U_BYTE, it.last)
|
||||
}
|
||||
ranges,
|
||||
{ _, it -> buffer.writeEnum(it) },
|
||||
{ _, it ->
|
||||
buffer.writeSizedInt(IntSize.U_BYTE, it.first)
|
||||
buffer.writeSizedInt(IntSize.U_BYTE, it.last)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -57,8 +57,8 @@ class RidingStatDefinition {
|
||||
val displayName = buffer.readNullable { buffer.readText() }
|
||||
val description = buffer.readNullable { buffer.readText() }
|
||||
val ranges = buffer.readMap<RidingStyle, IntRange>(
|
||||
{ buffer.readEnum<RidingStyle>(RidingStyle::class.java) },
|
||||
{ IntRange(buffer.readSizedInt(IntSize.U_BYTE), buffer.readSizedInt(IntSize.U_BYTE)) }
|
||||
{ buffer.readEnum<RidingStyle>(RidingStyle::class.java) },
|
||||
{ IntRange(buffer.readSizedInt(IntSize.U_BYTE), buffer.readSizedInt(IntSize.U_BYTE)) }
|
||||
)
|
||||
return RidingStatDefinition().apply {
|
||||
this.displayName = displayName
|
||||
|
||||
+4
-4
@@ -39,10 +39,10 @@ class RidingAnimationData
|
||||
var currRot = Vec3.ZERO
|
||||
var angDelta = Vec3.ZERO
|
||||
|
||||
// val stiffness = 90.0
|
||||
// val damping = 18.0
|
||||
val stiffness = 16.0
|
||||
val damping = 8.0
|
||||
val stiffness = 90.0
|
||||
val damping = 18.0
|
||||
// val stiffness = 16.0
|
||||
// val damping = 8.0
|
||||
|
||||
// Update velocity first
|
||||
val currentVelocity = Vec3(
|
||||
|
||||
@@ -127,6 +127,7 @@ class ParticleEvent(
|
||||
sourceAlive = storm.sourceAlive,
|
||||
sourceVisible = storm.sourceVisible,
|
||||
onDespawn = {},
|
||||
getParticleColor = storm.getParticleColor,
|
||||
targetPos = storm.targetPos,
|
||||
runtime = MoLangRuntime().setup(),
|
||||
entity = storm.entity
|
||||
|
||||
@@ -37,7 +37,6 @@ import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawner
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.preset.BasicSpawnDetailPreset
|
||||
import com.cobblemon.mod.common.api.spawning.preset.BestSpawnerConfig
|
||||
import com.cobblemon.mod.common.api.spawning.preset.PokemonSpawnDetailPreset
|
||||
|
||||
+10
-1
@@ -10,6 +10,8 @@ package com.cobblemon.mod.common.api.spawning
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Cobblemon.config
|
||||
import com.cobblemon.mod.common.api.spawning.influence.WorldSlicedSpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.prospecting.SpawningInfluenceProspector
|
||||
import com.cobblemon.mod.common.api.spawning.prospecting.SpawningProspector
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.SpawningArea
|
||||
@@ -79,6 +81,7 @@ object CobblemonSpawningProspector : SpawningProspector {
|
||||
val blocks = Array(area.length) { Array(height) { Array(area.width) { defaultBlockData } } }
|
||||
val skyLevel = Array(area.length) { Array(area.width) { world.maxBuildHeight } }
|
||||
val pos = BlockPos.MutableBlockPos()
|
||||
val worldSlicedSpawningInfluences = mutableListOf<WorldSlicedSpawningInfluence>()
|
||||
|
||||
val chunks = mutableMapOf<Pair<Int, Int>, ChunkAccess?>()
|
||||
val yRange = (baseY until baseY + height).reversed()
|
||||
@@ -98,6 +101,7 @@ object CobblemonSpawningProspector : SpawningProspector {
|
||||
light = world.getMaxLocalRawBrightness(pos),
|
||||
skyLight = skyLight
|
||||
)
|
||||
worldSlicedSpawningInfluences.addAll(SpawningInfluenceProspector.prospectors.mapNotNull { it.prospectBlock(world, pos, state) })
|
||||
if (canSeeSky) {
|
||||
skyLevel[x - area.baseX][z - area.baseZ] = y
|
||||
}
|
||||
@@ -108,6 +112,10 @@ object CobblemonSpawningProspector : SpawningProspector {
|
||||
}
|
||||
}
|
||||
|
||||
for (prospector in SpawningInfluenceProspector.prospectors) {
|
||||
worldSlicedSpawningInfluences.addAll(prospector.prospect(spawner, area))
|
||||
}
|
||||
|
||||
return WorldSlice(
|
||||
cause = area.cause,
|
||||
world = world,
|
||||
@@ -116,7 +124,8 @@ object CobblemonSpawningProspector : SpawningProspector {
|
||||
baseZ = area.baseZ,
|
||||
blocks = blocks,
|
||||
skyLevel = skyLevel,
|
||||
nearbyEntityPositions = nearbyEntityPositions
|
||||
nearbyEntityPositions = nearbyEntityPositions,
|
||||
influences = worldSlicedSpawningInfluences
|
||||
)
|
||||
}
|
||||
}
|
||||
+30
-8
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawnerFactory
|
||||
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import java.util.UUID
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
|
||||
@@ -32,24 +33,45 @@ object CobblemonWorldSpawnerManager : SpawnerManager() {
|
||||
init {
|
||||
PlatformEvents.SERVER_PLAYER_LOGIN.subscribe { this.onPlayerLogin(it.player) }
|
||||
PlatformEvents.SERVER_PLAYER_LOGOUT.subscribe { this.onPlayerLogout(it.player) }
|
||||
PlatformEvents.CHANGE_DIMENSION.subscribe { this.onDimensionChange(it.player, it.origin, it.destination) }
|
||||
}
|
||||
|
||||
fun onPlayerLogin(player: ServerPlayer) {
|
||||
// Disables spawning
|
||||
if (!Cobblemon.config.enableSpawning || server()?.gameRules?.getBoolean(CobblemonGameRules.DO_POKEMON_SPAWNING) == false) {
|
||||
if (!Cobblemon.config.enableSpawning || player.level().gameRules.getBoolean(CobblemonGameRules.DO_POKEMON_SPAWNING) == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
val spawner = PlayerSpawnerFactory.create(this, player)
|
||||
spawnersForPlayers[player.uuid] = spawner
|
||||
registerSpawner(spawner)
|
||||
registerPlayerSpawner(player)
|
||||
}
|
||||
|
||||
fun onPlayerLogout(player: ServerPlayer) {
|
||||
val spawner = spawnersForPlayers[player.uuid]
|
||||
if (spawner != null) {
|
||||
spawnersForPlayers.remove(player.uuid)
|
||||
unregisterSpawner(spawner)
|
||||
unregisterPlayerSpawner(player)
|
||||
}
|
||||
|
||||
fun onDimensionChange(player: ServerPlayer, origin: ServerLevel?, destination: ServerLevel?) {
|
||||
fun getSpawnRule(level: ServerLevel?) = level?.gameRules?.getBoolean(CobblemonGameRules.DO_POKEMON_SPAWNING)
|
||||
|
||||
if (!Cobblemon.config.enableSpawning || getSpawnRule(origin) == getSpawnRule(destination)) {
|
||||
return
|
||||
}
|
||||
|
||||
val spawnerAction = if (destination?.gameRules?.getBoolean(CobblemonGameRules.DO_POKEMON_SPAWNING) == false) {
|
||||
::unregisterPlayerSpawner
|
||||
} else {
|
||||
::registerPlayerSpawner
|
||||
}
|
||||
spawnerAction(player)
|
||||
}
|
||||
|
||||
private fun unregisterPlayerSpawner(player: ServerPlayer) {
|
||||
spawnersForPlayers.remove(player.uuid)?.let { unregisterSpawner(it) }
|
||||
}
|
||||
|
||||
private fun registerPlayerSpawner(player: ServerPlayer) {
|
||||
PlayerSpawnerFactory.create(this, player).also {
|
||||
spawnersForPlayers[player.uuid] = it
|
||||
registerSpawner(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.util.weightedSelection
|
||||
|
||||
object SpawnBucketUtils {
|
||||
fun chooseAdjustedSpawnBucket(buckets: List<SpawnBucket>, bucketLureStrength: Int): SpawnBucket {
|
||||
val baseValues = listOf(88.5F, 8.5F, 2.4F, 0.6F)
|
||||
val adjustments = listOf(-6.9F, 3.6F, 2.3F, 1F)
|
||||
|
||||
val adjustedWeights = buckets.mapIndexed { index, bucket ->
|
||||
if (index >= baseValues.size) {
|
||||
bucket to bucket.weight
|
||||
} else {
|
||||
val base = baseValues[index]
|
||||
val adjustment = adjustments[index]
|
||||
val adjusted = base + adjustment * bucketLureStrength
|
||||
bucket to adjusted.coerceAtLeast(0f) // we do not want the weights to be negative
|
||||
}
|
||||
}.toMap()
|
||||
|
||||
return buckets.weightedSelection { adjustedWeights[it]!! }!!
|
||||
}
|
||||
}
|
||||
@@ -71,10 +71,15 @@ open class SpawnerManager {
|
||||
|
||||
open fun onServerTick() {
|
||||
// Disables spawning
|
||||
if (!Cobblemon.config.enableSpawning || server()?.gameRules?.getBoolean(DO_POKEMON_SPAWNING) == false) {
|
||||
if (!Cobblemon.config.enableSpawning) {
|
||||
return
|
||||
}
|
||||
influences.removeIf { it.isExpired() }
|
||||
getSpawnersOfType<TickingSpawner>().forEach(TickingSpawner::tick)
|
||||
getSpawnersOfType<TickingSpawner>().forEach {
|
||||
if (it.getCauseEntity()?.level()?.gameRules?.getBoolean(DO_POKEMON_SPAWNING) == false) {
|
||||
return@forEach
|
||||
}
|
||||
it.tick()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,8 @@
|
||||
package com.cobblemon.mod.common.api.spawning
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.WorldSlicedSpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.prospecting.SpawningProspector
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
@@ -35,7 +37,8 @@ class WorldSlice(
|
||||
val baseZ: Int,
|
||||
val blocks: Array<Array<Array<BlockData>>>,
|
||||
val skyLevel: Array<Array<Int>>,
|
||||
var nearbyEntityPositions: List<Vec3>
|
||||
var nearbyEntityPositions: List<Vec3>,
|
||||
val influences: List<WorldSlicedSpawningInfluence>
|
||||
) {
|
||||
class BlockData(
|
||||
val state: BlockState,
|
||||
|
||||
+1
-11
@@ -55,7 +55,7 @@ class FishingSpawningCondition: SpawningCondition<FishingSpawningContext>() {
|
||||
}
|
||||
}
|
||||
if (bait != null) { // check for the bait on the bobber
|
||||
val pokerodBait = ctx.rodBait?.item
|
||||
val pokerodBait = ctx.baitStack.itemHolder.unwrapKey().orElse(null)?.location()
|
||||
if (pokerodBait != bait) {
|
||||
return false
|
||||
}
|
||||
@@ -66,16 +66,6 @@ class FishingSpawningCondition: SpawningCondition<FishingSpawningContext>() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/*if (ctx is FishingSpawningContext && (ctx as FishingSpawningContext).rodItem != null) { // check if the bait attracts certain EV yields
|
||||
val pokerodItem = (ctx as FishingSpawningContext).rodItem
|
||||
|
||||
// todo check if the EV yield of the berry matches the bait EV attract maybe?
|
||||
|
||||
if (// todo if bait EV yield != EV yield of pokemon consideration //Registries.ITEM.getId(pokerodItem?.bait?.item).path == )
|
||||
return false
|
||||
}*/
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
+6
@@ -54,6 +54,12 @@ interface AreaContextResolver {
|
||||
if (fittedContextCalculator != null) {
|
||||
val context = fittedContextCalculator.calculate(input)
|
||||
if (context != null) {
|
||||
slice.influences.forEach {
|
||||
if (it.appliesTo(context)) {
|
||||
context.influences.add(it.influence)
|
||||
}
|
||||
}
|
||||
|
||||
contexts.add(context)
|
||||
// The position BlockPos has been used in a context, editing the same one
|
||||
// will cause entities to spawn at the wrong location (buried in walls, usually).
|
||||
|
||||
+2
-1
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.api.spawning.context
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawnCause
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import com.cobblemon.mod.common.item.interactive.PokerodItem
|
||||
import com.cobblemon.mod.common.util.toVec3d
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
@@ -40,5 +41,5 @@ class FishingSpawningContext(
|
||||
val nearbyBlockTypes: List<Block> by lazy { nearbyBlocks.map { it.block }.distinct().toList() }
|
||||
val rodStack = cause.rodStack
|
||||
val rodItem = cause.rodItem
|
||||
val rodBait = cause.bait
|
||||
val baitStack = PokerodItem.getBaitStackOnRod(cause.rodStack)
|
||||
}
|
||||
@@ -55,13 +55,12 @@ class SpawnPool(val name: String) : JsonDataRegistry<SpawnSet>, Iterable<SpawnDe
|
||||
CobblemonSpawnPools.onServerLoad(server)
|
||||
}
|
||||
precalculate()
|
||||
this.observable.emit(this)
|
||||
}
|
||||
|
||||
val details = mutableListOf<SpawnDetail>()
|
||||
var precalculation: PrecalculationResult<*> = RootPrecalculation.generate(details, emptyList())
|
||||
val precalculators = mutableListOf<SpawningPrecalculation<*>>()
|
||||
// /** A set of all [RegisteredSpawningContext]s that are mentioned in this pool. */
|
||||
// val contexts = mutableSetOf<RegisteredSpawningContext<*>>()
|
||||
|
||||
override fun iterator() = details.iterator()
|
||||
|
||||
|
||||
+14
-80
@@ -12,26 +12,24 @@ import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.fishing.BobberSpawnPokemonEvent
|
||||
import com.cobblemon.mod.common.api.fishing.FishingBait
|
||||
import com.cobblemon.mod.common.api.fishing.SpawnBaitEffects
|
||||
import com.cobblemon.mod.common.api.fishing.SpawnBait
|
||||
import com.cobblemon.mod.common.api.pokemon.Natures
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.pokemon.egg.EggGroup
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnCause
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawnBaitInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.item.interactive.PokerodItem
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.pokemon.abilities.HiddenAbility
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import kotlin.random.Random.Default.nextInt
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import kotlin.random.Random.Default.nextInt
|
||||
|
||||
/**
|
||||
* A spawning cause that is embellished with fishing information. Could probably also
|
||||
@@ -48,7 +46,7 @@ class FishingSpawnCause(
|
||||
) : SpawnCause(spawner, bucket, entity) {
|
||||
companion object {
|
||||
const val FISHED_ASPECT = "fished"
|
||||
fun shinyReroll(pokemonEntity: PokemonEntity, effect: FishingBait.Effect) {
|
||||
fun shinyReroll(pokemonEntity: PokemonEntity, effect: SpawnBait.Effect) {
|
||||
if (pokemonEntity.pokemon.shiny) return
|
||||
|
||||
val shinyOdds = Cobblemon.config.shinyRate.toInt()
|
||||
@@ -62,7 +60,7 @@ class FishingSpawnCause(
|
||||
}
|
||||
}
|
||||
|
||||
fun alterNatureAttempt(pokemonEntity: PokemonEntity, effect: FishingBait.Effect) {
|
||||
fun alterNatureAttempt(pokemonEntity: PokemonEntity, effect: SpawnBait.Effect) {
|
||||
val baitStat = effect.subcategory?.let { it1 -> Stats.getStat(it1.path).identifier } ?: run {
|
||||
LOGGER.warn("One of your nature baits is missing a subcategory and failed to effect a fished Pokemon")
|
||||
return
|
||||
@@ -76,7 +74,7 @@ class FishingSpawnCause(
|
||||
pokemonEntity.pokemon.nature = Natures.getNature(takenNature.name.path) ?: return
|
||||
}
|
||||
|
||||
fun alterIVAttempt(pokemonEntity: PokemonEntity, effect: FishingBait.Effect) {
|
||||
fun alterIVAttempt(pokemonEntity: PokemonEntity, effect: SpawnBait.Effect) {
|
||||
val iv = effect.subcategory ?: return
|
||||
|
||||
if ((pokemonEntity.pokemon.ivs[Stats.getStat(iv.path)] ?: 0) + effect.value > 31) // if HP IV is already less than 3 away from 31
|
||||
@@ -85,7 +83,7 @@ class FishingSpawnCause(
|
||||
pokemonEntity.pokemon.ivs.set(Stats.getStat(iv.path), (pokemonEntity.pokemon.ivs[Stats.getStat(iv.path)] ?: 0) + (effect.value).toInt())
|
||||
}
|
||||
|
||||
fun alterGenderAttempt(pokemonEntity: PokemonEntity, effect: FishingBait.Effect) {
|
||||
fun alterGenderAttempt(pokemonEntity: PokemonEntity, effect: SpawnBait.Effect) {
|
||||
if (pokemonEntity.pokemon.species.maleRatio > 0 && pokemonEntity.pokemon.species.maleRatio < 1) // if the pokemon is allowed to be male or female
|
||||
when (effect.subcategory) {
|
||||
cobblemonResource("male") -> if (pokemonEntity.pokemon.gender != Gender.MALE) pokemonEntity.pokemon.gender = Gender.MALE
|
||||
@@ -93,7 +91,7 @@ class FishingSpawnCause(
|
||||
}
|
||||
}
|
||||
|
||||
fun alterLevelAttempt(pokemonEntity: PokemonEntity, effect: FishingBait.Effect) {
|
||||
fun alterLevelAttempt(pokemonEntity: PokemonEntity, effect: SpawnBait.Effect) {
|
||||
var level = pokemonEntity.pokemon.level + effect.value.toInt()
|
||||
if (level > Cobblemon.config.maxPokemonLevel)
|
||||
level = Cobblemon.config.maxPokemonLevel
|
||||
@@ -124,7 +122,7 @@ class FishingSpawnCause(
|
||||
|
||||
}
|
||||
|
||||
fun alterFriendshipAttempt(pokemonEntity: PokemonEntity, effect: FishingBait.Effect) {
|
||||
fun alterFriendshipAttempt(pokemonEntity: PokemonEntity, effect: SpawnBait.Effect) {
|
||||
if (pokemonEntity.pokemon.friendship + effect.value > Cobblemon.config.maxPokemonFriendship)
|
||||
pokemonEntity.pokemon.setFriendship(Cobblemon.config.maxPokemonFriendship)
|
||||
else
|
||||
@@ -133,18 +131,14 @@ class FishingSpawnCause(
|
||||
}
|
||||
|
||||
val rodItem = rodStack.item as? PokerodItem
|
||||
val bait = PokerodItem.getBaitOnRod(rodStack)
|
||||
// Determine the combined bait effects if any
|
||||
val baitEffects = SpawnBaitInfluence(SpawnBaitEffects.getEffectsFromRodItemStack(rodStack))
|
||||
|
||||
override fun affectSpawn(entity: Entity) {
|
||||
super.affectSpawn(entity)
|
||||
if (entity is PokemonEntity) {
|
||||
entity.pokemon.forcedAspects += FISHED_ASPECT
|
||||
|
||||
bait?.effects?.forEach { it ->
|
||||
if (Math.random() > it.chance) return
|
||||
FishingBait.Effects.getEffectFunction(it.type)?.invoke(entity, it)
|
||||
}
|
||||
|
||||
baitEffects.affectSpawn(entity)
|
||||
// Some of the bait actions might have changed the aspects and we need it to be
|
||||
// in the entityData IMMEDIATELY otherwise it will flash as what it would be
|
||||
// with the old aspects.
|
||||
@@ -154,68 +148,8 @@ class FishingSpawnCause(
|
||||
}
|
||||
}
|
||||
|
||||
// EV related bait effects
|
||||
override fun affectWeight(detail: SpawnDetail, ctx: SpawningContext, weight: Float): Float {
|
||||
// if bait exists and any effects are related to EV yields
|
||||
if (bait != null && bait.effects.any{ it.type == FishingBait.Effects.EV }){
|
||||
if (detail is PokemonSpawnDetail) {
|
||||
val detailSpecies = detail.pokemon.species?.let { PokemonSpecies.getByName(it) }
|
||||
val baitEVStat = bait.effects.firstOrNull { it.type == FishingBait.Effects.EV }?.subcategory?.path?.let { Stats.getStat(it) }
|
||||
|
||||
if (detailSpecies != null && baitEVStat != null) {
|
||||
val evYieldValue = detailSpecies.evYield[baitEVStat]?.toFloat() ?: 0f
|
||||
return when {
|
||||
evYieldValue > 0 -> super.affectWeight(detail, ctx, weight) // use original weight if EV yield is greater than 0
|
||||
else -> super.affectWeight(detail, ctx, 0f) // use spawn weight of 0 if EV yield is 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// if bait exists and any effects are related to Typing
|
||||
if (bait != null && bait.effects.any{ it.type == FishingBait.Effects.TYPING }){
|
||||
if (detail is PokemonSpawnDetail) {
|
||||
val detailSpecies = detail.pokemon.species?.let { PokemonSpecies.getByName(it) }
|
||||
val baitEffect = bait.effects.firstOrNull { it.type == FishingBait.Effects.TYPING }
|
||||
val baitTypingEffect = baitEffect?.subcategory?.path?.let { ElementalTypes.get(it) }
|
||||
|
||||
if (detailSpecies != null && baitTypingEffect != null) {
|
||||
val isMatchingType = detailSpecies.types.contains(baitTypingEffect)
|
||||
return when {
|
||||
isMatchingType -> super.affectWeight(detail, ctx, weight * baitEffect.value.toFloat()) // multiply weight by multiplier of bait effect if typing is found
|
||||
else -> super.affectWeight(detail, ctx, weight) // use base spawn weight if typing is not same as bait
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// if bait exists and any effects are related to Egg Groups
|
||||
if (bait != null && bait.effects.any { it.type == FishingBait.Effects.EGG_GROUP }) {
|
||||
if (detail is PokemonSpawnDetail) {
|
||||
val detailSpecies = detail.pokemon.species?.let { PokemonSpecies.getByName(it) }
|
||||
|
||||
if (detailSpecies != null) {
|
||||
// Collect all the egg group effects
|
||||
val eggGroupEffects = bait.effects.filter { it.type == FishingBait.Effects.EGG_GROUP }
|
||||
|
||||
// Check if any of the egg group effects match the species' egg groups
|
||||
val matchingEffect = eggGroupEffects.firstOrNull { effect ->
|
||||
val effectEggGroupKey = effect.subcategory?.path ?: return@firstOrNull false
|
||||
val eggGroup = EggGroup.fromIdentifier(effectEggGroupKey)
|
||||
if (eggGroup == null) {
|
||||
LOGGER.warn("Unknown egg group identifier: $effectEggGroupKey")
|
||||
return@firstOrNull false
|
||||
}
|
||||
detailSpecies.eggGroups.contains(eggGroup)
|
||||
}
|
||||
|
||||
if (matchingEffect != null) {
|
||||
val multiplier = matchingEffect.value
|
||||
return super.affectWeight(detail, ctx, (weight * multiplier).toFloat())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val weight = baitEffects.affectWeight(detail, ctx, weight)
|
||||
return super.affectWeight(detail, ctx, weight)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.influence
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawnCause
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.entity.Entity
|
||||
|
||||
class IncenseSweetInfluence(val pos: BlockPos? = null) : SpawningInfluence {
|
||||
|
||||
override fun affectSpawn(entity: Entity) {
|
||||
super.affectSpawn(entity)
|
||||
}
|
||||
|
||||
override fun affectWeight(detail: SpawnDetail, ctx: SpawningContext, weight: Float): Float {
|
||||
return super.affectWeight(detail, ctx, weight)
|
||||
}
|
||||
}
|
||||
+45
@@ -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.api.spawning.influence
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawnCause
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.entity.Entity
|
||||
|
||||
class SaccharineHoneyLogInfluence(val pos: BlockPos? = null) : SpawningInfluence {
|
||||
|
||||
var used = false
|
||||
val chanceForHA = 0.05
|
||||
|
||||
private fun markUsed() {
|
||||
used = true // todo even though I call this it is not saved.... hmmmm
|
||||
}
|
||||
|
||||
override fun affectSpawn(entity: Entity) {
|
||||
super.affectSpawn(entity)
|
||||
if (entity is PokemonEntity) {
|
||||
if (Math.random() <= chanceForHA) {
|
||||
FishingSpawnCause.alterHAAttempt(entity)
|
||||
}
|
||||
this.markUsed()
|
||||
}
|
||||
}
|
||||
|
||||
override fun affectWeight(detail: SpawnDetail, ctx: SpawningContext, weight: Float): Float {
|
||||
return super.affectWeight(detail, ctx, weight)
|
||||
}
|
||||
|
||||
fun wasUsed(): Boolean = used
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.influence
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.api.fishing.SpawnBait
|
||||
import com.cobblemon.mod.common.api.fishing.SpawnBait.Effects
|
||||
import com.cobblemon.mod.common.api.fishing.SpawnBaitUtils
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.pokemon.egg.EggGroup
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import com.cobblemon.mod.common.api.spawning.detail.PokemonSpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.entity.Entity
|
||||
|
||||
/**
|
||||
* A [SpawningInfluence] that applies some number of SpawnBait effects.
|
||||
*
|
||||
* @author Hiroku, Plastered_Crab
|
||||
* @since March 18th, 2025
|
||||
*/
|
||||
class SpawnBaitInfluence(val effects: List<SpawnBait.Effect>, val baitPos: BlockPos? = null) : SpawningInfluence {
|
||||
|
||||
var used: Boolean = false
|
||||
|
||||
private fun markUsed() {
|
||||
used = true
|
||||
}
|
||||
|
||||
override fun affectSpawn(entity: Entity) {
|
||||
super.affectSpawn(entity)
|
||||
if (entity is PokemonEntity) {
|
||||
val merged = SpawnBaitUtils.mergeEffects(effects)
|
||||
merged.forEach { effect ->
|
||||
if (Math.random() <= effect.chance) {
|
||||
markUsed()
|
||||
Effects.getEffectFunction(effect.type)?.invoke(entity, effect)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// EV related bait effects
|
||||
override fun affectWeight(detail: SpawnDetail, ctx: SpawningContext, weight: Float): Float {
|
||||
val merged = SpawnBaitUtils.mergeEffects(effects)
|
||||
|
||||
// if bait exists and any effects are related to EV yields
|
||||
if (merged.any { it.type == Effects.EV }){
|
||||
if (detail is PokemonSpawnDetail) {
|
||||
val detailSpecies = detail.pokemon.species?.let { PokemonSpecies.getByName(it) }
|
||||
val baitEVStat = effects.firstOrNull { it.type == Effects.EV }?.subcategory?.path?.let { Stats.getStat(it) }
|
||||
|
||||
if (detailSpecies != null && baitEVStat != null) {
|
||||
val evYieldValue = detailSpecies.evYield[baitEVStat]?.toFloat() ?: 0f
|
||||
return when {
|
||||
evYieldValue > 0 -> {
|
||||
markUsed()
|
||||
super.affectWeight(detail, ctx, weight)
|
||||
}
|
||||
else -> {
|
||||
markUsed()
|
||||
super.affectWeight(detail, ctx, 0f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// if bait exists and any effects are related to Typing
|
||||
if (merged.any { it.type == Effects.TYPING }){
|
||||
if (detail is PokemonSpawnDetail) {
|
||||
val detailSpecies = detail.pokemon.species?.let { PokemonSpecies.getByName(it) }
|
||||
val baitEffect = effects.firstOrNull { it.type == Effects.TYPING }
|
||||
val baitTypingEffect = baitEffect?.subcategory?.path?.let { ElementalTypes.get(it) }
|
||||
|
||||
if (detailSpecies != null && baitTypingEffect != null) {
|
||||
val isMatchingType = detailSpecies.types.contains(baitTypingEffect)
|
||||
return when {
|
||||
isMatchingType -> {
|
||||
markUsed()
|
||||
super.affectWeight(detail, ctx, weight * baitEffect.value.toFloat())
|
||||
}
|
||||
else -> super.affectWeight(detail, ctx, weight)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// if bait exists and any effects are related to Egg Groups
|
||||
if (merged.any { it.type == Effects.EGG_GROUP }) {
|
||||
if (detail is PokemonSpawnDetail) {
|
||||
val detailSpecies = detail.pokemon.species?.let { PokemonSpecies.getByName(it) }
|
||||
|
||||
if (detailSpecies != null) {
|
||||
// Collect all the egg group effects
|
||||
val eggGroupEffects = effects.filter { it.type == Effects.EGG_GROUP }
|
||||
|
||||
// Check if any of the egg group effects match the species' egg groups
|
||||
val matchingEffect = eggGroupEffects.firstOrNull { effect ->
|
||||
val effectEggGroupKey = effect.subcategory?.path ?: return@firstOrNull false
|
||||
val eggGroup = EggGroup.fromIdentifier(effectEggGroupKey)
|
||||
if (eggGroup == null) {
|
||||
LOGGER.warn("Unknown egg group identifier: $effectEggGroupKey")
|
||||
return@firstOrNull false
|
||||
}
|
||||
detailSpecies.eggGroups.contains(eggGroup)
|
||||
}
|
||||
|
||||
if (matchingEffect != null) {
|
||||
markUsed()
|
||||
val multiplier = matchingEffect.value
|
||||
return super.affectWeight(detail, ctx, (weight * multiplier).toFloat())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.affectWeight(detail, ctx, weight)
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.influence
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
import kotlin.math.sqrt
|
||||
import net.minecraft.core.BlockPos
|
||||
|
||||
/**
|
||||
* A type of [WorldSlicedSpawningInfluence] that is only applied to contexts within a particular radius
|
||||
* of a position.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since March 9th, 2025
|
||||
*/
|
||||
class WorldSlicedSpatialSpawningInfluence(
|
||||
val pos: BlockPos,
|
||||
val radius: Float,
|
||||
influence: SpawningInfluence
|
||||
) : WorldSlicedSpawningInfluence(influence) {
|
||||
override fun appliesTo(context: SpawningContext): Boolean {
|
||||
return sqrt(context.position.distSqr(pos)) <= radius
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.influence
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.WorldSlice
|
||||
import com.cobblemon.mod.common.api.spawning.context.SpawningContext
|
||||
|
||||
/**
|
||||
* A wrapping around a [SpawningInfluence] that was produced for a [WorldSlice]. This is wrapped
|
||||
* to provide a filtration mechanism on which of these can be applied to a [SpawningContext].
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since March 9th, 2025
|
||||
*/
|
||||
open class WorldSlicedSpawningInfluence(val influence: SpawningInfluence) {
|
||||
/** Whether this influence will apply to */
|
||||
open fun appliesTo(context: SpawningContext): Boolean = true
|
||||
}
|
||||
+3
-3
@@ -38,10 +38,10 @@ class BestSpawnerConfig {
|
||||
"seafloor" to 1F
|
||||
)
|
||||
val buckets = mutableListOf(
|
||||
SpawnBucket("common", 93.8F),
|
||||
SpawnBucket("uncommon", 5F),
|
||||
SpawnBucket("common", 91.6F),
|
||||
SpawnBucket("uncommon", 7F),
|
||||
SpawnBucket("rare", 1.0F),
|
||||
SpawnBucket("ultra-rare", 0.2F)
|
||||
SpawnBucket("ultra-rare", 0.4F)
|
||||
)
|
||||
|
||||
companion object {
|
||||
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.prospecting
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonPoiTypes
|
||||
import com.cobblemon.mod.common.api.spawning.influence.IncenseSweetInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SaccharineHoneyLogInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.WorldSlicedSpatialSpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.WorldSlicedSpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.SpawningArea
|
||||
import com.cobblemon.mod.common.util.math.pow
|
||||
import com.cobblemon.mod.common.util.toBlockPos
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Holder
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.ai.village.poi.PoiManager
|
||||
import net.minecraft.world.entity.ai.village.poi.PoiType
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.sqrt
|
||||
|
||||
object IncenseSweetProspector : SpawningInfluenceProspector {
|
||||
@JvmField
|
||||
val RANGE: Int = 32
|
||||
|
||||
override fun prospect(spawner: Spawner, area: SpawningArea): MutableList<WorldSlicedSpawningInfluence> {
|
||||
val world = area.world
|
||||
val listOfInfluences = mutableListOf<WorldSlicedSpawningInfluence>()
|
||||
|
||||
val searchRange = RANGE + ceil(sqrt(((area.length pow 2) + (area.width pow 2)).toDouble())).toInt()
|
||||
val centerPos = area.getCenter().toBlockPos()
|
||||
|
||||
val sweetIncensePositions = world.poiManager.findAll(
|
||||
{ holder: Holder<PoiType> -> holder.`is`(CobblemonPoiTypes.INCENSE_SWEET_KEY) },
|
||||
{ true },
|
||||
centerPos,
|
||||
searchRange,
|
||||
PoiManager.Occupancy.ANY
|
||||
).toList()
|
||||
|
||||
for (pos in sweetIncensePositions) {
|
||||
val influence = WorldSlicedSpatialSpawningInfluence(pos, RANGE.toFloat(), IncenseSweetInfluence(pos))
|
||||
listOfInfluences.add(influence)
|
||||
}
|
||||
|
||||
return listOfInfluences
|
||||
}
|
||||
|
||||
override fun prospectBlock(world: ServerLevel, pos: BlockPos, blockState: BlockState): WorldSlicedSpatialSpawningInfluence? { return null }
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.prospecting
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonPoiTypes
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawnBaitInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.WorldSlicedSpatialSpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.WorldSlicedSpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.SpawningArea
|
||||
import com.cobblemon.mod.common.block.LureCakeBlock
|
||||
import com.cobblemon.mod.common.block.entity.LureCakeBlockEntity
|
||||
import com.cobblemon.mod.common.util.math.pow
|
||||
import com.cobblemon.mod.common.util.toBlockPos
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Holder
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.ai.village.poi.PoiManager
|
||||
import net.minecraft.world.entity.ai.village.poi.PoiType
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.sqrt
|
||||
|
||||
object LureCakeProspector : SpawningInfluenceProspector {
|
||||
@JvmField
|
||||
val RANGE: Int = 48
|
||||
|
||||
override fun prospect(spawner: Spawner, area: SpawningArea): MutableList<WorldSlicedSpawningInfluence> {
|
||||
val world = area.world
|
||||
val listOfInfluences = mutableListOf<WorldSlicedSpawningInfluence>()
|
||||
|
||||
val searchRange = RANGE + ceil(sqrt(((area.length pow 2) + (area.width pow 2)).toDouble())).toInt()
|
||||
val lureCakePositions = world.poiManager.findAll({ holder: Holder<PoiType> -> holder.`is`(CobblemonPoiTypes.LURE_CAKE_KEY) },{ true },area.getCenter().toBlockPos(),searchRange, PoiManager.Occupancy.ANY).toList()
|
||||
|
||||
for (lureCakePos in lureCakePositions) {
|
||||
val blockState = world.getBlockState(lureCakePos)
|
||||
if (blockState.block !is LureCakeBlock) continue
|
||||
|
||||
val blockEntity = world.getBlockEntity(lureCakePos) as? LureCakeBlockEntity ?: continue
|
||||
val baitEffects = blockEntity.getBaitEffectsFromLureCake()
|
||||
|
||||
listOfInfluences.add(WorldSlicedSpatialSpawningInfluence(lureCakePos, RANGE.toFloat(), influence = SpawnBaitInfluence(baitEffects, lureCakePos)))
|
||||
}
|
||||
|
||||
return listOfInfluences
|
||||
}
|
||||
|
||||
override fun prospectBlock(world: ServerLevel, pos: BlockPos, blockState: BlockState): WorldSlicedSpatialSpawningInfluence? { return null }
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.prospecting
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonPoiTypes
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SaccharineHoneyLogInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.WorldSlicedSpatialSpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.WorldSlicedSpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.SpawningArea
|
||||
import com.cobblemon.mod.common.util.math.pow
|
||||
import com.cobblemon.mod.common.util.toBlockPos
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Holder
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.ai.village.poi.PoiManager
|
||||
import net.minecraft.world.entity.ai.village.poi.PoiType
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.sqrt
|
||||
|
||||
object SaccharineHoneyLogProspector : SpawningInfluenceProspector {
|
||||
@JvmField
|
||||
val RANGE: Int = 32
|
||||
|
||||
override fun prospect(spawner: Spawner, area: SpawningArea): MutableList<WorldSlicedSpawningInfluence> {
|
||||
val world = area.world
|
||||
val listOfInfluences = mutableListOf<WorldSlicedSpawningInfluence>()
|
||||
|
||||
val searchRange = RANGE + ceil(sqrt(((area.length pow 2) + (area.width pow 2)).toDouble())).toInt()
|
||||
val centerPos = area.getCenter().toBlockPos()
|
||||
|
||||
val honeyLogPositions = world.poiManager.findAll(
|
||||
{ holder: Holder<PoiType> -> holder.`is`(CobblemonPoiTypes.SACCHARINE_HONEY_LOG_KEY) },
|
||||
{ true },
|
||||
centerPos,
|
||||
searchRange,
|
||||
PoiManager.Occupancy.ANY
|
||||
).toList()
|
||||
|
||||
for (pos in honeyLogPositions) {
|
||||
val influence = WorldSlicedSpatialSpawningInfluence(pos, RANGE.toFloat(), SaccharineHoneyLogInfluence(pos))
|
||||
listOfInfluences.add(influence)
|
||||
}
|
||||
|
||||
return listOfInfluences
|
||||
}
|
||||
|
||||
override fun prospectBlock(world: ServerLevel, pos: BlockPos, blockState: BlockState): WorldSlicedSpatialSpawningInfluence? { return null }
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.spawning.prospecting
|
||||
|
||||
import com.cobblemon.mod.common.api.spawning.influence.WorldSlicedSpawningInfluence
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import com.cobblemon.mod.common.api.spawning.WorldSlice
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.Spawner
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.SpawningArea
|
||||
|
||||
/**
|
||||
* Prospects for [WorldSlicedSpawningInfluence] in a world at a given position. Occurs as part of a
|
||||
* [SpawningProspector] scanning a part of the world while formulating a [WorldSlice].
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since March 9th, 2025
|
||||
*/
|
||||
interface SpawningInfluenceProspector {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
val prospectors = mutableSetOf<SpawningInfluenceProspector>(
|
||||
LureCakeProspector,
|
||||
SaccharineHoneyLogProspector,
|
||||
IncenseSweetProspector
|
||||
)
|
||||
}
|
||||
|
||||
fun prospect(spawner: Spawner, area: SpawningArea) : MutableList<WorldSlicedSpawningInfluence>
|
||||
|
||||
fun prospectBlock(world: ServerLevel, pos: BlockPos, blockState: BlockState): WorldSlicedSpawningInfluence?
|
||||
}
|
||||
+8
-1
@@ -145,9 +145,16 @@ open class FlatContextWeightedSelector : SpawningSelector {
|
||||
}
|
||||
}
|
||||
|
||||
val selectedSpawn = spawnsToContexts.entries.toList().weightedSelection { it.value.highestWeight }!!
|
||||
val selectedSpawn = spawnsToContexts.entries.toList().weightedSelection { it.value.highestWeight }
|
||||
|
||||
// TODO clean this up later once we know the crash that happens is fixed
|
||||
if (selectedSpawn == null) {
|
||||
LOGGER.warn("FlatContextWeightedSelector failed: No spawn detail with positive weight was found for ${spawner.name}.")
|
||||
return null
|
||||
}
|
||||
|
||||
return selectedSpawn.value.chooseContext() to selectedSpawn.key
|
||||
|
||||
}
|
||||
|
||||
protected fun getProbabilitiesFromContextType(spawner: Spawner, contextSelectionData: ContextSelectionData): Map<SpawnDetail, Float> {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user