mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-21 14:46:25 -04:00
Compare commits
497
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ada7f0faf8 | ||
|
|
e1eff89259 | ||
|
|
cc149a0ff2 | ||
|
|
3fea718766 | ||
|
|
c99bf99052 | ||
|
|
e8019a0623 | ||
|
|
4c95cfc1b3 | ||
|
|
51a096913d | ||
|
|
980d95819e | ||
|
|
24aa65b2f1 | ||
|
|
19f33fe530 | ||
|
|
bbe8a6948a | ||
|
|
e46aaa5725 | ||
|
|
fc6c302c71 | ||
|
|
76cf856907 | ||
|
|
145d56e205 | ||
|
|
969b070300 | ||
|
|
e474ef607c | ||
|
|
a2ecccfac4 | ||
|
|
1a475bff87 | ||
|
|
8b6f5f55e6 | ||
|
|
39ed65e8ca | ||
|
|
35dab86ef4 | ||
|
|
2cc14d26b1 | ||
|
|
c29da11541 | ||
|
|
8188ce0ed2 | ||
|
|
301de140e3 | ||
|
|
4a41060533 | ||
|
|
ac55636c51 | ||
|
|
18eb50d4d2 | ||
|
|
87276de14d | ||
|
|
b7dc9ea6f6 | ||
|
|
ff59604526 | ||
|
|
b620ad27b6 | ||
|
|
78daec9c7b | ||
|
|
5565f22610 | ||
|
|
7582b08d56 | ||
|
|
2e101f023f | ||
|
|
d98cccfc0f | ||
|
|
07f087c35c | ||
|
|
f83bde399c | ||
|
|
19f0bc29f4 | ||
|
|
531f64394a | ||
|
|
af77534b96 | ||
|
|
fa5193a3db | ||
|
|
e3c95aa4a5 | ||
|
|
72740fb418 | ||
|
|
250f9e3cec | ||
|
|
26078ec29d | ||
|
|
5b68889689 | ||
|
|
bb3e86ac02 | ||
|
|
b96a6282d8 | ||
|
|
14ee3cd754 | ||
|
|
9c66c65b9e | ||
|
|
9ffbd14a81 | ||
|
|
7044cb35b2 | ||
|
|
e258d6439f | ||
|
|
221e51b023 | ||
|
|
5053c765fb | ||
|
|
bfe8d41102 | ||
|
|
c9fe117916 | ||
|
|
af3b6e3f2a | ||
|
|
1b7759b77d | ||
|
|
698c07f0b8 | ||
|
|
a4a094a624 | ||
|
|
b0d2df2917 | ||
|
|
f6ad1ab7aa | ||
|
|
3f85ce0c81 | ||
|
|
e25c3c3d7c | ||
|
|
0215a30c8d | ||
|
|
f16ec1d6d3 | ||
|
|
73e59159a0 | ||
|
|
5b7b430e5f | ||
|
|
4e6f2973c2 | ||
|
|
4f5799e5df | ||
|
|
822794230d | ||
|
|
54ea4903ba | ||
|
|
28ad0cce83 | ||
|
|
7fe1929609 | ||
|
|
e03082a75e | ||
|
|
8d0c27f0e4 | ||
|
|
91fc2dc896 | ||
|
|
d58603ff33 | ||
|
|
ab1ca295a3 | ||
|
|
157532f372 | ||
|
|
5cbe937e23 | ||
|
|
4fa196da94 | ||
|
|
3a1c3fc934 | ||
|
|
43aa0ec04a | ||
|
|
b4bf044f76 | ||
|
|
d35db46c1b | ||
|
|
b8a6c94fcb | ||
|
|
b069e448c1 | ||
|
|
18f41407c8 | ||
|
|
b659a662a2 | ||
|
|
dbb2e45e14 | ||
|
|
da491015a6 | ||
|
|
55db0d8af1 | ||
|
|
211821bc0f | ||
|
|
16a21f9d2e | ||
|
|
e69060bde6 | ||
|
|
ebdbbd5176 | ||
|
|
6e163d08f0 | ||
|
|
13c7b75b19 | ||
|
|
1ad36e39c5 | ||
|
|
f4d67b9b64 | ||
|
|
3c84afb95d | ||
|
|
2e615800ae | ||
|
|
0fc1239c77 | ||
|
|
38a0d149c5 | ||
|
|
4a4aaf3a94 | ||
|
|
53ca8f009d | ||
|
|
5b5c756d3c | ||
|
|
75410c3a72 | ||
|
|
87d001da80 | ||
|
|
8fee0e7f91 | ||
|
|
7985aed6bf | ||
|
|
5543b8a660 | ||
|
|
d7d855adc2 | ||
|
|
4fd50b8d2b | ||
|
|
be466ad252 | ||
|
|
53749e014b | ||
|
|
b4cdf371fe | ||
|
|
e0e30e7e11 | ||
|
|
cfec4e10cb | ||
|
|
614799cfcb | ||
|
|
ec367fd4df | ||
|
|
e415b281ee | ||
|
|
265aa6e124 | ||
|
|
2765a5584f | ||
|
|
d77cb36149 | ||
|
|
d37d95ee70 | ||
|
|
63f8e6251e | ||
|
|
5a3e9bb236 | ||
|
|
2fce916f05 | ||
|
|
52c4c35c0d | ||
|
|
40f4f80d6e | ||
|
|
721025281f | ||
|
|
08e6f68693 | ||
|
|
1e3fcf3e84 | ||
|
|
92a67ca0ca | ||
|
|
42600fc840 | ||
|
|
9917b57e1a | ||
|
|
b5e2f69207 | ||
|
|
c6c83c065b | ||
|
|
687381dc1b | ||
|
|
f088dd62bc | ||
|
|
3d1f9458f6 | ||
|
|
470d3807f1 | ||
|
|
1c74d498e6 | ||
|
|
4d3c46acc4 | ||
|
|
fbec87d2e0 | ||
|
|
397f8db5a0 | ||
|
|
36cd5f3894 | ||
|
|
b86f08b069 | ||
|
|
026897719d | ||
|
|
c4451ffb4f | ||
|
|
710b6404e7 | ||
|
|
b8f59110f0 | ||
|
|
75927fc1a9 | ||
|
|
0a0c1edffc | ||
|
|
18403c833d | ||
|
|
b9824e5708 | ||
|
|
57c1201ad0 | ||
|
|
4637bef5d2 | ||
|
|
37e0030d08 | ||
|
|
628db514b3 | ||
|
|
6207a01ae3 | ||
|
|
9046217867 | ||
|
|
40aaef68f9 | ||
|
|
09c7bd8e61 | ||
|
|
8df8cb9cfe | ||
|
|
c048e5752b | ||
|
|
e8aa06d633 | ||
|
|
64979ff742 | ||
|
|
0163619e87 | ||
|
|
258ffd25ea | ||
|
|
2dd0d3dcf1 | ||
|
|
cc5b65a1dd | ||
|
|
b7de250457 | ||
|
|
8d0c5bc05c | ||
|
|
f4e242a270 | ||
|
|
da3a513905 | ||
|
|
33af6a1557 | ||
|
|
62b07f7f8a | ||
|
|
7bddbcfc67 | ||
|
|
993c7a5cf0 | ||
|
|
44da19f3e0 | ||
|
|
6d97c6ea34 | ||
|
|
2a55ef114d | ||
|
|
c236d8147a | ||
|
|
cf90bf0b0f | ||
|
|
b109ff6edf | ||
|
|
4ea288cc34 | ||
|
|
98540294b1 | ||
|
|
5535a6a7cb | ||
|
|
dd426423a1 | ||
|
|
6237e44e7c | ||
|
|
09561f736a | ||
|
|
14e4fe66ac | ||
|
|
975c68cea0 | ||
|
|
6b77adbcef | ||
|
|
d12a8704a9 | ||
|
|
52fc6b2575 | ||
|
|
68ffe0bdbc | ||
|
|
4734c0a3cb | ||
|
|
1ed4d9ff9a | ||
|
|
8d0fc77be2 | ||
|
|
c45ef65645 | ||
|
|
0adfc64e35 | ||
|
|
80b4238c7e | ||
|
|
e16ae2544c | ||
|
|
f182cf4335 | ||
|
|
f5840c4794 | ||
|
|
cff65ab22e | ||
|
|
1d550b2cac | ||
|
|
c859cbae76 | ||
|
|
10e7962d85 | ||
|
|
767f820b7a | ||
|
|
06e4783f16 | ||
|
|
fe83b9d58e | ||
|
|
709e6f4a63 | ||
|
|
17f686488e | ||
|
|
db574332e5 | ||
|
|
73b72ff19d | ||
|
|
15aac5e20a | ||
|
|
b88f4335ee | ||
|
|
6916cd51f7 | ||
|
|
b2ebfcc3b0 | ||
|
|
3b73493801 | ||
|
|
bfb48e8583 | ||
|
|
1bfe5e2044 | ||
|
|
ace65eda66 | ||
|
|
01c44537d0 | ||
|
|
e414dd94c3 | ||
|
|
2d4800a733 | ||
|
|
90e193e5a0 | ||
|
|
c7e86cf767 | ||
|
|
d8906992a3 | ||
|
|
972c259f6d | ||
|
|
8228424191 | ||
|
|
9bb67087b3 | ||
|
|
0f08446732 | ||
|
|
af09a6a0c7 | ||
|
|
b4d2f39c48 | ||
|
|
1a12bbd493 | ||
|
|
8a24f635cf | ||
|
|
d6e066ddcd | ||
|
|
50335135c9 | ||
|
|
1ee6f83a5b | ||
|
|
e8b747a432 | ||
|
|
8f8804f3f4 | ||
|
|
ef826158ce | ||
|
|
d32314742d | ||
|
|
e8e0ca47dd | ||
|
|
ebcac6e782 | ||
|
|
63bfa634ae | ||
|
|
c3d482c78f | ||
|
|
7ea85dbd1e | ||
|
|
6cdb14d2f8 | ||
|
|
f041049576 | ||
|
|
e1aa6445fa | ||
|
|
f1b7ee5b9c | ||
|
|
9ea0f7e4f8 | ||
|
|
d0edd6ecbc | ||
|
|
1372505486 | ||
|
|
a4ce4bf99b | ||
|
|
7effc4c853 | ||
|
|
4cd504126b | ||
|
|
60ee7b819c | ||
|
|
28548d5b19 | ||
|
|
e6ec690811 | ||
|
|
dac49c2f42 | ||
|
|
d72dad355c | ||
|
|
40b5726c5b | ||
|
|
d32aa46832 | ||
|
|
5068e66fa7 | ||
|
|
482b682595 | ||
|
|
ffecc58979 | ||
|
|
eaaf2ca05c | ||
|
|
e91651553b | ||
|
|
874a5d2e8f | ||
|
|
70e49bbbdb | ||
|
|
39fce8ca06 | ||
|
|
d288fe46da | ||
|
|
cefc97320a | ||
|
|
a2094677cd | ||
|
|
eae4eb5121 | ||
|
|
ed3a008515 | ||
|
|
462074ce43 | ||
|
|
d54a85aa68 | ||
|
|
bf8433f6e9 | ||
|
|
374fc44089 | ||
|
|
f7664a04db | ||
|
|
51b0f768a0 | ||
|
|
106e487035 | ||
|
|
2d772f5bf7 | ||
|
|
63af1713b9 | ||
|
|
8fecb12829 | ||
|
|
d0b50a1ee0 | ||
|
|
07497d653e | ||
|
|
2ecbe28c87 | ||
|
|
80112e0b70 | ||
|
|
dfb28ed185 | ||
|
|
0cc9a75255 | ||
|
|
abfd718681 | ||
|
|
8271b7a979 | ||
|
|
251c2df78e | ||
|
|
c03e30bd9c | ||
|
|
f776542365 | ||
|
|
ecc793350a | ||
|
|
045ca3a07f | ||
|
|
a71bad07bd | ||
|
|
2085f12fef | ||
|
|
36c4ea3b1a | ||
|
|
804ad75ede | ||
|
|
be11568041 | ||
|
|
863b43f902 | ||
|
|
8ad54287e4 | ||
|
|
179d90d482 | ||
|
|
c3fb661f49 | ||
|
|
dccffe311f | ||
|
|
1769af7385 | ||
|
|
d7d8d766d1 | ||
|
|
54b2cc0a59 | ||
|
|
62696931df | ||
|
|
bfc7f83e07 | ||
|
|
db573455ea | ||
|
|
3af002a39c | ||
|
|
a15c44325d | ||
|
|
33fc67ed58 | ||
|
|
b9f2bcc3a3 | ||
|
|
8a5a88b4f1 | ||
|
|
af6b1190c1 | ||
|
|
7f0a6d4d48 | ||
|
|
d7e4298a91 | ||
|
|
923b4e4266 | ||
|
|
88e38bfa1a | ||
|
|
507a9a54b5 | ||
|
|
0b72a072bd | ||
|
|
c927cae609 | ||
|
|
474918e414 | ||
|
|
0e93383c90 | ||
|
|
abb44cf696 | ||
|
|
e6bd7cad72 | ||
|
|
07bba37c03 | ||
|
|
5896a74d1f | ||
|
|
e2db59c837 | ||
|
|
10bf69a79b | ||
|
|
172293c813 | ||
|
|
9bb653b8b7 | ||
|
|
7d06f1e2cd | ||
|
|
74d2f4f700 | ||
|
|
6ed4504273 | ||
|
|
8ee6799653 | ||
|
|
96cbc4eca6 | ||
|
|
ad24e529f5 | ||
|
|
a7b55e5d03 | ||
|
|
28db655376 | ||
|
|
006736cd71 | ||
|
|
2f4bdb336b | ||
|
|
f240dc1963 | ||
|
|
535c5f2e67 | ||
|
|
8b209e081b | ||
|
|
f7f276ecfb | ||
|
|
da7dbeaaec | ||
|
|
dea2ad4b12 | ||
|
|
fc0cd0dac4 | ||
|
|
019245472f | ||
|
|
cefb502f10 | ||
|
|
ee5e4d33b2 | ||
|
|
0fd954ffa5 | ||
|
|
60d3d737f9 | ||
|
|
7dd38bf043 | ||
|
|
4caba2fbeb | ||
|
|
e6b1529f27 | ||
|
|
a42ba8de43 | ||
|
|
078c961090 | ||
|
|
676342348a | ||
|
|
97442cb880 | ||
|
|
478804f652 | ||
|
|
55dc5c6760 | ||
|
|
0d3b89828a | ||
|
|
fab1bc6f80 | ||
|
|
6b4ff0ac84 | ||
|
|
193daed8ff | ||
|
|
1caf963323 | ||
|
|
bb94f872a9 | ||
|
|
628c8f6093 | ||
|
|
eac0f209ce | ||
|
|
9ac0fc1b36 | ||
|
|
2e05b25061 | ||
|
|
60fc0c1959 | ||
|
|
1cd112ac74 | ||
|
|
4fe54d3dba | ||
|
|
cb11c2b964 | ||
|
|
8aeb7a43c8 | ||
|
|
cd575e6b7d | ||
|
|
39dbf78ed2 | ||
|
|
7806503ea7 | ||
|
|
7e4054ad8f | ||
|
|
9d38ad78bf | ||
|
|
b59483e52f | ||
|
|
2058184da2 | ||
|
|
9c861392f8 | ||
|
|
d3717fb222 | ||
|
|
54c7e05c8f | ||
|
|
7148f9d954 | ||
|
|
3b9a8c8492 | ||
|
|
b7446fa029 | ||
|
|
9123cc3a2c | ||
|
|
f0dc9be471 | ||
|
|
819635f457 | ||
|
|
d3a2a5827e | ||
|
|
a9ed3750ad | ||
|
|
24fdae725e | ||
|
|
71fc844905 | ||
|
|
24910778d4 | ||
|
|
363c3e5f0a | ||
|
|
8d336fca3e | ||
|
|
ff27676187 | ||
|
|
1fd5d0ff4b | ||
|
|
46752a3911 | ||
|
|
76ad22b53d | ||
|
|
a2ddcaebf8 | ||
|
|
6fc725b6ff | ||
|
|
01efc8d9e0 | ||
|
|
3a05bd5e2e | ||
|
|
439c9647ca | ||
|
|
eb952319e0 | ||
|
|
4787c1d35b | ||
|
|
98394333da | ||
|
|
653b9be4a3 | ||
|
|
a3460a4b8f | ||
|
|
71024481f4 | ||
|
|
7c191981bd | ||
|
|
0be9ac9f59 | ||
|
|
c69f1e6adc | ||
|
|
a26a07337a | ||
|
|
fd74f157a8 | ||
|
|
885cde045a | ||
|
|
bfcaa4bda4 | ||
|
|
7370841e62 | ||
|
|
3c347214a8 | ||
|
|
91f9af1bed | ||
|
|
b32c2e1274 | ||
|
|
400f764054 | ||
|
|
5b6900b74a | ||
|
|
05d0adc947 | ||
|
|
24c2ac116a | ||
|
|
4f558d36e6 | ||
|
|
38218e4001 | ||
|
|
bd8e533bbd | ||
|
|
52b756c33d | ||
|
|
91ce0d9eab | ||
|
|
17ea2bb80f | ||
|
|
e76b047ed3 | ||
|
|
33be35f27b | ||
|
|
ea73382ea3 | ||
|
|
592b4276c8 | ||
|
|
a73cdfbb4f | ||
|
|
770a2e52f6 | ||
|
|
6629b27f33 | ||
|
|
73b06d2f99 | ||
|
|
a07a9a75c0 | ||
|
|
d6fdb4c6da | ||
|
|
65ab0f48e4 | ||
|
|
c5e036934a | ||
|
|
d9938a5cfd | ||
|
|
fc5d9615fc | ||
|
|
e160a42b83 | ||
|
|
fa68aa44c5 | ||
|
|
f3de9840b5 | ||
|
|
64e3909cea | ||
|
|
735c4b910e | ||
|
|
26a9a1f9e1 | ||
|
|
832ab8db95 | ||
|
|
1d9029ef51 | ||
|
|
a875ba7536 | ||
|
|
93de4785b4 | ||
|
|
765f0e5494 | ||
|
|
4fc232ff31 | ||
|
|
a4d75e9f32 | ||
|
|
a86ae09dc9 | ||
|
|
a5fbafe64d | ||
|
|
1de93b4933 | ||
|
|
f8dfc7c6cc | ||
|
|
accbed9c2b | ||
|
|
8b0e615777 | ||
|
|
746f12c724 | ||
|
|
a11d306a1b | ||
|
|
40d140e84d | ||
|
|
ffdb4842ac | ||
|
|
6baf60d07c | ||
|
|
cb3b7784b0 | ||
|
|
ee4f3b1629 | ||
|
|
518a7daa0e |
@@ -0,0 +1,16 @@
|
||||
### Additions
|
||||
- Rebuilt Pokémon AI to use Minecraft's Brain system, allowing for more complex behaviours and interactions.
|
||||
- As an early pass of this, pastured Pokémon will now sleep when appropriate, and may come up to you when they see you.
|
||||
- Probably also added a whole bunch of bugs.
|
||||
- Dog Pokémon (Growlithe, Arcanine, etc.) intimidate Skeletons.
|
||||
- Cat Pokémon (Meowth, Persian, etc.) intimidate Creepers and Phantoms.
|
||||
- Sleep-related Pokémon (Munsharna, Komala, etc.) intimidate Phantoms.
|
||||
- Added a Behaviour Editor to the NPC editing screen.
|
||||
- Added /behaviouredit command for opening the Behaviour Editor on Pokémon and NPCs.
|
||||
- Editing variables for Pokémon is not yet supported.
|
||||
|
||||
### MoLang & Datapacks
|
||||
- Added a `behaviours` datapack folder which motivates the Behaviour Editor screen on NPCs and Pokémon.
|
||||
- Added many default behaviours.
|
||||
- Removed many NPC presets that now exist as behaviours. This is a breaking change if you are using NPCs with these presets.
|
||||
- NPCs with these presets should be modified to instead list under `"behaviours"` all the equivalent behaviours.
|
||||
@@ -4,6 +4,29 @@
|
||||
- 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.
|
||||
- Added Lure Cakes, made from the Campfire Pot using honey and berries.
|
||||
- Lure Cakes can be used to modify the spawn rate of Pokémon in the wild.
|
||||
- Added the Saccharine Tree, which can be found in the wild and is used to obtain Honey Bottles.
|
||||
- The leaves of the tree can be harvested to obtain honey, which can be used in the Campfire Pot to make Lure Cakes.
|
||||
- The Log of the tree can be clicked on with honey to create a Honey Log, which increases the change of spawning a Pokemon with an Hidden Ability.
|
||||
- Clicking on the Progress Arrow will show the JEI Recipe Book for the Campfire Pot, which will show all recipes that can be made with it.
|
||||
- Added a Ton of Redstone Compatibility.
|
||||
- Dispenser can now Honey and Unhoney:
|
||||
- Saccharine Log
|
||||
- Saccharine Leaves
|
||||
- Redstone can Close and Open the Lid of a Cooking Pot
|
||||
- Powered = Closed
|
||||
- Unpowered = Open
|
||||
- Hoppers can be used to insert items into a Cooking pot
|
||||
- Top = Seasonals
|
||||
- All Sides = Crafting
|
||||
- Bottom = Extract the Result
|
||||
- Observer will recognise when a Cooking pot is Closed or Opened
|
||||
- Comparator Calculates a Signal Strength depending on the items inside the cooking pot
|
||||
- Sculk Sensor
|
||||
- Saccharine Leaves
|
||||
- Opening and Closing the Cooking Pot
|
||||
- Saccharine Log
|
||||
|
||||
### Datapack and Addon Changes
|
||||
- Renamed the fishing_baits datapack folder to spawn_bait_effects.
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
- 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.
|
||||
- improved filter by Name, now is available search by exact names or partial matches, for example "cha" will show Charmander, Charmeleon and Charizard among others that match.
|
||||
|
||||
### Developer
|
||||
- Added `RenamePCBoxEvent.Pre` and `RenamePCBoxEvent.Post` events to prevent players from renaming a box or changing their input.
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
### Additions
|
||||
- Pokémon can now spawn in herds, either as distinct herd groupings or simply several Pokémon spawning at once.
|
||||
|
||||
### Fixes
|
||||
- Fixed the "enabled" property in spawn files not actually being respected. Where do they find these devs?
|
||||
|
||||
### Developer
|
||||
- Spawning Influences now have the context of what the other buckets are when adjusting bucket weights. This will break existing influences that do bucket weight adjustment.
|
||||
- Renamed heaps of things in the spawning system to make more sense.
|
||||
- SpawningContext is now SpawnablePosition
|
||||
- WorldSlice is SpawningZone
|
||||
- SpawningProspector is now SpawningZoneGenerator
|
||||
- Renamed things in Spawn Rules to go with the other renames:
|
||||
- contextSelector is now spawnablePositionSelector
|
||||
- context is now spawnable_position
|
||||
+116
-4
@@ -21,6 +21,15 @@
|
||||
- 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.
|
||||
- Added the Clear Amulet, Grip Claw, Lagging Tail, Luminous Moss, Metal Alloy, Scroll of Darkness, Scroll of Waters
|
||||
- Added Recipes for Masterpiece Cup, Eject Pack
|
||||
- Added modification to Minecraft Creative Inventory search to account for item names that contain `poké` when input contains `poke`.
|
||||
- Added Campfire Pot as well as loads of new food items (Poke Puffs, Ponigiri, Sinister Tea, etc)
|
||||
- Added Hearty Grains, a new crop used in the new cooking mechanic
|
||||
- Added Tatami blocks and Tatami Mat blocks, made from Hearty Grain, for decorating builds
|
||||
- Added `/pcsearch <player> <pokemonProperties>` command that searches for a specific Pokémon within a player's PC.
|
||||
- Added `/pctake <player> <box> <slot>` command that takes a specific Pokémon from a player's PC. Removes the pokemon if target is self or ran from the server.
|
||||
- Added Hyper Training items (IV Modification) as well as some additional candy items to do so (Health Candy, Sickly Candy)
|
||||
|
||||
### Pokémon Added
|
||||
|
||||
@@ -32,12 +41,17 @@
|
||||
- Grumpig
|
||||
- Snorunt
|
||||
- Glalie
|
||||
- Latias
|
||||
- Latios
|
||||
|
||||
#### Gen 4
|
||||
- Bronzor
|
||||
- Bronzong
|
||||
- Croagunk
|
||||
- Toxicroak
|
||||
- Froslass
|
||||
- Glameow
|
||||
- Purugly
|
||||
|
||||
#### Gen 5
|
||||
- Pansage
|
||||
@@ -50,10 +64,22 @@
|
||||
- Musharna
|
||||
- Blitzle
|
||||
- Zebstrika
|
||||
- Drilbur
|
||||
- Excadrill
|
||||
- Trubbish
|
||||
- Garbodor
|
||||
- Gothita
|
||||
- Gothorita
|
||||
- Gothitelle
|
||||
- Solosis
|
||||
- Duosion
|
||||
- Reuniclus
|
||||
|
||||
#### Gen 6
|
||||
- Inkay
|
||||
- Malamar
|
||||
- Hawlucha
|
||||
- Dedenne
|
||||
- Noibat
|
||||
- Noivern
|
||||
|
||||
@@ -63,13 +89,20 @@
|
||||
#### Gen 8
|
||||
- Silicobra
|
||||
- Sandaconda
|
||||
- Sinistea
|
||||
- Polteageist
|
||||
|
||||
#### Gen 9
|
||||
- Smoliv
|
||||
- Dolliv
|
||||
- Arboliva
|
||||
- Tarountula
|
||||
- Spidops
|
||||
- Orthworm
|
||||
- Dudunsparce
|
||||
- Cyclizar
|
||||
- Poltchageist
|
||||
- Sinistcha
|
||||
|
||||
### Animation updates for the following Pokémon
|
||||
- Garchomp
|
||||
@@ -82,6 +115,15 @@
|
||||
- Delphox
|
||||
- Cinderace
|
||||
- Kangaskhan
|
||||
- Gossifleur
|
||||
- Eldegoss
|
||||
- Stonjourner
|
||||
- Wailmer
|
||||
- Lechonk
|
||||
- Oinkologne
|
||||
- Dratini
|
||||
- Dragonair
|
||||
- Dragonite
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
- Gyarados
|
||||
@@ -99,27 +141,52 @@
|
||||
- Grovyle
|
||||
- Sceptile
|
||||
- Honchkrow
|
||||
- Gible
|
||||
- Gabite
|
||||
- Garchomp
|
||||
- Pidgeot
|
||||
- Nosepass
|
||||
- Probopass
|
||||
- Kangaskhan
|
||||
- Cinderace
|
||||
- Magnemite
|
||||
- Magneton
|
||||
- Magnezone
|
||||
- Beldum
|
||||
- Metang
|
||||
- Metagross
|
||||
- Hoothoot
|
||||
- Noctowl
|
||||
- Teddiursa
|
||||
- Ursaring
|
||||
- Ursaluna
|
||||
- Heatmor
|
||||
- Bouffalant
|
||||
- Sigilyph
|
||||
- Sharpedo
|
||||
- Maractus
|
||||
- Clodsire
|
||||
- Scyther
|
||||
- Scizor
|
||||
- Cacturne
|
||||
- Taillow
|
||||
- Swellow
|
||||
- Added Syrupy Apples.
|
||||
- Seel
|
||||
- Dewgong
|
||||
|
||||
### 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
|
||||
- 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, Chipped Pot, Cracked Pot, Unremarkable Cup, Loaded Dice, Charcoal Stick, Dragon Fang, Miracle Seed, Mystic Water, Never Melt Ice, Twisted Spoon, Black Glasses, Fairy Feather, Hard Stone, Silver Powder, Soft Sand
|
||||
- Added alternate ingredient options to the following recipes: Cell Battery, 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.
|
||||
- Added our seeds tag into `#c:seeds`, which is now made use of for the Miracle Seed recipe.
|
||||
- Added herbs and snowballs to the consumable in PvE and Wild battle tags
|
||||
- Tweaked the Natural Materials Vanilla file to fit with the changes to tags
|
||||
- Substantially optimised spawning checks mainly by front-loading biome filtering.
|
||||
- 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.
|
||||
@@ -134,6 +201,18 @@
|
||||
- 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
|
||||
- Changed the recipes for Level, Lure, and Moon Balls to be cleaner
|
||||
- Renamed `pokemonId` and `type` to `species` in relevant Advancement triggers for conformity, this is a breaking change.
|
||||
- Added a separate `species` argument to the `pick_starter`, `pasture_use` and `resurrect_pokemon` Advancement triggers.
|
||||
- Made `CobblemonAgingDespawner` thresholds configurable via the config file.
|
||||
- Tweaked Berry flavor data to balance cooking pot mechanics
|
||||
- Made Red, Yellow, Green, Blue, Pink, Black, and White Apricorn Sprout and Saccharine Sapling able to be placed into flower pots.
|
||||
- Added all Potted Apricorn Sprouts, Potted Saccharine Saplings, and Potted Pep-Up Flowers to the `#minecraft:flower_pots` block tag
|
||||
- Corrected the healing values of the remedies and energy root, and reintroduced the friendship lowering mechanics for them, revivl herb, and heal powder
|
||||
- Updated battle language keys for side effects to use position-specific formats, improving grammatical consistency
|
||||
- Saccharine Leaves are now Collectable
|
||||
- Saccharine Leaves Age 1 or higher will now show Yellow particles when broken
|
||||
- Destroying a Saccharine Honey Log will now drop a Saccharine Log in stead of nothing
|
||||
|
||||
### Fixes
|
||||
- Fixed Particles sometimes facing the wrong direction (looking at you, Swords Dance)
|
||||
@@ -165,6 +244,25 @@
|
||||
- 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
|
||||
- Fixed Moon Stones not interacting properly with dripstone blocks.
|
||||
- Fixed some effects like particles from fishing rods appearing for players in the same coordinates in another world.
|
||||
- Fixed an issue with Sketch where the Pokémon using Sketch would not properly learn moves with special characters in their name (e.g. King's Shield, Baby-Doll Eyes, etc.)
|
||||
- Fixed wild Pokémon sometimes spawning with incorrect friendship values
|
||||
- Fixed typo while saving/loading NPCEntity causes data loss
|
||||
- Fixed an issue where catching a Pokémon while it was leashed to a fence would not update the fence.
|
||||
- Fixed the `dimensions` spawning condition using the incorrect ResourceLocation, causing it to not function properly.
|
||||
- Fix issue where locator X axis was not aligned with blockbench.
|
||||
- Fix issue where particle effects that play on frame 1 on sendout would never play (Gastly)
|
||||
- The Wiglett line will now sink in water again.
|
||||
- Fixed the Sprigatito line's portraits being zoomed in too far.
|
||||
- Fixed Floragato's battle cry animation from breaking.
|
||||
- Fixed the block texture name for the Pep-Up Flower being inaccurate
|
||||
- Fixed issue where the restoration tank would not accept valid items from a hopper.
|
||||
- Fixed energy root not being shearable
|
||||
- Fixed energy root always spreading into more energy roots instead of by chance (same as big root)
|
||||
- Fixed issue where Pokémon spawned by the "spawnallpokemon" command potentially receiving a raft.
|
||||
- Fixed logspam on NeoForge when adorn is not installed
|
||||
- Fixed Cobblemon crashing if it tries to load a bedrock model not meant for cobblemon (example: Qlipoth Awakening)
|
||||
|
||||
### Developer
|
||||
- A finished battle now has winners and losers set inside of `PokemonBattle` instead of them always being empty.
|
||||
@@ -191,6 +289,10 @@
|
||||
}
|
||||
}
|
||||
`
|
||||
- The IVs class has now been extended to include Hyper Trained values.
|
||||
- Added `Pokemon#hyperTrainIV()` and `IVs#setHyperTrainedIV(Stat, Int)`.
|
||||
- Added `HyperTrainedIvEvent.Pre` and `HyperTrainedIvEvent.Post`.
|
||||
- Added a `hoverText` option to PartySelectCallback, to display a tooltip on hovering over a Pokémon in the selection screen.
|
||||
|
||||
### 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)
|
||||
@@ -210,6 +312,15 @@
|
||||
- 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}`.
|
||||
- Added `play_sound_on_server` as an available Molang function for the `worldHolder` & `player` functions.
|
||||
- Added `run_molang_after` as an available Molang function for the `entity` functions when schedulable.
|
||||
- Added an optional parameter for `run_molang` to schedule the function.
|
||||
- Added `labels` & `has_label` as available Molang functions for the `speciesFunctions`
|
||||
- Added datapack-defined starter categories via `data/<namespace>/starters/*.json`, with built-in fallback and `useConfigStarters` merge option.
|
||||
- The format of the `remedies.json` file has changed to allow for individual friendshipDrop amounts per remedy
|
||||
- Fixed `entity.find_nearby_block` causing crashes when attempting to use a block tag
|
||||
- Spawn Filters can now access `v.spawn.class` to get the identifier of an NPC class for when trying to influence NPC spawns
|
||||
- Added `pokemon.hyper_train_iv` as an available Molang function.
|
||||
|
||||
## [1.6.1 (January 26th, 2025)](#1-6-1)
|
||||
|
||||
@@ -1024,6 +1135,7 @@
|
||||
}
|
||||
`
|
||||
- Added support for custom stashes, similar to Gimmighoul's coin and scrap stashes.
|
||||
- Added the ability to create custom brewing stand recipes.
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
@@ -2331,4 +2443,4 @@ Thank you so much to all of our community translators that bring the mod to the
|
||||
- Added species, ability, and move translations for `ko_ko`, `jp_jp`, `fr_fr`, `es_es`, `it_it`, and `zh_cn`.
|
||||
|
||||
## [1.0.0 (November 12th, 2022)](#1-0-0)
|
||||
- Initial release.
|
||||
- Initial release.
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
- Nodemaker bug, it thinks jumps are possible from water up an entire block - they aint
|
||||
https://gyazo.com/759b8285e7c07046ff2e54adf0d7a7ac
|
||||
|
||||
- Why is magikarp trying to path through ice
|
||||
https://gyazo.com/ae230758c529f885eeb0dd91e60530d2
|
||||
|
||||
- We should use mixins to put the path node filtering from OmniPathNodeMaker in the base classes otherwise
|
||||
NPC wandering will be jank too.
|
||||
+1
-1
@@ -5,7 +5,7 @@ plugins {
|
||||
|
||||
version = "${project.property("mod_version")}+${project.property("mc_version")}"
|
||||
|
||||
val isSnapshot = project.property("snapshot")?.equals("true") ?: false
|
||||
val isSnapshot = project.property("snapshot")?.equals("true") == true
|
||||
if (isSnapshot) {
|
||||
val fixedBranchName = versioning.info.branch.substringAfter("/")
|
||||
version = "$version-${fixedBranchName}-${versioning.info.build}"
|
||||
|
||||
+7
@@ -6,3 +6,10 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.duck;
|
||||
|
||||
import net.minecraft.world.item.crafting.RecipeManager;
|
||||
|
||||
public interface RecipeAwareSlot {
|
||||
void setRecipeManager(RecipeManager recipeManager);
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokemon.ai.EntityBehaviour;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.entity.ai.goal.AvoidEntityGoal;
|
||||
import net.minecraft.world.entity.monster.Creeper;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(Creeper.class)
|
||||
public class EntityCreeperMixin extends Mob {
|
||||
|
||||
private EntityCreeperMixin(net.minecraft.world.entity.EntityType<? extends Creeper> entityType, Level world) {
|
||||
super(entityType, world);
|
||||
}
|
||||
|
||||
@Inject(method = "registerGoals", at = @At(value = "TAIL"), cancellable = false)
|
||||
private void cobblemon$initGoals(CallbackInfo callbackInfo) {
|
||||
final Creeper creeper = (Creeper) (Object) this;
|
||||
// Pokemon Entities
|
||||
this.goalSelector.addGoal(
|
||||
3,
|
||||
new AvoidEntityGoal<>(
|
||||
creeper,
|
||||
PokemonEntity.class,
|
||||
6.0f,
|
||||
1.0,
|
||||
1.2,
|
||||
entity -> ((PokemonEntity)entity).getBehaviour().getEntityInteract().getAvoidedByCreeper() && ((PokemonEntity)entity).getBeamMode() != 1
|
||||
)
|
||||
);
|
||||
|
||||
// Players with shoulder mounted Pokemon
|
||||
this.goalSelector.addGoal(
|
||||
3,
|
||||
new AvoidEntityGoal<>(
|
||||
creeper,
|
||||
ServerPlayer.class,
|
||||
6.0f,
|
||||
1.0,
|
||||
1.2,
|
||||
entity -> EntityBehaviour.Companion.hasCreeperFearedShoulderMount((ServerPlayer)entity)
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.mixin;
|
||||
|
||||
import net.minecraft.world.entity.monster.Phantom;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
||||
@Mixin(targets = "net/minecraft/world/entity/monster/Phantom$PhantomSweepAttackGoal")
|
||||
public class EntityPhantomMixin {
|
||||
// TODO: Figure out how to access the outer class that wraps SwoopMovementGoal
|
||||
// Need to find the cat mons that are near the phantom
|
||||
|
||||
// @Inject(method = "shouldContinue", at = @At(value = "RETURN"), cancellable = true)
|
||||
// public void cobblemon$shouldContinue(CallbackInfoReturnable<Boolean> ci) {
|
||||
//// var goalSelectorField = PhantomEntity.class.getClasses();// PhantomEntity.class.getFields();// .class.getDeclaredField("goalSelector");
|
||||
//
|
||||
//// goalSelectorField.setAccessible(true);
|
||||
//// GoalSelector goalSelector = (GoalSelector) goalSelectorField.get(mobEntity);
|
||||
//// final SwoopMovementGoal phantom = (SwoopMovementGoal) (Object) this;
|
||||
//// if(ci.getReturnValue() == false) {
|
||||
//// var result = this$0.getWorld().getEntitiesByClass(
|
||||
//// PokemonEntity.class,
|
||||
//// this$0.getBoundingBox().expand(16.0),
|
||||
//// entity -> {
|
||||
//// return ((PokemonEntity) entity).getBehaviour().getEntityInteract().getAvoidedByPhantom();
|
||||
//// }
|
||||
//// ).isEmpty();
|
||||
////
|
||||
//// ci.setReturnValue(result);
|
||||
//// }
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -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.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.pokemon.ai.EntityBehaviour;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.Mob;
|
||||
import net.minecraft.world.entity.ai.goal.AvoidEntityGoal;
|
||||
import net.minecraft.world.entity.monster.AbstractSkeleton;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(AbstractSkeleton.class)
|
||||
public class EntitySkeletonMixin extends Mob {
|
||||
|
||||
private EntitySkeletonMixin(EntityType<? extends Mob> entityType, Level world) {
|
||||
super(entityType, world);
|
||||
}
|
||||
|
||||
@Inject(method = "registerGoals", at = @At(value = "TAIL"))
|
||||
private void cobblemon$initGoals(CallbackInfo callbackInfo) {
|
||||
final AbstractSkeleton skeleton = (AbstractSkeleton) (Object) this;
|
||||
// Pokemon Entities
|
||||
this.goalSelector.addGoal(
|
||||
3,
|
||||
new AvoidEntityGoal<>(
|
||||
skeleton,
|
||||
PokemonEntity.class,
|
||||
6.0f,
|
||||
1.0,
|
||||
1.2,
|
||||
entity -> ((PokemonEntity)entity).getBehaviour().getEntityInteract().getAvoidedBySkeleton() && ((PokemonEntity)entity).getBeamMode() != 1
|
||||
)
|
||||
);
|
||||
|
||||
// Players with shoulder mounted Pokemon
|
||||
this.goalSelector.addGoal(
|
||||
3,
|
||||
new AvoidEntityGoal<>(
|
||||
skeleton,
|
||||
ServerPlayer.class,
|
||||
6.0f,
|
||||
1.0,
|
||||
1.2,
|
||||
entity -> EntityBehaviour.Companion.hasSkeletonFearedShoulderMount((ServerPlayer)entity)
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ public abstract class EntityVillagerMixin {
|
||||
@Inject(method = "wantsToPickUp", at = @At(value = "RETURN"), cancellable = true)
|
||||
private void cobblemon$canGather(ItemStack stack, CallbackInfoReturnable<Boolean> ci) {
|
||||
final Villager villager = (Villager) (Object) this;
|
||||
if(ci.getReturnValue() == false && Objects.equals(villager.getVillagerData().getProfession(), VillagerProfession.FARMER) && villager.getInventory().canAddItem(stack)) {
|
||||
if (ci.getReturnValue() == false && Objects.equals(villager.getVillagerData().getProfession(), VillagerProfession.FARMER) && villager.getInventory().canAddItem(stack)) {
|
||||
if(VillagerGatherableItems.INSTANCE.getVillagerGatherableItems().contains(stack.getItem()))
|
||||
ci.setReturnValue(true);
|
||||
}
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
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 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;
|
||||
if (player.isPassenger() && player.getVehicle() instanceof PokemonEntity pokemonEntity) {
|
||||
var rideValue = pokemonEntity.<Float>ifRidingAvailableSupply(null, (behaviour, settings, state) -> {
|
||||
if (behaviour.canJump(settings, state, pokemonEntity, player)) return null;
|
||||
return behaviour.setRideBar(settings, state, pokemonEntity, player);
|
||||
});
|
||||
if (rideValue != null) {
|
||||
cir.setReturnValue(rideValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,9 +22,9 @@ public class PiglinBarterMixin {
|
||||
|
||||
@Inject(method = "isBarterCurrency", at = @At(value = "RETURN"), cancellable = true)
|
||||
private static void cobblemon$acceptsForBarter(ItemStack stack, CallbackInfoReturnable<Boolean> ci) {
|
||||
if(!ci.getReturnValue()) {
|
||||
if (!ci.getReturnValue()) {
|
||||
//TODO: Make a tag?
|
||||
if(stack.is(CobblemonItems.RELIC_COIN_POUCH))
|
||||
if (stack.is(CobblemonItems.RELIC_COIN_POUCH))
|
||||
ci.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,9 +21,9 @@ import org.spongepowered.asm.mixin.injection.Slice;
|
||||
public abstract class PointedDripstoneBlockMixin {
|
||||
|
||||
@Redirect(
|
||||
method = "canTipGrow(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/core/BlockPos;)Z",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;is(Lnet/minecraft/world/level/Block;)Z", ordinal = 0),
|
||||
slice = @Slice(from = @At(value = "FIELD", target = "Lnet/minecraft/world/level/block/Blocks;DRIPSTONE_BLOCK:Lnet/minecraft/world/level/Block;"))
|
||||
method = "canGrow(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockState;)Z",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;is(Lnet/minecraft/world/level/block/Block;)Z", ordinal = 0),
|
||||
slice = @Slice(from = @At(value = "FIELD", target = "Lnet/minecraft/world/level/block/Blocks;DRIPSTONE_BLOCK:Lnet/minecraft/world/level/block/Block;"))
|
||||
)
|
||||
private static boolean cobblemon$validateMoonStoneDripstone(BlockState instance, Block block) {
|
||||
return instance.is(CobblemonBlockTags.DRIPSTONE_GROWABLE);
|
||||
|
||||
@@ -8,12 +8,10 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.client.sound.BlockEntitySoundTracker;
|
||||
import com.cobblemon.mod.common.client.sound.EntitySoundTracker;
|
||||
import com.cobblemon.mod.common.client.sound.BattleMusicController;
|
||||
import com.cobblemon.mod.common.client.sound.SoundTracker;
|
||||
import com.cobblemon.mod.common.duck.SoundManagerDuck;
|
||||
import com.cobblemon.mod.common.duck.SoundEngineDuck;
|
||||
import com.cobblemon.mod.common.duck.SoundManagerDuck;
|
||||
import net.minecraft.client.resources.sounds.BiomeAmbientSoundsHandler;
|
||||
import net.minecraft.client.resources.sounds.SoundInstance;
|
||||
import net.minecraft.client.resources.sounds.UnderwaterAmbientSoundInstances;
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.world.CobblemonStructureIDs;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.LevelHeightAccessor;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.biome.BiomeSource;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
import net.minecraft.world.level.levelgen.RandomState;
|
||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||
import net.minecraft.world.level.levelgen.structure.StructurePiece;
|
||||
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@Mixin(Structure.class)
|
||||
public abstract class StructureMixin {
|
||||
// Define a set of structures that should not spawn below Sea Level
|
||||
@Unique
|
||||
private static final Set<ResourceLocation> RESTRICTED_STRUCTURES = new HashSet<>(Arrays.asList(
|
||||
CobblemonStructureIDs.STONJOURNER_HENGE,
|
||||
CobblemonStructureIDs.LUNA_HENGE,
|
||||
CobblemonStructureIDs.SOL_HENGE
|
||||
));
|
||||
|
||||
@Inject(method = "generate", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/levelgen/structure/StructureStart;isValid()Z"),
|
||||
cancellable = true)
|
||||
public void cobblemon$isValid(RegistryAccess registryAccess, ChunkGenerator chunkGenerator, BiomeSource biomeSource,
|
||||
RandomState randomState, StructureTemplateManager structureTemplateManager, long seed,
|
||||
ChunkPos chunkPos, int references, LevelHeightAccessor heightAccessor,
|
||||
Predicate<Holder<Biome>> validBiome,
|
||||
CallbackInfoReturnable<StructureStart> cir,
|
||||
@Local StructureStart structureStart) {
|
||||
ResourceLocation structureKey = registryAccess.registryOrThrow(Registries.STRUCTURE).getKey((Structure) (Object) this);
|
||||
if(!RESTRICTED_STRUCTURES.contains(structureKey)) {
|
||||
return;
|
||||
}
|
||||
for (StructurePiece piece : structureStart.getPieces()) {
|
||||
if (piece.getBoundingBox().minY() < chunkGenerator.getSeaLevel()) {
|
||||
cir.setReturnValue(StructureStart.INVALID_START);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.brewing;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonRecipeTypes;
|
||||
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandInput;
|
||||
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.world.Containers;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.alchemy.PotionBrewing;
|
||||
import net.minecraft.world.item.crafting.RecipeHolder;
|
||||
import net.minecraft.world.item.crafting.RecipeManager;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.LevelEvent;
|
||||
import net.minecraft.world.level.block.entity.BrewingStandBlockEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@Mixin(BrewingStandBlockEntity.class)
|
||||
public class BrewingStandBlockEntityMixin {
|
||||
|
||||
@WrapOperation(method = "serverTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/entity/BrewingStandBlockEntity;doBrew(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/core/NonNullList;)V"))
|
||||
private static void cobblemon$doBrew(Level level, BlockPos pos, NonNullList<ItemStack> slots, Operation<Void> original) {
|
||||
var recipe = cobblemon$fetchBrewingRecipe(slots, level);
|
||||
if(recipe == null) {
|
||||
original.call(level, pos, slots);
|
||||
return;
|
||||
}
|
||||
//copied from vanilla doBrew logic, but slightly tweaked to work for cobblemon, this was needed as replacing the loop was not quite possible inside doBrew
|
||||
ItemStack itemStack = slots.get(3);
|
||||
for(int i = 0; i < 3; ++i) {
|
||||
slots.set(i, recipe.getResult().copy());
|
||||
}
|
||||
|
||||
itemStack.shrink(1);
|
||||
if (itemStack.getItem().hasCraftingRemainingItem()) {
|
||||
ItemStack itemStack2 = new ItemStack(itemStack.getItem().getCraftingRemainingItem());
|
||||
if (itemStack.isEmpty()) {
|
||||
itemStack = itemStack2;
|
||||
} else {
|
||||
Containers.dropItemStack(level, pos.getX(), pos.getY(), pos.getZ(), itemStack2);
|
||||
}
|
||||
}
|
||||
|
||||
slots.set(3, itemStack);
|
||||
level.levelEvent(LevelEvent.SOUND_BREWING_STAND_BREW, pos, 0);
|
||||
}
|
||||
|
||||
@WrapOperation(method = "serverTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/entity/BrewingStandBlockEntity;isBrewable(Lnet/minecraft/world/item/alchemy/PotionBrewing;Lnet/minecraft/core/NonNullList;)Z"))
|
||||
private static boolean cobblemon$isBrewable(PotionBrewing potionBrewing, NonNullList<ItemStack> items, Operation<Boolean> original,
|
||||
@Local(argsOnly = true) Level level) {
|
||||
return cobblemon$fetchBrewingRecipe(items, level) != null || original.call(potionBrewing, items);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private static BrewingStandRecipe cobblemon$fetchBrewingRecipe(NonNullList<ItemStack> items, Level level) {
|
||||
ItemStack ingredient = items.get(3);
|
||||
List<ItemStack> bottles = items.subList(0, 3);
|
||||
|
||||
boolean allBottlesEmpty = true;
|
||||
for (ItemStack bottle : bottles) {
|
||||
if (!bottle.isEmpty()) {
|
||||
allBottlesEmpty = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ingredient.isEmpty() || allBottlesEmpty) {
|
||||
return null;
|
||||
}
|
||||
|
||||
BrewingStandInput input = new BrewingStandInput(ingredient, bottles);
|
||||
RecipeManager recipeManager = level.getRecipeManager();
|
||||
|
||||
Optional<RecipeHolder<BrewingStandRecipe>> recipeHolder =
|
||||
recipeManager.getRecipeFor(CobblemonRecipeTypes.INSTANCE.getBREWING_STAND(), input, level);
|
||||
|
||||
return recipeHolder.map(RecipeHolder::value).orElse(null);
|
||||
}
|
||||
}
|
||||
+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.mixin.brewing;
|
||||
|
||||
import com.cobblemon.mod.common.duck.RecipeAwareSlot;
|
||||
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.BrewingStandMenu;
|
||||
import net.minecraft.world.inventory.ContainerData;
|
||||
import net.minecraft.world.inventory.Slot;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(BrewingStandMenu.class)
|
||||
public abstract class BrewingStandMenuMixin {
|
||||
|
||||
@Inject(method = "<init>(ILnet/minecraft/world/entity/player/Inventory;Lnet/minecraft/world/Container;Lnet/minecraft/world/inventory/ContainerData;)V", at = @At("TAIL"))
|
||||
private void captureLevel(int containerId, Inventory playerInventory, Container brewingStandContainer, ContainerData brewingStandData, CallbackInfo ci) {
|
||||
var recipeManager = playerInventory.player.level().getRecipeManager();
|
||||
for (Slot slot : ((BrewingStandMenu) (Object) this).slots) {
|
||||
if (slot instanceof RecipeAwareSlot awareSlot) {
|
||||
awareSlot.setRecipeManager(recipeManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@WrapOperation(method = "quickMoveStack", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/inventory/BrewingStandMenu$PotionSlot;mayPlaceItem(Lnet/minecraft/world/item/ItemStack;)Z"))
|
||||
private boolean cobblemon$isPotionBottle(ItemStack stack, Operation<Boolean> original, @Local(argsOnly = true) Player player) {
|
||||
return BrewingStandRecipe.Companion.isBottle(stack, player.level().getRecipeManager()) || original.call(stack);
|
||||
}
|
||||
}
|
||||
@@ -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.mixin.brewing;
|
||||
|
||||
import com.cobblemon.mod.common.duck.RecipeAwareSlot;
|
||||
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe;
|
||||
import net.minecraft.world.inventory.BrewingStandMenu;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.crafting.RecipeManager;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(BrewingStandMenu.IngredientsSlot.class)
|
||||
public class IngredientSlotMixin implements RecipeAwareSlot {
|
||||
|
||||
@Unique
|
||||
private RecipeManager cobblemon$recipeManager;
|
||||
|
||||
@Override
|
||||
public void setRecipeManager(RecipeManager recipeManager) {
|
||||
this.cobblemon$recipeManager = recipeManager;
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "mayPlace",
|
||||
at = @At("HEAD"),
|
||||
cancellable = true
|
||||
)
|
||||
private void cobblemon$mayPlace(ItemStack stack, CallbackInfoReturnable<Boolean> cir) {
|
||||
if (BrewingStandRecipe.Companion.isInput(stack, cobblemon$recipeManager)) {
|
||||
cir.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.mixin.brewing;
|
||||
|
||||
import com.cobblemon.mod.common.duck.RecipeAwareSlot;
|
||||
import com.cobblemon.mod.common.item.crafting.brewingstand.BrewingStandRecipe;
|
||||
import net.minecraft.world.inventory.BrewingStandMenu;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.crafting.RecipeManager;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(BrewingStandMenu.PotionSlot.class)
|
||||
public class PotionSlotMixin implements RecipeAwareSlot {
|
||||
|
||||
@Unique
|
||||
private RecipeManager cobblemon$recipeManager;
|
||||
|
||||
@Override
|
||||
public void setRecipeManager(RecipeManager recipeManager) {
|
||||
this.cobblemon$recipeManager = recipeManager;
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "mayPlace",
|
||||
at = @At("HEAD"),
|
||||
cancellable = true
|
||||
)
|
||||
private void cobblemon$mayPlace(ItemStack stack, CallbackInfoReturnable<Boolean> cir) {
|
||||
if (BrewingStandRecipe.Companion.isBottle(stack, cobblemon$recipeManager)) {
|
||||
cir.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.api.riding.Rideable;
|
||||
import com.cobblemon.mod.common.client.MountedPokemonAnimationRenderController;
|
||||
import com.cobblemon.mod.common.client.render.camera.MountedCameraRenderer;
|
||||
@@ -51,11 +52,10 @@ public abstract class CameraMixin {
|
||||
@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;
|
||||
if (!(this.entity instanceof OrientationControllable controllable) || Cobblemon.config.getDisableRoll()) return;
|
||||
var controller = controllable.getOrientationController();
|
||||
if (!controller.isActive() && controller.getOrientation() != null) {
|
||||
if(this.returnTimer < 1) {
|
||||
@@ -128,9 +128,9 @@ public abstract class CameraMixin {
|
||||
this.rotation.set(newRotation);
|
||||
this.xRot = controller.getPitch();
|
||||
this.yRot = controller.getYaw();
|
||||
this.forwards.set(controller.getForwardVector());
|
||||
this.up.set(controller.getUpVector());
|
||||
this.left.set(controller.getLeftVector());
|
||||
OrientationController.Companion.getFORWARDS().rotate(this.rotation, this.forwards);
|
||||
OrientationController.Companion.getUP().rotate(this.rotation, this.up);
|
||||
OrientationController.Companion.getLEFT().rotate(this.rotation, this.left);
|
||||
}
|
||||
|
||||
@WrapOperation(method = "setup", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Camera;move(FFF)V", ordinal = 0))
|
||||
|
||||
+7
-6
@@ -19,7 +19,6 @@ 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;
|
||||
@@ -40,9 +39,11 @@ public abstract class ClientRecipeBookMixin {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Shadow private Map<RecipeBookCategories, List<RecipeCollection>> collectionsByTab;
|
||||
@Shadow
|
||||
private Map<RecipeBookCategories, List<RecipeCollection>> collectionsByTab;
|
||||
|
||||
@Shadow private List<RecipeCollection> allCollections;
|
||||
@Shadow
|
||||
private List<RecipeCollection> allCollections;
|
||||
|
||||
@Inject(method = "getCategory", at = @At(value = "HEAD"), cancellable = true)
|
||||
private static void addCustomCategory(RecipeHolder<?> recipe, CallbackInfoReturnable<RecipeBookCategories> cir) {
|
||||
@@ -56,7 +57,7 @@ public abstract class ClientRecipeBookMixin {
|
||||
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();
|
||||
case COMPLEX_DISHES -> var7 = CobblemonRecipeCategories.COOKING_POT_COMPLEX_DISHES.toVanillaCategory();
|
||||
default -> throw new MatchException(null, null);
|
||||
}
|
||||
cir.setReturnValue(var7);
|
||||
@@ -76,8 +77,8 @@ public abstract class ClientRecipeBookMixin {
|
||||
.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())));
|
||||
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();
|
||||
|
||||
@@ -10,27 +10,51 @@ package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork;
|
||||
import com.cobblemon.mod.common.OrientationControllable;
|
||||
import com.cobblemon.mod.common.api.orientation.OrientationController;
|
||||
import com.cobblemon.mod.common.api.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.cobblemon.mod.common.net.messages.server.orientation.ServerboundUpdateOrientationPacket;
|
||||
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.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.level.ClipContext;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
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.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(LocalPlayer.class)
|
||||
public abstract class LocalPlayerMixin extends LivingEntity {
|
||||
public abstract class LocalPlayerMixin extends AbstractClientPlayer implements OrientationControllable{
|
||||
|
||||
@Unique Matrix3f cobblemon$lastOrientation;
|
||||
|
||||
protected LocalPlayerMixin(EntityType<? extends LivingEntity> entityType, Level level) {
|
||||
super(entityType, level);
|
||||
@Shadow
|
||||
private float jumpRidingScale;
|
||||
|
||||
public LocalPlayerMixin(ClientLevel clientLevel, GameProfile gameProfile) {
|
||||
super(clientLevel, gameProfile);
|
||||
}
|
||||
|
||||
// @Inject(method = "sendPosition", at = @At("TAIL"))
|
||||
@@ -76,4 +100,73 @@ public abstract class LocalPlayerMixin extends LivingEntity {
|
||||
if (!(this instanceof OrientationControllable controllable)) return;
|
||||
controllable.getOrientationController().setActive(false);
|
||||
}
|
||||
|
||||
@Inject(method = "getJumpRidingScale", at = @At("HEAD"), cancellable = true)
|
||||
public void modifyJumpRidingScale(CallbackInfoReturnable<Float> cir) {
|
||||
LocalPlayer player = (LocalPlayer) (Object) this;
|
||||
if (player.isPassenger() && player.getVehicle() instanceof PokemonEntity pokemonEntity) {
|
||||
var rideValue = pokemonEntity.<Float>ifRidingAvailableSupply(null, (behaviour, settings, state) -> {
|
||||
if (behaviour.canJump(settings, state, pokemonEntity, player)) return null;
|
||||
return behaviour.setRideBar(settings, state, pokemonEntity, player);
|
||||
});
|
||||
if (rideValue != null) {
|
||||
cir.setReturnValue(rideValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -50,10 +50,10 @@ public class RecipeBookCategoriesMixin {
|
||||
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)));
|
||||
types.add(cobblemon$createCategory("COOKING_POT_FOODS", $VALUES.length + 1, new ItemStack(CobblemonItems.LEEK_AND_POTATO_STEW)));
|
||||
types.add(cobblemon$createCategory("COOKING_POT_MEDICINES", $VALUES.length + 2, new ItemStack(CobblemonItems.POTION)));
|
||||
types.add(cobblemon$createCategory("COOKING_POT_COMPLEX_DISHES", $VALUES.length + 3, new ItemStack(CobblemonItems.POKE_PUFF)));
|
||||
types.add(cobblemon$createCategory("COOKING_POT_MISC", $VALUES.length + 4, new ItemStack(CobblemonItems.PROTEIN)));
|
||||
$VALUES = types.toArray(RecipeBookCategories[]::new);
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ public class RecipeBookCategoriesMixin {
|
||||
CobblemonRecipeCategories.COOKING_POT_SEARCH.toVanillaCategory(),
|
||||
CobblemonRecipeCategories.COOKING_POT_FOODS.toVanillaCategory(),
|
||||
CobblemonRecipeCategories.COOKING_POT_MEDICINES.toVanillaCategory(),
|
||||
CobblemonRecipeCategories.COOKING_POT_BAITS.toVanillaCategory(),
|
||||
CobblemonRecipeCategories.COOKING_POT_COMPLEX_DISHES.toVanillaCategory(),
|
||||
CobblemonRecipeCategories.COOKING_POT_MISC.toVanillaCategory());
|
||||
cir.setReturnValue(var10000);
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.searchtree.IdSearchTree;
|
||||
import net.minecraft.client.searchtree.SearchTree;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Mixin(IdSearchTree.class)
|
||||
public abstract class SearchTreeMixin {
|
||||
@Unique
|
||||
private static final ThreadLocal<Boolean> reentryFlag = ThreadLocal.withInitial(() -> false);
|
||||
|
||||
/**
|
||||
* Runs an additional search using the original search term where every instance of 'e' is replaced with 'é'
|
||||
* Appends additional search results to original search results.
|
||||
*/
|
||||
@Inject(method = "search(Ljava/lang/String;)Ljava/util/List;", at = @At("RETURN"), cancellable = true)
|
||||
private void onSearch(String string, CallbackInfoReturnable<List> cir) {
|
||||
// If flag is true, skip to avoid infinite loop
|
||||
if (reentryFlag.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
reentryFlag.set(true);
|
||||
List originalResults = cir.getReturnValue();
|
||||
|
||||
if (!string.contains("poke")) {
|
||||
return;
|
||||
}
|
||||
|
||||
String modifiedString = string.replace("poke", "poké");
|
||||
List additionalResults = ((SearchTree)this).search(modifiedString);
|
||||
|
||||
Set combinedSet = new LinkedHashSet<>();
|
||||
combinedSet.addAll(originalResults);
|
||||
combinedSet.addAll(additionalResults);
|
||||
|
||||
cir.setReturnValue(new ArrayList<>(combinedSet));
|
||||
} finally {
|
||||
reentryFlag.set(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.client.render.TextClipping;
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.network.chat.Style;
|
||||
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;
|
||||
|
||||
/**
|
||||
* This mixin facilitates the gradual reveal of text with NPC dialogue. If there is a better way
|
||||
* to do this, I'd love to hear it.
|
||||
*
|
||||
* The idea is that somewhere static in the mod we have a control for how many characters can be drawn
|
||||
* and how many have been drawn so far, and this mixin will add to the latter and stop drawing characters
|
||||
* once it reaches the former.
|
||||
*
|
||||
* This relies STRONGLY on the code that sets the character cap to reset it to -1 after the text is rendered,
|
||||
* otherwise all text in Minecraft will stop drawing.
|
||||
*
|
||||
* Sites that take advantage of this mixin will do the following:
|
||||
* 1: Set the character cap, which resets the drawn counter to zero.
|
||||
* 2: Call whatever Minecraft function draws your text.
|
||||
* 3: Reset the character cap to -1, which will allow regular text to draw again.
|
||||
*
|
||||
* @author Hiroku
|
||||
* @since April 18th, 2025
|
||||
*/
|
||||
@Mixin(Font.StringRenderOutput.class)
|
||||
public class StringRenderOutputMixin {
|
||||
@Inject(method = "accept", at = @At(value = "HEAD"), cancellable = true)
|
||||
public void onAccept(int i, Style style, int j, CallbackInfoReturnable<Boolean> cir) {
|
||||
if (!TextClipping.canDrawAnotherCharacter()) {
|
||||
cir.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,9 +40,9 @@ import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
|
||||
import com.cobblemon.mod.common.api.scheduling.ServerRealTimeTaskTracker
|
||||
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
|
||||
import com.cobblemon.mod.common.api.spawning.BestSpawner
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawningProspector
|
||||
import com.cobblemon.mod.common.api.spawning.context.AreaContextResolver
|
||||
import com.cobblemon.mod.common.api.spawning.prospecting.SpawningProspector
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawningZoneGenerator
|
||||
import com.cobblemon.mod.common.api.spawning.position.AreaSpawnablePositionResolver
|
||||
import com.cobblemon.mod.common.api.spawning.SpawningZoneGenerator
|
||||
import com.cobblemon.mod.common.api.starter.StarterHandler
|
||||
import com.cobblemon.mod.common.api.storage.PokemonStoreManager
|
||||
import com.cobblemon.mod.common.api.storage.adapter.conversions.ReforgedConversion
|
||||
@@ -63,13 +63,10 @@ import com.cobblemon.mod.common.api.storage.player.adapter.PlayerDataMongoBacken
|
||||
import com.cobblemon.mod.common.api.storage.player.factory.CachedPlayerDataStoreFactory
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonEntityTypeTags
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import com.cobblemon.mod.common.battles.BagItems
|
||||
import com.cobblemon.mod.common.battles.BattleFormat
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
import com.cobblemon.mod.common.battles.BattleSide
|
||||
import com.cobblemon.mod.common.battles.ShowdownThread
|
||||
import com.cobblemon.mod.common.battles.*
|
||||
import com.cobblemon.mod.common.battles.actor.PokemonBattleActor
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.block.DispenserBehaviorRegistry
|
||||
import com.cobblemon.mod.common.client.CobblemonPack
|
||||
import com.cobblemon.mod.common.command.argument.*
|
||||
import com.cobblemon.mod.common.config.CobblemonConfig
|
||||
@@ -91,23 +88,11 @@ import com.cobblemon.mod.common.pokemon.aspects.SHINY_ASPECT
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.BlockClickEvolution
|
||||
import com.cobblemon.mod.common.pokemon.feature.TagSeasonResolver
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
import com.cobblemon.mod.common.pokemon.properties.AspectPropertyType
|
||||
import com.cobblemon.mod.common.pokemon.properties.BattleCloneProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.FreezeFrameProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.HiddenAbilityPropertyType
|
||||
import com.cobblemon.mod.common.pokemon.properties.NoAIProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.UnaspectPropertyType
|
||||
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.*
|
||||
import com.cobblemon.mod.common.pokemon.properties.tags.PokemonFlagProperty
|
||||
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
|
||||
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.ifDedicatedServer
|
||||
import com.cobblemon.mod.common.util.isLaterVersion
|
||||
import com.cobblemon.mod.common.util.party
|
||||
import com.cobblemon.mod.common.util.requestWallpapers
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import com.cobblemon.mod.common.world.feature.CobblemonPlacedFeatures
|
||||
import com.cobblemon.mod.common.world.feature.ore.CobblemonOrePlacedFeatures
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
|
||||
@@ -115,20 +100,8 @@ import com.mongodb.ConnectionString
|
||||
import com.mongodb.MongoClientSettings
|
||||
import com.mongodb.client.MongoClient
|
||||
import com.mongodb.client.MongoClients
|
||||
import java.io.File
|
||||
import java.io.FileReader
|
||||
import java.io.FileWriter
|
||||
import java.io.PrintWriter
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.properties.Delegates
|
||||
import kotlin.reflect.full.memberProperties
|
||||
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
|
||||
@@ -139,6 +112,17 @@ import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.storage.LevelResource
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import org.apache.logging.log4j.Logger
|
||||
import java.io.File
|
||||
import java.io.FileReader
|
||||
import java.io.FileWriter
|
||||
import java.io.PrintWriter
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.properties.Delegates
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
import kotlin.reflect.jvm.javaField
|
||||
|
||||
object Cobblemon {
|
||||
const val MODID = CobblemonBuildDetails.MOD_ID
|
||||
@@ -160,8 +144,8 @@ object Cobblemon {
|
||||
var isDedicatedServer = false
|
||||
val showdownThread = ShowdownThread()
|
||||
lateinit var config: CobblemonConfig
|
||||
var prospector: SpawningProspector = CobblemonSpawningProspector
|
||||
var areaContextResolver: AreaContextResolver = object : AreaContextResolver {}
|
||||
var spawningZoneGenerator: SpawningZoneGenerator = CobblemonSpawningZoneGenerator
|
||||
var areaSpawnablePositionResolver: AreaSpawnablePositionResolver = object : AreaSpawnablePositionResolver {}
|
||||
val bestSpawner = BestSpawner
|
||||
val battleRegistry = BattleRegistry
|
||||
var storage = PokemonStoreManager()
|
||||
@@ -213,6 +197,7 @@ object Cobblemon {
|
||||
implementation.registerEntityDataSerializers()
|
||||
implementation.registerCriteria()
|
||||
implementation.registerEntitySubPredicates()
|
||||
DispenserBehaviorRegistry.registerDispenserBehaviors()
|
||||
|
||||
DropEntry.register("command", CommandDropEntry::class.java)
|
||||
DropEntry.register("item", ItemDropEntry::class.java, isDefault = true)
|
||||
|
||||
@@ -15,6 +15,9 @@ object CobblemonActivities {
|
||||
val BATTLING = register(Activity("battling"))
|
||||
val ACTION_EFFECT = register(Activity("action_effect"))
|
||||
val NPC_CHATTING = register(Activity("npc_chatting"))
|
||||
val POKEMON_SLEEPING_ACTIVITY = register(Activity("pokemon_sleeping"))
|
||||
val POKEMON_GROW_CROP = register(Activity("pokemon_grow_crop"))
|
||||
val POKEMON_SLEEP_ON_TRAINER_BED = register(Activity("pokemon_sleep_on_trainer_bed"))
|
||||
|
||||
fun register(activity: Activity): Activity {
|
||||
activities.add(activity)
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.api.ai.CobblemonBehaviour
|
||||
import com.cobblemon.mod.common.api.ai.config.BehaviourConfig
|
||||
import com.cobblemon.mod.common.api.ai.config.task.TaskConfig
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry.Companion.JSON_EXTENSION
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.net.messages.client.data.BehaviourSyncPacket
|
||||
import com.cobblemon.mod.common.util.adapters.ActivityAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.BehaviourConfigAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionOrEntityVariableAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.TaskConfigAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.TranslatedTextAdapter
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.endsWith
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.mojang.datafixers.util.Either
|
||||
import java.io.File
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.server.packs.PackType
|
||||
import net.minecraft.server.packs.resources.ResourceManager
|
||||
import net.minecraft.world.entity.schedule.Activity
|
||||
|
||||
object CobblemonBehaviours : JsonDataRegistry<CobblemonBehaviour> {
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(Activity::class.java, ActivityAdapter)
|
||||
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
|
||||
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
|
||||
.registerTypeAdapter(BehaviourConfig::class.java, BehaviourConfigAdapter)
|
||||
.registerTypeAdapter(TaskConfig::class.java, TaskConfigAdapter)
|
||||
.registerTypeAdapter(
|
||||
TypeToken.getParameterized(Either::class.java, Expression::class.java, MoLangConfigVariable::class.java).type,
|
||||
ExpressionOrEntityVariableAdapter
|
||||
)
|
||||
.registerTypeAdapter(Component::class.java, TranslatedTextAdapter)
|
||||
.registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter)
|
||||
.create()
|
||||
|
||||
override val typeToken = TypeToken.get(CobblemonBehaviour::class.java)
|
||||
override val resourcePath = "behaviours"
|
||||
override val id: ResourceLocation = cobblemonResource("behaviours")
|
||||
override val type = PackType.SERVER_DATA
|
||||
override val observable = SimpleObservable<CobblemonBehaviours>()
|
||||
|
||||
/**
|
||||
* Any behaviours that are put into /pokemon/auto will be automatically
|
||||
* applied to all Pokémon species/forms that don't define a baseAI list of
|
||||
* behaviour configurations. This is an addon-friendly way of defining the general
|
||||
* rules of Pokémon AI without it being unavoidable for specific
|
||||
* species.
|
||||
*/
|
||||
val autoPokemonBehaviours = mutableListOf<CobblemonBehaviour>()
|
||||
|
||||
val behaviours = mutableMapOf<ResourceLocation, CobblemonBehaviour>()
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
player.sendPacket(BehaviourSyncPacket(behaviours.filter { it.value.visible }))
|
||||
}
|
||||
|
||||
override fun reload(manager: ResourceManager) {
|
||||
autoPokemonBehaviours.clear()
|
||||
val data = mutableMapOf<ResourceLocation, CobblemonBehaviour>()
|
||||
manager.listResources(resourcePath) { path -> path.endsWith(JSON_EXTENSION) }.forEach { (identifier, resource) ->
|
||||
resource.open().use { stream ->
|
||||
stream.bufferedReader().use { reader ->
|
||||
val resolvedIdentifier = ResourceLocation.fromNamespaceAndPath(identifier.namespace, File(identifier.path).nameWithoutExtension)
|
||||
val behaviour = parse(reader, resolvedIdentifier)
|
||||
if ("pokemon/auto/" in identifier.path) {
|
||||
autoPokemonBehaviours.add(behaviour)
|
||||
}
|
||||
data[resolvedIdentifier] = behaviour
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reload(data)
|
||||
Cobblemon.LOGGER.info("Loaded ${behaviours.size} entity behaviours")
|
||||
observable.emit(this)
|
||||
}
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, CobblemonBehaviour>) {
|
||||
behaviours.clear()
|
||||
behaviours.putAll(data)
|
||||
}
|
||||
}
|
||||
@@ -97,6 +97,18 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
|
||||
val CAMPFIRE: BlockEntityType<CampfireBlockEntity> = this.create("campfire_pot",
|
||||
BlockEntityType.Builder.of(::CampfireBlockEntity, CobblemonBlocks.CAMPFIRE).build(null)
|
||||
)
|
||||
@JvmField
|
||||
val COPPER_OVEN: BlockEntityType<CopperOvenBlockEntity> = this.create("copper_oven",
|
||||
BlockEntityType.Builder.of(::CopperOvenBlockEntity, CobblemonBlocks.COPPER_OVEN).build(null)
|
||||
)
|
||||
@JvmField
|
||||
val COPPER_WASHER: BlockEntityType<CopperWasherBlockEntity> = this.create("copper_washer",
|
||||
BlockEntityType.Builder.of(::CopperWasherBlockEntity, CobblemonBlocks.COPPER_WASHER).build(null)
|
||||
)
|
||||
@JvmField
|
||||
val COPPER_FRIDGE: BlockEntityType<CopperFridgeBlockEntity> = this.create("copper_fridge",
|
||||
BlockEntityType.Builder.of(::CopperFridgeBlockEntity, CobblemonBlocks.COPPER_FRIDGE).build(null)
|
||||
)
|
||||
|
||||
/*@JvmField
|
||||
val LURE_CAKE: BlockEntityType<LureCakeBlockEntity> =
|
||||
|
||||
@@ -15,10 +15,14 @@ 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.general.BaleBlock
|
||||
import com.cobblemon.mod.common.block.grower.SaccharineTreeGrower
|
||||
import com.cobblemon.mod.common.block.sign.CobblemonHangingSignBlock
|
||||
import com.cobblemon.mod.common.block.sign.CobblemonSignBlock
|
||||
import com.cobblemon.mod.common.block.sign.CobblemonWallHangingSignBlock
|
||||
import com.cobblemon.mod.common.block.sign.CobblemonWallSignBlock
|
||||
import com.cobblemon.mod.common.block.general.HorizontalRotationCarpetBlock
|
||||
import com.cobblemon.mod.common.block.general.HorizontalRotationalBlock
|
||||
import com.cobblemon.mod.common.mixin.invoker.*
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
@@ -175,11 +179,11 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
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")
|
||||
val STRIPPED_SACCHARINE_LOG = this.create("stripped_saccharine_log", RotatedPillarBlock(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")
|
||||
val STRIPPED_SACCHARINE_WOOD = this.create("stripped_saccharine_wood", RotatedPillarBlock(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
|
||||
@@ -222,7 +226,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
@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))
|
||||
val SACCHARINE_SAPLING = this.create("saccharine_sapling", SaplingBlock(SaccharineTreeGrower(), 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)))
|
||||
@@ -446,7 +450,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
|
||||
@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
|
||||
@@ -488,6 +492,17 @@ 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 COPPER_FAN = create("copper_fan", CopperFanBlock(BlockBehaviour.Properties.of().pushReaction(PushReaction.DESTROY).mapColor(MapColor.COLOR_ORANGE).requiresCorrectToolForDrops().strength(3.0F, 6.0F).sound(SoundType.COPPER)))
|
||||
@JvmField
|
||||
val COPPER_MOWER = create("copper_mower", CopperMowerBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_ORANGE).requiresCorrectToolForDrops().strength(3.0F, 6.0F).sound(SoundType.COPPER)))
|
||||
@JvmField
|
||||
val COPPER_OVEN = create("copper_oven", CopperOvenBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_ORANGE).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().strength(3.0F, 6.0F).sound(SoundType.COPPER)))
|
||||
@JvmField
|
||||
val COPPER_WASHER = this.create("copper_washer", CopperWasherBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_ORANGE).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().strength(3.0F, 6.0F).sound(SoundType.COPPER)))
|
||||
@JvmField
|
||||
val COPPER_FRIDGE = this.create("copper_fridge", CopperFridgeBlock(BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_ORANGE).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().strength(3.0F, 6.0F).sound(SoundType.COPPER)))
|
||||
|
||||
@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)))
|
||||
|
||||
@@ -515,6 +530,30 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
@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)))
|
||||
|
||||
@JvmField
|
||||
val POTTED_RED_APRICORN_SAPLING = this.create("potted_red_apricorn_sapling", BlocksInvoker.createFlowerPotBlock(RED_APRICORN_SAPLING))
|
||||
@JvmField
|
||||
val POTTED_YELLOW_APRICORN_SAPLING = this.create("potted_yellow_apricorn_sapling", BlocksInvoker.createFlowerPotBlock(YELLOW_APRICORN_SAPLING))
|
||||
@JvmField
|
||||
val POTTED_GREEN_APRICORN_SAPLING = this.create("potted_green_apricorn_sapling", BlocksInvoker.createFlowerPotBlock(GREEN_APRICORN_SAPLING))
|
||||
@JvmField
|
||||
val POTTED_BLUE_APRICORN_SAPLING = this.create("potted_blue_apricorn_sapling", BlocksInvoker.createFlowerPotBlock(BLUE_APRICORN_SAPLING))
|
||||
@JvmField
|
||||
val POTTED_PINK_APRICORN_SAPLING = this.create("potted_pink_apricorn_sapling", BlocksInvoker.createFlowerPotBlock(PINK_APRICORN_SAPLING))
|
||||
@JvmField
|
||||
val POTTED_BLACK_APRICORN_SAPLING = this.create("potted_black_apricorn_sapling", BlocksInvoker.createFlowerPotBlock(BLACK_APRICORN_SAPLING))
|
||||
@JvmField
|
||||
val POTTED_WHITE_APRICORN_SAPLING = this.create("potted_white_apricorn_sapling", BlocksInvoker.createFlowerPotBlock(WHITE_APRICORN_SAPLING))
|
||||
@JvmField
|
||||
val POTTED_SACCHARINE_SAPLING = this.create("potted_saccharine_sapling", BlocksInvoker.createFlowerPotBlock(SACCHARINE_SAPLING))
|
||||
|
||||
@JvmField
|
||||
val HEARTY_GRAIN_BALE = this.create("hearty_grain_bale", BaleBlock(BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).instrument(NoteBlockInstrument.BANJO).strength(0.5F).sound(SoundType.GRASS)))
|
||||
@JvmField
|
||||
val TATAMI_BLOCK = this.create("tatami_block", HorizontalRotationalBlock(BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.PLANT).sound(SoundType.GRASS)))
|
||||
@JvmField
|
||||
val TATAMI_MAT = this.create("tatami_mat", HorizontalRotationCarpetBlock(BlockBehaviour.Properties.of().ignitedByLava().mapColor(MapColor.PLANT).sound(SoundType.GRASS)))
|
||||
|
||||
/**
|
||||
* Returns a map of all the blocks that can be stripped with an axe in the format of input - output.
|
||||
*
|
||||
|
||||
@@ -1,58 +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
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.ai.config.BrainConfig
|
||||
import com.cobblemon.mod.common.api.ai.config.task.TaskConfig
|
||||
import com.cobblemon.mod.common.api.data.DataRegistry
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.util.adapters.ActivityAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.BrainConfigAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.TaskConfigAdapter
|
||||
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.entity.schedule.Activity
|
||||
|
||||
object CobblemonBrainConfigs : JsonDataRegistry<List<BrainConfig>> {
|
||||
override val gson: Gson = GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.registerTypeAdapter(Activity::class.java, ActivityAdapter)
|
||||
.registerTypeAdapter(Expression::class.java, ExpressionAdapter)
|
||||
.registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter)
|
||||
.registerTypeAdapter(BrainConfig::class.java, BrainConfigAdapter)
|
||||
.registerTypeAdapter(TaskConfig::class.java, TaskConfigAdapter)
|
||||
.create()
|
||||
|
||||
override val typeToken = TypeToken.getParameterized(List::class.java, BrainConfig::class.java) as TypeToken<List<BrainConfig>>
|
||||
override val resourcePath = "brain_presets"
|
||||
override val id: ResourceLocation = cobblemonResource("brain_presets")
|
||||
override val type = PackType.SERVER_DATA
|
||||
override val observable = SimpleObservable<CobblemonBrainConfigs>()
|
||||
|
||||
val presets = mutableMapOf<ResourceLocation, List<BrainConfig>>()
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
// TODO implement probs ay
|
||||
}
|
||||
|
||||
override fun reload(data: Map<ResourceLocation, List<BrainConfig>>) {
|
||||
presets.clear()
|
||||
presets.putAll(data)
|
||||
}
|
||||
}
|
||||
@@ -63,10 +63,13 @@ object CobblemonCommands {
|
||||
SpectateBattleCommand.register(dispatcher)
|
||||
CobblemonConfigCommand.register(dispatcher)
|
||||
UnlockPCBoxWallpaperCommand.register(dispatcher)
|
||||
BehaviourEditCommand.register(dispatcher)
|
||||
ChangePCBoxesCommand.register(dispatcher)
|
||||
MarkGiveCommand.register(dispatcher)
|
||||
MarkTakeCommand.register(dispatcher)
|
||||
MarkGiveAllCommand.register(dispatcher)
|
||||
PcSearchCommand.register(dispatcher)
|
||||
PcTakeCommand.register(dispatcher)
|
||||
|
||||
// Possibly lock down registration if and only if under dev environment or running in an environment
|
||||
// with a certain system environment variable set
|
||||
|
||||
@@ -8,18 +8,14 @@
|
||||
|
||||
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.components.RodBaitComponent
|
||||
import com.cobblemon.mod.common.item.components.*
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import com.mojang.serialization.Codec
|
||||
import net.minecraft.core.Registry
|
||||
import net.minecraft.core.component.DataComponentType
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.network.codec.ByteBufCodecs
|
||||
import net.minecraft.resources.ResourceKey
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
@@ -60,6 +56,25 @@ object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>
|
||||
.networkSynchronized(FoodColourComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
val INGREDIENT: DataComponentType<IngredientComponent> = create("ingredient", DataComponentType.builder<IngredientComponent>()
|
||||
.persistent(IngredientComponent.CODEC)
|
||||
.networkSynchronized(IngredientComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
val FOOD: DataComponentType<FoodComponent> = create("food", DataComponentType.builder<FoodComponent>()
|
||||
.persistent(FoodComponent.CODEC)
|
||||
.networkSynchronized(FoodComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
val MOB_EFFECTS: DataComponentType<MobEffectsComponent> = create("mob_effects", DataComponentType.builder<MobEffectsComponent>()
|
||||
.persistent(MobEffectsComponent.CODEC)
|
||||
.networkSynchronized(MobEffectsComponent.PACKET_CODEC)
|
||||
.build())
|
||||
|
||||
val CRAFTED: DataComponentType<Boolean> = create("crafted", DataComponentType.builder<Boolean>()
|
||||
.persistent(Codec.BOOL)
|
||||
.networkSynchronized(ByteBufCodecs.BOOL)
|
||||
.build())
|
||||
|
||||
fun register() {
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:pokemon_item"), POKEMON_ITEM)
|
||||
@@ -68,6 +83,9 @@ object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>
|
||||
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)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:ingredient"), INGREDIENT)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:food"), FOOD)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:mob_effects"), MOB_EFFECTS)
|
||||
}
|
||||
|
||||
override val registry = BuiltInRegistries.DATA_COMPONENT_TYPE
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.api.item.ability.AbilityChanger
|
||||
import com.cobblemon.mod.common.api.mulch.MulchVariant
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.api.pokemon.Natures
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stat
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.text.blue
|
||||
@@ -34,10 +35,13 @@ import com.cobblemon.mod.common.item.berry.PPRestoringBerryItem
|
||||
import com.cobblemon.mod.common.item.berry.PortionHealingBerryItem
|
||||
import com.cobblemon.mod.common.item.berry.StatusCuringBerryItem
|
||||
import com.cobblemon.mod.common.item.berry.VolatileCuringBerryItem
|
||||
import com.cobblemon.mod.common.item.food.PonigiriItem
|
||||
import com.cobblemon.mod.common.item.food.SinisterTeaItem
|
||||
import com.cobblemon.mod.common.item.interactive.*
|
||||
import com.cobblemon.mod.common.item.interactive.ability.AbilityChangeItem
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import com.cobblemon.mod.common.pokeball.PokeBall
|
||||
import com.cobblemon.mod.common.pokemon.IVs
|
||||
import com.cobblemon.mod.common.pokemon.helditem.CobblemonHeldItemManager
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.core.Registry
|
||||
@@ -53,6 +57,8 @@ import net.minecraft.world.food.FoodProperties
|
||||
import net.minecraft.world.item.BlockItem
|
||||
import net.minecraft.world.item.HangingSignItem
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.Item.Properties
|
||||
import net.minecraft.world.item.ItemNameBlockItem
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.item.Rarity
|
||||
@@ -186,22 +192,29 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
|
||||
val campfire_pots = mutableListOf<CampfirePotItem>()
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_BLACK = campfirePotItem(CobblemonBlocks.BLACK_CAMPFIRE_POT, "black")
|
||||
val CAMPFIRE_POT_RED = campfirePotItem(CobblemonBlocks.RED_CAMPFIRE_POT, "red")
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_BLUE = campfirePotItem(CobblemonBlocks.BLUE_CAMPFIRE_POT, "blue")
|
||||
val CAMPFIRE_POT_YELLOW = campfirePotItem(CobblemonBlocks.YELLOW_CAMPFIRE_POT, "yellow")
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_GREEN = campfirePotItem(CobblemonBlocks.GREEN_CAMPFIRE_POT, "green")
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_BLUE = campfirePotItem(CobblemonBlocks.BLUE_CAMPFIRE_POT, "blue")
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_PINK = campfirePotItem(CobblemonBlocks.PINK_CAMPFIRE_POT, "pink")
|
||||
@JvmField
|
||||
val CAMPFIRE_POT_RED = campfirePotItem(CobblemonBlocks.RED_CAMPFIRE_POT, "red")
|
||||
val CAMPFIRE_POT_BLACK = campfirePotItem(CobblemonBlocks.BLACK_CAMPFIRE_POT, "black")
|
||||
@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))
|
||||
val HEARTY_GRAINS = compostableItem("hearty_grains", ItemNameBlockItem(CobblemonBlocks.HEARTY_GRAINS, Properties().rarity(Rarity.COMMON)))
|
||||
@JvmField
|
||||
val HEARTY_GRAIN_BALE = compostableBlockItem("hearty_grain_bale", CobblemonBlocks.HEARTY_GRAIN_BALE, 0.85f)
|
||||
|
||||
@JvmField
|
||||
val TATAMI_BLOCK = blockItem("tatami_block", CobblemonBlocks.TATAMI_BLOCK)
|
||||
@JvmField
|
||||
val TATAMI_MAT = blockItem("tatami_mat", CobblemonBlocks.TATAMI_MAT)
|
||||
|
||||
@JvmField
|
||||
val VIVICHOKE = compostableItem("vivichoke")
|
||||
@@ -334,10 +347,10 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@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))
|
||||
val SACCHARINE_SAPLING = compostableBlockItem("saccharine_sapling", CobblemonBlocks.SACCHARINE_SAPLING)
|
||||
|
||||
@JvmField
|
||||
val BUGWORT = bugwortItem("bugwort", BugwortItem(CobblemonBlocks.BUGWORT))
|
||||
val BUGWORT = compostableBlockItem("bugwort", CobblemonBlocks.BUGWORT)
|
||||
@JvmField
|
||||
val POKE_BAIT = noSettingsItem("poke_bait")
|
||||
|
||||
@@ -348,260 +361,105 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
|
||||
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)
|
||||
val APRIJUICE_GREEN = aprijuiceItem(Apricorn.GREEN)
|
||||
@JvmField
|
||||
val APRIJUICE_BLUE = aprijuiceItem(Apricorn.BLUE)
|
||||
@JvmField
|
||||
val APRIJUICE_PINK = aprijuiceItem(Apricorn.PINK)
|
||||
@JvmField
|
||||
val APRIJUICE_BLACK = aprijuiceItem(Apricorn.BLACK)
|
||||
@JvmField
|
||||
val APRIJUICE_WHITE = aprijuiceItem(Apricorn.WHITE)
|
||||
|
||||
@JvmField
|
||||
val POKE_PUFF = noSettingsItem("poke_puff") // todo make a PokePuffItem class for friendship boosting purposes
|
||||
val PONIGIRI = create("ponigiri", PonigiriItem())
|
||||
|
||||
@JvmField
|
||||
val SINISTER_TEA = create("sinister_tea", SinisterTeaItem())
|
||||
|
||||
@JvmField
|
||||
val POKE_PUFF = pokepuffItem("poke_puff")
|
||||
|
||||
// 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)
|
||||
}
|
||||
})
|
||||
val TASTY_TAIL = noSettingsItem("tasty_tail")
|
||||
|
||||
@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 // todo get final values for this from vera
|
||||
val PEWTER_CRUNCHIES = regionalFoodItem("pewter_crunchies", 16, 10, 1.2f, MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1f, false)
|
||||
|
||||
@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 // todo get final values for this from vera
|
||||
val RAGE_CANDY_BAR = regionalFoodItem("rage_candy_bar", 16, 10, 1.2f, MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1f, false)
|
||||
|
||||
@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 // todo get final values for this from vera
|
||||
val LAVA_COOKIE = regionalFoodItem("lava_cookie", 16, 10, 1.2f, MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1f)
|
||||
|
||||
@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 // todo get final values for this from vera
|
||||
val OLD_GATEAU = regionalFoodItem("old_gateau", 16, 10, 1.2f, MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1f)
|
||||
|
||||
@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 // todo get final values for this from vera
|
||||
val CASTELIACONE = regionalFoodItem("casteliacone", 16, 10, 1.2f, MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1f)
|
||||
|
||||
@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 // todo get final values for this from vera
|
||||
val SHALOUR_SABLE = regionalFoodItem("shalour_sable", 16, 10, 1.2f, MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1f)
|
||||
|
||||
@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 get final values for this from vera
|
||||
val LUMIOSE_GALETTE = regionalFoodItem("lumiose_galette", 16, 10, 1.2f, MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1f)
|
||||
|
||||
/*@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 // todo get final values for this from vera
|
||||
val BIG_MALASADA = regionalFoodItem("big_malasada", 16, 10, 1.2f, MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1f)
|
||||
|
||||
@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 get final values for this from vera
|
||||
val SMOKED_TAIL_CURRY = regionalFoodItem("smoked_tail_curry", 16, 10, 1.2f, MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1f, false, ItemStack(Items.BOWL, 1))
|
||||
|
||||
/*@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)
|
||||
}
|
||||
})*/
|
||||
@JvmField // todo get final values for this from vera
|
||||
val JUBILIFE_MUFFIN = regionalFoodItem("jubilife_muffin", 16, 10, 1.2f, MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1f)
|
||||
|
||||
// todo we might need to wait on these for later?
|
||||
@JvmField // todo get final values for this from vera
|
||||
val OPEN_FACED_SANDWICH = regionalFoodItem("open_faced_sandwich", 16, 10, 1.2f, MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1f)
|
||||
|
||||
// todo we might need to wait on these for later? These impact battles and may be harder to do
|
||||
/*@JvmField
|
||||
val CHOICE_DUMPLING = noSettingsItem("choice_dumpling") // todo make a ChoiceDumpingItem class for breeding purposes
|
||||
val CHOICE_DUMPLING = noSettingsItem("choice_dumpling") // todo make a ChoiceDumpingItem class for battle purposes
|
||||
@JvmField
|
||||
val SWAP_SNACK = noSettingsItem("swap_snack") // todo make a SwapSnackItem class for breeding purposes
|
||||
val SWAP_SNACK = noSettingsItem("swap_snack") // todo make a SwapSnackItem class for battle purposes
|
||||
@JvmField
|
||||
val TWICE_SPICED_BEETROOT = noSettingsItem("twice_spiced_beetroot") // todo make a TwiceSpiceBeetrootItem class for breeding purposes
|
||||
val TWICE_SPICED_BEETROOT = noSettingsItem("twice_spiced_beetroot") // todo make a TwiceSpiceBeetrootItem class for battle purposes
|
||||
*/
|
||||
@JvmField
|
||||
val POTATO_MOCHI = create("potato_mochi", object : Item(Properties().stacksTo(16)
|
||||
val POTATO_MOCHI = create("potato_mochi", CobblemonItem(Properties().stacksTo(16)
|
||||
.food(FoodProperties.Builder()
|
||||
.nutrition(10)
|
||||
.saturationModifier(1.2F)
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
|
||||
.nutrition(10) // todo get final values for this from vera
|
||||
.saturationModifier(1.2F) // todo get final values for this from vera
|
||||
.alwaysEdible()
|
||||
.build())) {
|
||||
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
|
||||
user.removeAllEffects()
|
||||
return super.finishUsingItem(stack, world, user)
|
||||
}
|
||||
})
|
||||
.build())))
|
||||
@JvmField
|
||||
val FRIED_RICE = create("fried_rice", object : Item(Properties().stacksTo(16)
|
||||
val FRIED_RICE = create("fried_rice", CobblemonItem(Properties().stacksTo(16)
|
||||
.food(FoodProperties.Builder()
|
||||
.nutrition(10)
|
||||
.saturationModifier(1.2F)
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
|
||||
.nutrition(10) // todo get final values for this from vera
|
||||
.saturationModifier(1.2F) // todo get final values for this from vera
|
||||
.alwaysEdible()
|
||||
.build())) {
|
||||
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
|
||||
user.removeAllEffects()
|
||||
return super.finishUsingItem(stack, world, user)
|
||||
}
|
||||
})
|
||||
.build())))
|
||||
@JvmField
|
||||
val CANDIED_APPLE = create("candied_apple", object : Item(Properties().stacksTo(16)
|
||||
val CANDIED_APPLE = create("candied_apple", CobblemonItem(Properties().stacksTo(16)
|
||||
.food(FoodProperties.Builder()
|
||||
.nutrition(10)
|
||||
.saturationModifier(1.2F)
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
|
||||
.nutrition(10) // todo get final values for this from vera
|
||||
.saturationModifier(1.2F) // todo get final values for this from vera
|
||||
.alwaysEdible()
|
||||
.build())) {
|
||||
override fun finishUsingItem(stack: ItemStack, world: Level, user: LivingEntity): ItemStack {
|
||||
user.removeAllEffects()
|
||||
return super.finishUsingItem(stack, world, user)
|
||||
}
|
||||
})
|
||||
.build())))
|
||||
@JvmField
|
||||
val CANDIED_BERRY = create("candied_berry", object : Item(Properties().stacksTo(16)
|
||||
val CANDIED_BERRY = create("candied_berry", CobblemonItem(Properties().stacksTo(16)
|
||||
.food(FoodProperties.Builder()
|
||||
.nutrition(10)
|
||||
.saturationModifier(1.2F)
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F)
|
||||
.nutrition(10) // todo get final values for this from vera
|
||||
.saturationModifier(1.2F) // todo get final values for this from vera
|
||||
.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?
|
||||
.build())))
|
||||
|
||||
//@JvmField
|
||||
//val SCATTER_BANG = this.create("scatter_bang", ScatterBangItem(Item.Settings()))
|
||||
@@ -625,6 +483,17 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val INCENSE_SWEET = blockItem("incense_sweet", CobblemonBlocks.INCENSE_SWEET)
|
||||
|
||||
@JvmField
|
||||
val COPPER_FAN = blockItem("copper_fan", CobblemonBlocks.COPPER_FAN)
|
||||
@JvmField
|
||||
val COPPER_MOWER = blockItem("copper_mower", CobblemonBlocks.COPPER_MOWER)
|
||||
@JvmField
|
||||
val COPPER_OVEN = blockItem("copper_oven", CobblemonBlocks.COPPER_OVEN)
|
||||
@JvmField
|
||||
val COPPER_WASHER = blockItem("copper_washer", CobblemonBlocks.COPPER_WASHER)
|
||||
@JvmField
|
||||
val COPPER_FRIDGE = blockItem("copper_fridge", CobblemonBlocks.COPPER_FRIDGE)
|
||||
|
||||
|
||||
// Evolution items
|
||||
@JvmField val LINK_CABLE = create("link_cable", LinkCableItem())
|
||||
@@ -665,6 +534,9 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField val AUSPICIOUS_ARMOR = heldItem("auspicious_armor")
|
||||
@JvmField val MALICIOUS_ARMOR = heldItem("malicious_armor")
|
||||
@JvmField val SHELL_HELMET = heldItem("shell_helmet")
|
||||
@JvmField val METAL_ALLOY = noSettingsItem("metal_alloy")
|
||||
@JvmField val SCROLL_OF_DARKNESS = noSettingsItem("scroll_of_darkness")
|
||||
@JvmField val SCROLL_OF_WATERS = noSettingsItem("scroll_of_waters")
|
||||
|
||||
private val berries = mutableMapOf<ResourceLocation, BerryItem>()
|
||||
// Plants
|
||||
@@ -743,6 +615,33 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val GALARICA_NUTS = create("galarica_nuts", GalaricaNutItem())
|
||||
|
||||
// Hyper Training Items
|
||||
val hyperTrainingItems = mutableListOf<HyperTrainingItem>()
|
||||
@JvmField
|
||||
val HEALTH_CANDY = hyperTrainingItem("health_candy", 1, setOf(Stats.HP), 0..IVs.MAX_VALUE)
|
||||
@JvmField
|
||||
val MIGHTY_CANDY = hyperTrainingItem("mighty_candy", 1, setOf(Stats.ATTACK), 0..IVs.MAX_VALUE)
|
||||
@JvmField
|
||||
val TOUGH_CANDY = hyperTrainingItem("tough_candy", 1, setOf(Stats.DEFENCE), 0..IVs.MAX_VALUE)
|
||||
@JvmField
|
||||
val SMART_CANDY = hyperTrainingItem("smart_candy", 1, setOf(Stats.SPECIAL_ATTACK), 0..IVs.MAX_VALUE)
|
||||
@JvmField
|
||||
val COURAGE_CANDY = hyperTrainingItem("courage_candy", 1, setOf(Stats.SPECIAL_DEFENCE), 0..IVs.MAX_VALUE)
|
||||
@JvmField
|
||||
val QUICK_CANDY = hyperTrainingItem("quick_candy", 1, setOf(Stats.SPEED), 0..IVs.MAX_VALUE)
|
||||
@JvmField
|
||||
val SICKLY_CANDY = hyperTrainingItem("sickly_candy", -1, setOf(Stats.HP), 0..IVs.MAX_VALUE)
|
||||
@JvmField
|
||||
val WEAK_CANDY = hyperTrainingItem("weak_candy", -1, setOf(Stats.ATTACK), 0..IVs.MAX_VALUE)
|
||||
@JvmField
|
||||
val BRITTLE_CANDY = hyperTrainingItem("brittle_candy", -1, setOf(Stats.DEFENCE), 0..IVs.MAX_VALUE)
|
||||
@JvmField
|
||||
val NUMB_CANDY = hyperTrainingItem("numb_candy", -1, setOf(Stats.SPECIAL_ATTACK), 0..IVs.MAX_VALUE)
|
||||
@JvmField
|
||||
val COWARD_CANDY = hyperTrainingItem("coward_candy", -1, setOf(Stats.SPECIAL_DEFENCE), 0..IVs.MAX_VALUE)
|
||||
@JvmField
|
||||
val SLOW_CANDY = hyperTrainingItem("slow_candy", -1, setOf(Stats.SPEED), 0..IVs.MAX_VALUE)
|
||||
|
||||
// Medicine
|
||||
@JvmField
|
||||
val RARE_CANDY = candyItem("rare_candy", Rarity.RARE) { _, pokemon -> pokemon.getExperienceToNextLevel() }
|
||||
@@ -797,11 +696,11 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val MEDICINAL_LEEK = heldItem("medicinal_leek", MedicinalLeekItem(CobblemonBlocks.MEDICINAL_LEEK, Item.Properties().food(FoodProperties.Builder().fast().nutrition(1).saturationModifier(0.2f).build())), "leek")
|
||||
@JvmField
|
||||
val ROASTED_LEEK = create("roasted_leek", Item(Item.Properties().food(FoodProperties.Builder().fast().nutrition(3).saturationModifier(0.3f).build())))
|
||||
val ROASTED_LEEK = create("roasted_leek", CobblemonItem(Item.Properties().food(FoodProperties.Builder().fast().nutrition(3).saturationModifier(0.3f).build())))
|
||||
@JvmField
|
||||
val BRAISED_VIVICHOKE = create("braised_vivichoke", Item(Item.Properties().food(FoodProperties.Builder().nutrition(6).saturationModifier(0.6f).build())))
|
||||
val BRAISED_VIVICHOKE = create("braised_vivichoke", foodItem(6, 0.6F))
|
||||
@JvmField
|
||||
val VIVICHOKE_DIP = create("vivichoke_dip", object : Item(Properties().stacksTo(1)
|
||||
val VIVICHOKE_DIP = create("vivichoke_dip", object : CobblemonItem(Properties().stacksTo(1)
|
||||
.food(FoodProperties.Builder()
|
||||
.nutrition(10)
|
||||
.saturationModifier(1.2F)
|
||||
@@ -821,13 +720,15 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val PEP_UP_FLOWER = compostableBlockItem("pep_up_flower", CobblemonBlocks.PEP_UP_FLOWER)
|
||||
@JvmField
|
||||
val MEDICINAL_BREW = create("medicinal_brew", Item(Item.Properties()))
|
||||
val MEDICINAL_BREW = noSettingsItem("medicinal_brew")
|
||||
@JvmField
|
||||
val REMEDY = create("remedy", RemedyItem(RemedyItem.NORMAL))
|
||||
@JvmField
|
||||
val FINE_REMEDY = create("fine_remedy", RemedyItem(RemedyItem.FINE))
|
||||
@JvmField
|
||||
val SUPERB_REMEDY = create("superb_remedy", RemedyItem(RemedyItem.SUPERB))
|
||||
@JvmField
|
||||
val MOOMOO_MILK = noSettingsItem("moomoo_milk")
|
||||
|
||||
@JvmField
|
||||
val POTION = create("potion", PotionItem(PotionType.POTION))
|
||||
@@ -843,7 +744,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val HEAL_POWDER = create("heal_powder", HealPowderItem())
|
||||
@JvmField
|
||||
val LEEK_AND_POTATO_STEW = create("leek_and_potato_stew", Item(Item.Properties().food(FoodProperties.Builder().nutrition(8).saturationModifier(0.6f).usingConvertsTo(Items.BOWL).build()).stacksTo(1)))
|
||||
val LEEK_AND_POTATO_STEW = create("leek_and_potato_stew", CobblemonItem(Item.Properties().food(FoodProperties.Builder().nutrition(8).saturationModifier(0.6f).usingConvertsTo(Items.BOWL).build()).stacksTo(1)))
|
||||
@JvmField
|
||||
val REVIVE = create("revive", ReviveItem(max = false))
|
||||
@JvmField
|
||||
@@ -1062,8 +963,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
val CHOICE_SCARF = heldItem("choice_scarf")
|
||||
@JvmField
|
||||
val CLEANSE_TAG = heldItem("cleanse_tag")
|
||||
// @JvmField
|
||||
// val CLEAR_AMULET = heldItem("clear_amulet")
|
||||
@JvmField
|
||||
val CLEAR_AMULET = heldItem("clear_amulet")
|
||||
@JvmField
|
||||
val COVERT_CLOAK = heldItem("covert_cloak")
|
||||
@JvmField
|
||||
@@ -1092,16 +993,16 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
val FOCUS_SASH = heldItem("focus_sash")
|
||||
@JvmField
|
||||
val GRASSY_SEED = heldItem("grassy_seed")
|
||||
// @JvmField
|
||||
// val GRIP_CLAW = heldItem("grip_claw")
|
||||
@JvmField
|
||||
val GRIP_CLAW = heldItem("grip_claw")
|
||||
@JvmField
|
||||
val HARD_STONE = heldItem("hard_stone")
|
||||
@JvmField
|
||||
val HEAVY_DUTY_BOOTS = heldItem("heavy_duty_boots")
|
||||
@JvmField
|
||||
val IRON_BALL = heldItem("iron_ball")
|
||||
// @JvmField
|
||||
// val LAGGING_TAIL = heldItem("lagging_tail")
|
||||
@JvmField
|
||||
val LAGGING_TAIL = heldItem("lagging_tail")
|
||||
@JvmField
|
||||
val LEFTOVERS = heldItem("leftovers")
|
||||
@JvmField
|
||||
@@ -1114,8 +1015,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
val LOADED_DICE = heldItem("loaded_dice")
|
||||
@JvmField
|
||||
val LUCKY_EGG = heldItem("lucky_egg")
|
||||
// @JvmField
|
||||
// val LUMINOUS_MOSS = heldItem("luminous_moss")
|
||||
@JvmField
|
||||
val LUMINOUS_MOSS = heldItem("luminous_moss")
|
||||
@JvmField
|
||||
val MAGNET = heldItem("magnet")
|
||||
@JvmField
|
||||
@@ -1642,6 +1543,44 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
return item
|
||||
}
|
||||
|
||||
private fun pokepuffItem(name: String): PokePuffItem {
|
||||
val item = create("poke_puff", PokePuffItem())
|
||||
return item
|
||||
}
|
||||
|
||||
private fun regionalFoodItem(
|
||||
name: String,
|
||||
stacksTo: Int,
|
||||
nutrition: Int,
|
||||
saturationModifier: Float,
|
||||
effect: MobEffectInstance? = null,
|
||||
effectChance: Float? = null,
|
||||
alwaysEdible: Boolean = false,
|
||||
convertsToOnUse: ItemStack? = null
|
||||
): RegionalFoodItem {
|
||||
val foodPropertiesBuilder = FoodProperties.Builder()
|
||||
.nutrition(nutrition)
|
||||
.saturationModifier(saturationModifier)
|
||||
|
||||
if (effect != null && effectChance != null) {
|
||||
foodPropertiesBuilder.effect(effect, effectChance)
|
||||
}
|
||||
|
||||
if (alwaysEdible == true) {
|
||||
foodPropertiesBuilder.alwaysEdible()
|
||||
}
|
||||
|
||||
if (convertsToOnUse != null && !convertsToOnUse.isEmpty) {
|
||||
foodPropertiesBuilder.usingConvertsTo(convertsToOnUse.item)
|
||||
}
|
||||
|
||||
val properties = Item.Properties()
|
||||
.stacksTo(stacksTo)
|
||||
.food(foodPropertiesBuilder.build())
|
||||
|
||||
return create(name, RegionalFoodItem(properties))
|
||||
}
|
||||
|
||||
private fun heldItem(name: String, remappedName: String? = null): CobblemonItem = create(
|
||||
name,
|
||||
CobblemonItem(Item.Properties()).also {
|
||||
@@ -1653,11 +1592,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
private fun heldItem(name: String, item: Item, remappedName: String? = null) = create(
|
||||
name = name,
|
||||
entry = item.also {
|
||||
if (remappedName != null) {
|
||||
remappedName?.let { remappedName ->
|
||||
CobblemonHeldItemManager.registerRemap(it, remappedName)
|
||||
CobblemonHeldItemManager.registerRemap(Items.BONE, "thickclub")
|
||||
CobblemonHeldItemManager.registerRemap(Items.SNOWBALL, "snowball")
|
||||
CobblemonHeldItemManager.registerRemap(Items.GOLD_BLOCK, "bignugget")
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -1687,6 +1623,12 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
return item
|
||||
}
|
||||
|
||||
private fun hyperTrainingItem(name: String, increaseAmount: Int, targetStats: Set<Stat>, validRange: IntRange): HyperTrainingItem {
|
||||
val item = this.create(name, HyperTrainingItem(increaseAmount, targetStats, validRange))
|
||||
hyperTrainingItems.add(item)
|
||||
return item
|
||||
}
|
||||
|
||||
private fun apricornItem(name: String, apricornItem: ApricornItem): ApricornItem {
|
||||
val finalName = "${name}_apricorn"
|
||||
val item = this.create(finalName, apricornItem)
|
||||
@@ -1701,20 +1643,6 @@ 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"
|
||||
@@ -1731,7 +1659,7 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
}
|
||||
|
||||
private fun compostableItem(name: String, item: Item? = null, increaseLevelChance: Float = .65f): Item {
|
||||
val createdItem = this.create(name, item ?: Item(Item.Properties()))
|
||||
val createdItem = this.create(name, item ?: CobblemonItem(Item.Properties()))
|
||||
compostable(createdItem, increaseLevelChance)
|
||||
return createdItem
|
||||
}
|
||||
@@ -1749,6 +1677,6 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
}
|
||||
|
||||
private fun foodItem(nutrition: Int, saturationModifier: Float): Item {
|
||||
return Item(Item.Properties().food(FoodProperties.Builder().nutrition(nutrition).saturationModifier(saturationModifier).build()))
|
||||
return CobblemonItem(Item.Properties().food(FoodProperties.Builder().nutrition(nutrition).saturationModifier(saturationModifier).build()))
|
||||
}
|
||||
}
|
||||
@@ -16,14 +16,32 @@ import com.mojang.serialization.codecs.PrimitiveCodec
|
||||
import net.minecraft.core.UUIDUtil
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import java.util.Optional
|
||||
import java.util.UUID
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
object CobblemonMemories {
|
||||
val memories = mutableMapOf<String, MemoryModuleType<*>>()
|
||||
|
||||
/*
|
||||
* When a memory doesn't have a codec provided, it's because it doesn't
|
||||
* get serialized during relogs. This makes sense for things like battles which
|
||||
* do not survive a relog therefore any memory of it should be temporary.
|
||||
*/
|
||||
|
||||
val BATTLING_POKEMON = register("battling_pokemon", ListCodec(UUIDUtil.CODEC, 0, 31))
|
||||
val NPC_BATTLING = register("npc_battling", PrimitiveCodec.BOOL)
|
||||
val DIALOGUES = register<List<ActiveDialogue>>("npc_dialogues")
|
||||
val ACTIVE_ACTION_EFFECT = register<ActionEffectContext>("active_action_effect")
|
||||
val POKEMON_FLYING = register("pokemon_flying", PrimitiveCodec.BOOL)
|
||||
val POKEMON_DROWSY = register("pokemon_drowsy", PrimitiveCodec.BOOL)
|
||||
val POKEMON_SLEEPING = register("pokemon_sleeping", PrimitiveCodec.BOOL)
|
||||
val POKEMON_BATTLE = register<UUID>("pokemon_battle")
|
||||
val PATH_COOLDOWN = register<Boolean>("path_cooldown")
|
||||
val TARGETED_BATTLE_POKEMON = register<UUID>("targeted_battle_pokemon")
|
||||
val NEAREST_VISIBLE_ATTACKER = register<LivingEntity>("nearest_visible_attacker")
|
||||
val NEARBY_GROWABLE_CROPS = register<BlockPos>("nearby_growable_crops")
|
||||
val RECENTLY_ATE_GRASS = register<Boolean>("recently_ate_grass")
|
||||
|
||||
fun <U> register(id: String, codec: Codec<U>): MemoryModuleType<U> {
|
||||
val memoryModule = MemoryModuleType(Optional.of(codec))
|
||||
@@ -36,4 +54,4 @@ object CobblemonMemories {
|
||||
memories[id] = memoryModule
|
||||
return memoryModule
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,9 +10,7 @@ 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
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.api.net.NetworkPacket
|
||||
import com.cobblemon.mod.common.client.net.OpenBehaviourEditorHandler
|
||||
import com.cobblemon.mod.common.client.net.CalculateSeatPositionsHandler
|
||||
import com.cobblemon.mod.common.client.net.PlayerInteractOptionsHandler
|
||||
import com.cobblemon.mod.common.client.net.SetClientPlayerDataHandler
|
||||
@@ -60,6 +61,7 @@ import com.cobblemon.mod.common.client.net.trade.TradeProcessStartedHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeStartedHandler
|
||||
import com.cobblemon.mod.common.client.net.trade.TradeUpdatedHandler
|
||||
import com.cobblemon.mod.common.net.PacketRegisterInfo
|
||||
import com.cobblemon.mod.common.net.messages.client.OpenBehaviourEditorPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.CalculateSeatPositionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.PlayerInteractOptionsPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.SetClientPlayerDataPacket
|
||||
@@ -138,6 +140,7 @@ import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamRequestPack
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.BattleTeamResponsePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.RemoveSpectatorPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.battle.SpectateBattlePacket
|
||||
import com.cobblemon.mod.common.net.messages.server.behaviour.SetEntityBehaviourPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.block.AdjustBlockEntityViewerCountPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectCancelledPacket
|
||||
import com.cobblemon.mod.common.net.messages.server.callback.move.MoveSelectedPacket
|
||||
@@ -184,6 +187,7 @@ import com.cobblemon.mod.common.net.serverhandling.battle.SpectateBattleHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.TeamLeaveHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.TeamRequestHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.battle.TeamRequestResponseHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.behaviour.SetEntityBehaviourHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.block.AdjustBlockEntityViewerCountHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.move.MoveSelectCancelledHandler
|
||||
import com.cobblemon.mod.common.net.serverhandling.callback.move.MoveSelectedHandler
|
||||
@@ -255,6 +259,7 @@ object CobblemonNetwork {
|
||||
|
||||
// Pokemon Update Packets
|
||||
list.add(PacketRegisterInfo(FriendshipUpdatePacket.ID, FriendshipUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(FullnessUpdatePacket.ID, FullnessUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(MoveSetUpdatePacket.ID, MoveSetUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(NatureUpdatePacket.ID, NatureUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
list.add(PacketRegisterInfo(ShinyUpdatePacket.ID, ShinyUpdatePacket::decode, PokemonUpdatePacketHandler()))
|
||||
@@ -382,6 +387,7 @@ object CobblemonNetwork {
|
||||
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(BehaviourSyncPacket.ID, BehaviourSyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
list.add(PacketRegisterInfo(MarkRegistrySyncPacket.ID, MarkRegistrySyncPacket::decode, DataRegistrySyncPacketHandler()))
|
||||
|
||||
// Effects
|
||||
@@ -436,6 +442,9 @@ object CobblemonNetwork {
|
||||
list.add(PacketRegisterInfo(CloseNPCEditorPacket.ID, CloseNPCEditorPacket::decode, CloseNPCEditorHandler))
|
||||
list.add(PacketRegisterInfo(OpenNPCEditorPacket.ID, OpenNPCEditorPacket::decode, OpenNPCEditorHandler))
|
||||
|
||||
// Behaviours
|
||||
list.add(PacketRegisterInfo(OpenBehaviourEditorPacket.ID, OpenBehaviourEditorPacket::decode, OpenBehaviourEditorHandler))
|
||||
|
||||
// Pokédex scanning
|
||||
list.add(PacketRegisterInfo(ServerConfirmedRegisterPacket.ID, ServerConfirmedRegisterPacket::decode, ServerConfirmedRegisterHandler))
|
||||
|
||||
@@ -551,6 +560,9 @@ object CobblemonNetwork {
|
||||
// Cooking
|
||||
list.add(PacketRegisterInfo(ToggleCookingPotLidPacket.ID, ToggleCookingPotLidPacket::decode, ToggleCookingPotLidHandler))
|
||||
|
||||
// Behaviour Packets
|
||||
list.add(PacketRegisterInfo(SetEntityBehaviourPacket.ID, SetEntityBehaviourPacket::decode, SetEntityBehaviourHandler))
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ object CobblemonPoiTypes: PlatformRegistry<Registry<PoiType>, ResourceKey<Regist
|
||||
@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")
|
||||
val INCENSE_SWEET_KEY: ResourceKey<PoiType> = createKey("incense_sweet")
|
||||
@JvmField
|
||||
val INCENSE_SWEET = create(INCENSE_SWEET_KEY.location().path, PoiType(getBlockStates(CobblemonBlocks.INCENSE_SWEET), 0, 1))
|
||||
|
||||
|
||||
@@ -15,13 +15,13 @@ 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_COMPLEX_DISHES("COOKING_POT_COMPLEX_DISHES"),
|
||||
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()
|
||||
COOKING_POT_FOODS.toVanillaCategory(), COOKING_POT_MISC.toVanillaCategory(), COOKING_POT_MEDICINES.toVanillaCategory(), COOKING_POT_COMPLEX_DISHES.toVanillaCategory()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ 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.item.crafting.brewingstand.BrewingStandRecipe
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import net.minecraft.core.Registry
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
@@ -24,6 +25,8 @@ object CobblemonRecipeSerializers : PlatformRegistry<Registry<RecipeSerializer<*
|
||||
val COOKING_POT_COOKING: RecipeSerializer<*> = register("cobblemon:cooking_pot", CookingPotRecipe.Serializer())
|
||||
val COOKING_POT_SHAPELESS: RecipeSerializer<*> = register("cobblemon:cooking_pot_shapeless", CookingPotShapelessRecipe.Serializer())
|
||||
|
||||
val BREWING_STAND: RecipeSerializer<*> = register("cobblemon:brewing_stand", BrewingStandRecipe.Serializer())
|
||||
|
||||
override val registry: Registry<RecipeSerializer<*>>
|
||||
get() = BuiltInRegistries.RECIPE_SERIALIZER
|
||||
override val resourceKey: ResourceKey<Registry<RecipeSerializer<*>>>
|
||||
|
||||
@@ -11,6 +11,7 @@ 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.item.crafting.brewingstand.BrewingStandRecipe
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import net.minecraft.core.Registry
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
@@ -24,6 +25,8 @@ object CobblemonRecipeTypes : PlatformRegistry<Registry<RecipeType<*>>, Resource
|
||||
val COOKING_POT_COOKING: RecipeType<CookingPotRecipe> = register("cobblemon:cooking_pot")
|
||||
val COOKING_POT_SHAPELESS: RecipeType<CookingPotShapelessRecipe> = register("cobblemon:cooking_pot_shapeless")
|
||||
|
||||
val BREWING_STAND: RecipeType<BrewingStandRecipe> = register("cobblemon:brewing_stand")
|
||||
|
||||
override val registry: Registry<RecipeType<*>>
|
||||
get() = BuiltInRegistries.RECIPE_TYPE
|
||||
override val resourceKey: ResourceKey<Registry<RecipeType<*>>>
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.sensors.DefendOwnerSensor
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.sensors.DrowsySensor
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.sensors.PokemonAdultSensor
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.sensors.PokemonGrowableCropSensor
|
||||
import com.cobblemon.mod.common.pokemon.ai.PokemonDisturbancesSensor
|
||||
import com.cobblemon.mod.common.entity.sensor.BattlingPokemonSensor
|
||||
import com.cobblemon.mod.common.entity.sensor.NPCBattlingSensor
|
||||
import java.util.function.Supplier
|
||||
@@ -20,10 +25,20 @@ object CobblemonSensors {
|
||||
|
||||
val NPC_BATTLING = register("npc_battling", ::NPCBattlingSensor)
|
||||
val BATTLING_POKEMON = register("battling_pokemon", ::BattlingPokemonSensor)
|
||||
// val NPC_BATTLING = register("npc_battling", ::NPCBattlingSensor)
|
||||
val POKEMON_DROWSY = register("pokemon_drowsy", ::DrowsySensor)
|
||||
|
||||
val POKEMON_ADULT = register("pokemon_adult_sensor", ::PokemonAdultSensor)
|
||||
|
||||
val POKEMON_DISTURBANCE = register("pokemon_disturbance_sensor", ::PokemonDisturbancesSensor)
|
||||
|
||||
val POKEMON_DEFEND_OWNER = register("pokemon_owner_under_attack", ::DefendOwnerSensor)
|
||||
|
||||
val NEARBY_GROWABLE_CROPS = register("nearby_growable_crops", ::PokemonGrowableCropSensor)
|
||||
|
||||
fun <E : Entity, U : Sensor<E>> register(id: String, supplier: Supplier<U>): SensorType<U> {
|
||||
val sensor = SensorType(supplier)
|
||||
sensors[id] = sensor
|
||||
return sensor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,8 +43,18 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
@JvmField
|
||||
val PC_WALLPAPER_UNLOCK = this.create("pc.wallpaper.unlock")
|
||||
|
||||
@JvmField
|
||||
val NPC_GIBBER_GENERIC = this.create("entity.npc.gibber.generic")
|
||||
@JvmField
|
||||
val NPC_GIBBER_SPEECH_TYPE_1_1 = this.create("entity.npc.gibber.speech_type_1_1")
|
||||
@JvmField
|
||||
val NPC_GIBBER_SPEECH_TYPE_1_2 = this.create("entity.npc.gibber.speech_type_1_2")
|
||||
@JvmField
|
||||
val NPC_GIBBER_SPEECH_TYPE_1_3 = this.create("entity.npc.gibber.speech_type_1_3")
|
||||
|
||||
@JvmField
|
||||
val VILLAGER_WORK_NURSE = this.create("entity.villager.work_nurse")
|
||||
|
||||
@JvmField
|
||||
val HEALING_MACHINE_ACTIVE = this.create("block.healing_machine.active")
|
||||
|
||||
@@ -115,6 +125,7 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
@JvmField
|
||||
val MOCHI_USE = this.create("item.medicine.feather.use")
|
||||
|
||||
|
||||
@JvmField
|
||||
val MULCH_PLACE = this.create("block.mulch.place")
|
||||
@JvmField
|
||||
@@ -206,6 +217,8 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
val BERRY_HARVEST = this.create("block.berry_bush.harvest")
|
||||
@JvmField
|
||||
val BERRY_EAT = this.create("item.berry.eat")
|
||||
@JvmField
|
||||
val BERRY_EAT_FULL = this.create("item.berry.eat.full")
|
||||
|
||||
@JvmField
|
||||
val BIG_ROOT_BREAK = this.create("block.big_root.break")
|
||||
@@ -460,4 +473,4 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
)
|
||||
|
||||
private fun create(name: String): SoundEvent = this.create(name, SoundEvent.createVariableRangeEvent(cobblemonResource(name)))
|
||||
}
|
||||
}
|
||||
|
||||
+3
-32
@@ -18,7 +18,7 @@ import java.util.Optional
|
||||
|
||||
class AspectCriterion(
|
||||
playerCtx: Optional<ContextAwarePredicate>,
|
||||
val pokemon: ResourceLocation,
|
||||
val species: ResourceLocation,
|
||||
val aspects: List<String>
|
||||
): SimpleCriterionCondition<MutableMap<ResourceLocation, MutableSet<String>>>(playerCtx) {
|
||||
|
||||
@@ -26,42 +26,13 @@ class AspectCriterion(
|
||||
val CODEC: Codec<AspectCriterion> = RecordCodecBuilder.create { it.group(
|
||||
//All three of these codecs used to use Codecs.createStrictOptionalFieldCodec, that no longer exists
|
||||
ContextAwarePredicate.CODEC.optionalFieldOf("player").forGetter(AspectCriterion::playerCtx),
|
||||
ResourceLocation.CODEC.optionalFieldOf("pokemon", cobblemonResource("pikachu")).forGetter(AspectCriterion::pokemon),
|
||||
ResourceLocation.CODEC.optionalFieldOf("species", cobblemonResource("pikachu")).forGetter(AspectCriterion::species),
|
||||
Codec.STRING.listOf().optionalFieldOf("aspects", listOf()).forGetter(AspectCriterion::aspects)
|
||||
) .apply(it, ::AspectCriterion) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayer, context: MutableMap<ResourceLocation, MutableSet<String>>): Boolean {
|
||||
val caughtAspects = context.getOrDefault(pokemon, mutableSetOf())
|
||||
val caughtAspects = context.getOrDefault(species, mutableSetOf())
|
||||
return this.aspects.all { it in caughtAspects }
|
||||
}
|
||||
}
|
||||
|
||||
//open class AspectCriterionTrigger(identifier: Identifier, criterionClass: Class<AspectCriterionCondition>) : SimpleCriterionTrigger<MutableMap<Identifier, MutableSet<String>>, AspectCriterionCondition>(identifier, criterionClass) {
|
||||
//
|
||||
//}
|
||||
//
|
||||
//class AspectCriterionCondition(id: Identifier, predicate: LootContextPredicate) : SimpleCriterionCondition<MutableMap<Identifier, MutableSet<String>>>(id, predicate) {
|
||||
// var pokemon = Identifier.of("cobblemon:pikachu")
|
||||
// var aspects = mutableListOf<String>()
|
||||
// override fun toJson(json: JsonObject) {
|
||||
// json.add("aspects", JsonArray(aspects.size).also {
|
||||
// aspects.forEach { aspect -> it.add(aspect) }
|
||||
// })
|
||||
// json.addProperty("pokemon", pokemon.toString())
|
||||
// }
|
||||
//
|
||||
// override fun fromJson(json: JsonObject) {
|
||||
// aspects.clear()
|
||||
// json.getAsJsonArray("aspects").forEach { element ->
|
||||
// aspects.add(element.asString)
|
||||
// }
|
||||
// pokemon = json.get("pokemon").asString.asIdentifierDefaultingNamespace()
|
||||
// }
|
||||
//
|
||||
// override fun matches(player: ServerPlayer, context: MutableMap<Identifier, MutableSet<String>>): Boolean {
|
||||
// val caughtAspects = context.getOrDefault(pokemon, mutableSetOf())
|
||||
// return this.aspects.all { it in caughtAspects }
|
||||
// }
|
||||
//
|
||||
//}
|
||||
+4
-21
@@ -21,40 +21,23 @@ import java.util.Optional
|
||||
* @author Hiroku
|
||||
* @since November 4th, 2022
|
||||
*/
|
||||
open class CountablePokemonTypeContext(times: Int, var type: String) : CountableContext(times)
|
||||
open class CountablePokemonTypeContext(times: Int, var species: String) : CountableContext(times)
|
||||
|
||||
class CaughtPokemonCriterion(
|
||||
playerCtx: Optional<ContextAwarePredicate>,
|
||||
val type: String,
|
||||
val species: String,
|
||||
count: Int
|
||||
): CountableCriterion<CountablePokemonTypeContext>(playerCtx, count) {
|
||||
|
||||
companion object {
|
||||
val CODEC: Codec<CaughtPokemonCriterion> = RecordCodecBuilder.create { it.group(
|
||||
EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter(CaughtPokemonCriterion::playerCtx),
|
||||
Codec.STRING.optionalFieldOf("type", "any").forGetter(CaughtPokemonCriterion::type),
|
||||
Codec.STRING.optionalFieldOf("species", "any").forGetter(CaughtPokemonCriterion::species),
|
||||
Codec.INT.optionalFieldOf("count", 0).forGetter(CaughtPokemonCriterion::count)
|
||||
).apply(it, ::CaughtPokemonCriterion) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayer, context: CountablePokemonTypeContext): Boolean {
|
||||
return super.matches(player, context) && (context.type == type || type == "any")
|
||||
return super.matches(player, context) && (context.species == species || species == "any")
|
||||
}
|
||||
}
|
||||
|
||||
//class CaughtPokemonCriterionCondition(id: Identifier, predicate: LootContextPredicate) : CountableCriterionCondition<CountablePokemonTypeContext>(id, predicate) {
|
||||
// var type = "any"
|
||||
// override fun toJson(json: JsonObject) {
|
||||
// super.toJson(json)
|
||||
// json.addProperty("type", type)
|
||||
// }
|
||||
//
|
||||
// override fun fromJson(json: JsonObject) {
|
||||
// super.fromJson(json)
|
||||
// type = json.get("type")?.asString ?: "any"
|
||||
// }
|
||||
//
|
||||
// override fun matches(player: ServerPlayer, context: CountablePokemonTypeContext): Boolean {
|
||||
// return super.matches(player, context) && (context.type == type || type == "any")
|
||||
// }
|
||||
//}
|
||||
+5
-2
@@ -19,17 +19,20 @@ import java.util.Optional
|
||||
|
||||
class PokemonCriterion(
|
||||
playerCtx: Optional<ContextAwarePredicate>,
|
||||
val species: String,
|
||||
val properties: PokemonProperties
|
||||
): SimpleCriterionCondition<Pokemon>(playerCtx) {
|
||||
|
||||
companion object {
|
||||
val CODEC: Codec<PokemonCriterion> = RecordCodecBuilder.create { it.group(
|
||||
EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter(PokemonCriterion::playerCtx),
|
||||
Codec.STRING.optionalFieldOf("species", "any").forGetter(PokemonCriterion::species),
|
||||
PokemonProperties.CODEC.optionalFieldOf("properties", PokemonProperties()).forGetter(PokemonCriterion::properties)
|
||||
).apply(it, ::PokemonCriterion) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayer, context: Pokemon): Boolean {
|
||||
return properties.matches(context)
|
||||
var speciesCheck = (species.equals(context.species.resourceIdentifier.path) || species.equals(context.species.resourceIdentifier.toString())) || species.equals("any")
|
||||
return speciesCheck && properties.matches(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -17,22 +17,22 @@ import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import java.util.Optional
|
||||
|
||||
class PokemonInteractContext(val type: ResourceLocation, val item: ResourceLocation)
|
||||
class PokemonInteractContext(val species: ResourceLocation, val item: ResourceLocation)
|
||||
|
||||
class PokemonInteractCriterion(
|
||||
playerCtx: Optional<ContextAwarePredicate>,
|
||||
val type: String,
|
||||
val species: String,
|
||||
val item: String
|
||||
): SimpleCriterionCondition<PokemonInteractContext>(playerCtx) {
|
||||
companion object {
|
||||
val CODEC: Codec<PokemonInteractCriterion> = RecordCodecBuilder.create { it.group(
|
||||
EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter(PokemonInteractCriterion::playerCtx),
|
||||
Codec.STRING.optionalFieldOf("type", "any").forGetter(PokemonInteractCriterion::type),
|
||||
Codec.STRING.optionalFieldOf("species", "any").forGetter(PokemonInteractCriterion::species),
|
||||
Codec.STRING.optionalFieldOf("item", "any").forGetter(PokemonInteractCriterion::item)
|
||||
).apply(it, ::PokemonInteractCriterion) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayer, context: PokemonInteractContext): Boolean {
|
||||
return (context.type == this.type.asIdentifierDefaultingNamespace() || this.type == "any") && (context.item == this.item.asIdentifierDefaultingNamespace() || this.item == "any")
|
||||
return (context.species == this.species.asIdentifierDefaultingNamespace() || this.species == "any") && (context.item == this.item.asIdentifierDefaultingNamespace() || this.item == "any")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -17,23 +17,23 @@ import net.minecraft.advancements.critereon.EntityPredicate
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
class ReelInPokemonContext(val pokemonId : ResourceLocation, val baitId: ResourceLocation)
|
||||
class ReelInPokemonContext(val species : ResourceLocation, val baitId: ResourceLocation)
|
||||
|
||||
class ReelInPokemonCriterionCondition(
|
||||
playerCtx: Optional<ContextAwarePredicate>,
|
||||
val pokemonId: String,
|
||||
val species: String,
|
||||
val baitId: String
|
||||
) : SimpleCriterionCondition<ReelInPokemonContext>(playerCtx) {
|
||||
|
||||
companion object {
|
||||
val CODEC: Codec<ReelInPokemonCriterionCondition> = RecordCodecBuilder.create { it.group(
|
||||
EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter { it.playerCtx },
|
||||
Codec.STRING.optionalFieldOf("pokemonId", "any").forGetter { it.pokemonId },
|
||||
Codec.STRING.optionalFieldOf("species", "any").forGetter { it.species },
|
||||
Codec.STRING.optionalFieldOf("baitId", "empty_bait").forGetter { it.baitId }
|
||||
).apply(it, { playerCtx, pokemonId, baitId -> ReelInPokemonCriterionCondition(playerCtx, pokemonId, baitId.ifEmpty { "empty_bait" }) }) }
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayer, context: ReelInPokemonContext): Boolean {
|
||||
return (context.pokemonId == this.pokemonId.asIdentifierDefaultingNamespace() || this.pokemonId == "any") && (context.baitId == this.baitId.asIdentifierDefaultingNamespace() || this.baitId == "empty_bait")
|
||||
return (context.species == this.species.asIdentifierDefaultingNamespace() || this.species == "any") && (context.baitId == this.baitId.asIdentifierDefaultingNamespace() || this.baitId == "empty_bait")
|
||||
}
|
||||
}
|
||||
|
||||
+12
-4
@@ -8,12 +8,15 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.config.BrainConfig
|
||||
import com.cobblemon.mod.common.api.ai.config.BehaviourConfig
|
||||
import com.cobblemon.mod.common.entity.MoLangScriptingEntity
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.schedule.Activity
|
||||
import net.minecraft.world.entity.schedule.Schedule
|
||||
|
||||
class BrainConfigurationContext {
|
||||
class BehaviourConfigurationContext {
|
||||
var appliedBehaviours: Set<ResourceLocation> = setOf()
|
||||
|
||||
var defaultActivity = Activity.IDLE
|
||||
var coreActivities = setOf(Activity.CORE)
|
||||
@@ -24,11 +27,16 @@ class BrainConfigurationContext {
|
||||
return activities.firstOrNull { it.activity == activity } ?: ActivityConfigurationContext(activity).also(activities::add)
|
||||
}
|
||||
|
||||
fun apply(entity: LivingEntity, brainConfigs: List<BrainConfig>) {
|
||||
fun apply(entity: LivingEntity, behaviourConfigs: List<BehaviourConfig>) {
|
||||
val brain = entity.brain
|
||||
|
||||
if (entity is MoLangScriptingEntity) {
|
||||
entity.registerVariables(behaviourConfigs.flatMap { it.getVariables(entity) })
|
||||
entity.initializeScripting()
|
||||
}
|
||||
|
||||
// Setup the brain config
|
||||
brainConfigs.forEach { it.configure(entity, this) }
|
||||
behaviourConfigs.forEach { it.configure(entity, this) }
|
||||
|
||||
// Apply the brain config
|
||||
activities.forEach { it.apply(entity) }
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.ai.config.BehaviourConfig
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
|
||||
import com.cobblemon.mod.common.util.asTranslated
|
||||
import com.cobblemon.mod.common.util.resolve
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class CobblemonBehaviour(
|
||||
val name: Component = "".asTranslated(),
|
||||
val description: Component = "".asTranslated(),
|
||||
/** Some behaviours aren't really worth showing on the client, namely ones that are simply conditional bundles of other behaviours. */
|
||||
val visible: Boolean = true,
|
||||
val entityType: ResourceLocation? = null,
|
||||
val configurations: List<BehaviourConfig> = mutableListOf(),
|
||||
val undo: ExpressionLike? = null,
|
||||
val undoScript: ResourceLocation? = null,
|
||||
) {
|
||||
fun canBeApplied(entity: LivingEntity) = entityType?.let { entityType == entity.type.builtInRegistryHolder().unwrapKey().get().location() } != false
|
||||
fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
|
||||
configurations.forEach { it.configure(entity, behaviourConfigurationContext) }
|
||||
}
|
||||
|
||||
/** Undoes anything that needs undoing once this configuration is being removed from an entity that had it before. */
|
||||
fun undo(entity: LivingEntity) {
|
||||
val runtime = MoLangRuntime().setup()
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (undoScript != null) {
|
||||
CobblemonScripts.run(undoScript, runtime)
|
||||
}
|
||||
if (undo != null) {
|
||||
runtime.resolve(undo)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.api.ai
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.mojang.datafixers.util.Either
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
|
||||
typealias ExpressionOrEntityVariable = Either<Expression, MoLangConfigVariable>
|
||||
|
||||
fun List<ExpressionOrEntityVariable>.asVariables() = mapNotNull { it.right().getOrNull() }
|
||||
|
||||
|
||||
+20
-18
@@ -8,32 +8,34 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.config.task.TaskConfig
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.schedule.Activity
|
||||
|
||||
class AddTasksToActivity : BrainConfig {
|
||||
val activity = Activity.IDLE
|
||||
val condition = "true".asExpressionLike()
|
||||
class AddTasksToActivity : BehaviourConfig {
|
||||
val activity: Activity? = null
|
||||
// Can be useful to add to multiple activities at once
|
||||
val activities = mutableListOf<Activity>()
|
||||
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
val tasksByPriority = mutableMapOf<Int, List<TaskConfig>>()
|
||||
override fun getVariables(entity: LivingEntity) = tasksByPriority.values.flatten().flatMap { it.getVariables(entity) } + listOf(condition).asVariables()
|
||||
|
||||
override fun configure(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext) {
|
||||
val runtime = MoLangRuntime().setup()
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return
|
||||
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
|
||||
if (!checkCondition(entity, condition)) return
|
||||
|
||||
val activities = if (activity != null) (activities + activity) else activities
|
||||
|
||||
val activity = brainConfigurationContext.getOrCreateActivity(activity)
|
||||
tasksByPriority.forEach { (priority, taskConfigs) ->
|
||||
val tasks = taskConfigs.flatMap { it.createTasks(entity, brainConfigurationContext) }
|
||||
activity.addTasks(priority, *tasks.toTypedArray())
|
||||
val tasks = taskConfigs.flatMap { it.createTasks(entity, behaviourConfigurationContext) }
|
||||
for (activity in activities) {
|
||||
val activityContext = behaviourConfigurationContext.getOrCreateActivity(activity)
|
||||
activityContext.addTasks(priority, *tasks.toTypedArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.api.ai.config
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class AddVariablesConfig(val variables: List<MoLangConfigVariable> = emptyList()) : BehaviourConfig {
|
||||
override fun getVariables(entity: LivingEntity) = variables
|
||||
|
||||
// Configuration happens naturally through the override on variables
|
||||
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonBehaviours
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class ApplyBehaviours : BehaviourConfig {
|
||||
var condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
@SerializedName("behaviours", alternate = ["behaviors"])
|
||||
val behaviours = mutableListOf<ResourceLocation>()
|
||||
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
|
||||
return if (checkCondition(entity, condition)) {
|
||||
behaviours.flatMap {
|
||||
CobblemonBehaviours.behaviours[it]?.configurations?.flatMap { it.getVariables(entity) } ?: emptyList()
|
||||
} + listOf(condition).asVariables()
|
||||
} else {
|
||||
listOf(condition).asVariables()
|
||||
}
|
||||
}
|
||||
|
||||
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
|
||||
if (!checkCondition(entity, condition)) return
|
||||
|
||||
val configurations = behaviours.map { CobblemonBehaviours.behaviours[it]?.takeIf { it.canBeApplied(entity) } ?: return Cobblemon.LOGGER.warn("Behaviour $it not found") }
|
||||
// Why not just add the presets to the context directly?
|
||||
// Nested preset application is a thing, and I only want to track the top level presets.
|
||||
// i.e. if a preset applies another preset, I don't want to track the inner preset, since it's redundant if we track the top one.
|
||||
val originalContextBehaviours = behaviourConfigurationContext.appliedBehaviours.toMutableSet()
|
||||
configurations.forEach {
|
||||
it.configure(entity, behaviourConfigurationContext)
|
||||
}
|
||||
originalContextBehaviours.addAll(behaviours)
|
||||
behaviourConfigurationContext.appliedBehaviours = originalContextBehaviours
|
||||
}
|
||||
}
|
||||
@@ -1,35 +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.ai.config
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonBrainConfigs
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class ApplyPresets : BrainConfig {
|
||||
val condition = "true".asExpressionLike()
|
||||
val presets = mutableListOf<ResourceLocation>()
|
||||
override fun configure(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext) {
|
||||
val runtime = MoLangRuntime().setup()
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return
|
||||
|
||||
val presetConfigs = presets.flatMap { CobblemonBrainConfigs.presets[it] ?: return Cobblemon.LOGGER.warn("Preset $it not found") }
|
||||
presetConfigs.forEach { it.configure(entity, brainConfigurationContext) }
|
||||
}
|
||||
}
|
||||
@@ -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.ai.config
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
/**
|
||||
* Something that contributes to the construction of an entity's brain. Implementations are expected to make
|
||||
* their changes using the provided [BehaviourConfigurationContext] which helps stage the details of the entity's
|
||||
* brain before locking into the highly immutable structure that Mojang uses.
|
||||
*
|
||||
* A brain config has access to the [LivingEntity] it's for but note that this is, in most cases, an extremely
|
||||
* young version of the entity that is not fully initialized and might die if you try getting exotic with it.
|
||||
*
|
||||
* @see BehaviourConfigurationContext
|
||||
* @author Hiroku
|
||||
* @since October 13th, 2024
|
||||
*/
|
||||
interface BehaviourConfig {
|
||||
companion object {
|
||||
val types = mutableMapOf<ResourceLocation, Class<out BehaviourConfig>>(
|
||||
cobblemonResource("script") to ScriptBehaviourConfig::class.java,
|
||||
cobblemonResource("custom_script") to CustomScriptBehaviourConfig::class.java,
|
||||
cobblemonResource("add_tasks_to_activity") to AddTasksToActivity::class.java,
|
||||
cobblemonResource("apply_behaviours") to ApplyBehaviours::class.java,
|
||||
cobblemonResource("set_default_activity") to SetDefaultActivity::class.java,
|
||||
cobblemonResource("set_core_activities") to SetCoreActivities::class.java,
|
||||
cobblemonResource("add_variables") to AddVariablesConfig::class.java,
|
||||
cobblemonResource("set_variables") to SetVariablesConfig::class.java,
|
||||
)
|
||||
}
|
||||
|
||||
fun checkCondition(entity: LivingEntity, expressionOrEntityVariable: ExpressionOrEntityVariable): Boolean {
|
||||
val runtime = MoLangRuntime().setup()
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
return runtime.resolveBoolean(expressionOrEntityVariable.map({ it }, { "q.entity.config.${it.variableName}".asExpression() }))
|
||||
}
|
||||
|
||||
fun getVariables(entity: LivingEntity): List<MoLangConfigVariable>
|
||||
fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext)
|
||||
}
|
||||
@@ -1,41 +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.ai.config
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
/**
|
||||
* Something that contributes to the construction of an entity's brain. Implementations are expected to make
|
||||
* their changes using the provided [BrainConfigurationContext] which helps stage the details of the entity's
|
||||
* brain before locking into the highly immutable structure that Mojang uses.
|
||||
*
|
||||
* A brain config has access to the [LivingEntity] it's for but note that this is, in most cases, an extremely
|
||||
* young version of the entity that is not fully initialized and might die if you try getting exotic with it.
|
||||
*
|
||||
* @see BrainConfigurationContext
|
||||
* @author Hiroku
|
||||
* @since October 13th, 2024
|
||||
*/
|
||||
interface BrainConfig {
|
||||
companion object {
|
||||
val types = mutableMapOf<String, Class<out BrainConfig>>(
|
||||
"script" to ScriptBrainConfig::class.java,
|
||||
"add_tasks_to_activity" to AddTasksToActivity::class.java,
|
||||
"apply_presets" to ApplyPresets::class.java,
|
||||
"set_default_activity" to SetDefaultActivity::class.java,
|
||||
"set_core_activities" to SetCoreActivities::class.java
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
// fun encode(buffer: RegistryFriendlyByteBuf)
|
||||
// fun decode(buffer: RegistryFriendlyByteBuf)
|
||||
fun configure(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext)
|
||||
}
|
||||
+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.api.ai.config
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolve
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class CustomScriptBehaviourConfig : BehaviourConfig {
|
||||
var condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
val variables: List<MoLangConfigVariable> = emptyList()
|
||||
val script: ExpressionLike = "0".asExpressionLike()
|
||||
|
||||
companion object {
|
||||
val runtime = MoLangRuntime().setup()
|
||||
}
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = variables
|
||||
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
|
||||
if (!checkCondition(entity, condition)) return
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
runtime.resolve(script)
|
||||
}
|
||||
}
|
||||
@@ -1,16 +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.ai.config
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
object DummyBrainConfig : BrainConfig {
|
||||
override fun configure(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext) {}
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
# Brain Configuration
|
||||
# Behaviour Configuration
|
||||
|
||||
A "Brain" is a Java Edition AI concept for more modern entities. It has tasks that are listed inside of 'activities',
|
||||
A "Brain" is a Java Edition AI concept for more modern entities. It has tasks that are listed inside 'activities',
|
||||
and in some cases a schedule which determines which activities will occur during different times of the day. There is
|
||||
also a set of core activities, and a default activity. In Minecraft, the most complex usage of the Brain AI system
|
||||
is on villagers which have schedules that control their behaviour during the day and night as well as child villager play behaviours.
|
||||
|
||||
Cobblemon's NPCs use the Brain AI system. As part of that, Cobblemon added the concept of a Brain Configuration
|
||||
that allows Java Edition brains to be configured in a more data-driven way.
|
||||
Cobblemon's Pokémon and NPCs use the Brain AI system. As part of that, Cobblemon added the concept of a Behaviour Configuration
|
||||
that allows Java Edition brains to be configured in a more data-driven way, as well as to support the configuration of
|
||||
other logical properties of entities that are configured at the same initialization step.
|
||||
|
||||
By default, without any brain configuration, the default activity will be `minecraft:idle` and the core activities will be `[minecraft:core]`.
|
||||
The activities would not have any tasks though.
|
||||
@@ -48,18 +49,18 @@ The activities that were added by Cobblemon are:
|
||||
- `cobblemon:action_effect`: For when the entity is performing an action effect. Usually registered as an almost empty activity that simply prevents the entity from doing other things.
|
||||
- `cobblemon:npc_chatting`: Intended for NPC entities using dialogue so that they look at their chat partner and do nothing else.
|
||||
|
||||
## Brain Configuration Format
|
||||
A brain is configured using a series of "Brain Configurations". Each configuration is a JSON object that contains
|
||||
a "type" field which determines the action to perform when configuring a brain. Many different types are available.
|
||||
## Behaviour Configuration Format
|
||||
A Behaviour is configured using a series of "Behaviour Configurations". Each configuration is a JSON object that contains
|
||||
a "type" field which determines the action to perform when configuring an entity. Many different types are available.
|
||||
|
||||
### script
|
||||
The `script` type executes a MoLang script which will apply some changes to the brain.
|
||||
The `script` type executes a MoLang script which will apply some changes to the entity or brain.
|
||||
- `script`: The MoLang script to execute. This will be a resource location for the `molang` datapack folder. Something like `cobblemon:some_script`.
|
||||
- `condition`: A MoLang expression (with `q.entity` as the entity) that determines if the script should be executed. Defaults to `"true"`.
|
||||
|
||||
### add_tasks_to_activity
|
||||
The 'add_tasks_to_activity' type adds a list of tasks to an activity.
|
||||
- `activity`: The activity to add the tasks to. This must be a pre-existing activity - a brain configuration cannot
|
||||
- `activity`: The activity to add the tasks to. This must be a pre-existing activity - a behaviour configuration cannot
|
||||
create new activities.
|
||||
- `condition`: A MoLang expression (with `q.entity` as the entity) that determines if the tasks should be added. If this
|
||||
is not present, the tasks will always be added.
|
||||
@@ -96,24 +97,107 @@ The `set_core_activities` type sets the core activities of the brain. It has onl
|
||||
### set_default_activity
|
||||
The `set_default_activity` type sets the default activity of the brain. It has only one property, `activity`, which is the activity to set as the default.
|
||||
|
||||
### apply_preset
|
||||
The `apply_preset` type applies a preset to the brain. Brain presets are JSON arrays under the `brain_presets` datapack folder.
|
||||
This is a way to apply a set of configurations to the brain.
|
||||
- `preset`: The name of the preset to apply. This is the name of the file in the `brain_presets` folder without the `.json` extension.
|
||||
- `condition`: A MoLang expression (with `q.entity` as the entity) that determines if the preset should be applied. Defaults to `"true"`.
|
||||
### apply_behaviours
|
||||
The `apply_behaviours` type applies some number of other Behaviours to the entity. These behaviours are JSONs under the `behaviours` datapack folder.
|
||||
This is a way to apply a set of configurations to the entity.
|
||||
- `behaviours`: A list of behaviour resource locations to apply. This is the name of the file in the `behaviours` folder without the `.json` extension.
|
||||
- `condition`: A MoLang expression (with `q.entity` as the entity) that determines if the behaviour should be applied. Defaults to `"true"`.
|
||||
- `visible`: Whether the behaviour should be visible in the UI. Defaults to `true`. If it is not visible, name and description can be left out.
|
||||
- `name`: The name of the behaviour. This is used in the UI to label the behaviour. This can be a translation key.
|
||||
- `description`: A description of the behaviour. This is used in the UI to describe what the behaviour does. This can be a translation key.
|
||||
- `entityType`: The entity type that the behaviour applies to. Defaults to null. This is used to determine if the behaviour should be applied to the entity type..
|
||||
|
||||
Example brain preset (`uses_healing_machine.json`):
|
||||
Example behaviour (`uses_healing_machine.json`):
|
||||
```json
|
||||
[
|
||||
{
|
||||
"type": "add_tasks_to_activity",
|
||||
"activity": "idle",
|
||||
"tasksByPriority": {
|
||||
"1": [
|
||||
"heal_using_healing_machine",
|
||||
"go_to_healing_machine"
|
||||
]
|
||||
{
|
||||
"name": "cobblemon.behaviour.uses_healing_machine.name",
|
||||
"description": "cobblemon.behaviour.uses_healing_machine.desc",
|
||||
"entityType": "cobblemon:npc",
|
||||
"visible": true,
|
||||
"configurations": [
|
||||
{
|
||||
"type": "add_tasks_to_activity",
|
||||
"activity": "idle",
|
||||
"tasksByPriority": {
|
||||
"1": [
|
||||
"heal_using_healing_machine",
|
||||
"go_to_healing_machine"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### add_variables
|
||||
The `add_variables` type adds some number of MoLang variables to the entity that can be configured in-game or left with defaults.
|
||||
- `variables`: A list of objects, each representing a variable that can be configured.
|
||||
|
||||
Each variable has the following properties:
|
||||
- `variableName`: The name of the variable. This is the name that will be accessible from MoLang scripts.
|
||||
- `defaultValue`: The default value of the variable. This is a MoLang expression that will be used if the variable is not set.
|
||||
- `displayName`: The display name of the variable. This is used in the UI to label the variable. This can be a translation key.
|
||||
- `description`: A description of the variable. This is used in the UI to describe what the variable does. This can be a translation key.
|
||||
- `type`: The type of the variable. This can be `TEXT`, `NUMBER`, or `BOOLEAN`.
|
||||
|
||||
Example:
|
||||
```json
|
||||
{
|
||||
"type": "add_variables",
|
||||
"variables": [
|
||||
{
|
||||
"variableName": "can_heal_using_machine",
|
||||
"defaultValue": "false",
|
||||
"displayName": "Can Use Healing Machine",
|
||||
"description": "Whether or not the entity can use a healing machine.",
|
||||
"type": "BOOLEAN"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### set_variables
|
||||
The `set_variables` type sets some values for pre-established variables. This is useful in cases where a preset has defined a variable
|
||||
but it's locked in by a specific entity using that preset. This strongly forces the variable to a specific value. In future this
|
||||
probably should deregister the variable so that the client cannot edit them once they've been forced, as currently that will
|
||||
be possible yet the value will get repeatedly overwritten.
|
||||
|
||||
The values inside the variables map can be MoLang expressions (with `q.entity` as the entity) or simple JSON primitives.
|
||||
|
||||
Example:
|
||||
```json
|
||||
{
|
||||
"type": "set_variables",
|
||||
"variables": {
|
||||
"aggressive": true,
|
||||
"attack_range": "10"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### script
|
||||
The `script` type executes a registered MoLang script which will apply some changes to the brain or entity. This can be
|
||||
useful if the goal is to apply some kind of configuration to the entity that would otherwise be performed by an NPC preset
|
||||
or NPC class. `q.entity` will refer to the entity. This is powerful when combined with [add_variables](#add_variables)
|
||||
configs in the same behaviour preset.
|
||||
|
||||
Example:
|
||||
```json
|
||||
{
|
||||
"type": "script",
|
||||
"script": "cobblemon:configure_npc_party"
|
||||
}
|
||||
```
|
||||
|
||||
### custom_script
|
||||
The `custom_script` type executes a custom MoLang script from this config which will apply some changes to the brain or
|
||||
entity. This is useful for when you want to apply some kind of configuration to the entity that would otherwise be
|
||||
by an NPC preset or NPC class. `q.entity` will refer to the entity.
|
||||
|
||||
Example:
|
||||
```json
|
||||
{
|
||||
"type": "custom_script",
|
||||
"script": "q.entity.set_pathfinding_malus('WATER', -1);"
|
||||
}
|
||||
```
|
||||
+15
-11
@@ -13,12 +13,13 @@ import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.ai.ActivityConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.util.activityRegistry
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
@@ -30,13 +31,16 @@ import com.mojang.datafixers.util.Pair
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class ScriptBrainConfig : BrainConfig {
|
||||
class ScriptBehaviourConfig : BehaviourConfig {
|
||||
val condition = "true".asExpressionLike()
|
||||
val script = cobblemonResource("dummy")
|
||||
val variables = mutableListOf<MoLangConfigVariable>()
|
||||
|
||||
override fun configure(entity: LivingEntity, context: BrainConfigurationContext) {
|
||||
override fun getVariables(entity: LivingEntity) = variables
|
||||
|
||||
override fun configure(entity: LivingEntity, context: BehaviourConfigurationContext) {
|
||||
val runtime = MoLangRuntime().setup()
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!runtime.resolveBoolean(condition)) return
|
||||
|
||||
val struct = createBrainStruct(entity, context)
|
||||
@@ -48,30 +52,30 @@ class ScriptBrainConfig : BrainConfig {
|
||||
runtime.resolve(script, mapOf("brain" to struct))
|
||||
}
|
||||
|
||||
fun createBrainStruct(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext): QueryStruct {
|
||||
fun createBrainStruct(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): QueryStruct {
|
||||
return QueryStruct(hashMapOf()).addStandardFunctions()
|
||||
.addFunction("entity") { (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()) }
|
||||
.addFunction("entity") { entity.asMostSpecificMoLangValue() }
|
||||
.addFunction("create_activity") { params ->
|
||||
val name = params.getString(0).asIdentifierDefaultingNamespace()
|
||||
val activity = entity.level().activityRegistry.get(name) ?: return@addFunction run {
|
||||
Cobblemon.LOGGER.error("Tried loading activity $name as part of an entity brain but that activity does not exist")
|
||||
DoubleValue.ZERO
|
||||
}
|
||||
val existingActivityBuilder = brainConfigurationContext.activities.find { it.activity == activity }
|
||||
val existingActivityBuilder = behaviourConfigurationContext.activities.find { it.activity == activity }
|
||||
if (existingActivityBuilder != null) {
|
||||
return@addFunction createActivityStruct(existingActivityBuilder)
|
||||
} else {
|
||||
val activityConfigurationContext = ActivityConfigurationContext(activity)
|
||||
brainConfigurationContext.activities.add(activityConfigurationContext)
|
||||
behaviourConfigurationContext.activities.add(activityConfigurationContext)
|
||||
return@addFunction createActivityStruct(activityConfigurationContext)
|
||||
}
|
||||
}
|
||||
.addFunction("set_core_activities") { params ->
|
||||
brainConfigurationContext.coreActivities = params.params.map { (it as ObjectValue<ActivityConfigurationContext>).obj.activity }.toSet()
|
||||
behaviourConfigurationContext.coreActivities = params.params.map { (it as ObjectValue<ActivityConfigurationContext>).obj.activity }.toSet()
|
||||
return@addFunction DoubleValue.ONE
|
||||
}
|
||||
.addFunction("set_default_activity") { params ->
|
||||
brainConfigurationContext.defaultActivity = params.get<ObjectValue<ActivityConfigurationContext>>(0).obj.activity
|
||||
behaviourConfigurationContext.defaultActivity = params.get<ObjectValue<ActivityConfigurationContext>>(0).obj.activity
|
||||
return@addFunction DoubleValue.ONE
|
||||
}
|
||||
}
|
||||
@@ -8,13 +8,15 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.schedule.Activity
|
||||
|
||||
class SetCoreActivities : BrainConfig {
|
||||
class SetCoreActivities : BehaviourConfig {
|
||||
val activities = mutableListOf<Activity>()
|
||||
override fun configure(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext) {
|
||||
brainConfigurationContext.coreActivities = activities.toSet()
|
||||
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
|
||||
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
|
||||
behaviourConfigurationContext.coreActivities = activities.toSet()
|
||||
}
|
||||
}
|
||||
@@ -8,13 +8,15 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.schedule.Activity
|
||||
|
||||
class SetDefaultActivity : BrainConfig {
|
||||
class SetDefaultActivity : BehaviourConfig {
|
||||
val activity: Activity = Activity.IDLE
|
||||
override fun configure(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext) {
|
||||
brainConfigurationContext.defaultActivity = activity
|
||||
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
|
||||
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
|
||||
behaviourConfigurationContext.defaultActivity = activity
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.setup
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.MoLangScriptingEntity
|
||||
import com.cobblemon.mod.common.util.resolve
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class SetVariablesConfig : BehaviourConfig {
|
||||
var variableValues = mutableMapOf<String, ExpressionLike>()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
|
||||
|
||||
override fun configure(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) {
|
||||
val runtime = MoLangRuntime().setup()
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (entity is MoLangScriptingEntity) {
|
||||
variableValues.forEach { (variableName, valueExpression) ->
|
||||
entity.config.setDirectly(variableName, runtime.resolve(valueExpression))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.config.task.WanderTaskConfig.Companion.WANDER
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.entity.ai.util.HoverRandomPos
|
||||
|
||||
class AirWanderTaskConfig : SingleTaskConfig {
|
||||
val condition = booleanVariable(WANDER, "air_wanders", true).asExpressible()
|
||||
val wanderChance = numberVariable(WANDER, "air_wander_chance", 1/(20 * 1F)).asExpressible()
|
||||
val horizontalRange = numberVariable(WANDER, "horizontal_wander_range", 20).asExpressible()
|
||||
val verticalRange = numberVariable(WANDER, "vertical_wander_range", 5).asExpressible()
|
||||
val speedMultiplier = numberVariable(SharedEntityVariables.MOVEMENT_CATEGORY, SharedEntityVariables.WALK_SPEED, 0.35).asExpressible()
|
||||
val minUpwardsMovement: ExpressionOrEntityVariable = Either.left("3.0".asExpression())
|
||||
val minDownwardsMovement: ExpressionOrEntityVariable = Either.left("3.0".asExpression())
|
||||
|
||||
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
|
||||
return listOf(condition, wanderChance, horizontalRange, verticalRange, speedMultiplier, minUpwardsMovement, minDownwardsMovement).asVariables()
|
||||
}
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
val wanderChanceExpression = wanderChance.asSimplifiedExpression(entity)
|
||||
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.absent(MemoryModuleType.WALK_TARGET),
|
||||
it.registered(MemoryModuleType.LOOK_TARGET)
|
||||
).apply(it) { walkTarget, lookTarget ->
|
||||
Trigger { world, entity, time ->
|
||||
if (entity !is PathfinderMob || entity.isInWater) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
val wanderChance = runtime.resolveFloat(wanderChanceExpression)
|
||||
if (wanderChance <= 0 || world.random.nextFloat() > wanderChance) return@Trigger false
|
||||
|
||||
val rotVec = entity.getViewVector(0F)
|
||||
val target = HoverRandomPos.getPos(entity, horizontalRange.resolveInt(), verticalRange.resolveInt(), rotVec.x, rotVec.y, 1.5707964f, minUpwardsMovement.resolveInt(), minDownwardsMovement.resolveInt())
|
||||
?: return@Trigger false
|
||||
walkTarget.set(WalkTarget(target, speedMultiplier.resolveFloat(), 3))
|
||||
lookTarget.set(BlockPosTracker(target))
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
-10
@@ -8,25 +8,34 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class AllOfTaskConfig : TaskConfig {
|
||||
val condition = "true".asExpressionLike()
|
||||
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
val tasks: List<TaskConfig> = emptyList()
|
||||
|
||||
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
|
||||
return if (checkCondition(entity, condition))
|
||||
tasks.flatMap { it.getVariables(entity) } + listOf(condition).asVariables()
|
||||
else
|
||||
listOf(condition).asVariables()
|
||||
}
|
||||
|
||||
override fun createTasks(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): List<BehaviorControl<in LivingEntity>> {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return emptyList()
|
||||
return tasks.flatMap { it.createTasks(entity, brainConfigurationContext) }
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return emptyList()
|
||||
return tasks.flatMap { it.createTasks(entity, behaviourConfigurationContext) }
|
||||
}
|
||||
}
|
||||
+9
-9
@@ -8,24 +8,24 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.entity.ai.AttackAngryAtTask
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class AttackAngryAtTaskConfig : SingleTaskConfig {
|
||||
val condition = "true".asExpressionLike()
|
||||
val condition = booleanVariable(SharedEntityVariables.ATTACKING_CATEGORY, "should_attack_angry_at", true).asExpressible()
|
||||
override fun getVariables(entity: LivingEntity) = listOf(condition).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
return AttackAngryAtTask.create()
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.npc.ai.MeleeAttackTask
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.BattleFlightTask
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class BattleFlightTaskConfig : SingleTaskConfig {
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
if (entity !is PokemonEntity) {
|
||||
return null
|
||||
}
|
||||
return BattleFlightTask.create()
|
||||
}
|
||||
}
|
||||
+10
-8
@@ -8,24 +8,26 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.VillagerCalmDown
|
||||
|
||||
class CalmDownTaskConfig : SingleTaskConfig {
|
||||
var condition = "true".asExpression()
|
||||
var condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
override fun getVariables(entity: LivingEntity) = listOf(condition).asVariables()
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
return VillagerCalmDown.create()
|
||||
}
|
||||
}
|
||||
+13
-14
@@ -8,30 +8,29 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveInt
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.DoNothing
|
||||
|
||||
class DoNothingTaskConfig : SingleTaskConfig {
|
||||
val condition: ExpressionLike = "true".asExpressionLike()
|
||||
val minDurationTicks = "40".asExpression()
|
||||
val maxDurationTicks = "80".asExpression()
|
||||
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
val minDurationTicks: ExpressionOrEntityVariable = Either.left("40".asExpression())
|
||||
val maxDurationTicks: ExpressionOrEntityVariable = Either.left("80".asExpression())
|
||||
override fun getVariables(entity: LivingEntity) = listOf(condition, minDurationTicks, maxDurationTicks).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
return DoNothing(runtime.resolveInt(minDurationTicks), runtime.resolveInt(maxDurationTicks))
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
return DoNothing(minDurationTicks.resolveInt(), maxDurationTicks.resolveInt())
|
||||
}
|
||||
}
|
||||
+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.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.EatGrassTask
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class EatGrassTaskConfig : SingleTaskConfig {
|
||||
companion object {
|
||||
const val EATING_GRASS = "eating_grass"
|
||||
const val COOLDOWN = "eating_grass_cooldown_ticks"
|
||||
const val EAT_GRASS_CHANCE = "eat_grass_chance"
|
||||
}
|
||||
|
||||
val cooldown = numberVariable(category = EATING_GRASS, name = COOLDOWN, default = 20 * 20).asExpressible()
|
||||
val eatGrassChance = numberVariable(category = EATING_GRASS, name = EAT_GRASS_CHANCE, default = 1 / (20 * 20F)).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
|
||||
return listOf(
|
||||
cooldown,
|
||||
eatGrassChance
|
||||
).asVariables()
|
||||
}
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
if (entity !is PokemonEntity) {
|
||||
return null
|
||||
}
|
||||
|
||||
val chance = eatGrassChance.resolveFloat()
|
||||
if (chance == 0F) {
|
||||
return null
|
||||
}
|
||||
|
||||
return WrapperLivingEntityTask(
|
||||
EatGrassTask(
|
||||
chance,
|
||||
cooldown.resolveInt().toLong()
|
||||
),
|
||||
PokemonEntity::class.java
|
||||
)
|
||||
}
|
||||
}
|
||||
+21
-14
@@ -8,14 +8,13 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
@@ -24,15 +23,21 @@ import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
|
||||
class ExitBattleWhenHurtTaskConfig : SingleTaskConfig {
|
||||
var condition = "true".asExpression()
|
||||
var includePassiveDamage = true
|
||||
var condition = booleanVariable(SharedEntityVariables.BATTLING_CATEGORY, "exit_battle_when_hurt", true).asExpressible()
|
||||
var includePassiveDamage = booleanVariable(SharedEntityVariables.BATTLING_CATEGORY, "exit_battle_from_passive_damage", true).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition,
|
||||
includePassiveDamage
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
val includePassiveDamage = includePassiveDamage.resolveBoolean()
|
||||
if (!condition.resolveBoolean()) return null
|
||||
|
||||
if (entity is NPCEntity) {
|
||||
fun cancelNPCBattles(npcEntity: NPCEntity): Boolean {
|
||||
@@ -52,7 +57,7 @@ class ExitBattleWhenHurtTaskConfig : SingleTaskConfig {
|
||||
.apply(it) { _, _ -> Trigger { world, entity, _ -> return@Trigger cancelNPCBattles(entity as NPCEntity) } }
|
||||
}
|
||||
}
|
||||
} else { return null }/* else if (entity is PokemonEntity) { TODO uncomment when pokemon have brain :)
|
||||
} else if (entity is PokemonEntity) {
|
||||
fun cancelPokemonBattle(pokemonEntity: PokemonEntity): Boolean {
|
||||
val battle = BattleRegistry.getBattle(pokemonEntity.battleId ?: return false)
|
||||
battle?.end()
|
||||
@@ -61,15 +66,17 @@ class ExitBattleWhenHurtTaskConfig : SingleTaskConfig {
|
||||
|
||||
return if (includePassiveDamage) {
|
||||
BehaviorBuilder.create {
|
||||
it.group(it.present(MemoryModuleType.HURT_BY), it.present(CobblemonMemories.POKEMON_BATTLING))
|
||||
it.group(it.present(MemoryModuleType.HURT_BY), it.present(CobblemonMemories.POKEMON_BATTLE))
|
||||
.apply(it) { _, _ -> Trigger { world, entity, _ -> return@Trigger cancelPokemonBattle(entity as PokemonEntity) } }
|
||||
}
|
||||
} else {
|
||||
BehaviorBuilder.create {
|
||||
it.group(it.present(MemoryModuleType.HURT_BY_ENTITY), it.present(CobblemonMemories.POKEMON_BATTLING))
|
||||
it.group(it.present(MemoryModuleType.HURT_BY_ENTITY), it.present(CobblemonMemories.POKEMON_BATTLE))
|
||||
.apply(it) { _, _ -> Trigger { world, entity, _ -> return@Trigger cancelPokemonBattle(entity as PokemonEntity) } }
|
||||
}
|
||||
}
|
||||
}*/
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.util.closestPosition
|
||||
import com.cobblemon.mod.common.util.getIsSubmerged
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.level.LevelReader
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.pathfinder.PathComputationType
|
||||
|
||||
/**
|
||||
* Moves to the nearest surface it can find so it can breathe.
|
||||
*/
|
||||
class FindAirTaskConfig : SingleTaskConfig {
|
||||
val walkSpeed = numberVariable(SharedEntityVariables.MOVEMENT_CATEGORY, SharedEntityVariables.WALK_SPEED, 0.35).asExpressible()
|
||||
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
|
||||
return listOf(walkSpeed).asVariables()
|
||||
}
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
if (entity !is PathfinderMob) {
|
||||
return null
|
||||
}
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.absent(MemoryModuleType.WALK_TARGET),
|
||||
it.absent(CobblemonMemories.PATH_COOLDOWN)
|
||||
).apply(it) { walkTarget, pathCooldown ->
|
||||
Trigger { world, entity, time ->
|
||||
if (!entity.getIsSubmerged()) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
val iterable = BlockPos.betweenClosed(
|
||||
Mth.floor(entity.x - 4.0),
|
||||
entity.blockY - 1,
|
||||
Mth.floor(entity.z - 4.0),
|
||||
Mth.floor(entity.x + 4.0),
|
||||
Mth.floor(entity.y + 8.0),
|
||||
Mth.floor(entity.z + 4.0)
|
||||
)
|
||||
|
||||
pathCooldown.setWithExpiry(true, 20L)
|
||||
|
||||
val blockPos = entity.closestPosition(iterable) { isAirPos(entity.level(), it) }
|
||||
?: return@Trigger false
|
||||
|
||||
walkTarget.set(WalkTarget(blockPos.above(), 0.35F, 0))
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isAirPos(world: LevelReader, pos: BlockPos): Boolean {
|
||||
val blockState = world.getBlockState(pos)
|
||||
val aboveState = world.getBlockState(pos.above())
|
||||
val notFluid = world.getFluidState(pos.above()).isEmpty || blockState.`is`(Blocks.BUBBLE_COLUMN)
|
||||
val canPathfindThroughAbove = aboveState.isPathfindable(PathComputationType.LAND)
|
||||
val solidBelow = !blockState.isPathfindable(PathComputationType.LAND)
|
||||
|
||||
return notFluid && canPathfindThroughAbove && solidBelow
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.FindRestingPlaceTask
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class FindRestingPlaceTaskConfig : SingleTaskConfig {
|
||||
val horizontalSearchDistance: ExpressionOrEntityVariable = Either.left("16".asExpression())
|
||||
val verticalSearchDistance: ExpressionOrEntityVariable = Either.left("5".asExpression())
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(horizontalSearchDistance, verticalSearchDistance).asVariables()
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
return WrapperLivingEntityTask(
|
||||
FindRestingPlaceTask.create(horizontalSearchDistance.resolveInt(), verticalSearchDistance.resolveInt()),
|
||||
PokemonEntity::class.java
|
||||
)
|
||||
}
|
||||
}
|
||||
+19
-15
@@ -8,14 +8,12 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.resolveInt
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.FLEE_DESIRED_DISTANCE
|
||||
import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.FLEE_SPEED_MULTIPLIER
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
@@ -24,18 +22,24 @@ import net.minecraft.world.entity.ai.behavior.SetWalkTargetAwayFrom
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
|
||||
class FleeAttackerTaskConfig : SingleTaskConfig {
|
||||
var condition = "true".asExpression()
|
||||
var speedMultiplier = "0.5".asExpression()
|
||||
var desiredDistance = "9".asExpression()
|
||||
var condition = booleanVariable(SharedEntityVariables.FEAR_CATEGORY, "flee_attacker", true).asExpressible()
|
||||
var speedMultiplier = numberVariable(SharedEntityVariables.FEAR_CATEGORY, FLEE_SPEED_MULTIPLIER, 0.5).asExpressible()
|
||||
var desiredDistance = numberVariable(SharedEntityVariables.FEAR_CATEGORY, FLEE_DESIRED_DISTANCE, 9).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition,
|
||||
speedMultiplier,
|
||||
desiredDistance
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition) || entity !is PathfinderMob) return null
|
||||
val speedMultiplier = runtime.resolveFloat(speedMultiplier)
|
||||
val desiredDistance = runtime.resolveInt(desiredDistance)
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean() || entity !is PathfinderMob) return null
|
||||
val speedMultiplier = speedMultiplier.resolveFloat()
|
||||
val desiredDistance = desiredDistance.resolveInt()
|
||||
return WrapperLivingEntityTask(
|
||||
SetWalkTargetAwayFrom.entity(MemoryModuleType.HURT_BY_ENTITY, speedMultiplier, desiredDistance, false),
|
||||
PathfinderMob::class.java
|
||||
|
||||
+15
-15
@@ -8,14 +8,12 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.util.resolveInt
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.FLEE_DESIRED_DISTANCE
|
||||
import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.FLEE_SPEED_MULTIPLIER
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
@@ -24,18 +22,20 @@ import net.minecraft.world.entity.ai.behavior.SetWalkTargetAwayFrom
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
|
||||
class FleeNearestHostileTaskConfig : SingleTaskConfig {
|
||||
var condition = "true".asExpression()
|
||||
var speedMultiplier = "0.5".asExpression()
|
||||
var desiredDistance = "9".asExpression()
|
||||
var condition = booleanVariable(SharedEntityVariables.FEAR_CATEGORY, "flee_nearest_hostile", true).asExpressible()
|
||||
var speedMultiplier = numberVariable(SharedEntityVariables.FEAR_CATEGORY, FLEE_SPEED_MULTIPLIER, 0.5).asExpressible()
|
||||
var desiredDistance = numberVariable(SharedEntityVariables.FEAR_CATEGORY, FLEE_DESIRED_DISTANCE, 9).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(condition, speedMultiplier, desiredDistance).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition) || entity !is PathfinderMob) return null
|
||||
val speedMultiplier = runtime.resolveFloat(speedMultiplier)
|
||||
val desiredDistance = runtime.resolveInt(desiredDistance)
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean() || entity !is PathfinderMob) return null
|
||||
val speedMultiplier = speedMultiplier.resolveFloat()
|
||||
val desiredDistance = desiredDistance.resolveInt()
|
||||
return WrapperLivingEntityTask(
|
||||
SetWalkTargetAwayFrom.entity(MemoryModuleType.NEAREST_HOSTILE, speedMultiplier, desiredDistance, false),
|
||||
PathfinderMob::class.java
|
||||
|
||||
+13
-15
@@ -8,32 +8,30 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.entity.ai.FollowWalkTargetTask
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveInt
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class FollowWalkTargetTaskConfig : SingleTaskConfig {
|
||||
val condition: ExpressionLike = "true".asExpressionLike()
|
||||
val minRunTicks: Expression = "150".asExpression()
|
||||
val maxRunTicks: Expression = "250".asExpression()
|
||||
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
val minRunTicks: ExpressionOrEntityVariable = Either.left("150".asExpression())
|
||||
val maxRunTicks: ExpressionOrEntityVariable = Either.left("250".asExpression())
|
||||
|
||||
override fun createTask(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext): BehaviorControl<LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
override fun getVariables(entity: LivingEntity) = listOf(minRunTicks, maxRunTicks).asVariables()
|
||||
|
||||
override fun createTask(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): BehaviorControl<LivingEntity>? {
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
return WrapperLivingEntityTask(
|
||||
FollowWalkTargetTask(runtime.resolveInt(minRunTicks), runtime.resolveInt(maxRunTicks)),
|
||||
FollowWalkTargetTask(minRunTicks.resolveInt(), maxRunTicks.resolveInt()),
|
||||
PathfinderMob::class.java
|
||||
)
|
||||
}
|
||||
|
||||
+14
-10
@@ -8,26 +8,30 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.ATTACKING_CATEGORY
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.entity.ai.GetAngryAtAttackerTask
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class GetAngryAtAttackerTaskConfig : SingleTaskConfig {
|
||||
val condition: ExpressionLike = "true".asExpressionLike()
|
||||
companion object {
|
||||
const val GET_ANGRY_AT_ATTACKER = "get_angry_at_attacker"
|
||||
}
|
||||
|
||||
val condition = booleanVariable(ATTACKING_CATEGORY, GET_ANGRY_AT_ATTACKER, true).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(condition).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
return GetAngryAtAttackerTask.create()
|
||||
}
|
||||
}
|
||||
+26
-21
@@ -8,38 +8,43 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.entity.npc.ai.GoToHealingMachineTask
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class GoToHealingMachineTaskConfig(
|
||||
val condition: ExpressionLike = "true".asExpressionLike(),
|
||||
val horizontalSearchRange: Expression = "10".asExpression(),
|
||||
val verticalSearchRange: Expression = "5".asExpression(),
|
||||
val speedMultiplier: Expression = "0.35".asExpression(),
|
||||
val completionRange: Expression = "1".asExpression()
|
||||
) : SingleTaskConfig {
|
||||
class GoToHealingMachineTaskConfig : SingleTaskConfig {
|
||||
val condition = booleanVariable(SELF_HEALING, USE_HEALING_MACHINES, true).asExpressible()
|
||||
val horizontalSearchRange: ExpressionOrEntityVariable = Either.left("10".asExpression())
|
||||
val verticalSearchRange: ExpressionOrEntityVariable = Either.left("5".asExpression())
|
||||
val completionRange: ExpressionOrEntityVariable = Either.left("1".asExpression())
|
||||
val walkSpeed = numberVariable(SharedEntityVariables.MOVEMENT_CATEGORY, SharedEntityVariables.WALK_SPEED, 0.35).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(condition, walkSpeed, horizontalSearchRange, verticalSearchRange, completionRange).asVariables()
|
||||
|
||||
companion object {
|
||||
const val SELF_HEALING = "self_healing"
|
||||
const val USE_HEALING_MACHINES = "use_healing_machines"
|
||||
}
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
|
||||
return GoToHealingMachineTask.create(
|
||||
horizontalSearchRange = horizontalSearchRange,
|
||||
verticalSearchRange = verticalSearchRange,
|
||||
speedMultiplier = speedMultiplier,
|
||||
completionRange = completionRange
|
||||
horizontalSearchRange = horizontalSearchRange.asExpression(),
|
||||
verticalSearchRange = verticalSearchRange.asExpression(),
|
||||
speedMultiplier = walkSpeed.asExpression(),
|
||||
completionRange = completionRange.asExpression()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.util.closestPosition
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.floor
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.PathfinderMob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.entity.ai.memory.WalkTarget
|
||||
import net.minecraft.world.level.pathfinder.PathComputationType
|
||||
|
||||
/**
|
||||
* Seeks land if it's underwater.
|
||||
*/
|
||||
class GoToLandTaskConfig : SingleTaskConfig {
|
||||
val walkSpeed = numberVariable(SharedEntityVariables.MOVEMENT_CATEGORY, SharedEntityVariables.WALK_SPEED, 0.35).asExpressible()
|
||||
override fun getVariables(entity: LivingEntity): List<MoLangConfigVariable> {
|
||||
return listOf(walkSpeed).asVariables()
|
||||
}
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
if (entity !is PathfinderMob) {
|
||||
return null
|
||||
}
|
||||
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.absent(MemoryModuleType.WALK_TARGET),
|
||||
it.absent(CobblemonMemories.PATH_COOLDOWN)
|
||||
).apply(it) { walkTarget, pathCooldown ->
|
||||
Trigger { world, entity, time ->
|
||||
if (!entity.isInLiquid) {
|
||||
return@Trigger false
|
||||
}
|
||||
|
||||
entity as PathfinderMob
|
||||
|
||||
val iterable = BlockPos.betweenClosed(
|
||||
Mth.floor(entity.x - 8.0),
|
||||
entity.blockY,
|
||||
Mth.floor(entity.z - 8.0),
|
||||
Mth.floor(entity.x + 8.0),
|
||||
Mth.floor(entity.y + 2.0),
|
||||
Mth.floor(entity.z + 8.0)
|
||||
)
|
||||
|
||||
pathCooldown.setWithExpiry(true, 40L)
|
||||
|
||||
val blockPos = entity.closestPosition(iterable) {
|
||||
isSafeLandPosAround(entity.level() as ServerLevel, it, entity)
|
||||
} ?: return@Trigger false
|
||||
|
||||
walkTarget.set(WalkTarget(blockPos.above(), 0.35F, 1))
|
||||
return@Trigger true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun isSafeLandPos(world: ServerLevel, pos: BlockPos, mob: PathfinderMob): Boolean {
|
||||
val blockState = world.getBlockState(pos)
|
||||
|
||||
val isFluid = world.getFluidState(pos.above()).isEmpty.not()
|
||||
val solidBelow = blockState.isSolid
|
||||
|
||||
if (isFluid || !solidBelow) {
|
||||
return false
|
||||
} else {
|
||||
val mutable = BlockPos.MutableBlockPos()
|
||||
val minY = pos.y + 1
|
||||
val maxY = minY + ceil(mob.bbHeight).toInt()
|
||||
for (y in minY..maxY) {
|
||||
val aboveState = world.getBlockState(mutable.set(pos.x, y, pos.z))
|
||||
val canPathfindThroughAbove = aboveState.isPathfindable(PathComputationType.LAND)
|
||||
if (!canPathfindThroughAbove) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
fun isSafeLandPosAround(world: ServerLevel, pos: BlockPos, mob: PathfinderMob): Boolean {
|
||||
val minX = pos.x
|
||||
val maxX = minX + floor(mob.bbWidth).toInt()
|
||||
val minZ = pos.z
|
||||
val maxZ = minZ + floor(mob.bbWidth).toInt()
|
||||
|
||||
val mutable = BlockPos.MutableBlockPos()
|
||||
for (x in minX..maxX) {
|
||||
for (z in minZ..maxZ) {
|
||||
if (!isSafeLandPos(world, mutable.set(x, pos.y, z), mob)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.GoToSleepTask
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class GoToSleepTaskConfig : SingleTaskConfig {
|
||||
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
return WrapperLivingEntityTask(GoToSleepTask.create(), PokemonEntity::class.java)
|
||||
}
|
||||
}
|
||||
+16
-13
@@ -8,29 +8,32 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.config.task.GoToHealingMachineTaskConfig.Companion.SELF_HEALING
|
||||
import com.cobblemon.mod.common.api.ai.config.task.GoToHealingMachineTaskConfig.Companion.USE_HEALING_MACHINES
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.entity.npc.ai.HealUsingHealingMachineTask
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class HealUsingHealingMachineTaskConfig : SingleTaskConfig {
|
||||
val condition: ExpressionLike = "true".asExpressionLike()
|
||||
val horizontalUseRange = "3".asExpression()
|
||||
val verticalUseRange = "2".asExpression()
|
||||
val condition = booleanVariable(SELF_HEALING, USE_HEALING_MACHINES, true).asExpressible()
|
||||
val horizontalUseRange: ExpressionOrEntityVariable = Either.left("2".asExpression())
|
||||
val verticalUseRange: ExpressionOrEntityVariable = Either.left("1".asExpression())
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(condition, horizontalUseRange, verticalUseRange).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
return HealUsingHealingMachineTask(horizontalUseRange, verticalUseRange)
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
return HealUsingHealingMachineTask(horizontalUseRange.asExpression(), verticalUseRange.asExpression())
|
||||
}
|
||||
}
|
||||
+23
-11
@@ -8,29 +8,41 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.entity.npc.ai.LookAtBattlingPokemonTask
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.resolveInt
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class LookAtBattlingPokemonTaskConfig : SingleTaskConfig {
|
||||
val minDurationTicks = "40".asExpression()
|
||||
val maxDurationTicks = "80".asExpression()
|
||||
companion object {
|
||||
const val LOOK_AT_BATTLING_POKEMON = "look_at_battling_pokemon"
|
||||
}
|
||||
|
||||
val condition = booleanVariable(SharedEntityVariables.BATTLING_CATEGORY, LOOK_AT_BATTLING_POKEMON, true).asExpressible()
|
||||
val minDurationTicks: ExpressionOrEntityVariable = Either.left("40".asExpression())
|
||||
val maxDurationTicks: ExpressionOrEntityVariable = Either.left("80".asExpression())
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition,
|
||||
minDurationTicks,
|
||||
maxDurationTicks
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!resolveBooleanVariable(LOOK_AT_BATTLING_POKEMON)) return null
|
||||
return LookAtBattlingPokemonTask.create(
|
||||
minDurationTicks = runtime.resolveInt(minDurationTicks),
|
||||
maxDurationTicks = runtime.resolveInt(maxDurationTicks)
|
||||
minDurationTicks = minDurationTicks.resolveInt(),
|
||||
maxDurationTicks = maxDurationTicks.resolveInt()
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
+19
-14
@@ -8,29 +8,34 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveFloat
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.SEE_DISTANCE
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.SetEntityLookTarget
|
||||
|
||||
class LookAtEntitiesTaskConfig : SingleTaskConfig {
|
||||
val condition: ExpressionLike = "true".asExpressionLike()
|
||||
val maxDistance = "15".asExpression()
|
||||
companion object {
|
||||
const val LOOK_AT_ENTITIES = "look_at_entities"
|
||||
}
|
||||
|
||||
val condition = booleanVariable(SharedEntityVariables.LOOKING_CATEGORY, LOOK_AT_ENTITIES, true).asExpressible()
|
||||
val maxDistance = numberVariable(SharedEntityVariables.LOOKING_CATEGORY, SEE_DISTANCE, 15).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition,
|
||||
maxDistance
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
return SetEntityLookTarget.create(runtime.resolveFloat(maxDistance))
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
return SetEntityLookTarget.create(maxDistance.resolveFloat())
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -8,13 +8,15 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.npc.ai.LookAtSpeakerTask
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class LookAtSpeakerTaskConfig : SingleTaskConfig {
|
||||
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
) = LookAtSpeakerTask.create()
|
||||
}
|
||||
+18
-15
@@ -8,33 +8,36 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveInt
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.Mob
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.LookAtTargetSink
|
||||
|
||||
class LookAtTargetTaskConfig : SingleTaskConfig {
|
||||
val condition: ExpressionLike = "true".asExpressionLike()
|
||||
val minDurationTicks: Expression = "40".asExpression()
|
||||
val maxDurationTicks: Expression = "80".asExpression()
|
||||
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
val minDurationTicks: ExpressionOrEntityVariable = Either.left("80".asExpression())
|
||||
val maxDurationTicks: ExpressionOrEntityVariable = Either.left("160".asExpression())
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition,
|
||||
minDurationTicks,
|
||||
maxDurationTicks
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
return WrapperLivingEntityTask(LookAtTargetSink(runtime.resolveInt(minDurationTicks), runtime.resolveInt(maxDurationTicks)), Mob::class.java)
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
return WrapperLivingEntityTask(LookAtTargetSink(minDurationTicks.resolveInt(), maxDurationTicks.resolveInt()), Mob::class.java)
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.LookAtTargetedBattlePokemonTask
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class LookAtTargetedBattlePokemonTaskConfig : SingleTaskConfig {
|
||||
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity> {
|
||||
return WrapperLivingEntityTask(LookAtTargetedBattlePokemonTask.create(), PokemonEntity::class.java)
|
||||
}
|
||||
}
|
||||
+18
-7
@@ -8,18 +8,29 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.ai.config.task.SharedEntityVariables.LOOKING_CATEGORY
|
||||
import com.cobblemon.mod.common.entity.ai.LookInDirectionTask
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class LookInDirectionTaskConfig : SingleTaskConfig {
|
||||
var yaw: Expression = "0".asExpression()
|
||||
var pitch: Expression = "0".asExpression()
|
||||
var condition = booleanVariable(LOOKING_CATEGORY, "locked_rotation", true).asExpressible()
|
||||
var yaw = numberVariable(LOOKING_CATEGORY, "locked_yaw", 0F).asExpressible()
|
||||
var pitch = numberVariable(LOOKING_CATEGORY, "locked_pitch", 0F).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition,
|
||||
yaw,
|
||||
pitch
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
) = LookInDirectionTask(yaw, pitch)
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
) = LookInDirectionTask(
|
||||
shouldLock = condition.asExpression(),
|
||||
yaw = yaw.asExpression(),
|
||||
pitch = pitch.asExpression()
|
||||
)
|
||||
}
|
||||
+17
-14
@@ -8,32 +8,35 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.entity.npc.ai.MeleeAttackTask
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class MeleeAttackTaskConfig : SingleTaskConfig {
|
||||
val condition = "true".asExpressionLike()
|
||||
val range = "1.5".asExpression()
|
||||
val cooldownTicks = "30".asExpression()
|
||||
val condition = booleanVariable(SharedEntityVariables.ATTACKING_CATEGORY, "attacks_melee", true).asExpressible()
|
||||
val range = numberVariable(SharedEntityVariables.ATTACKING_CATEGORY, "melee_range", 1.5F).asExpressible()
|
||||
val cooldownTicks = numberVariable(SharedEntityVariables.ATTACKING_CATEGORY, "melee_cooldown", 30).asExpressible()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition,
|
||||
range,
|
||||
cooldownTicks
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!condition.resolveBoolean()) return null
|
||||
|
||||
return MeleeAttackTask.create(
|
||||
range = range,
|
||||
cooldownTicks = cooldownTicks
|
||||
range = range.asExpression(),
|
||||
cooldownTicks = cooldownTicks.asExpression()
|
||||
)
|
||||
}
|
||||
}
|
||||
+14
-6
@@ -8,20 +8,28 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.entity.ai.MoveToAttackTargetTask
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
class MoveToAttackTargetTaskConfig : SingleTaskConfig {
|
||||
val speedMultiplier = "0.5".asExpression()
|
||||
val closeEnoughDistance = "1".asExpression()
|
||||
val speedMultiplier = numberVariable(SharedEntityVariables.ATTACKING_CATEGORY, "attacking_movement_speed", 0.5).asExpressible()
|
||||
val closeEnoughDistance: ExpressionOrEntityVariable = Either.left("1".asExpression())
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
speedMultiplier,
|
||||
closeEnoughDistance
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
) = MoveToAttackTargetTask.create(
|
||||
speedMultiplier = speedMultiplier,
|
||||
closeEnoughDistance = closeEnoughDistance
|
||||
speedMultiplier = speedMultiplier.asExpression(),
|
||||
closeEnoughDistance = closeEnoughDistance.asExpression()
|
||||
)
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.ai.WrapperLivingEntityTask
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.tasks.MoveToOwnerTask
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
|
||||
class MoveToOwnerTaskConfig : SingleTaskConfig {
|
||||
val condition: ExpressionOrEntityVariable = Either.left("true".asExpression())
|
||||
var completionRange: ExpressionOrEntityVariable = Either.left("4.0".asExpression())
|
||||
var speedMultiplier: ExpressionOrEntityVariable = Either.left("0.4".asExpression())
|
||||
var teleportDistance: ExpressionOrEntityVariable = Either.left("24.0".asExpression())
|
||||
var maxDistance: ExpressionOrEntityVariable = Either.left("14.0".asExpression())
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(
|
||||
condition,
|
||||
completionRange,
|
||||
speedMultiplier,
|
||||
teleportDistance,
|
||||
maxDistance
|
||||
).asVariables()
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
return WrapperLivingEntityTask(
|
||||
MoveToOwnerTask.create(
|
||||
condition = condition.asExpression(),
|
||||
completionRange = completionRange.asExpression(),
|
||||
speedMultiplier = speedMultiplier.asExpression(),
|
||||
teleportDistance = teleportDistance.asExpression(),
|
||||
maxDistance = maxDistance.asExpression()
|
||||
),
|
||||
PokemonEntity::class.java
|
||||
)
|
||||
}
|
||||
}
|
||||
+8
-8
@@ -8,17 +8,15 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.toDF
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.DoNothing
|
||||
import net.minecraft.world.entity.ai.behavior.RunOne
|
||||
|
||||
/**
|
||||
@@ -34,15 +32,17 @@ import net.minecraft.world.entity.ai.behavior.RunOne
|
||||
class OneOfTaskConfig : SingleTaskConfig {
|
||||
class OneOfTaskOption {
|
||||
val weight: Int = 1
|
||||
val task: TaskConfig = SingleTaskConfig { _, _ -> DoNothing(0, 1) }
|
||||
val task: TaskConfig = SingleTaskConfig.nothing()
|
||||
}
|
||||
|
||||
val condition: ExpressionLike = "true".asExpressionLike()
|
||||
val options = mutableListOf<OneOfTaskOption>()
|
||||
|
||||
override fun createTask(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
override fun getVariables(entity: LivingEntity) = options.flatMap { it.task.getVariables(entity) }
|
||||
|
||||
override fun createTask(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): BehaviorControl<in LivingEntity>? {
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!runtime.resolveBoolean(condition)) return null
|
||||
return RunOne(options.map { it.task.createTasks(entity, brainConfigurationContext).first() toDF it.weight })
|
||||
return RunOne(options.map { it.task.createTasks(entity, behaviourConfigurationContext).first() toDF it.weight })
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.BlockPosTracker
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder
|
||||
import net.minecraft.world.entity.ai.behavior.declarative.Trigger
|
||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class PointToSpawnTaskConfig : SingleTaskConfig {
|
||||
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
|
||||
override fun createTask(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): BehaviorControl<in LivingEntity>? {
|
||||
return BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.registered(MemoryModuleType.LOOK_TARGET),
|
||||
it.absent(MemoryModuleType.WALK_TARGET)
|
||||
).apply(it) { lookTargetMemory, _ ->
|
||||
Trigger { world, entity, _ ->
|
||||
val lookTarget = entity.brain.getMemory(MemoryModuleType.LOOK_TARGET).orElse(null)
|
||||
if (lookTarget == null) {
|
||||
lookTargetMemory.set(BlockPosTracker(Vec3.atCenterOf(entity.level().sharedSpawnPos).with(Direction.Axis.Y, entity.eyeY)))
|
||||
return@Trigger true
|
||||
} else {
|
||||
return@Trigger false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Task Configuration
|
||||
|
||||
A task configuration is responsible for producing one or multiple tasks as part of a
|
||||
[BrainConfiguration](../README.md). Tasks are the smallest unit of behaviour in a brain and are executed
|
||||
[Behaviour Configuration](../README.md). Tasks are the smallest unit of behaviour in a brain and are executed
|
||||
as part of an activity.
|
||||
|
||||
A task configuration can be a simple string that represents the type of task to create, or a JSON object
|
||||
@@ -183,4 +183,17 @@ the script to avoid lagging the game.
|
||||
### look_in_direction
|
||||
The 'look_in_direction' type creates a task that will make the entity look in a specific direction at all times where they aren't being told to look elsewhere.
|
||||
- `yaw`: A MoLang expression that determines the yaw angle (degrees) of the entity. Defaults to `0`.
|
||||
- `pitch`: A MoLang expression that determines the pitch angle (degrees) of the entity. Defaults to `0`.
|
||||
- `pitch`: A MoLang expression that determines the pitch angle (degrees) of the entity. Defaults to `0`.
|
||||
|
||||
### move_to_owner
|
||||
The 'move_to_owner' type creates a task that will make the entity move to its owner. This will only work for entities that
|
||||
can be owned, like Pokémon.
|
||||
- `condition`: A MoLang expression (with `q.entity` as the entity) that determines if this entire task should exist on the entity or not. This runs at the time of entity creation, not on tick.
|
||||
- `completionRange`: A MoLang expression that determines the distance from the owner that the entity needs to be for the path to be considered complete. Defaults to 4.
|
||||
- `speedMultiplier`: A MoLang expression that determines the speed multiplier for moving to the owner. Defaults to 0.4 which is slightly above the normal walk speed.
|
||||
- `teleportDistance`: A MoLang expression that determines the distance from the owner the entity must be before it resorts to teleporting. A value of -1 will cause it to never teleport. Defaults to 24.
|
||||
- `maxDistance`: A MoLang expression that determines the maximum distance from the owner that the entity can be to move to them. Defaults to 14.
|
||||
|
||||
### point_to_spawn
|
||||
The 'point_to_spawn' type creates a task that will make the entity point to the spawn point of the world whenever they
|
||||
are not moving and are idling. This is basically only here for Nosepass.
|
||||
+8
-8
@@ -8,17 +8,15 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.struct.QueryStruct
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.weightedSelection
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.DoNothing
|
||||
|
||||
/**
|
||||
* Randomly chooses one of the possible tasks to add to the brain. This differs from [OneOfTaskConfig] in that
|
||||
@@ -34,19 +32,21 @@ import net.minecraft.world.entity.ai.behavior.DoNothing
|
||||
class RandomTaskConfig : TaskConfig {
|
||||
class RandomTaskChoice {
|
||||
val weight = 1.0
|
||||
val task: TaskConfig = SingleTaskConfig { _, _ -> DoNothing(0, 1) }
|
||||
val task: TaskConfig = SingleTaskConfig.nothing()
|
||||
}
|
||||
|
||||
val condition: ExpressionLike = "true".asExpressionLike()
|
||||
val choices = mutableListOf<RandomTaskChoice>()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = choices.flatMap { it.task.getVariables(entity) }
|
||||
|
||||
override fun createTasks(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): List<BehaviorControl<in LivingEntity>> {
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: QueryStruct(hashMapOf()))
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
if (!runtime.resolveBoolean(condition)) return emptyList()
|
||||
val task = choices.weightedSelection { it.weight }?.task ?: throw IllegalStateException("No tasks to choose from in random_task config")
|
||||
return task.createTasks(entity, brainConfigurationContext)
|
||||
return task.createTasks(entity, behaviourConfigurationContext)
|
||||
}
|
||||
}
|
||||
@@ -9,11 +9,12 @@
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.asVariables
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
@@ -31,18 +32,28 @@ import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
||||
* @since December 2nd, 2024
|
||||
*/
|
||||
class RunScript : SingleTaskConfig {
|
||||
val script = cobblemonResource("dummy")
|
||||
companion object {
|
||||
const val SCRIPT_CATEGORY = "script"
|
||||
}
|
||||
|
||||
val script = stringVariable(SCRIPT_CATEGORY, "script", "cobblemon:dummy_script").asExpressible()
|
||||
val variables = mutableListOf<MoLangConfigVariable>()
|
||||
|
||||
override fun getVariables(entity: LivingEntity) = listOf(script).asVariables() + variables
|
||||
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? = BehaviorBuilder.create {
|
||||
it.group(
|
||||
it.registered(MemoryModuleType.LOOK_TARGET) // I think I need to have at least something here?
|
||||
).apply(it) { _ ->
|
||||
Trigger { world, entity, _ ->
|
||||
runtime.withQueryValue("entity", (entity as? PosableEntity)?.struct ?: entity.asMostSpecificMoLangValue())
|
||||
return@Trigger CobblemonScripts.run(script, runtime) == DoubleValue.ONE
|
||||
runtime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
return@Trigger CobblemonScripts.run(
|
||||
identifier = script.resolveString().asIdentifierDefaultingNamespace(),
|
||||
runtime = runtime
|
||||
) == DoubleValue.ONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
object SharedEntityVariables {
|
||||
const val MOVEMENT_CATEGORY = "movement"
|
||||
const val FEAR_CATEGORY = "fear"
|
||||
const val ATTACKING_CATEGORY = "attacking"
|
||||
const val BATTLING_CATEGORY = "battling"
|
||||
const val LOOKING_CATEGORY = "looking"
|
||||
|
||||
const val WALK_SPEED = "walk_speed"
|
||||
const val FLEE_SPEED_MULTIPLIER = "flee_speed_multiplier"
|
||||
const val FLEE_DESIRED_DISTANCE = "flee_desired_distance"
|
||||
const val SEE_DISTANCE = "see_distance"
|
||||
}
|
||||
+22
-8
@@ -8,17 +8,31 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.cobblemon.mod.common.api.ai.BrainConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.npc.configuration.MoLangConfigVariable
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
import net.minecraft.world.entity.ai.behavior.DoNothing
|
||||
|
||||
fun interface SingleTaskConfig : TaskConfig {
|
||||
override fun createTasks(
|
||||
entity: LivingEntity,
|
||||
brainConfigurationContext: BrainConfigurationContext
|
||||
): List<BehaviorControl<in LivingEntity>> {
|
||||
return createTask(entity, brainConfigurationContext)?.let { listOf(it) } ?: emptyList()
|
||||
interface SingleTaskConfig : TaskConfig {
|
||||
companion object {
|
||||
fun nothing() = object : SingleTaskConfig {
|
||||
override fun getVariables(entity: LivingEntity) = emptyList<MoLangConfigVariable>()
|
||||
override fun createTask(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): BehaviorControl<in LivingEntity>? {
|
||||
return DoNothing(0, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun createTask(entity: LivingEntity, brainConfigurationContext: BrainConfigurationContext): BehaviorControl<in LivingEntity>?
|
||||
override fun createTasks(
|
||||
entity: LivingEntity,
|
||||
behaviourConfigurationContext: BehaviourConfigurationContext
|
||||
): List<BehaviorControl<in LivingEntity>> {
|
||||
return createTask(entity, behaviourConfigurationContext)?.let { listOf(it) } ?: emptyList()
|
||||
}
|
||||
|
||||
fun createTask(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext): BehaviorControl<in LivingEntity>?
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user