mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-31 14:28:54 -04:00
Compare commits
277
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 | ||
|
|
17f686488e | ||
|
|
db574332e5 | ||
|
|
b88f4335ee | ||
|
|
1bfe5e2044 | ||
|
|
ace65eda66 | ||
|
|
c3d482c78f | ||
|
|
7effc4c853 | ||
|
|
4cd504126b | ||
|
|
60ee7b819c | ||
|
|
28548d5b19 | ||
|
|
e6ec690811 | ||
|
|
dac49c2f42 | ||
|
|
874a5d2e8f | ||
|
|
70e49bbbdb | ||
|
|
39fce8ca06 | ||
|
|
d288fe46da | ||
|
|
cefc97320a | ||
|
|
374fc44089 | ||
|
|
f7664a04db | ||
|
|
2d772f5bf7 | ||
|
|
63af1713b9 | ||
|
|
8fecb12829 | ||
|
|
d0b50a1ee0 | ||
|
|
07497d653e | ||
|
|
dfb28ed185 | ||
|
|
0cc9a75255 | ||
|
|
abfd718681 | ||
|
|
8271b7a979 | ||
|
|
251c2df78e | ||
|
|
c03e30bd9c | ||
|
|
ecc793350a | ||
|
|
a71bad07bd | ||
|
|
1769af7385 | ||
|
|
88e38bfa1a | ||
|
|
507a9a54b5 | ||
|
|
0b72a072bd | ||
|
|
c927cae609 | ||
|
|
10bf69a79b | ||
|
|
172293c813 | ||
|
|
9bb653b8b7 | ||
|
|
a7b55e5d03 | ||
|
|
28db655376 | ||
|
|
006736cd71 | ||
|
|
f240dc1963 | ||
|
|
535c5f2e67 | ||
|
|
8b209e081b | ||
|
|
f7f276ecfb | ||
|
|
fc0cd0dac4 | ||
|
|
019245472f | ||
|
|
cefb502f10 | ||
|
|
ee5e4d33b2 | ||
|
|
0fd954ffa5 | ||
|
|
60d3d737f9 | ||
|
|
1caf963323 | ||
|
|
bb94f872a9 | ||
|
|
65ab0f48e4 |
No files matched your search
+3
-2
@@ -2,8 +2,9 @@
|
||||
- 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.
|
||||
- Growlithe and Arcanine intimidate Skeletons.
|
||||
- Meowth intimidate Creepers and Phantoms.
|
||||
- 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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
+99
-4
@@ -21,8 +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
|
||||
|
||||
@@ -34,12 +41,17 @@
|
||||
- Grumpig
|
||||
- Snorunt
|
||||
- Glalie
|
||||
- Latias
|
||||
- Latios
|
||||
|
||||
#### Gen 4
|
||||
- Bronzor
|
||||
- Bronzong
|
||||
- Croagunk
|
||||
- Toxicroak
|
||||
- Froslass
|
||||
- Glameow
|
||||
- Purugly
|
||||
|
||||
#### Gen 5
|
||||
- Pansage
|
||||
@@ -52,10 +64,22 @@
|
||||
- Musharna
|
||||
- Blitzle
|
||||
- Zebstrika
|
||||
- Drilbur
|
||||
- Excadrill
|
||||
- Trubbish
|
||||
- Garbodor
|
||||
- Gothita
|
||||
- Gothorita
|
||||
- Gothitelle
|
||||
- Solosis
|
||||
- Duosion
|
||||
- Reuniclus
|
||||
|
||||
#### Gen 6
|
||||
- Inkay
|
||||
- Malamar
|
||||
- Hawlucha
|
||||
- Dedenne
|
||||
- Noibat
|
||||
- Noivern
|
||||
|
||||
@@ -65,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
|
||||
@@ -84,6 +115,15 @@
|
||||
- Delphox
|
||||
- Cinderace
|
||||
- Kangaskhan
|
||||
- Gossifleur
|
||||
- Eldegoss
|
||||
- Stonjourner
|
||||
- Wailmer
|
||||
- Lechonk
|
||||
- Oinkologne
|
||||
- Dratini
|
||||
- Dragonair
|
||||
- Dragonite
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
- Gyarados
|
||||
@@ -101,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.
|
||||
@@ -136,10 +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)
|
||||
@@ -180,6 +253,16 @@
|
||||
- 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.
|
||||
@@ -206,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)
|
||||
@@ -225,8 +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)
|
||||
|
||||
@@ -1041,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:
|
||||
@@ -2348,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.
|
||||
+5
-4
@@ -6,9 +6,10 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.block
|
||||
package com.cobblemon.mod.common.duck;
|
||||
|
||||
import com.cobblemon.mod.common.block.grower.SaccharineTreeGrower
|
||||
import net.minecraft.world.level.block.SaplingBlock
|
||||
import net.minecraft.world.item.crafting.RecipeManager;
|
||||
|
||||
class SaccharineSaplingBlock(properties : Properties) : SaplingBlock(SaccharineTreeGrower(), properties)
|
||||
public interface RecipeAwareSlot {
|
||||
void setRecipeManager(RecipeManager recipeManager);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+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;
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -68,6 +68,8 @@ object CobblemonCommands {
|
||||
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,13 +8,14 @@
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.block.PotComponent
|
||||
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
|
||||
|
||||
@@ -70,6 +71,11 @@ object CobblemonItemComponents : PlatformRegistry<Registry<DataComponentType<*>>
|
||||
.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)
|
||||
Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.parse("cobblemon:bait"), BAIT)
|
||||
|
||||
@@ -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
|
||||
@@ -40,6 +41,7 @@ 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
|
||||
@@ -55,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
|
||||
@@ -188,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")
|
||||
@@ -336,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")
|
||||
|
||||
@@ -350,19 +361,19 @@ 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 PONIGIRI = create("ponigiri", PonigiriItem())
|
||||
@@ -371,169 +382,84 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
val SINISTER_TEA = create("sinister_tea", SinisterTeaItem())
|
||||
|
||||
@JvmField
|
||||
val POKE_PUFF = pokepuffItem("poke_puff") // todo make a PokePuffItem class for friendship boosting purposes
|
||||
val POKE_PUFF = pokepuffItem("poke_puff")
|
||||
|
||||
// FOODS
|
||||
@JvmField
|
||||
val SWEET_HEART = noSettingsItem("sweet_heart") // todo make a SweetHeartItem class for breeding purposes
|
||||
|
||||
@JvmField
|
||||
val TASTY_TAIL = create("tasty_tail", object : Item(Properties().stacksTo(16)
|
||||
.food(FoodProperties.Builder()
|
||||
.nutrition(8)
|
||||
.saturationModifier(12.8F)
|
||||
.alwaysEdible()
|
||||
.build())) {})
|
||||
val TASTY_TAIL = noSettingsItem("tasty_tail")
|
||||
|
||||
@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) // todo get final values for this from vera
|
||||
.saturationModifier(1.2F) // todo get final values for this from vera
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F) // todo get final values for this from vera
|
||||
.alwaysEdible()
|
||||
.build())) {})
|
||||
@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 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) // todo get final values for this from vera
|
||||
.saturationModifier(1.2F) // todo get final values for this from vera
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F) // todo get final values for this from vera
|
||||
.alwaysEdible()
|
||||
.build())) {})
|
||||
@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 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) // todo get final values for this from vera
|
||||
.saturationModifier(1.2F) // todo get final values for this from vera
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F) // todo get final values for this from vera
|
||||
.alwaysEdible()
|
||||
.build())) {})
|
||||
@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 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) // todo get final values for this from vera
|
||||
.saturationModifier(1.2F) // todo get final values for this from vera
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F) // todo get final values for this from vera
|
||||
.alwaysEdible()
|
||||
.build())) {})
|
||||
@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 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) // todo get final values for this from vera
|
||||
.saturationModifier(1.2F) // todo get final values for this from vera
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F) // todo get final values for this from vera
|
||||
.alwaysEdible()
|
||||
.build())) {})
|
||||
@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 SHALOUR_SABLE = create("shalour_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) // todo get final values for this from vera
|
||||
.saturationModifier(1.2F) // todo get final values for this from vera
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F) // todo get final values for this from vera
|
||||
.alwaysEdible()
|
||||
.build())) {})
|
||||
@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 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) // todo get final values for this from vera
|
||||
.saturationModifier(1.2F) // todo get final values for this from vera
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F) // todo get final values for this from vera
|
||||
.alwaysEdible()
|
||||
.build())) {})
|
||||
@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
|
||||
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) // todo get final values for this from vera
|
||||
.saturationModifier(1.2F) // todo get final values for this from vera
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F) // todo get final values for this from vera
|
||||
.alwaysEdible()
|
||||
.build())) {})
|
||||
@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 // 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 SMOKED_TAIL_CURRY = regionalFoodItem("smoked_tail_curry", 16, 10, 1.2f, MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1f, false, ItemStack(Items.BOWL, 1))
|
||||
|
||||
@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) // todo get final values for this from vera
|
||||
.saturationModifier(1.2F) // todo get final values for this from vera
|
||||
.effect(MobEffectInstance(MobEffects.ABSORPTION, 900, 0), 1F) // todo get final values for this from vera
|
||||
.alwaysEdible()
|
||||
.build())) {})
|
||||
@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)
|
||||
|
||||
/*@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 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?
|
||||
// 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) // todo get final values for this from vera
|
||||
.saturationModifier(1.2F) // todo get final values for this from vera
|
||||
.alwaysEdible()
|
||||
.build())) {})
|
||||
.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) // todo get final values for this from vera
|
||||
.saturationModifier(1.2F) // todo get final values for this from vera
|
||||
.alwaysEdible()
|
||||
.build())) {})
|
||||
.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) // todo get final values for this from vera
|
||||
.saturationModifier(1.2F) // todo get final values for this from vera
|
||||
.alwaysEdible()
|
||||
.build())) {})
|
||||
.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) // todo get final values for this from vera
|
||||
.saturationModifier(1.2F) // todo get final values for this from vera
|
||||
.alwaysEdible()
|
||||
.build())) {})
|
||||
|
||||
// todo etc?
|
||||
.build())))
|
||||
|
||||
//@JvmField
|
||||
//val SCATTER_BANG = this.create("scatter_bang", ScatterBangItem(Item.Settings()))
|
||||
@@ -557,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())
|
||||
@@ -597,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
|
||||
@@ -675,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() }
|
||||
@@ -729,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)
|
||||
@@ -753,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))
|
||||
@@ -775,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
|
||||
@@ -994,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
|
||||
@@ -1024,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
|
||||
@@ -1046,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
|
||||
@@ -1579,6 +1548,39 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
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 {
|
||||
@@ -1590,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")
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -1624,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)
|
||||
@@ -1638,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"
|
||||
@@ -1668,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
|
||||
}
|
||||
@@ -1686,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()))
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -259,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()))
|
||||
|
||||
@@ -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<*>>>
|
||||
|
||||
@@ -125,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
|
||||
@@ -216,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")
|
||||
|
||||
+2
-1
@@ -32,6 +32,7 @@ class PokemonCriterion(
|
||||
}
|
||||
|
||||
override fun matches(player: ServerPlayer, context: Pokemon): Boolean {
|
||||
return (species.equals(context.species.resourceIdentifier.path) || species.equals(context.species.resourceIdentifier.toString())) && 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)
|
||||
}
|
||||
}
|
||||
+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()
|
||||
}
|
||||
}
|
||||
@@ -94,7 +94,8 @@ interface TaskConfig {
|
||||
cobblemonResource("point_to_spawn") to PointToSpawnTaskConfig::class.java,
|
||||
cobblemonResource("eat_grass") to EatGrassTaskConfig::class.java,
|
||||
cobblemonResource("find_air") to FindAirTaskConfig::class.java,
|
||||
cobblemonResource("go_to_land") to GoToLandTaskConfig::class.java
|
||||
cobblemonResource("go_to_land") to GoToLandTaskConfig::class.java,
|
||||
cobblemonResource("battle_flight_task") to BattleFlightTaskConfig::class.java
|
||||
)
|
||||
|
||||
val runtime = MoLangRuntime().setup()
|
||||
|
||||
@@ -125,10 +125,11 @@ open class PartySelectPokemonDTO(
|
||||
val heldItem: ItemStack = ItemStack.EMPTY,
|
||||
var currentHealth: Int,
|
||||
var maxHealth: Int,
|
||||
var enabled: Boolean
|
||||
var enabled: Boolean,
|
||||
var hoverText: List<Component> = emptyList()
|
||||
) {
|
||||
@JvmOverloads
|
||||
constructor(pokemon: Pokemon, enabled: Boolean = true): this(
|
||||
constructor(pokemon: Pokemon, enabled: Boolean = true, hoverText: List<Component> = emptyList()): this(
|
||||
pokemonProperties = pokemon.createPokemonProperties(
|
||||
PokemonPropertyExtractor.SPECIES,
|
||||
PokemonPropertyExtractor.LEVEL,
|
||||
@@ -140,7 +141,8 @@ open class PartySelectPokemonDTO(
|
||||
heldItem = pokemon.heldItemNoCopy(),
|
||||
currentHealth = pokemon.currentHealth,
|
||||
maxHealth = pokemon.maxHealth,
|
||||
enabled = enabled
|
||||
enabled = enabled,
|
||||
hoverText = hoverText
|
||||
)
|
||||
|
||||
constructor(buffer: RegistryFriendlyByteBuf): this(
|
||||
@@ -149,7 +151,8 @@ open class PartySelectPokemonDTO(
|
||||
heldItem = buffer.readItemStack(),
|
||||
currentHealth = buffer.readInt(),
|
||||
maxHealth = buffer.readInt(),
|
||||
enabled = buffer.readBoolean()
|
||||
enabled = buffer.readBoolean(),
|
||||
hoverText = buffer.readList { buffer.readText() }
|
||||
)
|
||||
|
||||
fun writeToBuffer(buffer: RegistryFriendlyByteBuf) {
|
||||
@@ -159,6 +162,6 @@ open class PartySelectPokemonDTO(
|
||||
buffer.writeInt(currentHealth)
|
||||
buffer.writeInt(maxHealth)
|
||||
buffer.writeBoolean(enabled)
|
||||
buffer.writeCollection(hoverText) { _, text -> buffer.writeText(text) }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -29,9 +29,12 @@ private val bubbleColourMap = mapOf(
|
||||
|
||||
fun getColourMixFromSeasonings(seasonings: List<ItemStack>, forBubbles: Boolean = false): Int? {
|
||||
val flavors = seasonings
|
||||
.flatMap { Seasonings.getFlavoursFromItemStack(it).entries }
|
||||
.groupingBy { it.key }
|
||||
.fold(0) { acc, entry -> acc + entry.value }
|
||||
.mapNotNull { Seasonings.getFlavoursFromItemStack(it) }
|
||||
.flatMap { it.entries }
|
||||
.groupingBy { it.key }
|
||||
.fold(0) { acc, entry -> acc + entry.value }
|
||||
|
||||
if (flavors.isEmpty()) return null
|
||||
|
||||
val maxFlavorValue = flavors.values.maxOrNull()
|
||||
val dominantFlavors = flavors.filter { it.value == maxFlavorValue }.map { it.key }
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.cooking
|
||||
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
|
||||
data class MobCookingEffects(
|
||||
val appliedEffects: List<SerializableMobEffectInstance> = emptyList()
|
||||
) {
|
||||
companion object {
|
||||
val CODEC: Codec<MobCookingEffects> = RecordCodecBuilder.create { builder ->
|
||||
builder.group(
|
||||
SerializableMobEffectInstance.CODEC.listOf().optionalFieldOf("appliedEffects", emptyList()).forGetter { it.appliedEffects }
|
||||
).apply(builder, ::MobCookingEffects)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,21 +52,6 @@ object MobEffectUtils {
|
||||
}
|
||||
|
||||
private fun mergeAmplifiers(amplifiers: List<Int>): Int {
|
||||
if (amplifiers.isEmpty()) return 0
|
||||
|
||||
val sorted = amplifiers.sortedDescending()
|
||||
var result = 0.0
|
||||
|
||||
for ((index, value) in sorted.withIndex()) {
|
||||
val multiplier = when (index) {
|
||||
0 -> 1.0
|
||||
1 -> 0.75
|
||||
2 -> 0.5
|
||||
else -> 0.25
|
||||
}
|
||||
result += (value + 1) * multiplier
|
||||
}
|
||||
|
||||
return ceil(result).toInt() - 1
|
||||
return amplifiers.maxOrNull() ?: 0 // we do not want the power of the effects to combine, just take the highest one used of that type
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,8 @@ import net.minecraft.network.codec.ByteBufCodecs
|
||||
import net.minecraft.network.codec.StreamCodec
|
||||
import net.minecraft.world.item.DyeColor
|
||||
import net.minecraft.world.item.Item
|
||||
import java.util.Optional
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
|
||||
data class Seasoning(
|
||||
val ingredient: RegistryLikeCondition<Item>,
|
||||
@@ -29,33 +31,33 @@ data class Seasoning(
|
||||
@SerializedName("colour", alternate = ["color"])
|
||||
val colour: DyeColor,
|
||||
@SerializedName("baitEffects")
|
||||
val baitEffects: List<SpawnBait.Effect> = emptyList(),
|
||||
val baitEffects: List<SpawnBait.Effect>? = null,
|
||||
@SerializedName("food")
|
||||
val food: Food? = null,
|
||||
@SerializedName("mobEffects")
|
||||
val mobEffects: MobCookingEffects? = null
|
||||
val mobEffects: List<SerializableMobEffectInstance>? = null
|
||||
) {
|
||||
companion object {
|
||||
val CODEC: Codec<Seasoning> = RecordCodecBuilder.create { builder ->
|
||||
builder.group(
|
||||
ITEM_REGISTRY_LIKE_CODEC.fieldOf("ingredient").forGetter { it.ingredient },
|
||||
Codec.unboundedMap(Flavour.CODEC, Codec.INT).fieldOf("flavours").forGetter { it.flavours }, // Use map codec
|
||||
Codec.unboundedMap(Flavour.CODEC, Codec.INT).optionalFieldOf("flavours").forGetter { Optional.ofNullable(it.flavours) },
|
||||
DyeColor.CODEC.fieldOf("colour").forGetter { it.colour },
|
||||
SpawnBait.Effect.CODEC.listOf().optionalFieldOf("baitEffects", emptyList()).forGetter { it.baitEffects },
|
||||
Food.CODEC.optionalFieldOf("food", Food(0, 0f)).forGetter { it.food ?: Food(0, 0f) },
|
||||
MobCookingEffects.CODEC.optionalFieldOf("mobEffects", MobCookingEffects()).forGetter { it.mobEffects ?: MobCookingEffects() }
|
||||
).apply(builder, ::Seasoning)
|
||||
SpawnBait.Effect.CODEC.listOf().optionalFieldOf("baitEffects").forGetter { Optional.ofNullable(it.baitEffects) },
|
||||
Food.CODEC.optionalFieldOf("food").forGetter { Optional.ofNullable(it.food) },
|
||||
SerializableMobEffectInstance.CODEC.listOf().optionalFieldOf("mobEffects").forGetter { Optional.ofNullable(it.mobEffects) }
|
||||
).apply(builder) { item, flavours, colour, baitEffects, food, mobEffects ->
|
||||
Seasoning(
|
||||
item,
|
||||
flavours.getOrNull(),
|
||||
colour,
|
||||
baitEffects.getOrNull(),
|
||||
food.getOrNull(),
|
||||
mobEffects.getOrNull()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val STREAM_CODEC: StreamCodec<ByteBuf, Seasoning> = ByteBufCodecs.fromCodec(CODEC)
|
||||
|
||||
val BLANK_SEASONING = Seasoning(
|
||||
ingredient = RegistryLikeIdentifierCondition<Item>(cobblemonResource("blank")),
|
||||
flavours = Flavour.entries.associate { it to 0 },
|
||||
colour = DyeColor.WHITE,
|
||||
baitEffects = emptyList(),
|
||||
food = Food(),
|
||||
mobEffects = MobCookingEffects()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,10 @@ import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
|
||||
import com.cobblemon.mod.common.api.conditional.RegistryLikeIdentifierCondition
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.fishing.SpawnBait
|
||||
import com.cobblemon.mod.common.api.fishing.SpawnBaitEffects
|
||||
import com.cobblemon.mod.common.api.fishing.SpawnBaitUtils
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.item.components.FoodComponent
|
||||
import com.cobblemon.mod.common.net.messages.client.cooking.SeasoningRegistrySyncPacket
|
||||
import com.cobblemon.mod.common.util.adapters.IdentifierAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.ItemLikeConditionAdapter
|
||||
@@ -43,14 +46,6 @@ object Seasonings : JsonDataRegistry<Seasoning> {
|
||||
|
||||
val seasonings = mutableListOf<Seasoning>()
|
||||
|
||||
val BLANK_SEASONING = Seasoning(
|
||||
ingredient = RegistryLikeIdentifierCondition<Item>(cobblemonResource("blank")),
|
||||
flavours = emptyMap(),
|
||||
colour = DyeColor.WHITE,
|
||||
food = Food(),
|
||||
mobEffects = MobCookingEffects()
|
||||
)
|
||||
|
||||
override fun sync(player: ServerPlayer) {
|
||||
SeasoningRegistrySyncPacket(seasonings.toList()).sendToPlayer(player)
|
||||
}
|
||||
@@ -64,7 +59,7 @@ object Seasonings : JsonDataRegistry<Seasoning> {
|
||||
colour = it.colour,
|
||||
baitEffects = emptyList(),
|
||||
food = Food(),
|
||||
mobEffects = MobCookingEffects()
|
||||
mobEffects = emptyList()
|
||||
)
|
||||
}.toMutableMap()
|
||||
finalData.putAll(data)
|
||||
@@ -76,19 +71,27 @@ object Seasonings : JsonDataRegistry<Seasoning> {
|
||||
this.seasonings.addAll(seasonings)
|
||||
}
|
||||
|
||||
fun getFlavoursFromItemStack(stack: ItemStack): Map<Flavour, Int> {
|
||||
fun getFlavoursFromItemStack(stack: ItemStack): Map<Flavour, Int>? {
|
||||
val holder = stack.itemHolder
|
||||
val seasoning = seasonings.find { it.ingredient.fits(holder) } ?: BLANK_SEASONING
|
||||
val inherentFlavours = stack.get(CobblemonItemComponents.FLAVOUR)?.flavours ?: emptyMap()
|
||||
val seasoningFlavours = seasoning.flavours ?: emptyMap()
|
||||
val seasoning = seasonings.find { it.ingredient.fits(holder) }
|
||||
val inherentFlavours = stack.get(CobblemonItemComponents.FLAVOUR)?.flavours
|
||||
val seasoningFlavours = seasoning?.flavours
|
||||
|
||||
return seasoningFlavours.mapValues { (flavour, value) ->
|
||||
inherentFlavours.getOrDefault(flavour, 0) + value
|
||||
if (seasoningFlavours.isNullOrEmpty() && inherentFlavours.isNullOrEmpty())
|
||||
return null
|
||||
|
||||
return (seasoningFlavours ?: emptyMap()).mapValues { (flavour, value) ->
|
||||
value + (inherentFlavours?.getOrDefault(flavour, 0) ?: 0)
|
||||
}
|
||||
}
|
||||
|
||||
fun getFoodFromItemStack(stack: ItemStack): Food? {
|
||||
return getFromItemStack(stack)?.food
|
||||
fun hasFlavors(stack: ItemStack): Boolean {
|
||||
val flavors = getFlavoursFromItemStack(stack)
|
||||
return !flavors.isNullOrEmpty() && flavors.any { it.value != 0 }
|
||||
}
|
||||
|
||||
fun getFoodComponentFromItemStack(stack: ItemStack): FoodComponent? {
|
||||
return getFromItemStack(stack)?.food?.toComponent()
|
||||
}
|
||||
|
||||
fun hasFood(stack: ItemStack): Boolean {
|
||||
@@ -96,17 +99,26 @@ object Seasonings : JsonDataRegistry<Seasoning> {
|
||||
return effects.hunger > 0 || effects.saturation > 0f
|
||||
}
|
||||
|
||||
fun getMobEffectFromItemStack(stack: ItemStack): MobCookingEffects? {
|
||||
return getFromItemStack(stack)?.mobEffects
|
||||
fun getMobEffectsFromItemStack(stack: ItemStack): List<SerializableMobEffectInstance> {
|
||||
return getFromItemStack(stack)?.mobEffects ?: emptyList()
|
||||
}
|
||||
|
||||
fun hasMobEffect(stack: ItemStack): Boolean {
|
||||
val effects = getFromItemStack(stack)?.mobEffects ?: return false
|
||||
return effects.appliedEffects.isNotEmpty()
|
||||
return !getFromItemStack(stack)?.mobEffects.isNullOrEmpty()
|
||||
}
|
||||
|
||||
fun getBaitEffectsFromItemStack(stack: ItemStack): List<SpawnBait.Effect> {
|
||||
return getFromItemStack(stack)?.baitEffects ?: emptyList()
|
||||
val primaryEffects = SpawnBaitEffects.getEffectsFromItemStack(stack)
|
||||
return if (primaryEffects.isNotEmpty()) {
|
||||
primaryEffects
|
||||
} else {
|
||||
getFromItemStack(stack)?.baitEffects ?: emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
fun hasBaitEffects(stack: ItemStack): Boolean {
|
||||
return SpawnBaitEffects.getEffectsFromItemStack(stack).isNotEmpty() ||
|
||||
!(getFromItemStack(stack)?.baitEffects.isNullOrEmpty())
|
||||
}
|
||||
|
||||
fun getFromItemStack(stack: ItemStack): Seasoning? {
|
||||
|
||||
@@ -24,6 +24,7 @@ sealed interface DialogueFaceProvider {
|
||||
|
||||
companion object {
|
||||
val types = mutableMapOf(
|
||||
"artificial" to ArtificialDialogueFaceProvider::class.java,
|
||||
"player" to PlayerDialogueFaceProvider::class.java,
|
||||
"standard" to ArtificialDialogueFaceProvider::class.java,
|
||||
"expression" to ExpressionLikeDialogueFaceProvider::class.java
|
||||
|
||||
@@ -72,6 +72,8 @@ object CobblemonEvents {
|
||||
@JvmField
|
||||
val FRIENDSHIP_UPDATED = EventObservable<FriendshipUpdatedEvent>()
|
||||
@JvmField
|
||||
val FULLNESS_UPDATED = EventObservable<FullnessUpdatedEvent>()
|
||||
@JvmField
|
||||
val POKEMON_FAINTED = EventObservable<PokemonFaintedEvent>()
|
||||
@JvmField
|
||||
val EVOLUTION_ACCEPTED = CancelableObservable<EvolutionAcceptedEvent>()
|
||||
@@ -169,6 +171,11 @@ object CobblemonEvents {
|
||||
@JvmField
|
||||
val EV_GAINED_EVENT_POST = EventObservable<EvGainedEvent.Post>()
|
||||
|
||||
@JvmField
|
||||
val HYPER_TRAINED_IV_PRE = CancelableObservable<HyperTrainedIvEvent.Pre>()
|
||||
@JvmField
|
||||
val HYPER_TRAINED_IV_POST = EventObservable<HyperTrainedIvEvent.Post>()
|
||||
|
||||
@JvmField
|
||||
val POKEMON_RELEASED_EVENT_PRE = CancelableObservable<ReleasePokemonEvent.Pre>()
|
||||
@JvmField
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.events.pokemon
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
|
||||
/**
|
||||
* Event that is fired when a player owned Pokémon has its fullness changed
|
||||
*/
|
||||
data class FullnessUpdatedEvent(
|
||||
val pokemon: Pokemon,
|
||||
val newFullnessInitial: Int
|
||||
) {
|
||||
var newFullness: Int = newFullnessInitial
|
||||
set(value) {
|
||||
field = value.coerceIn(0, pokemon.getMaxFullness())
|
||||
}
|
||||
}
|
||||
+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.events.pokemon
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.events.Cancelable
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stat
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
|
||||
/**
|
||||
* Fired during a Hyper Training mutation.
|
||||
*
|
||||
* @see [Pre]
|
||||
* @see [Post]
|
||||
*/
|
||||
interface HyperTrainedIvEvent {
|
||||
|
||||
/**
|
||||
* The [Stat] having whose IV is being hyper-trained.
|
||||
*/
|
||||
val stat: Stat
|
||||
|
||||
/**
|
||||
* The [Pokemon] being hyper-trained.
|
||||
*/
|
||||
val pokemon: Pokemon
|
||||
|
||||
/**
|
||||
* Fired before Hyper Training occurs, cancelling will cause the mutation to be flagged as not successful.
|
||||
*/
|
||||
class Pre(override val pokemon: Pokemon, override val stat: Stat, var value: Int) : HyperTrainedIvEvent, Cancelable() {
|
||||
val context = mutableMapOf(
|
||||
"pokemon" to pokemon.struct,
|
||||
"stat" to StringValue(stat.toString()),
|
||||
"value" to DoubleValue(value)
|
||||
)
|
||||
val functions = moLangFunctionMap(cancelFunc)
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired after Hyper Training occurs, this is purely for notification purposes.
|
||||
*/
|
||||
class Post(override val pokemon: Pokemon, override val stat: Stat, val value: Int) : HyperTrainedIvEvent {
|
||||
val context = mutableMapOf(
|
||||
"pokemon" to pokemon.struct,
|
||||
"stat" to StringValue(stat.toString()),
|
||||
"value" to DoubleValue(value)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.api.fishing
|
||||
import com.cobblemon.mod.common.CobblemonItemComponents
|
||||
import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
|
||||
import com.cobblemon.mod.common.api.conditional.RegistryLikeIdentifierCondition
|
||||
import com.cobblemon.mod.common.api.cooking.Seasonings
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.net.messages.client.data.SpawnBaitRegistrySyncPacket
|
||||
@@ -85,7 +86,7 @@ object SpawnBaitEffects : JsonDataRegistry<SpawnBait> {
|
||||
(it.ingredient as RegistryLikeIdentifierCondition<Item>).identifier.path == identifier.path
|
||||
}
|
||||
|
||||
if (seasoning != null && seasoning.baitEffects.isNotEmpty()) {
|
||||
if (seasoning != null && !seasoning.baitEffects.isNullOrEmpty()) {
|
||||
return SpawnBait(
|
||||
item = seasoning.ingredient,
|
||||
effects = seasoning.baitEffects
|
||||
@@ -96,8 +97,9 @@ object SpawnBaitEffects : JsonDataRegistry<SpawnBait> {
|
||||
return null
|
||||
}
|
||||
|
||||
// if it has bait effects and is not listed as a seasoning then it is a bait
|
||||
fun isFishingBait(stack: ItemStack): Boolean {
|
||||
val holder = stack.itemHolder
|
||||
return stack.has(CobblemonItemComponents.BAIT_EFFECTS) || effectsMap.values.any { it.item.fits(holder) }
|
||||
return effectsMap.values.any { it.item.fits(holder) }
|
||||
}
|
||||
}
|
||||
@@ -17,25 +17,20 @@ object SpawnBaitUtils {
|
||||
return grouped.map { (key, groupEffects) ->
|
||||
val (type, subcategory) = key
|
||||
|
||||
if (type == SpawnBait.Effects.RARITY_BUCKET) {
|
||||
// we want to keep the highest rarity bucket effect instead of merging them
|
||||
groupEffects.maxByOrNull { it.value }!!
|
||||
} else {
|
||||
val count = groupEffects.size
|
||||
val totalChance = groupEffects.sumOf { it.chance }
|
||||
val totalValue = groupEffects.sumOf { it.value }
|
||||
val count = groupEffects.size
|
||||
val totalChance = groupEffects.sumOf { it.chance }
|
||||
val totalValue = groupEffects.sumOf { it.value }
|
||||
|
||||
val multiplier = when (count) {
|
||||
2 -> 0.8
|
||||
3 -> 0.6
|
||||
else -> 1.0
|
||||
}
|
||||
|
||||
val adjustedChance = (totalChance * multiplier).coerceAtMost(1.0)
|
||||
val adjustedValue = ceil(totalValue * multiplier)
|
||||
|
||||
SpawnBait.Effect(type, subcategory, adjustedChance, adjustedValue)
|
||||
val multiplier = when (count) {
|
||||
2 -> 0.8
|
||||
3 -> 0.6
|
||||
else -> 1.0
|
||||
}
|
||||
|
||||
val adjustedChance = (totalChance * multiplier).coerceAtMost(1.0)
|
||||
val adjustedValue = ceil(totalValue * multiplier)
|
||||
|
||||
SpawnBait.Effect(type, subcategory, adjustedChance, adjustedValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-1
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.api.callback.MoveSelectCallbacks
|
||||
import com.cobblemon.mod.common.api.callback.PartyMoveSelectCallbacks
|
||||
import com.cobblemon.mod.common.api.moves.Move
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.battles.BagItemActionResponse
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
@@ -92,7 +93,13 @@ interface PokemonAndMoveSelectingItem {
|
||||
}
|
||||
}
|
||||
|
||||
fun canUseOnPokemon(stack: ItemStack, pokemon: Pokemon): Boolean
|
||||
fun canUseOnPokemon(stack: ItemStack, pokemon: Pokemon): Boolean {
|
||||
if (stack.`is`(CobblemonItemTags.POKE_FOOD)) {
|
||||
return !pokemon.isFull()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun canUseOnBattlePokemon(stack: ItemStack, battlePokemon: BattlePokemon): Boolean = bagItem!!.canUse(stack, battlePokemon.actor.battle, battlePokemon)
|
||||
fun canUseOnMove(stack: ItemStack, pokemon: Pokemon, move: Move): Boolean = canUseOnMove(stack, move)
|
||||
fun canUseOnMove(stack: ItemStack, move: Move): Boolean
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.advancement.CobblemonCriteria
|
||||
import com.cobblemon.mod.common.advancement.criterion.PokemonInteractContext
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.api.callback.PartySelectCallbacks
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.battles.BagItemActionResponse
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
@@ -105,7 +106,13 @@ interface PokemonSelectingItem {
|
||||
}
|
||||
}
|
||||
|
||||
fun canUseOnPokemon(stack: ItemStack, pokemon: Pokemon): Boolean
|
||||
fun canUseOnPokemon(stack: ItemStack, pokemon: Pokemon): Boolean {
|
||||
if (stack.`is`(CobblemonItemTags.POKE_FOOD)) {
|
||||
return !pokemon.isFull()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun canUseOnBattlePokemon(stack: ItemStack, battlePokemon: BattlePokemon): Boolean = bagItem!!.canUse(stack, battlePokemon.actor.battle, battlePokemon)
|
||||
|
||||
fun interactWithSpecificBattle(player: ServerPlayer, stack: ItemStack, battlePokemon: BattlePokemon): InteractionResultHolder<ItemStack> {
|
||||
@@ -136,6 +143,7 @@ interface PokemonSelectingItem {
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
return InteractionResultHolder.success(stack)
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.cobblemon.mod.common.CobblemonActivities
|
||||
import com.cobblemon.mod.common.CobblemonBlockEntities
|
||||
import com.cobblemon.mod.common.CobblemonMemories
|
||||
import com.cobblemon.mod.common.CobblemonUnlockableWallpapers
|
||||
import com.cobblemon.mod.common.Environment
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.ActorType
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
@@ -45,6 +46,9 @@ import com.cobblemon.mod.common.api.pokedex.SeenPercent
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.scheduling.ClientTaskTracker
|
||||
import com.cobblemon.mod.common.api.scheduling.Schedulable
|
||||
import com.cobblemon.mod.common.api.scheduling.ServerTaskTracker
|
||||
import com.cobblemon.mod.common.api.scripting.CobblemonScripts
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
import com.cobblemon.mod.common.api.storage.PokemonStore
|
||||
@@ -69,7 +73,9 @@ import com.cobblemon.mod.common.net.messages.client.animation.PlayPosableAnimati
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.sound.UnvalidatedPlaySoundS2CPacket
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.pokemon.IVs
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.pokemon.evolution.variants.ItemInteractionEvolution
|
||||
@@ -97,6 +103,7 @@ import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.sounds.SoundSource
|
||||
import net.minecraft.tags.TagKey
|
||||
import net.minecraft.world.damagesource.DamageSource
|
||||
import net.minecraft.world.damagesource.DamageTypes
|
||||
@@ -198,7 +205,15 @@ object MoLangFunctions {
|
||||
runtime.environment.variable = params.environment.variable
|
||||
runtime.environment.context = params.environment.context
|
||||
val expression = params.getString(0).asExpressionLike()
|
||||
runtime.resolve(expression)
|
||||
val delayInSeconds = params.getDoubleOrNull(1)?.toFloat() ?: 0.0f
|
||||
if (delayInSeconds > 0.0f) {
|
||||
val tracker = if (Cobblemon.implementation.environment() == Environment.SERVER) ServerTaskTracker else ClientTaskTracker
|
||||
tracker.after(delayInSeconds) {
|
||||
runtime.resolve(expression)
|
||||
}
|
||||
} else {
|
||||
runtime.resolve(expression)
|
||||
}
|
||||
},
|
||||
"system_time_millis" to java.util.function.Function { _ ->
|
||||
DoubleValue(System.currentTimeMillis())
|
||||
@@ -345,6 +360,27 @@ object MoLangFunctions {
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
map.put("play_sound_on_server") { params ->
|
||||
val sound = params.getString(0).asResource()
|
||||
val soundSource = params.getString(1).uppercase()
|
||||
val x = params.getDouble(2)
|
||||
val y = params.getDouble(3)
|
||||
val z = params.getDouble(4)
|
||||
val player = params.getOrNull<MoValue>(5)?.let {
|
||||
if (it is StringValue) world.getPlayerByUUID(UUID.fromString(it.value))
|
||||
else if (it is ObjectValue<*>) it.obj
|
||||
else null
|
||||
} as? ServerPlayer
|
||||
val volume = params.getDoubleOrNull(6)?.toFloat() ?: 1.0f
|
||||
val pitch = params.getDoubleOrNull(7)?.toFloat() ?: 1.0f
|
||||
|
||||
val packet = UnvalidatedPlaySoundS2CPacket(sound, SoundSource.valueOf(soundSource), x, y, z, volume, pitch)
|
||||
if (player != null) {
|
||||
packet.sendToPlayer(player)
|
||||
} else {
|
||||
packet.sendToPlayersAround(x, y, z, 16.0, world.dimension())
|
||||
}
|
||||
}
|
||||
map.put("get_entities_around") { params ->
|
||||
val x = params.getDouble(0)
|
||||
val y = params.getDouble(1)
|
||||
@@ -405,6 +441,15 @@ object MoLangFunctions {
|
||||
val command = params.getString(0)
|
||||
player.server.commands.performPrefixedCommand(player.createCommandSourceStack(), command)
|
||||
}
|
||||
map.put("play_sound_on_server") { params ->
|
||||
val sound = params.getString(0).asResource()
|
||||
val soundSource = SoundSource.valueOf(params.getString(1).uppercase())
|
||||
val volume = params.getDoubleOrNull(2)?.toFloat() ?: 1.0f
|
||||
val pitch = params.getDoubleOrNull(3)?.toFloat() ?: 1.0f
|
||||
|
||||
val packet = UnvalidatedPlaySoundS2CPacket(sound, soundSource, player.x, player.y, player.z, volume, pitch)
|
||||
packet.sendToPlayer(player)
|
||||
}
|
||||
map.put("is_party_at_full_health") { _ ->
|
||||
DoubleValue(player.party().none(Pokemon::canBeHealed)) }
|
||||
map.put("can_heal_at_healer") { params ->
|
||||
@@ -619,8 +664,9 @@ object MoLangFunctions {
|
||||
map.put("biome") { _ -> entity.level().getBiome(entity.blockPosition()).asBiomeMoLangValue() }
|
||||
map.put("is_passenger") { DoubleValue(entity.isPassenger) }
|
||||
map.put("find_nearby_block") { params ->
|
||||
val type = params.getString(0).asIdentifierDefaultingNamespace(namespace = "minecraft")
|
||||
val isTag = type.path.startsWith("#")
|
||||
val input = params.getString(0)
|
||||
val isTag = input.contains("#")
|
||||
val type = input.replace("#", "").asIdentifierDefaultingNamespace(namespace = "minecraft")
|
||||
val range = params.getDoubleOrNull(1) ?: 10
|
||||
val blockPos = entity.level().getBlockStatesWithPos(AABB.ofSize(entity.position(), range.toDouble(), range.toDouble(), range.toDouble()))
|
||||
.filter { it.first.blockHolder.let { if (isTag) it.`is`(TagKey.create(Registries.BLOCK, type)) else it.`is`(type) } }
|
||||
@@ -676,6 +722,17 @@ object MoLangFunctions {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (entity is Schedulable) {
|
||||
map.put("run_molang_after") { params ->
|
||||
val expression = params.getString(0).asExpressionLike()
|
||||
val delayInSeconds = params.getDouble(1).toFloat()
|
||||
val runtime = MoLangRuntime()
|
||||
runtime.environment.cloneFrom(params.environment)
|
||||
entity.after(delayInSeconds) {
|
||||
runtime.resolve(expression)
|
||||
}
|
||||
}
|
||||
}
|
||||
// q.entity.spawn_bedrock_particles(effect, locator, [player]) - sends to everyone nearby or just to the player if they're set. Locator is necessary even if unused on non-posables.
|
||||
map.put("spawn_bedrock_particles") { params ->
|
||||
val particle = params.getString(0).asResource()
|
||||
@@ -1047,6 +1104,19 @@ object MoLangFunctions {
|
||||
map.put("apply_potential_marks") {
|
||||
return@put DoubleValue(pokemon.applyPotentialMarks())
|
||||
}
|
||||
map.put("hyper_train_iv") { params ->
|
||||
val statId = params.getString(0)
|
||||
val stat = Stats.getStat(statId)
|
||||
val value = params.getIntOrNull(1) ?: IVs.MAX_VALUE
|
||||
|
||||
if (Stats.PERMANENT.contains(stat)) {
|
||||
pokemon.hyperTrainIV(stat, value)
|
||||
return@put DoubleValue.ONE
|
||||
} else {
|
||||
Cobblemon.LOGGER.error("Unknown or non-permanent stat: ${stat.toString()}")
|
||||
return@put DoubleValue.ZERO
|
||||
}
|
||||
}
|
||||
map
|
||||
}
|
||||
)
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.moves
|
||||
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
|
||||
object HiddenPowerUtil {
|
||||
val hiddenPowerTable = arrayOf(
|
||||
ElementalTypes.FIGHTING,
|
||||
ElementalTypes.FLYING,
|
||||
ElementalTypes.POISON,
|
||||
ElementalTypes.GROUND,
|
||||
ElementalTypes.ROCK,
|
||||
ElementalTypes.BUG,
|
||||
ElementalTypes.GHOST,
|
||||
ElementalTypes.STEEL,
|
||||
ElementalTypes.FIRE,
|
||||
ElementalTypes.WATER,
|
||||
ElementalTypes.GRASS,
|
||||
ElementalTypes.ELECTRIC,
|
||||
ElementalTypes.PSYCHIC,
|
||||
ElementalTypes.ICE,
|
||||
ElementalTypes.DRAGON,
|
||||
ElementalTypes.DARK
|
||||
)
|
||||
|
||||
fun getHiddenPowerType(pokemon: Pokemon?): ElementalType {
|
||||
if (pokemon == null) {
|
||||
return ElementalTypes.NORMAL
|
||||
}
|
||||
val ivs = pokemon.ivs
|
||||
val ivArray = arrayOf(
|
||||
ivs[Stats.HP],
|
||||
ivs[Stats.ATTACK],
|
||||
ivs[Stats.DEFENCE],
|
||||
ivs[Stats.SPEED],
|
||||
ivs[Stats.SPECIAL_ATTACK],
|
||||
ivs[Stats.SPECIAL_DEFENCE]
|
||||
).map { it ?: return@getHiddenPowerType ElementalTypes.NORMAL }
|
||||
var tableIndex = 0
|
||||
ivArray.forEachIndexed { index, it ->
|
||||
tableIndex += (it % 2) shl index
|
||||
}
|
||||
tableIndex = tableIndex * 15 / 63
|
||||
return hiddenPowerTable[tableIndex.coerceAtMost(hiddenPowerTable.size - 1)]
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,6 @@ import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategories
|
||||
import com.cobblemon.mod.common.api.moves.categories.DamageCategory
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.types.ElementalType
|
||||
import com.cobblemon.mod.common.api.types.ElementalTypes
|
||||
import com.cobblemon.mod.common.battles.MoveTarget
|
||||
@@ -100,24 +99,6 @@ open class MoveTemplate(
|
||||
Moves::getByName,
|
||||
MoveTemplate::name
|
||||
) { id -> "No MoveTemplate for ID $id" }
|
||||
val hiddenPowerTable = arrayOf(
|
||||
ElementalTypes.FIGHTING,
|
||||
ElementalTypes.FLYING,
|
||||
ElementalTypes.POISON,
|
||||
ElementalTypes.GROUND,
|
||||
ElementalTypes.ROCK,
|
||||
ElementalTypes.BUG,
|
||||
ElementalTypes.GHOST,
|
||||
ElementalTypes.STEEL,
|
||||
ElementalTypes.FIRE,
|
||||
ElementalTypes.WATER,
|
||||
ElementalTypes.GRASS,
|
||||
ElementalTypes.ELECTRIC,
|
||||
ElementalTypes.PSYCHIC,
|
||||
ElementalTypes.ICE,
|
||||
ElementalTypes.DRAGON,
|
||||
ElementalTypes.DARK
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,21 +127,7 @@ open class MoveTemplate(
|
||||
return this.elementalType
|
||||
}
|
||||
if (name == "hiddenpower") {
|
||||
val ivs = pokemon.ivs
|
||||
val ivArray = arrayOf(
|
||||
ivs[Stats.HP],
|
||||
ivs[Stats.ATTACK],
|
||||
ivs[Stats.DEFENCE],
|
||||
ivs[Stats.SPEED],
|
||||
ivs[Stats.SPECIAL_ATTACK],
|
||||
ivs[Stats.SPECIAL_DEFENCE]
|
||||
).map { it ?: return@getEffectiveElementalType ElementalTypes.NORMAL }
|
||||
var tableIndex = 0
|
||||
ivArray.forEachIndexed { index, it ->
|
||||
tableIndex += (it % 2) shl index
|
||||
}
|
||||
tableIndex = tableIndex * 15 / 63
|
||||
return hiddenPowerTable[tableIndex.coerceAtMost(hiddenPowerTable.size - 1)]
|
||||
return HiddenPowerUtil.getHiddenPowerType(pokemon)
|
||||
}
|
||||
// TODO: Handle ability suppression: clientactivebattlepokemon needs data about volatiles
|
||||
// TODO: Handle Liquid Voice: need to know what moves have the sound flag
|
||||
|
||||
-1
@@ -16,7 +16,6 @@ import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.api.scheduling.after
|
||||
import com.cobblemon.mod.common.entity.ai.OmniPathNavigation.NavigationContext
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.ai.PokemonNavigation
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
@@ -96,6 +96,8 @@ object CobblemonPermissions {
|
||||
@JvmStatic
|
||||
val PC = this.create("${COMMAND_PREFIX}pc", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
@JvmStatic
|
||||
val PC_SEARCH = this.create("${COMMAND_PREFIX}pcsearch", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
@JvmStatic
|
||||
val POKEBOX = this.create("${COMMAND_PREFIX}pokebox", PermissionLevel.CHEAT_COMMANDS_AND_COMMAND_BLOCKS)
|
||||
|
||||
@JvmStatic
|
||||
|
||||
@@ -43,6 +43,7 @@ import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import com.mojang.brigadier.StringReader
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.JsonOps
|
||||
import java.util.UUID
|
||||
import kotlin.math.min
|
||||
import kotlin.random.Random
|
||||
@@ -51,6 +52,7 @@ import net.minecraft.commands.arguments.item.ItemParser
|
||||
import net.minecraft.core.HolderLookup
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.nbt.NbtOps
|
||||
import net.minecraft.nbt.StringTag
|
||||
import net.minecraft.nbt.Tag
|
||||
import net.minecraft.network.chat.Component
|
||||
@@ -59,6 +61,7 @@ import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.Level
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
|
||||
/**
|
||||
* A grouping of typical, selectable properties for a Pokémon. This is serializable
|
||||
@@ -402,6 +405,9 @@ open class PokemonProperties {
|
||||
ivs.forEach { stat ->
|
||||
pokemon.setIV(stat.key, stat.value)
|
||||
}
|
||||
ivs.hyperTrainedIVs.forEach { stat ->
|
||||
pokemon.hyperTrainIV(stat.key, stat.value)
|
||||
}
|
||||
}
|
||||
evs?.let { evs ->
|
||||
evs.forEach { stat ->
|
||||
@@ -633,8 +639,8 @@ open class PokemonProperties {
|
||||
nature?.let { nbt.putString(DataKeys.POKEMON_NATURE, it) }
|
||||
ability?.let { nbt.putString(DataKeys.POKEMON_ABILITY, it) }
|
||||
status?.let { nbt.putString(DataKeys.POKEMON_STATUS_NAME, it) }
|
||||
ivs?.let { nbt.put(DataKeys.POKEMON_IVS, it.saveToNBT(CompoundTag())) }
|
||||
evs?.let { nbt.put(DataKeys.POKEMON_EVS, it.saveToNBT(CompoundTag())) }
|
||||
ivs?.let { nbt.put(DataKeys.POKEMON_IVS, IVs.CODEC.encodeStart(NbtOps.INSTANCE, it).result().get()) }
|
||||
evs?.let { nbt.put(DataKeys.POKEMON_EVS, EVs.CODEC.encodeStart(NbtOps.INSTANCE, it).result().get()) }
|
||||
type?.let { nbt.putString(DataKeys.ELEMENTAL_TYPE, it) }
|
||||
teraType?.let { nbt.putString(DataKeys.POKEMON_TERA_TYPE, it) }
|
||||
dmaxLevel?.let { nbt.putInt(DataKeys.POKEMON_DMAX_LEVEL, it) }
|
||||
@@ -664,8 +670,8 @@ open class PokemonProperties {
|
||||
nature = if (tag.contains(DataKeys.POKEMON_NATURE)) tag.getString(DataKeys.POKEMON_NATURE) else null
|
||||
ability = if (tag.contains(DataKeys.POKEMON_ABILITY)) tag.getString(DataKeys.POKEMON_ABILITY) else null
|
||||
status = if (tag.contains(DataKeys.POKEMON_STATUS_NAME)) tag.getString(DataKeys.POKEMON_STATUS_NAME) else null
|
||||
ivs = if (tag.contains(DataKeys.POKEMON_IVS)) IVs().loadFromNBT(tag.getCompound(DataKeys.POKEMON_IVS)) as IVs else null
|
||||
evs = if (tag.contains(DataKeys.POKEMON_EVS)) EVs().loadFromNBT(tag.getCompound(DataKeys.POKEMON_EVS)) as EVs else null
|
||||
ivs = if (tag.contains(DataKeys.POKEMON_IVS)) IVs.CODEC.decode(NbtOps.INSTANCE, tag.getCompound(DataKeys.POKEMON_IVS)).result().getOrNull()?.first else null
|
||||
evs = if (tag.contains(DataKeys.POKEMON_EVS)) EVs.CODEC.decode(NbtOps.INSTANCE, tag.getCompound(DataKeys.POKEMON_EVS)).result().getOrNull()?.first else null
|
||||
type = if (tag.contains(DataKeys.ELEMENTAL_TYPE)) tag.getString(DataKeys.ELEMENTAL_TYPE) else null
|
||||
teraType = if (tag.contains(DataKeys.POKEMON_TERA_TYPE)) tag.getString(DataKeys.POKEMON_TERA_TYPE) else null
|
||||
dmaxLevel = if (tag.contains(DataKeys.POKEMON_DMAX_LEVEL)) tag.getInt(DataKeys.POKEMON_DMAX_LEVEL) else null
|
||||
@@ -697,8 +703,8 @@ open class PokemonProperties {
|
||||
nature?.let { json.addProperty(DataKeys.POKEMON_NATURE, it) }
|
||||
ability?.let { json.addProperty(DataKeys.POKEMON_ABILITY, it) }
|
||||
status?.let { json.addProperty(DataKeys.POKEMON_STATUS_NAME, it) }
|
||||
ivs?.let { json.add(DataKeys.POKEMON_IVS, it.saveToJSON(JsonObject())) }
|
||||
evs?.let { json.add(DataKeys.POKEMON_EVS, it.saveToJSON(JsonObject())) }
|
||||
ivs?.let { json.add(DataKeys.POKEMON_IVS, IVs.CODEC.encodeStart(JsonOps.INSTANCE, it).result().get()) }
|
||||
evs?.let { json.add(DataKeys.POKEMON_EVS, EVs.CODEC.encodeStart(JsonOps.INSTANCE, it).result().get()) }
|
||||
type?.let { json.addProperty(DataKeys.ELEMENTAL_TYPE, it) }
|
||||
teraType?.let { json.addProperty(DataKeys.POKEMON_TERA_TYPE, it) }
|
||||
dmaxLevel?.let { json.addProperty(DataKeys.POKEMON_DMAX_LEVEL, it) }
|
||||
@@ -729,8 +735,8 @@ open class PokemonProperties {
|
||||
nature = json.get(DataKeys.POKEMON_NATURE)?.asString
|
||||
ability = json.get(DataKeys.POKEMON_ABILITY)?.asString
|
||||
status = json.get(DataKeys.POKEMON_STATUS_NAME)?.asString
|
||||
ivs = json.getAsJsonObject(DataKeys.POKEMON_IVS)?.let { IVs().loadFromJSON(it) } as? IVs
|
||||
evs = json.getAsJsonObject(DataKeys.POKEMON_EVS)?.let { EVs().loadFromJSON(it) } as? EVs
|
||||
ivs = json.getAsJsonObject(DataKeys.POKEMON_IVS)?.let { IVs.CODEC.decode(JsonOps.INSTANCE, it).result().getOrNull()?.first }
|
||||
evs = json.getAsJsonObject(DataKeys.POKEMON_EVS)?.let { EVs.CODEC.decode(JsonOps.INSTANCE, it).result().getOrNull()?.first }
|
||||
type = json.get(DataKeys.ELEMENTAL_TYPE)?.asString
|
||||
teraType = json.get(DataKeys.POKEMON_TERA_TYPE)?.asString
|
||||
dmaxLevel = json.get(DataKeys.POKEMON_DMAX_LEVEL)?.asInt
|
||||
|
||||
+4
-2
@@ -39,9 +39,9 @@ interface RidingBehaviour<Settings : RidingBehaviourSettings, State : RidingBeha
|
||||
|
||||
fun speed(settings: Settings, state: State, vehicle: PokemonEntity, driver: Player): Float
|
||||
|
||||
fun clampPassengerRotation(settings: Settings, state: State, entity: PokemonEntity, driver: LivingEntity) {}
|
||||
fun clampPassengerRotation(settings: Settings, state: State, vehicle: PokemonEntity, driver: LivingEntity) {}
|
||||
|
||||
fun updatePassengerRotation(settings: Settings, state: State, entity: PokemonEntity, driver: LivingEntity) {}
|
||||
fun updatePassengerRotation(settings: Settings, state: State, vehicle: PokemonEntity, driver: LivingEntity) {}
|
||||
|
||||
fun rotation(settings: Settings, state: State, vehicle: PokemonEntity, driver: LivingEntity): Vec2
|
||||
|
||||
@@ -88,6 +88,8 @@ interface RidingBehaviour<Settings : RidingBehaviourSettings, State : RidingBeha
|
||||
|
||||
fun shouldRotatePlayerHead(settings: Settings, state: State, vehicle: PokemonEntity): Boolean
|
||||
|
||||
fun maxUpStep(settings: Settings, state: State, vehicle: PokemonEntity): Float? = null
|
||||
|
||||
fun createDefaultState(settings: Settings): State
|
||||
|
||||
}
|
||||
+2
-2
@@ -23,8 +23,8 @@ import net.minecraft.world.phys.Vec3
|
||||
* @author landonjw
|
||||
*/
|
||||
open class RidingBehaviourState {
|
||||
open val rideVelocity: SidedRidingState<Vec3> = ridingState(Vec3.ZERO, Side.BOTH)
|
||||
open val stamina: SidedRidingState<Float> = ridingState(1.0F, Side.BOTH)
|
||||
open val rideVelocity: SidedRidingState<Vec3> = ridingState(Vec3.ZERO, Side.CLIENT)
|
||||
open val stamina: SidedRidingState<Float> = ridingState(1.0F, Side.CLIENT)
|
||||
|
||||
open fun reset() {
|
||||
rideVelocity.set(Vec3.ZERO, true)
|
||||
|
||||
+13
-8
@@ -8,23 +8,28 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.behaviour
|
||||
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.*
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.air.*
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.composite.CompositeBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.land.HorseBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.land.VehicleBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BoatBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.BurstBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.types.liquid.DolphinBehaviour
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
|
||||
object RidingBehaviours {
|
||||
val behaviours = mutableMapOf<ResourceLocation, RidingBehaviour<RidingBehaviourSettings, RidingBehaviourState>>()
|
||||
|
||||
init {
|
||||
register(BirdAirBehaviour.KEY, BirdAirBehaviour())
|
||||
register(BirdBehaviour.KEY, BirdBehaviour())
|
||||
register(DolphinBehaviour.KEY, DolphinBehaviour())
|
||||
register(GenericLandBehaviour.KEY, GenericLandBehaviour())
|
||||
register(GenericSwimBehaviour.KEY, GenericSwimBehaviour())
|
||||
register(GliderAirBehaviour.KEY, GliderAirBehaviour())
|
||||
register(HorseBehaviour.KEY, HorseBehaviour())
|
||||
register(BoatBehaviour.KEY, BoatBehaviour())
|
||||
register(GliderBehaviour.KEY, GliderBehaviour())
|
||||
register(HelicopterBehaviour.KEY, HelicopterBehaviour())
|
||||
register(JetAirBehaviour.KEY, JetAirBehaviour())
|
||||
register(SwimDashBehaviour.KEY, SwimDashBehaviour())
|
||||
register(VehicleLandBehaviour.KEY, VehicleLandBehaviour())
|
||||
register(JetBehaviour.KEY, JetBehaviour())
|
||||
register(BurstBehaviour.KEY, BurstBehaviour())
|
||||
register(VehicleBehaviour.KEY, VehicleBehaviour())
|
||||
register(HoverBehaviour.KEY, HoverBehaviour())
|
||||
register(CompositeBehaviour.KEY, CompositeBehaviour())
|
||||
}
|
||||
|
||||
+16
-1
@@ -26,7 +26,7 @@ import net.minecraft.world.phys.Vec3
|
||||
class RidingController<Settings : RidingBehaviourSettings, State : RidingBehaviourState>(val behaviour: RidingBehaviour<Settings, State>) : RidingBehaviour<Settings, State> {
|
||||
|
||||
override val key = behaviour.key
|
||||
|
||||
|
||||
override fun getRidingStyle(settings: Settings, state: State): RidingStyle {
|
||||
return behaviour.getRidingStyle(settings, state)
|
||||
}
|
||||
@@ -45,6 +45,16 @@ class RidingController<Settings : RidingBehaviourSettings, State : RidingBehavio
|
||||
return behaviour.speed(settings, state, vehicle, driver)
|
||||
}
|
||||
|
||||
override fun updatePassengerRotation(
|
||||
settings: Settings,
|
||||
state: State,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
) {
|
||||
if (!isActive(settings, state, vehicle)) return
|
||||
return behaviour.updatePassengerRotation(settings, state, vehicle, driver)
|
||||
}
|
||||
|
||||
override fun clampPassengerRotation(settings: Settings, state: State, vehicle: PokemonEntity, driver: LivingEntity) {
|
||||
if (!isActive(settings, state, vehicle)) return
|
||||
return behaviour.clampPassengerRotation(settings, state, vehicle, driver)
|
||||
@@ -175,6 +185,11 @@ class RidingController<Settings : RidingBehaviourSettings, State : RidingBehavio
|
||||
return behaviour.setRideBar(settings, state, vehicle, driver)
|
||||
}
|
||||
|
||||
override fun maxUpStep(settings: Settings, state: State, vehicle: PokemonEntity): Float? {
|
||||
if (!isActive(settings, state, vehicle)) return null
|
||||
return behaviour.maxUpStep(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun createDefaultState(settings: Settings): State {
|
||||
return behaviour.createDefaultState(settings)
|
||||
}
|
||||
|
||||
-267
@@ -1,267 +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.riding.behaviour.types
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourState
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviour
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.RidingBehaviourSettings
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.SmoothDouble
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
|
||||
class GenericSwimBehaviour : RidingBehaviour<GenericSwimSettings, RidingBehaviourState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("swim/generic")
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
|
||||
override fun getRidingStyle(settings: GenericSwimSettings, state: RidingBehaviourState): RidingStyle {
|
||||
return RidingStyle.LIQUID
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<GenericSwimSettings, RidingBehaviourState>(PoseType.FLOAT)
|
||||
.with(PoseOption(PoseType.SWIM) { _, _, entity -> entity.isSwimming && entity.entityData.get(PokemonEntity.MOVING) })
|
||||
|
||||
override fun isActive(settings: GenericSwimSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
|
||||
return Shapes.create(vehicle.boundingBox).blockPositionsAsListRounded().any {
|
||||
if (vehicle.isInWater || vehicle.isUnderWater) {
|
||||
return@any true
|
||||
}
|
||||
val blockState = vehicle.level().getBlockState(it)
|
||||
return@any !blockState.fluidState.isEmpty
|
||||
}
|
||||
}
|
||||
|
||||
override fun pose(settings: GenericSwimSettings, state: RidingBehaviourState, vehicle: PokemonEntity): PoseType {
|
||||
return poseProvider.select(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun speed(settings: GenericSwimSettings, state: RidingBehaviourState, vehicle: PokemonEntity, driver: Player): Float {
|
||||
return vehicle.runtime.resolveFloat(settings.speed)
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
settings: GenericSwimSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
return Vec2(driver.xRot * 0.5f, driver.yRot)
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: GenericSwimSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
val runtime = vehicle.runtime
|
||||
val driveFactor = runtime.resolveFloat(settings.driveFactor)
|
||||
val strafeFactor = runtime.resolveFloat(settings.strafeFactor)
|
||||
val f = driver.xxa * strafeFactor
|
||||
var g = driver.zza * driveFactor
|
||||
if (g <= 0.0f) {
|
||||
g *= runtime.resolveFloat(settings.reverseDriveFactor)
|
||||
}
|
||||
|
||||
val velocity = Vec3(f.toDouble(), 0.0, g.toDouble())
|
||||
|
||||
return velocity
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: GenericSwimSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: GenericSwimSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
|
||||
//Might need to add the smoothing here for default.
|
||||
val invertRoll = if (Cobblemon.config.invertRoll) -1 else 1
|
||||
val invertPitch = if (Cobblemon.config.invertPitch) -1 else 1
|
||||
return Vec3(0.0, mouseY * invertPitch, mouseX * invertRoll)
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
settings: GenericSwimSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return vehicle.runtime.resolveBoolean(settings.canJump)
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: GenericSwimSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return 0.0f
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: GenericSwimSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
val runtime = vehicle.runtime
|
||||
runtime.environment.query.addFunction("jump_strength") { DoubleValue(jumpStrength.toDouble()) }
|
||||
val jumpVector = settings.jumpVector.map { runtime.resolveFloat(it) }
|
||||
return Vec3(jumpVector[0].toDouble(), jumpVector[1].toDouble(), jumpVector[2].toDouble())
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: GenericSwimSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
return regularGravity
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: GenericSwimSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return 1.0f
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(settings: GenericSwimSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: GenericSwimSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): ResourceLocation {
|
||||
return cobblemonResource("no_pose")
|
||||
}
|
||||
|
||||
override fun inertia(settings: GenericSwimSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Double {
|
||||
return 0.5
|
||||
}
|
||||
|
||||
override fun shouldRoll(settings: GenericSwimSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(settings: GenericSwimSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun dismountOnShift(settings: GenericSwimSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(
|
||||
settings: GenericSwimSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(
|
||||
settings: GenericSwimSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun createDefaultState(settings: GenericSwimSettings) = RidingBehaviourState()
|
||||
|
||||
}
|
||||
|
||||
class GenericSwimSettings : RidingBehaviourSettings {
|
||||
override val key = GenericSwimBehaviour.KEY
|
||||
|
||||
var canJump = "true".asExpression()
|
||||
private set
|
||||
|
||||
var jumpVector = listOf("0".asExpression(), "0.3".asExpression(), "0".asExpression())
|
||||
private set
|
||||
|
||||
var speed = "1.0".asExpression()
|
||||
private set
|
||||
|
||||
var driveFactor = "1.0".asExpression()
|
||||
private set
|
||||
|
||||
var reverseDriveFactor = "0.25".asExpression()
|
||||
private set
|
||||
|
||||
var strafeFactor = "0.2".asExpression()
|
||||
private set
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(key)
|
||||
buffer.writeExpression(canJump)
|
||||
buffer.writeExpression(jumpVector[0])
|
||||
buffer.writeExpression(jumpVector[1])
|
||||
buffer.writeExpression(jumpVector[2])
|
||||
buffer.writeExpression(speed)
|
||||
buffer.writeExpression(driveFactor)
|
||||
buffer.writeExpression(reverseDriveFactor)
|
||||
buffer.writeExpression(strafeFactor)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
canJump = buffer.readExpression()
|
||||
jumpVector = listOf(
|
||||
buffer.readExpression(),
|
||||
buffer.readExpression(),
|
||||
buffer.readExpression()
|
||||
)
|
||||
speed = buffer.readExpression()
|
||||
driveFactor = buffer.readExpression()
|
||||
reverseDriveFactor = buffer.readExpression()
|
||||
strafeFactor = buffer.readExpression()
|
||||
}
|
||||
}
|
||||
+46
-46
@@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types.air
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangMath.lerp
|
||||
@@ -33,31 +33,31 @@ import net.minecraft.world.phys.Vec3
|
||||
import org.joml.Vector3f
|
||||
import kotlin.math.*
|
||||
|
||||
class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("air/bird")
|
||||
}
|
||||
|
||||
override val key: ResourceLocation = KEY
|
||||
|
||||
override fun getRidingStyle(settings: BirdAirSettings, state: BirdAirState): RidingStyle {
|
||||
override fun getRidingStyle(settings: BirdSettings, state: BirdState): RidingStyle {
|
||||
return RidingStyle.AIR
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<BirdAirSettings, BirdAirState>(PoseType.HOVER)
|
||||
val poseProvider = PoseProvider<BirdSettings, BirdState>(PoseType.HOVER)
|
||||
.with(PoseOption(PoseType.FLY) { _, state, _ -> state.rideVelocity.get().z > 0.2 })
|
||||
|
||||
override fun isActive(settings: BirdAirSettings, state: BirdAirState, vehicle: PokemonEntity): Boolean {
|
||||
override fun isActive(settings: BirdSettings, state: BirdState, vehicle: PokemonEntity): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun pose(settings: BirdAirSettings, state: BirdAirState, vehicle: PokemonEntity): PoseType {
|
||||
override fun pose(settings: BirdSettings, state: BirdState, vehicle: PokemonEntity): PoseType {
|
||||
return poseProvider.select(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun speed(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
settings: BirdSettings,
|
||||
state: BirdState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
@@ -65,8 +65,8 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
settings: BirdSettings,
|
||||
state: BirdState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
@@ -74,8 +74,8 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
settings: BirdSettings,
|
||||
state: BirdState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
@@ -122,7 +122,7 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
/*
|
||||
* Calculates the change in the ride space vector due to player input and ride state
|
||||
*/
|
||||
fun calculateRideSpaceVel(settings: BirdAirSettings, state: BirdAirState, vehicle: PokemonEntity, driver: Player) {
|
||||
fun calculateRideSpaceVel(settings: BirdSettings, state: BirdState, vehicle: PokemonEntity, driver: Player) {
|
||||
//retrieve stats
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val glideTopSpeed = vehicle.runtime.resolveDouble(settings.glidespeedExpr)
|
||||
@@ -240,8 +240,8 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
settings: BirdSettings,
|
||||
state: BirdState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
@@ -282,8 +282,8 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
settings: BirdSettings,
|
||||
state: BirdState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
@@ -367,8 +367,8 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
settings: BirdSettings,
|
||||
state: BirdState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
@@ -376,8 +376,8 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
settings: BirdSettings,
|
||||
state: BirdState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
@@ -385,8 +385,8 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
settings: BirdSettings,
|
||||
state: BirdState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
@@ -395,8 +395,8 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
settings: BirdSettings,
|
||||
state: BirdState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
@@ -404,8 +404,8 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
settings: BirdSettings,
|
||||
state: BirdState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
@@ -420,16 +420,16 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
settings: BirdSettings,
|
||||
state: BirdState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
settings: BirdSettings,
|
||||
state: BirdState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): ResourceLocation {
|
||||
@@ -439,44 +439,44 @@ class BirdAirBehaviour : RidingBehaviour<BirdAirSettings, BirdAirState> {
|
||||
return cobblemonResource("no_pose")
|
||||
}
|
||||
|
||||
override fun inertia(settings: BirdAirSettings, state: BirdAirState, vehicle: PokemonEntity): Double {
|
||||
override fun inertia(settings: BirdSettings, state: BirdState, vehicle: PokemonEntity): Double {
|
||||
return 0.5
|
||||
}
|
||||
|
||||
override fun shouldRoll(settings: BirdAirSettings, state: BirdAirState, vehicle: PokemonEntity): Boolean {
|
||||
override fun shouldRoll(settings: BirdSettings, state: BirdState, vehicle: PokemonEntity): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(settings: BirdAirSettings, state: BirdAirState, vehicle: PokemonEntity): Boolean {
|
||||
override fun turnOffOnGround(settings: BirdSettings, state: BirdState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun dismountOnShift(settings: BirdAirSettings, state: BirdAirState, vehicle: PokemonEntity): Boolean {
|
||||
override fun dismountOnShift(settings: BirdSettings, state: BirdState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
settings: BirdSettings,
|
||||
state: BirdState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(
|
||||
settings: BirdAirSettings,
|
||||
state: BirdAirState,
|
||||
settings: BirdSettings,
|
||||
state: BirdState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun createDefaultState(settings: BirdAirSettings) = BirdAirState()
|
||||
override fun createDefaultState(settings: BirdSettings) = BirdState()
|
||||
|
||||
}
|
||||
|
||||
class BirdAirSettings : RidingBehaviourSettings {
|
||||
override val key = BirdAirBehaviour.KEY
|
||||
class BirdSettings : RidingBehaviourSettings {
|
||||
override val key = BirdBehaviour.KEY
|
||||
|
||||
var infiniteAltitude: Expression = "false".asExpression()
|
||||
private set
|
||||
@@ -518,7 +518,7 @@ class BirdAirSettings : RidingBehaviourSettings {
|
||||
}
|
||||
}
|
||||
|
||||
class BirdAirState : RidingBehaviourState() {
|
||||
class BirdState : RidingBehaviourState() {
|
||||
var gliding = ridingState(false, Side.CLIENT)
|
||||
var lastGlide = ridingState(-100L, Side.CLIENT)
|
||||
var currRollCorrectionForce = ridingState(0.0, Side.CLIENT)
|
||||
@@ -542,10 +542,10 @@ class BirdAirState : RidingBehaviourState() {
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "BirdAirState(rideVelocity=${rideVelocity.get()}, stamina=${stamina.get()}, gliding=${gliding.get()})"
|
||||
return "BirdState(rideVelocity=${rideVelocity.get()}, stamina=${stamina.get()}, gliding=${gliding.get()})"
|
||||
}
|
||||
|
||||
override fun copy() = BirdAirState().also {
|
||||
override fun copy() = BirdState().also {
|
||||
it.rideVelocity.set(this.rideVelocity.get(), forced = true)
|
||||
it.stamina.set(this.stamina.get(), forced = true)
|
||||
it.gliding.set(this.gliding.get(), forced = true)
|
||||
@@ -554,7 +554,7 @@ class BirdAirState : RidingBehaviourState() {
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
if (previous !is BirdAirState) return false
|
||||
if (previous !is BirdState) return false
|
||||
if (previous.gliding.get() != gliding.get()) return true
|
||||
return super.shouldSync(previous)
|
||||
}
|
||||
+27
-27
@@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types.air
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
@@ -29,34 +29,34 @@ import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourState> {
|
||||
class GliderBehaviour : RidingBehaviour<GliderSettings, RidingBehaviourState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("air/glider")
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
|
||||
override fun getRidingStyle(settings: GliderAirSettings, state: RidingBehaviourState): RidingStyle {
|
||||
override fun getRidingStyle(settings: GliderSettings, state: RidingBehaviourState): RidingStyle {
|
||||
return RidingStyle.AIR
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<GliderAirSettings, RidingBehaviourState>(PoseType.HOVER)
|
||||
val poseProvider = PoseProvider<GliderSettings, RidingBehaviourState>(PoseType.HOVER)
|
||||
.with(PoseOption(PoseType.FLY) { _, _, entity -> entity.entityData.get(PokemonEntity.MOVING) })
|
||||
|
||||
override fun isActive(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
|
||||
override fun isActive(settings: GliderSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun pose(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity): PoseType {
|
||||
override fun pose(settings: GliderSettings, state: RidingBehaviourState, vehicle: PokemonEntity): PoseType {
|
||||
return poseProvider.select(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun speed(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity, driver: Player): Float {
|
||||
override fun speed(settings: GliderSettings, state: RidingBehaviourState, vehicle: PokemonEntity, driver: Player): Float {
|
||||
return vehicle.runtime.resolveFloat(settings.speed)
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
settings: GliderAirSettings,
|
||||
settings: GliderSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
@@ -65,7 +65,7 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: GliderAirSettings,
|
||||
settings: GliderSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
@@ -80,7 +80,7 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: GliderAirSettings,
|
||||
settings: GliderSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
@@ -90,7 +90,7 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: GliderAirSettings,
|
||||
settings: GliderSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
@@ -109,12 +109,12 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
|
||||
return Vec3(0.0, mouseY * invertPitch, mouseX * invertRoll)
|
||||
}
|
||||
|
||||
override fun canJump(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity, driver: Player): Boolean {
|
||||
override fun canJump(settings: GliderSettings, state: RidingBehaviourState, vehicle: PokemonEntity, driver: Player): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: GliderAirSettings,
|
||||
settings: GliderSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
@@ -123,7 +123,7 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: GliderAirSettings,
|
||||
settings: GliderSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
@@ -133,7 +133,7 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: GliderAirSettings,
|
||||
settings: GliderSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
@@ -142,7 +142,7 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: GliderAirSettings,
|
||||
settings: GliderSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
@@ -150,12 +150,12 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
|
||||
return 1.0f
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
|
||||
override fun useAngVelSmoothing(settings: GliderSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: GliderAirSettings,
|
||||
settings: GliderSettings,
|
||||
state: RidingBehaviourState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
@@ -163,35 +163,35 @@ class GliderAirBehaviour : RidingBehaviour<GliderAirSettings, RidingBehaviourSta
|
||||
return cobblemonResource("no_pose")
|
||||
}
|
||||
|
||||
override fun inertia(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Double {
|
||||
override fun inertia(settings: GliderSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Double {
|
||||
return 0.5
|
||||
}
|
||||
|
||||
override fun shouldRoll(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
|
||||
override fun shouldRoll(settings: GliderSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
|
||||
override fun turnOffOnGround(settings: GliderSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun dismountOnShift(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
|
||||
override fun dismountOnShift(settings: GliderSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
|
||||
override fun shouldRotatePokemonHead(settings: GliderSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(settings: GliderAirSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
|
||||
override fun shouldRotatePlayerHead(settings: GliderSettings, state: RidingBehaviourState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun createDefaultState(settings: GliderAirSettings) = RidingBehaviourState()
|
||||
override fun createDefaultState(settings: GliderSettings) = RidingBehaviourState()
|
||||
}
|
||||
|
||||
class GliderAirSettings : RidingBehaviourSettings {
|
||||
override val key = GliderAirBehaviour.KEY
|
||||
class GliderSettings : RidingBehaviourSettings {
|
||||
override val key = GliderBehaviour.KEY
|
||||
|
||||
var glideSpeed: Expression = "0.1".asExpression()
|
||||
private set
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types.air
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types.air
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
+43
-43
@@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types.air
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
@@ -30,21 +30,21 @@ import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import kotlin.math.*
|
||||
|
||||
class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
|
||||
class JetBehaviour : RidingBehaviour<JetSettings, JetState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("air/jet")
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
|
||||
override fun getRidingStyle(settings: JetAirSettings, state: JetAirState): RidingStyle {
|
||||
override fun getRidingStyle(settings: JetSettings, state: JetState): RidingStyle {
|
||||
return RidingStyle.AIR
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<JetAirSettings, JetAirState>(PoseType.HOVER)
|
||||
val poseProvider = PoseProvider<JetSettings, JetState>(PoseType.HOVER)
|
||||
.with(PoseOption(PoseType.FLY) { _, state, _ -> state.rideVelocity.get().z > 0.1 })
|
||||
|
||||
override fun isActive(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Boolean {
|
||||
override fun isActive(settings: JetSettings, state: JetState, vehicle: PokemonEntity): Boolean {
|
||||
return Shapes.create(vehicle.boundingBox).blockPositionsAsListRounded().any {
|
||||
//Need to check other fluids
|
||||
if (vehicle.isInWater || vehicle.isUnderWater) {
|
||||
@@ -59,11 +59,11 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
|
||||
}
|
||||
}
|
||||
|
||||
override fun pose(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): PoseType {
|
||||
override fun pose(settings: JetSettings, state: JetState, vehicle: PokemonEntity): PoseType {
|
||||
return poseProvider.select(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun speed(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity, driver: Player): Float {
|
||||
override fun speed(settings: JetSettings, state: JetState, vehicle: PokemonEntity, driver: Player): Float {
|
||||
//retrieve stats
|
||||
val topSpeed = vehicle.runtime.resolveDouble(settings.speedExpr)
|
||||
val staminaStat = vehicle.runtime.resolveDouble(settings.staminaExpr)
|
||||
@@ -104,8 +104,8 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
settings: JetAirSettings,
|
||||
state: JetAirState,
|
||||
settings: JetSettings,
|
||||
state: JetState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
@@ -113,8 +113,8 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: JetAirSettings,
|
||||
state: JetAirState,
|
||||
settings: JetSettings,
|
||||
state: JetState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
@@ -153,8 +153,8 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
|
||||
* Calculates the change in the ride space vector due to player input and ride state
|
||||
*/
|
||||
private fun calculateRideSpaceVel(
|
||||
settings: JetAirSettings,
|
||||
state: JetAirState,
|
||||
settings: JetSettings,
|
||||
state: JetState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
) {
|
||||
@@ -186,8 +186,8 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: JetAirSettings,
|
||||
state: JetAirState,
|
||||
settings: JetSettings,
|
||||
state: JetState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
@@ -211,8 +211,8 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: JetAirSettings,
|
||||
state: JetAirState,
|
||||
settings: JetSettings,
|
||||
state: JetState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
@@ -273,8 +273,8 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
settings: JetAirSettings,
|
||||
state: JetAirState,
|
||||
settings: JetSettings,
|
||||
state: JetState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
@@ -282,8 +282,8 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: JetAirSettings,
|
||||
state: JetAirState,
|
||||
settings: JetSettings,
|
||||
state: JetState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
@@ -291,8 +291,8 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: JetAirSettings,
|
||||
state: JetAirState,
|
||||
settings: JetSettings,
|
||||
state: JetState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
@@ -301,8 +301,8 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: JetAirSettings,
|
||||
state: JetAirState,
|
||||
settings: JetSettings,
|
||||
state: JetState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
@@ -310,8 +310,8 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: JetAirSettings,
|
||||
state: JetAirState,
|
||||
settings: JetSettings,
|
||||
state: JetState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
@@ -326,52 +326,52 @@ class JetAirBehaviour : RidingBehaviour<JetAirSettings, JetAirState> {
|
||||
return 1.0f + normalizedSpeed.pow(2).toFloat() * 0.2f
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Boolean {
|
||||
override fun useAngVelSmoothing(settings: JetSettings, state: JetState, vehicle: PokemonEntity): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: JetAirSettings,
|
||||
state: JetAirState,
|
||||
settings: JetSettings,
|
||||
state: JetState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): ResourceLocation {
|
||||
return cobblemonResource("no_pose")
|
||||
}
|
||||
|
||||
override fun inertia(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Double {
|
||||
override fun inertia(settings: JetSettings, state: JetState, vehicle: PokemonEntity): Double {
|
||||
return 1.0
|
||||
}
|
||||
|
||||
override fun shouldRoll(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Boolean {
|
||||
override fun shouldRoll(settings: JetSettings, state: JetState, vehicle: PokemonEntity): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Boolean {
|
||||
override fun turnOffOnGround(settings: JetSettings, state: JetState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun dismountOnShift(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Boolean {
|
||||
override fun dismountOnShift(settings: JetSettings, state: JetState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(
|
||||
settings: JetAirSettings,
|
||||
state: JetAirState,
|
||||
settings: JetSettings,
|
||||
state: JetState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(settings: JetAirSettings, state: JetAirState, vehicle: PokemonEntity): Boolean {
|
||||
override fun shouldRotatePlayerHead(settings: JetSettings, state: JetState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun createDefaultState(settings: JetAirSettings) = JetAirState()
|
||||
override fun createDefaultState(settings: JetSettings) = JetState()
|
||||
}
|
||||
|
||||
class JetAirSettings : RidingBehaviourSettings {
|
||||
override val key = JetAirBehaviour.KEY
|
||||
class JetSettings : RidingBehaviourSettings {
|
||||
override val key = JetBehaviour.KEY
|
||||
|
||||
var gravity: Expression = "0".asExpression()
|
||||
private set
|
||||
@@ -428,7 +428,7 @@ class JetAirSettings : RidingBehaviourSettings {
|
||||
}
|
||||
}
|
||||
|
||||
class JetAirState : RidingBehaviourState() {
|
||||
class JetState : RidingBehaviourState() {
|
||||
var currSpeed = ridingState(0.0, Side.CLIENT)
|
||||
var currMouseXForce = ridingState(0.0, Side.CLIENT)
|
||||
var currMouseYForce = ridingState(0.0, Side.CLIENT)
|
||||
@@ -451,7 +451,7 @@ class JetAirState : RidingBehaviourState() {
|
||||
currMouseYForce.set(0.0, forced = true)
|
||||
}
|
||||
|
||||
override fun copy() = JetAirState().also {
|
||||
override fun copy() = JetState().also {
|
||||
it.currSpeed.set(currSpeed.get(), forced = true)
|
||||
it.stamina.set(stamina.get(), forced = true)
|
||||
it.rideVelocity.set(rideVelocity.get(), forced = true)
|
||||
@@ -460,7 +460,7 @@ class JetAirState : RidingBehaviourState() {
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
if (previous !is JetAirState) return false
|
||||
if (previous !is JetState) return false
|
||||
if (previous.currSpeed != currSpeed) return true
|
||||
return super.shouldSync(previous)
|
||||
}
|
||||
+59
-59
@@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types.land
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
@@ -30,25 +30,25 @@ import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import kotlin.math.*
|
||||
|
||||
class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandState> {
|
||||
class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("land/generic")
|
||||
val KEY = cobblemonResource("land/horse")
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
|
||||
override fun getRidingStyle(settings: GenericLandSettings, state: GenericLandState): RidingStyle {
|
||||
override fun getRidingStyle(settings: HorseSettings, state: HorseState): RidingStyle {
|
||||
return RidingStyle.LAND
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<GenericLandSettings, GenericLandState>(PoseType.STAND)
|
||||
val poseProvider = PoseProvider<HorseSettings, HorseState>(PoseType.STAND)
|
||||
.with(PoseOption(PoseType.WALK) { _, state, _ ->
|
||||
return@PoseOption abs(state.rideVelocity.get().z) > 0.0
|
||||
})
|
||||
|
||||
override fun isActive(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
settings: HorseSettings,
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return Shapes.create(vehicle.boundingBox).blockPositionsAsListRounded().any {
|
||||
@@ -66,16 +66,16 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
}
|
||||
|
||||
override fun pose(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
settings: HorseSettings,
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity
|
||||
): PoseType {
|
||||
return this.poseProvider.select(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun speed(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
settings: HorseSettings,
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
@@ -102,8 +102,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
}
|
||||
|
||||
override fun updatePassengerRotation(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
settings: HorseSettings,
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
) {
|
||||
@@ -128,8 +128,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
}
|
||||
|
||||
override fun clampPassengerRotation(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
settings: HorseSettings,
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
) {
|
||||
@@ -143,8 +143,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
|
||||
|
||||
override fun rotation(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
settings: HorseSettings,
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
@@ -161,8 +161,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
* without it being instant.
|
||||
*/
|
||||
fun calcRotAmount(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
settings: HorseSettings,
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Float {
|
||||
@@ -198,8 +198,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
|
||||
|
||||
override fun velocity(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
settings: HorseSettings,
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
@@ -209,8 +209,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
}
|
||||
|
||||
private fun calculateRideSpaceVel(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
settings: HorseSettings,
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Vec3 {
|
||||
@@ -293,8 +293,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
settings: HorseSettings,
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
@@ -303,8 +303,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
settings: HorseSettings,
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
@@ -324,8 +324,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
settings: HorseSettings,
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
@@ -333,8 +333,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
settings: HorseSettings,
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
@@ -343,8 +343,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
settings: HorseSettings,
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
@@ -353,8 +353,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
settings: HorseSettings,
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
@@ -362,8 +362,8 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
settings: HorseSettings,
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
@@ -371,16 +371,16 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
settings: HorseSettings,
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
settings: HorseSettings,
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): ResourceLocation {
|
||||
@@ -392,58 +392,58 @@ class GenericLandBehaviour : RidingBehaviour<GenericLandSettings, GenericLandSta
|
||||
}
|
||||
|
||||
override fun inertia(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
settings: HorseSettings,
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity
|
||||
): Double {
|
||||
return 1.0
|
||||
}
|
||||
|
||||
override fun shouldRoll(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
settings: HorseSettings,
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
settings: HorseSettings,
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun dismountOnShift(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
settings: HorseSettings,
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
settings: HorseSettings,
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(
|
||||
settings: GenericLandSettings,
|
||||
state: GenericLandState,
|
||||
settings: HorseSettings,
|
||||
state: HorseState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun createDefaultState(settings: GenericLandSettings) = GenericLandState()
|
||||
override fun createDefaultState(settings: HorseSettings) = HorseState()
|
||||
}
|
||||
|
||||
class GenericLandSettings : RidingBehaviourSettings {
|
||||
override val key = GenericLandBehaviour.KEY
|
||||
class HorseSettings : RidingBehaviourSettings {
|
||||
override val key = HorseBehaviour.KEY
|
||||
|
||||
var canJump = "true".asExpression()
|
||||
private set
|
||||
@@ -486,7 +486,7 @@ class GenericLandSettings : RidingBehaviourSettings {
|
||||
|
||||
}
|
||||
|
||||
class GenericLandState : RidingBehaviourState() {
|
||||
class HorseState : RidingBehaviourState() {
|
||||
var sprinting = ridingState(false, Side.CLIENT)
|
||||
var inAir = ridingState(false, Side.CLIENT)
|
||||
|
||||
@@ -508,7 +508,7 @@ class GenericLandState : RidingBehaviourState() {
|
||||
inAir.set(false, forced = true)
|
||||
}
|
||||
|
||||
override fun copy() = GenericLandState().also {
|
||||
override fun copy() = HorseState().also {
|
||||
it.rideVelocity.set(this.rideVelocity.get(), forced = true)
|
||||
it.stamina.set(this.stamina.get(), forced = true)
|
||||
it.sprinting.set(this.sprinting.get(), forced = true)
|
||||
@@ -516,7 +516,7 @@ class GenericLandState : RidingBehaviourState() {
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
if (previous !is GenericLandState) return false
|
||||
if (previous !is HorseState) return false
|
||||
if (previous.sprinting.get() != sprinting.get()) return true
|
||||
if (previous.inAir.get() != inAir.get()) return true
|
||||
return super.shouldSync(previous)
|
||||
+46
-46
@@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types.land
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
@@ -31,7 +31,7 @@ import kotlin.math.absoluteValue
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandState> {
|
||||
class VehicleBehaviour : RidingBehaviour<VehicleSettings, VehicleState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("land/vehicle")
|
||||
|
||||
@@ -54,14 +54,14 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
|
||||
|
||||
override val key = KEY
|
||||
|
||||
override fun getRidingStyle(settings: VehicleLandSettings, state: VehicleLandState): RidingStyle {
|
||||
override fun getRidingStyle(settings: VehicleSettings, state: VehicleState): RidingStyle {
|
||||
return RidingStyle.LAND
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<VehicleLandSettings, VehicleLandState>(PoseType.STAND)
|
||||
val poseProvider = PoseProvider<VehicleSettings, VehicleState>(PoseType.STAND)
|
||||
.with(PoseOption(PoseType.WALK) { _, _, entity -> entity.entityData.get(PokemonEntity.MOVING) })
|
||||
|
||||
override fun isActive(settings: VehicleLandSettings, state: VehicleLandState, vehicle: PokemonEntity): Boolean {
|
||||
override fun isActive(settings: VehicleSettings, state: VehicleState, vehicle: PokemonEntity): Boolean {
|
||||
return Shapes.create(vehicle.boundingBox).blockPositionsAsListRounded().any {
|
||||
//Need to check other fluids
|
||||
if (vehicle.isInWater || vehicle.isUnderWater) {
|
||||
@@ -76,13 +76,13 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
|
||||
}
|
||||
}
|
||||
|
||||
override fun pose(settings: VehicleLandSettings, state: VehicleLandState, vehicle: PokemonEntity): PoseType {
|
||||
override fun pose(settings: VehicleSettings, state: VehicleState, vehicle: PokemonEntity): PoseType {
|
||||
return poseProvider.select(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun speed(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
settings: VehicleSettings,
|
||||
state: VehicleState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
@@ -101,8 +101,8 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
settings: VehicleSettings,
|
||||
state: VehicleState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
@@ -113,8 +113,8 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
settings: VehicleSettings,
|
||||
state: VehicleState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
@@ -134,8 +134,8 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
settings: VehicleSettings,
|
||||
state: VehicleState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
@@ -144,8 +144,8 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
settings: VehicleSettings,
|
||||
state: VehicleState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
@@ -164,8 +164,8 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
settings: VehicleSettings,
|
||||
state: VehicleState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
@@ -173,8 +173,8 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
settings: VehicleSettings,
|
||||
state: VehicleState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
@@ -182,8 +182,8 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
settings: VehicleSettings,
|
||||
state: VehicleState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
@@ -195,8 +195,8 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
settings: VehicleSettings,
|
||||
state: VehicleState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
@@ -204,8 +204,8 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
settings: VehicleSettings,
|
||||
state: VehicleState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
@@ -213,67 +213,67 @@ class VehicleLandBehaviour : RidingBehaviour<VehicleLandSettings, VehicleLandSta
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
settings: VehicleSettings,
|
||||
state: VehicleState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
settings: VehicleSettings,
|
||||
state: VehicleState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): ResourceLocation {
|
||||
return cobblemonResource("no_pose")
|
||||
}
|
||||
|
||||
override fun inertia(settings: VehicleLandSettings, state: VehicleLandState, vehicle: PokemonEntity): Double {
|
||||
override fun inertia(settings: VehicleSettings, state: VehicleState, vehicle: PokemonEntity): Double {
|
||||
return 0.5
|
||||
}
|
||||
|
||||
override fun shouldRoll(settings: VehicleLandSettings, state: VehicleLandState, vehicle: PokemonEntity): Boolean {
|
||||
override fun shouldRoll(settings: VehicleSettings, state: VehicleState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
settings: VehicleSettings,
|
||||
state: VehicleState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun dismountOnShift(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
settings: VehicleSettings,
|
||||
state: VehicleState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
settings: VehicleSettings,
|
||||
state: VehicleState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(
|
||||
settings: VehicleLandSettings,
|
||||
state: VehicleLandState,
|
||||
settings: VehicleSettings,
|
||||
state: VehicleState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun createDefaultState(settings: VehicleLandSettings) = VehicleLandState()
|
||||
override fun createDefaultState(settings: VehicleSettings) = VehicleState()
|
||||
}
|
||||
|
||||
class VehicleLandSettings : RidingBehaviourSettings {
|
||||
override val key = VehicleLandBehaviour.KEY
|
||||
class VehicleSettings : RidingBehaviourSettings {
|
||||
override val key = VehicleBehaviour.KEY
|
||||
|
||||
var canJump = "true".asExpression()
|
||||
private set
|
||||
@@ -329,7 +329,7 @@ class VehicleLandSettings : RidingBehaviourSettings {
|
||||
}
|
||||
}
|
||||
|
||||
class VehicleLandState : RidingBehaviourState() {
|
||||
class VehicleState : RidingBehaviourState() {
|
||||
var currSpeed = ridingState(0.0, Side.BOTH)
|
||||
var deltaRotation = ridingState(Vec2.ZERO, Side.BOTH)
|
||||
|
||||
@@ -340,10 +340,10 @@ class VehicleLandState : RidingBehaviourState() {
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "VehicleLandState(currSpeed=${currSpeed.get()}, deltaRotation=${deltaRotation.get()})"
|
||||
return "VehicleState(currSpeed=${currSpeed.get()}, deltaRotation=${deltaRotation.get()})"
|
||||
}
|
||||
|
||||
override fun copy() = VehicleLandState().also {
|
||||
override fun copy() = VehicleState().also {
|
||||
it.rideVelocity.set(rideVelocity.get(), forced = true)
|
||||
it.stamina.set(stamina.get(), forced = true)
|
||||
it.currSpeed.set(currSpeed.get(), forced = true)
|
||||
+383
@@ -0,0 +1,383 @@
|
||||
/*
|
||||
* 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.riding.behaviour.types.liquid
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
import com.cobblemon.mod.common.api.riding.RidingStyle
|
||||
import com.cobblemon.mod.common.api.riding.behaviour.*
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseOption
|
||||
import com.cobblemon.mod.common.api.riding.posing.PoseProvider
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.util.SmoothDouble
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
class BoatBehaviour : RidingBehaviour<BoatSettings, BoatState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("liquid/boat")
|
||||
val TOP_SPEED = 2.0
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
|
||||
override fun getRidingStyle(settings: BoatSettings, state: BoatState): RidingStyle {
|
||||
return RidingStyle.LIQUID
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<BoatSettings, BoatState>(PoseType.FLOAT)
|
||||
.with(PoseOption(PoseType.SWIM) { _, _, entity -> entity.isSwimming && entity.entityData.get(PokemonEntity.MOVING) })
|
||||
|
||||
override fun isActive(settings: BoatSettings, state: BoatState, vehicle: PokemonEntity): Boolean {
|
||||
if (state.jumpBuffer.get() != -1) {
|
||||
return true
|
||||
}
|
||||
return Shapes.create(vehicle.boundingBox).blockPositionsAsListRounded().any {
|
||||
if (vehicle.isInWater || vehicle.isUnderWater) {
|
||||
return@any true
|
||||
}
|
||||
val blockState = vehicle.level().getBlockState(it)
|
||||
return@any !blockState.fluidState.isEmpty
|
||||
}
|
||||
}
|
||||
|
||||
override fun tick(
|
||||
settings: BoatSettings,
|
||||
state: BoatState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
) {
|
||||
if (state.jumpBuffer.get() > 5) {
|
||||
if ((vehicle.isInWater || vehicle.isUnderWater || vehicle.onGround())) {
|
||||
state.jumpBuffer.set(-1)
|
||||
}
|
||||
}
|
||||
else if (state.jumpBuffer.get() > -1) {
|
||||
state.jumpBuffer.set(state.jumpBuffer.get() + 1)
|
||||
}
|
||||
|
||||
if (driver.zza == 0f && (vehicle.isInWater || vehicle.isUnderWater)) {
|
||||
if (state.staminaBuffer.get() >= 20) {
|
||||
val staminaIncrease = vehicle.getRideStat(RidingStat.STAMINA, RidingStyle.LIQUID, 1.0, 2.0)
|
||||
state.stamina.set(min(1.0f, state.stamina.get() + 0.01f * staminaIncrease.toFloat()))
|
||||
}
|
||||
}
|
||||
else if (abs(state.rideVelocity.get().z) > 0.1) {
|
||||
consumeStamina(vehicle, state, 0.01f)
|
||||
}
|
||||
state.staminaBuffer.set(state.staminaBuffer.get() + 1)
|
||||
super.tick(settings, state, vehicle, driver, input)
|
||||
}
|
||||
|
||||
override fun pose(settings: BoatSettings, state: BoatState, vehicle: PokemonEntity): PoseType {
|
||||
return poseProvider.select(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun speed(settings: BoatSettings, state: BoatState, vehicle: PokemonEntity, driver: Player): Float {
|
||||
return state.rideVelocity.get().length().toFloat()
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
settings: BoatSettings,
|
||||
state: BoatState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
state.deltaRotation.set(state.deltaRotation.get() * 0.8)
|
||||
return Vec2(vehicle.xRot, vehicle.yRot + state.deltaRotation.get().toFloat())
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: BoatSettings,
|
||||
state: BoatState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
): Vec3 {
|
||||
applyStrafeRotation(vehicle, driver, state)
|
||||
|
||||
var velocity = state.rideVelocity.get()
|
||||
velocity = applyVelocityFromInput(velocity, vehicle, driver, state)
|
||||
velocity = applyGravity(velocity, vehicle, settings, state)
|
||||
velocity = applyJump(velocity, vehicle, driver, state)
|
||||
state.rideVelocity.set(velocity)
|
||||
return state.rideVelocity.get()
|
||||
}
|
||||
|
||||
private fun applyVelocityFromInput(velocity: Vec3, vehicle: PokemonEntity, driver: Player, state: BoatState): Vec3 {
|
||||
val speed = vehicle.getRideStat(RidingStat.SPEED, RidingStyle.LIQUID, 0.8, TOP_SPEED)
|
||||
val acceleration = vehicle.getRideStat(RidingStat.ACCELERATION, RidingStyle.LIQUID, 0.05, 0.5)
|
||||
|
||||
if (state.jumpBuffer.get() != -1 || !(vehicle.isInWater || vehicle.isUnderWater)) {
|
||||
return velocity
|
||||
}
|
||||
|
||||
val forwardInput = driver.zza.toDouble()
|
||||
val delta = when {
|
||||
!hasStamina(state) || forwardInput == 0.0 -> -velocity.z * 0.04
|
||||
forwardInput < 0.0 -> when {
|
||||
velocity.z < 0.0 -> forwardInput * acceleration * 0.5
|
||||
else -> min(forwardInput * acceleration * 0.5, -velocity.z * 0.04) // We never want it to be slower to reverse than no input
|
||||
}
|
||||
else -> forwardInput * acceleration
|
||||
}
|
||||
|
||||
return Vec3(
|
||||
velocity.x,
|
||||
velocity.y,
|
||||
Mth.clamp(velocity.z + delta, -speed * 0.25, speed)
|
||||
)
|
||||
}
|
||||
|
||||
private fun applyJump(velocity: Vec3, vehicle: PokemonEntity, driver: Player, state: BoatState): Vec3 {
|
||||
if (!driver.jumping) return velocity // Not jumping
|
||||
if (state.jumpBuffer.get() != -1) return velocity // Already jumped very recently
|
||||
if (!hasStamina(state)) return velocity // Has no stamina
|
||||
|
||||
val jumpStrength = vehicle.getRideStat(RidingStat.JUMP, RidingStyle.LIQUID, 1.0, 2.5)
|
||||
state.jumpBuffer.set(0)
|
||||
consumeStamina(vehicle, state, 0.05f)
|
||||
return Vec3(velocity.x, velocity.y + jumpStrength, velocity.z)
|
||||
}
|
||||
|
||||
private fun applyGravity(velocity: Vec3, vehicle: PokemonEntity, settings: BoatSettings, state: BoatState): Vec3 {
|
||||
if (state.jumpBuffer.get() == -1 && vehicle.isInWater || vehicle.isUnderWater) {
|
||||
return Vec3(velocity.x, -0.05, velocity.z)
|
||||
}
|
||||
val terminalVelocity = vehicle.runtime.resolveDouble(settings.terminalVelocity)
|
||||
val gravity = (9.8 / ( 20.0)) * 0.2
|
||||
return Vec3(velocity.x, max(velocity.y - gravity, terminalVelocity), velocity.z)
|
||||
}
|
||||
|
||||
private fun applyStrafeRotation(vehicle: PokemonEntity, driver: Player, state: BoatState) {
|
||||
val skill = vehicle.getRideStat(RidingStat.SKILL, RidingStyle.LIQUID, 0.5, 1.5)
|
||||
val strafe = driver.xxa
|
||||
if (abs(strafe) > 0) {
|
||||
val increase = if (strafe > 0) -1 else 1
|
||||
state.deltaRotation.set(state.deltaRotation.get() + increase * skill)
|
||||
}
|
||||
}
|
||||
|
||||
private fun hasStamina(state: BoatState): Boolean {
|
||||
return state.stamina.get() != 0f
|
||||
}
|
||||
|
||||
private fun consumeStamina(vehicle: PokemonEntity, state: BoatState, drain: Float) {
|
||||
val stamina = vehicle.getRideStat(RidingStat.STAMINA, RidingStyle.LIQUID, 1.0, 5.0)
|
||||
state.stamina.set(max(0f, state.stamina.get() - drain / stamina.toFloat()))
|
||||
state.staminaBuffer.set(0)
|
||||
}
|
||||
|
||||
override fun updatePassengerRotation(
|
||||
settings: BoatSettings,
|
||||
state: BoatState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
) {
|
||||
driver.yRot += state.deltaRotation.get().toFloat() * 0.887f
|
||||
driver.yHeadRot += state.deltaRotation.get().toFloat() * 0.887f
|
||||
clampPassengerRotation(settings, state, vehicle, driver)
|
||||
}
|
||||
|
||||
override fun clampPassengerRotation(
|
||||
settings: BoatSettings,
|
||||
state: BoatState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
) {
|
||||
driver.setYBodyRot(vehicle.yRot)
|
||||
val f: Float = Mth.wrapDegrees(driver.yRot - vehicle.yRot)
|
||||
val g = Mth.clamp(f, -105.0f, 105.0f)
|
||||
driver.yRotO += g - f
|
||||
driver.yRot = driver.yRot + g - f
|
||||
driver.setYHeadRot(driver.yRot)
|
||||
vehicle.setYHeadRot(driver.yRot)
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: BoatSettings,
|
||||
state: BoatState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: BoatSettings,
|
||||
state: BoatState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
mouseX: Double,
|
||||
mouseYSmoother: SmoothDouble,
|
||||
mouseXSmoother: SmoothDouble,
|
||||
sensitivity: Double,
|
||||
deltaTime: Double
|
||||
): Vec3 {
|
||||
if (driver !is OrientationControllable) return Vec3.ZERO
|
||||
|
||||
//Might need to add the smoothing here for default.
|
||||
val invertRoll = if (Cobblemon.config.invertRoll) -1 else 1
|
||||
val invertPitch = if (Cobblemon.config.invertPitch) -1 else 1
|
||||
return Vec3(0.0, mouseY * invertPitch, mouseX * invertRoll)
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
settings: BoatSettings,
|
||||
state: BoatState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: BoatSettings,
|
||||
state: BoatState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return (state.stamina.get() / 1.0f)
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: BoatSettings,
|
||||
state: BoatState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
): Vec3 {
|
||||
return Vec3.ZERO
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: BoatSettings,
|
||||
state: BoatState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: BoatSettings,
|
||||
state: BoatState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
if (state.rideVelocity.get().z > TOP_SPEED * 0.8) {
|
||||
return Mth.lerp((state.rideVelocity.get().z - (TOP_SPEED * 0.8)) / (TOP_SPEED * 0.2), 1.0, 1.2).toFloat()
|
||||
}
|
||||
return 1.0f
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(settings: BoatSettings, state: BoatState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: BoatSettings,
|
||||
state: BoatState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): ResourceLocation {
|
||||
return cobblemonResource("no_pose")
|
||||
}
|
||||
|
||||
override fun inertia(settings: BoatSettings, state: BoatState, vehicle: PokemonEntity): Double {
|
||||
return 0.5
|
||||
}
|
||||
|
||||
override fun shouldRoll(settings: BoatSettings, state: BoatState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(settings: BoatSettings, state: BoatState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun dismountOnShift(settings: BoatSettings, state: BoatState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(
|
||||
settings: BoatSettings,
|
||||
state: BoatState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return vehicle.runtime.resolveBoolean(settings.rotatePokemonHead)
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(
|
||||
settings: BoatSettings,
|
||||
state: BoatState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun maxUpStep(settings: BoatSettings, state: BoatState, vehicle: PokemonEntity) = 0f
|
||||
|
||||
override fun createDefaultState(settings: BoatSettings) = BoatState()
|
||||
|
||||
}
|
||||
|
||||
class BoatSettings : RidingBehaviourSettings {
|
||||
override val key = BoatBehaviour.KEY
|
||||
|
||||
var terminalVelocity = "-2.0".asExpression()
|
||||
private set
|
||||
|
||||
var rotatePokemonHead = "true".asExpression()
|
||||
private set
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(key)
|
||||
buffer.writeExpression(terminalVelocity)
|
||||
}
|
||||
|
||||
override fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
terminalVelocity = buffer.readExpression()
|
||||
}
|
||||
}
|
||||
|
||||
class BoatState : RidingBehaviourState() {
|
||||
val deltaRotation = ridingState(0.0, Side.CLIENT)
|
||||
val jumpBuffer = ridingState(-1, Side.CLIENT)
|
||||
val staminaBuffer = ridingState(0, Side.CLIENT)
|
||||
|
||||
override fun copy() = BoatState().also {
|
||||
it.deltaRotation.set(deltaRotation.get(), true)
|
||||
it.rideVelocity.set(rideVelocity.get(), true)
|
||||
it.stamina.set(stamina.get(), true)
|
||||
it.jumpBuffer.set(jumpBuffer.get(), true)
|
||||
it.staminaBuffer.set(staminaBuffer.get(), true)
|
||||
}
|
||||
|
||||
override fun shouldSync(previous: RidingBehaviourState): Boolean {
|
||||
if (previous !is BoatState) return false
|
||||
return super.shouldSync(previous)
|
||||
}
|
||||
|
||||
}
|
||||
+44
-44
@@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types.liquid
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.OrientationControllable
|
||||
@@ -27,22 +27,22 @@ import net.minecraft.world.phys.Vec2
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
|
||||
class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
|
||||
class BurstBehaviour : RidingBehaviour<BurstSettings, BurstState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("swim/dash")
|
||||
val KEY = cobblemonResource("liquid/burst")
|
||||
const val DASH_TICKS: Int = 60
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
|
||||
override fun getRidingStyle(settings: SwimDashSettings, state: SwimDashState): RidingStyle {
|
||||
override fun getRidingStyle(settings: BurstSettings, state: BurstState): RidingStyle {
|
||||
return RidingStyle.LIQUID
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<SwimDashSettings, SwimDashState>(PoseType.FLOAT)
|
||||
val poseProvider = PoseProvider<BurstSettings, BurstState>(PoseType.FLOAT)
|
||||
.with(PoseOption(PoseType.SWIM) { _, _, entity -> entity.isSwimming && entity.entityData.get(PokemonEntity.MOVING) })
|
||||
|
||||
override fun isActive(settings: SwimDashSettings, state: SwimDashState, vehicle: PokemonEntity): Boolean {
|
||||
override fun isActive(settings: BurstSettings, state: BurstState, vehicle: PokemonEntity): Boolean {
|
||||
//This could be kinda weird... what if the top of the mon is in a fluid but the bottom isnt?
|
||||
return Shapes.create(vehicle.boundingBox).blockPositionsAsListRounded().any {
|
||||
if (vehicle.isInWater || vehicle.isUnderWater) {
|
||||
@@ -53,13 +53,13 @@ class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
|
||||
}
|
||||
}
|
||||
|
||||
override fun pose(settings: SwimDashSettings, state: SwimDashState, vehicle: PokemonEntity): PoseType {
|
||||
override fun pose(settings: BurstSettings, state: BurstState, vehicle: PokemonEntity): PoseType {
|
||||
return poseProvider.select(settings, state, vehicle)
|
||||
}
|
||||
|
||||
override fun speed(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
settings: BurstSettings,
|
||||
state: BurstState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
@@ -77,8 +77,8 @@ class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
|
||||
}
|
||||
|
||||
override fun rotation(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
settings: BurstSettings,
|
||||
state: BurstState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: LivingEntity
|
||||
): Vec2 {
|
||||
@@ -86,8 +86,8 @@ class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
|
||||
}
|
||||
|
||||
override fun velocity(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
settings: BurstSettings,
|
||||
state: BurstState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
input: Vec3
|
||||
@@ -102,8 +102,8 @@ class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
|
||||
}
|
||||
|
||||
override fun angRollVel(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
settings: BurstSettings,
|
||||
state: BurstState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
deltaTime: Double
|
||||
@@ -112,8 +112,8 @@ class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
|
||||
}
|
||||
|
||||
override fun rotationOnMouseXY(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
settings: BurstSettings,
|
||||
state: BurstState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
mouseY: Double,
|
||||
@@ -132,8 +132,8 @@ class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
|
||||
}
|
||||
|
||||
override fun canJump(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
settings: BurstSettings,
|
||||
state: BurstState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Boolean {
|
||||
@@ -141,8 +141,8 @@ class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
|
||||
}
|
||||
|
||||
override fun setRideBar(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
settings: BurstSettings,
|
||||
state: BurstState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
@@ -150,8 +150,8 @@ class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
|
||||
}
|
||||
|
||||
override fun jumpForce(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
settings: BurstSettings,
|
||||
state: BurstState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player,
|
||||
jumpStrength: Int
|
||||
@@ -160,8 +160,8 @@ class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
|
||||
}
|
||||
|
||||
override fun gravity(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
settings: BurstSettings,
|
||||
state: BurstState,
|
||||
vehicle: PokemonEntity,
|
||||
regularGravity: Double
|
||||
): Double {
|
||||
@@ -169,64 +169,64 @@ class SwimDashBehaviour : RidingBehaviour<SwimDashSettings, SwimDashState> {
|
||||
}
|
||||
|
||||
override fun rideFovMultiplier(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
settings: BurstSettings,
|
||||
state: BurstState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): Float {
|
||||
return 1.0f
|
||||
}
|
||||
|
||||
override fun useAngVelSmoothing(settings: SwimDashSettings, state: SwimDashState, vehicle: PokemonEntity): Boolean {
|
||||
override fun useAngVelSmoothing(settings: BurstSettings, state: BurstState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun useRidingAltPose(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
settings: BurstSettings,
|
||||
state: BurstState,
|
||||
vehicle: PokemonEntity,
|
||||
driver: Player
|
||||
): ResourceLocation {
|
||||
return cobblemonResource("no_pose")
|
||||
}
|
||||
|
||||
override fun inertia(settings: SwimDashSettings, state: SwimDashState, vehicle: PokemonEntity): Double {
|
||||
override fun inertia(settings: BurstSettings, state: BurstState, vehicle: PokemonEntity): Double {
|
||||
return 0.5
|
||||
}
|
||||
|
||||
override fun shouldRoll(settings: SwimDashSettings, state: SwimDashState, vehicle: PokemonEntity): Boolean {
|
||||
override fun shouldRoll(settings: BurstSettings, state: BurstState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun turnOffOnGround(settings: SwimDashSettings, state: SwimDashState, vehicle: PokemonEntity): Boolean {
|
||||
override fun turnOffOnGround(settings: BurstSettings, state: BurstState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun dismountOnShift(settings: SwimDashSettings, state: SwimDashState, vehicle: PokemonEntity): Boolean {
|
||||
override fun dismountOnShift(settings: BurstSettings, state: BurstState, vehicle: PokemonEntity): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePokemonHead(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
settings: BurstSettings,
|
||||
state: BurstState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun shouldRotatePlayerHead(
|
||||
settings: SwimDashSettings,
|
||||
state: SwimDashState,
|
||||
settings: BurstSettings,
|
||||
state: BurstState,
|
||||
vehicle: PokemonEntity
|
||||
): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun createDefaultState(settings: SwimDashSettings) = SwimDashState()
|
||||
override fun createDefaultState(settings: BurstSettings) = BurstState()
|
||||
}
|
||||
|
||||
class SwimDashSettings : RidingBehaviourSettings {
|
||||
override val key = SwimDashBehaviour.KEY
|
||||
class BurstSettings : RidingBehaviourSettings {
|
||||
override val key = BurstBehaviour.KEY
|
||||
|
||||
var dashSpeed = 1F
|
||||
private set
|
||||
@@ -241,7 +241,7 @@ class SwimDashSettings : RidingBehaviourSettings {
|
||||
}
|
||||
}
|
||||
|
||||
class SwimDashState : RidingBehaviourState() {
|
||||
class BurstState : RidingBehaviourState() {
|
||||
var dashing = ridingState(false, Side.BOTH)
|
||||
var ticks = ridingState(0, Side.BOTH)
|
||||
|
||||
@@ -252,10 +252,10 @@ class SwimDashState : RidingBehaviourState() {
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "SwimDashState(dashing=${dashing.get()}, ticks=${ticks.get()})"
|
||||
return "BurstState(dashing=${dashing.get()}, ticks=${ticks.get()})"
|
||||
}
|
||||
|
||||
override fun copy() = SwimDashState().also {
|
||||
override fun copy() = BurstState().also {
|
||||
it.rideVelocity.set(rideVelocity.get(), forced = true)
|
||||
it.stamina.set(stamina.get(), forced = true)
|
||||
it.dashing.set(dashing.get(), forced = true)
|
||||
+2
-2
@@ -6,7 +6,7 @@
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types
|
||||
package com.cobblemon.mod.common.api.riding.behaviour.types.liquid
|
||||
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
@@ -32,7 +32,7 @@ import kotlin.math.sin
|
||||
|
||||
class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("swim/dolphin")
|
||||
val KEY = cobblemonResource("liquid/dolphin")
|
||||
}
|
||||
|
||||
override val key = KEY
|
||||
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.api.spawning.detail
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.npc.NPCClass
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnBucket
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
@@ -16,6 +17,7 @@ import com.cobblemon.mod.common.api.spawning.selection.SpawnSelectionData
|
||||
import com.cobblemon.mod.common.entity.npc.NPCEntity
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlin.math.ceil
|
||||
|
||||
/**
|
||||
* A [SpawnDetail] describing an [NPCEntity] spawn.
|
||||
@@ -37,6 +39,16 @@ class NPCSpawnDetail : SpawnDetail() {
|
||||
val minLevel: Expression = "1".asExpression()
|
||||
val maxLevel: Expression = "100".asExpression()
|
||||
|
||||
|
||||
override fun autoLabel() {
|
||||
val npcClass = this.npcClass
|
||||
|
||||
struct.addFunction("class") { StringValue(npcClass.resourceIdentifier.toString()) }
|
||||
labels.add(npcClass.resourceIdentifier.toString())
|
||||
|
||||
super.autoLabel()
|
||||
}
|
||||
|
||||
override fun createSpawnAction(
|
||||
spawnablePosition: SpawnablePosition,
|
||||
bucket: SpawnBucket,
|
||||
|
||||
@@ -151,6 +151,11 @@ open class PlayerPartyStore(
|
||||
removeList.add(it)
|
||||
}
|
||||
removeList.forEach { pokemon.evolutionProxy.server().remove(it) }
|
||||
|
||||
// Metabolism for Fullness
|
||||
if (pokemon.currentFullness > 0) {
|
||||
pokemon.tickMetabolism()
|
||||
}
|
||||
}
|
||||
// Friendship
|
||||
// ToDo expand this down the line just a very basic implementation for the first releases
|
||||
|
||||
@@ -44,7 +44,17 @@ class Search(
|
||||
"legendary" -> PokemonFilter { pokemon -> pokemon.isLegendary() }
|
||||
"mythical" -> PokemonFilter { pokemon -> pokemon.isMythical() }
|
||||
"ultrabeast", "ultra_beast" -> PokemonFilter { pokemon -> pokemon.isUltraBeast() }
|
||||
else -> PokemonFilter { pokemon -> PokemonProperties.parse(filter).matches(pokemon) }
|
||||
else -> {
|
||||
val nameFilter = filter.lowercase(Locale.ROOT)
|
||||
PokemonFilter { pokemon ->
|
||||
// search by partial name
|
||||
if (pokemon.species.resourceIdentifier.path.contains(nameFilter)) {
|
||||
return@PokemonFilter true
|
||||
}
|
||||
// search by exactly match in different props
|
||||
return@PokemonFilter PokemonProperties.parse(filter).matches(pokemon)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inverted) {
|
||||
|
||||
@@ -57,7 +57,8 @@ object CobblemonBlockTags {
|
||||
@JvmField val MACHINES = createTag("machines")
|
||||
@JvmField val MANSION_BLOCKS = createTag("mansion_blocks")
|
||||
@JvmField val MEDICINAL_LEEK_PLANTABLE = createTag("medicinal_leek_plantable")
|
||||
@JvmField val HEARTY_GRAINS_PLANTABLE = createTag("hearty_grains_plantable")
|
||||
@JvmField val HEARTY_GRAINS_LAND_PLANTABLE = createTag("hearty_grains_land_plantable")
|
||||
@JvmField val HEARTY_GRAINS_WATER_PLANTABLE = createTag("hearty_grains_water_plantable")
|
||||
@JvmField val MINTS = createTag("mints")
|
||||
@JvmField val MOON_STONE_ORES = createTag("moon_stone_ores")
|
||||
@JvmField val NATURAL = createTag("natural")
|
||||
|
||||
@@ -28,6 +28,7 @@ object CobblemonItemTags {
|
||||
@JvmField val APRICORN_POKE_BALLS = create("apricorn_poke_balls")
|
||||
@JvmField val APRICORN_SPROUTS = create("apricorn_sprouts")
|
||||
@JvmField val APRICORNS = create("apricorns")
|
||||
@JvmField val APRIJUICES = create("aprijuices")
|
||||
/** This tag is only used for a Torterra aspect based easter egg evolution at the moment.
|
||||
* It simply includes the 'minecraft:azalea' and 'minecraft:flowering_azalea' items by default. */
|
||||
@JvmField val AZALEA_TREE = create("azalea_tree")
|
||||
@@ -51,6 +52,7 @@ object CobblemonItemTags {
|
||||
@JvmField val FIRE_STONE_ORES = create("fire_stone_ores")
|
||||
@JvmField val FOSSIL_MACHINE_PARTS = create("fossil_machine_parts")
|
||||
@JvmField val FOSSILS = create("fossils")
|
||||
@JvmField val FULL_HEAL_INGREDIENTS = create("full_heal_ingredients")
|
||||
@JvmField val GILDED_CHESTS = create("gilded_chests")
|
||||
@JvmField val HANGING_SIGNS = create("hanging_signs")
|
||||
@JvmField val HERBS = create("herbs")
|
||||
@@ -60,6 +62,7 @@ object CobblemonItemTags {
|
||||
@JvmField val MINT_LEAF = create("mint_leaf")
|
||||
@JvmField val MINT_SEEDS = create("mint_seeds")
|
||||
@JvmField val MINTS = create("mints")
|
||||
@JvmField val MOCHIS = create("mochis")
|
||||
@JvmField val MOON_STONE_ORES = create("moon_stone_ores")
|
||||
@JvmField val MUTATED_BERRIES = create("mutated_berries")
|
||||
@JvmField val PLANTS = create("plants")
|
||||
@@ -67,6 +70,7 @@ object CobblemonItemTags {
|
||||
@JvmField val POKE_RODS = create("poke_rods")
|
||||
@JvmField val POKEDEX = create("pokedex")
|
||||
@JvmField val POKEDEX_SCREEN = create("pokedex_screen")
|
||||
@JvmField val POKE_FOOD = create("poke_food")
|
||||
@JvmField val POTIONS = create("potions")
|
||||
@JvmField val PROTEIN_INGREDIENTS = create("protein_ingredients")
|
||||
/** See [COOKED_MEAT] */
|
||||
@@ -74,14 +78,18 @@ object CobblemonItemTags {
|
||||
@JvmField val RED_TUMBLESTONE_BRICKS = create("red_tumblestone_bricks")
|
||||
@JvmField val RED_TUMBLESTONES = create("red_tumblestones")
|
||||
@JvmField val REMEDIES = create("remedies")
|
||||
@JvmField val REMEDY_BERRIES = create("remedy_berries")
|
||||
@JvmField val RESTORES = create("restores")
|
||||
@JvmField val REVIVES = create("revives")
|
||||
@JvmField val SANDWICH_VEGGIE = create("sandwich_veggies")
|
||||
@JvmField val SEEDS = create("seeds")
|
||||
@JvmField val SHINY_STONE_ORES = create("shiny_stone_ores")
|
||||
@JvmField val SIGNS = create("signs")
|
||||
@JvmField val SKY_TUMBLESTONE_BRICKS = create("sky_tumblestone_bricks")
|
||||
@JvmField val SKY_TUMBLESTONES = create("sky_tumblestones")
|
||||
@JvmField val SUN_STONE_ORES = create("sun_stone_ores")
|
||||
@JvmField val SUPER_POTION_INGREDIENTS = create("super_potion_ingredients")
|
||||
@JvmField val FULL_HEAL_BOTTLES = create("full_heal_bottles")
|
||||
@JvmField val SWEETS = create("sweets")
|
||||
@JvmField val TEACUPS = create("teacups")
|
||||
@JvmField val TEAPOTS = create("teapots")
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleStartedPostEvent
|
||||
import com.cobblemon.mod.common.api.events.battles.BattleStartedPreEvent
|
||||
import com.cobblemon.mod.common.api.moves.HiddenPowerUtil
|
||||
import com.cobblemon.mod.common.api.pokemon.helditem.HeldItemProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
@@ -96,7 +97,7 @@ object BattleRegistry {
|
||||
// Gender
|
||||
packedTeamBuilder.append("${pk.gender.showdownName}|")
|
||||
// IVs
|
||||
val ivsInOrder = Stats.PERMANENT.map { pk.ivs.getOrDefault(it) }.joinToString(separator = ",")
|
||||
val ivsInOrder = Stats.PERMANENT.map { pk.ivs.getEffectiveBattleIV(it) }.joinToString(separator = ",")
|
||||
packedTeamBuilder.append("$ivsInOrder|")
|
||||
// Shiny
|
||||
packedTeamBuilder.append("${if (pk.shiny) "S" else ""}|")
|
||||
@@ -111,7 +112,9 @@ object BattleRegistry {
|
||||
val pokeball = pokemon.effectedPokemon.caughtBall.name.path.replace("_", "")
|
||||
packedTeamBuilder.append("$pokeball,")
|
||||
// Hidden Power Type
|
||||
packedTeamBuilder.append(",")
|
||||
// This is empty if the pokemon is not Hyper Trained, and the provided type corresponds to base IVs and not battle IVs.
|
||||
val hiddenPowerType = if (pk.ivs.hyperTrainedIVs.any()) HiddenPowerUtil.getHiddenPowerType(pk).name.replaceFirstChar { it.uppercase() } else ""
|
||||
packedTeamBuilder.append("$hiddenPowerType,")
|
||||
// Gigantamax
|
||||
packedTeamBuilder.append("${if (pk.gmaxFactor) "G" else ""},")
|
||||
// DynamaxLevel
|
||||
|
||||
+1
-1
@@ -100,7 +100,7 @@ class ActivateInstruction(val instructionSet: InstructionSet, val message: Battl
|
||||
// Includes spited move and the PP it was reduced by
|
||||
"spite", "eeriespell" -> battleLang("activate.spite", pokemonName, extraEffect, message.argumentAt(3)!!)
|
||||
// Don't need additional lang, announced elsewhere
|
||||
"toxicdebris", "shedskin", "iceface", "owntempo" -> return@dispatch GO
|
||||
"toxicdebris", "shedskin", "iceface", "owntempo", "vitalspirit" -> return@dispatch GO
|
||||
// Add activation to each Pokemon's history
|
||||
"destinybond" -> {
|
||||
battle.activePokemon.mapNotNull { it.battlePokemon?.uuid }.forEach { battle.minorBattleActions[it] = message }
|
||||
|
||||
+4
-2
@@ -28,8 +28,10 @@ class SideEndInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
val side = if (message.argumentAt(0)?.get(1) == '1') battle.side1 else battle.side2
|
||||
val effect = message.effectAt(1) ?: return@dispatchWaiting
|
||||
battle.sides.forEach {
|
||||
val subject = if (it == side) battleLang("side_subject.ally") else battleLang("side_subject.opponent")
|
||||
val lang = battleLang("sideend.${effect.id}", subject)
|
||||
val isAllySide = it == side
|
||||
val positionSpecificKey = if (isAllySide) "sideend.ally.${effect.id}" else "sideend.opponent.${effect.id}"
|
||||
val lang = battleLang(positionSpecificKey)
|
||||
|
||||
it.broadcastChatMessage(lang)
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -29,8 +29,10 @@ class SideStartInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
val side = if (message.argumentAt(0)?.get(1) == '1') battle.side1 else battle.side2
|
||||
val effect = message.effectAt(1) ?: return@dispatchWaiting
|
||||
battle.sides.forEach {
|
||||
val subject = if (it == side) battleLang("side_subject.ally") else battleLang("side_subject.opponent")
|
||||
val lang = battleLang("sidestart.${effect.id}", subject)
|
||||
val isAllySide = it == side
|
||||
val positionSpecificKey = if (isAllySide) "sidestart.ally.${effect.id}" else "sidestart.opponent.${effect.id}"
|
||||
val lang = battleLang(positionSpecificKey)
|
||||
|
||||
it.broadcastChatMessage(lang)
|
||||
}
|
||||
|
||||
|
||||
@@ -10,18 +10,12 @@ package com.cobblemon.mod.common.block
|
||||
|
||||
import com.mojang.serialization.MapCodec
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.InteractionResult
|
||||
import net.minecraft.world.entity.EquipmentSlot
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import net.minecraft.world.phys.shapes.CollisionContext
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
@@ -30,24 +24,6 @@ import net.minecraft.world.phys.shapes.VoxelShape
|
||||
class BigRootBlock(settings: Properties) : RootBlock(settings) {
|
||||
override fun getShape(state: BlockState, world: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape = AABB
|
||||
|
||||
override fun useWithoutItem(
|
||||
state: BlockState,
|
||||
world: Level,
|
||||
pos: BlockPos,
|
||||
player: Player,
|
||||
blockHitResult: BlockHitResult
|
||||
): InteractionResult {
|
||||
val stack = player.getItemInHand(InteractionHand.MAIN_HAND)
|
||||
if (stack.`is`(Items.SHEARS)) {
|
||||
this.attemptShear(world, state, pos) {
|
||||
player.onEquippedItemBroken(stack.item, EquipmentSlot.MAINHAND)
|
||||
stack.hurtAndBreak(1, player, EquipmentSlot.MAINHAND)
|
||||
}
|
||||
return InteractionResult.sidedSuccess(world.isClientSide)
|
||||
}
|
||||
return super.useWithoutItem(state, world, pos, player, blockHitResult)
|
||||
}
|
||||
|
||||
override fun shearedResultingState(): BlockState = Blocks.HANGING_ROOTS.defaultBlockState()
|
||||
|
||||
override fun shearedDrop(): ItemStack = Items.STRING.defaultInstance
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.block.entity.CakeBlockEntity
|
||||
import com.cobblemon.mod.common.item.components.FoodColourComponent
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.DyeColor
|
||||
@@ -20,33 +21,53 @@ import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.LevelReader
|
||||
import net.minecraft.world.level.block.BaseEntityBlock
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.Rotation
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.StateDefinition
|
||||
import net.minecraft.world.level.block.state.properties.DirectionProperty
|
||||
import net.minecraft.world.phys.shapes.CollisionContext
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
|
||||
abstract class CakeBlock(settings: Properties): BaseEntityBlock(settings) {
|
||||
companion object {
|
||||
val FACING: DirectionProperty = DirectionProperty.create("facing", Direction.Plane.HORIZONTAL)
|
||||
|
||||
val SHAPE_BY_BITE = arrayOf(
|
||||
box(1.0, 0.0, 1.0, 15.0, 9.0, 15.0),
|
||||
box(3.0, 0.0, 1.0, 15.0, 9.0, 15.0),
|
||||
box(5.0, 0.0, 1.0, 15.0, 9.0, 15.0),
|
||||
box(7.0, 0.0, 1.0, 15.0, 9.0, 15.0),
|
||||
box(9.0, 0.0, 1.0, 15.0, 9.0, 15.0),
|
||||
box(11.0, 0.0, 1.0, 15.0, 9.0, 15.0),
|
||||
box(13.0, 0.0, 1.0, 15.0, 9.0, 15.0)
|
||||
box(1.0, 0.0, 1.0, 15.0, 9.0, 15.0),
|
||||
box(3.0, 0.0, 1.0, 15.0, 9.0, 15.0),
|
||||
box(5.0, 0.0, 1.0, 15.0, 9.0, 15.0),
|
||||
box(7.0, 0.0, 1.0, 15.0, 9.0, 15.0),
|
||||
box(9.0, 0.0, 1.0, 15.0, 9.0, 15.0),
|
||||
box(11.0, 0.0, 1.0, 15.0, 9.0, 15.0),
|
||||
box(13.0, 0.0, 1.0, 15.0, 9.0, 15.0)
|
||||
)
|
||||
|
||||
enum class Rotation {
|
||||
NONE,
|
||||
CLOCKWISE_90,
|
||||
CLOCKWISE_180,
|
||||
COUNTERCLOCKWISE_90
|
||||
}
|
||||
}
|
||||
|
||||
override fun setPlacedBy(
|
||||
level: Level,
|
||||
pos: BlockPos,
|
||||
state: BlockState,
|
||||
placer: LivingEntity?,
|
||||
stack: ItemStack
|
||||
) {
|
||||
init {
|
||||
registerDefaultState(stateDefinition.any().setValue(FACING, Direction.NORTH))
|
||||
}
|
||||
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
|
||||
super.createBlockStateDefinition(builder)
|
||||
builder.add(FACING)
|
||||
}
|
||||
|
||||
override fun setPlacedBy(level: Level, pos: BlockPos, state: BlockState, placer: LivingEntity?, stack: ItemStack) {
|
||||
super.setPlacedBy(level, pos, state, placer, stack)
|
||||
|
||||
if (placer != null) {
|
||||
level.setBlock(pos, state.setValue(FACING, placer.direction.opposite), 2)
|
||||
}
|
||||
|
||||
val blockEntity = level.getBlockEntity(pos) as? CakeBlockEntity
|
||||
blockEntity?.initializeFromItemStack(stack)
|
||||
}
|
||||
@@ -57,19 +78,60 @@ abstract class CakeBlock(settings: Properties): BaseEntityBlock(settings) {
|
||||
}
|
||||
|
||||
override fun getShape(
|
||||
state: BlockState,
|
||||
level: BlockGetter,
|
||||
pos: BlockPos,
|
||||
context: CollisionContext
|
||||
): VoxelShape? {
|
||||
return SHAPE_BY_BITE[getBites(level, pos)]
|
||||
state: BlockState,
|
||||
level: BlockGetter,
|
||||
pos: BlockPos,
|
||||
context: CollisionContext
|
||||
): VoxelShape {
|
||||
val bites = getBites(level, pos)
|
||||
val blockEntity = level.getBlockEntity(pos) as? CakeBlockEntity
|
||||
val maxBites = blockEntity?.maxBites ?: 6
|
||||
|
||||
val visualStage = ((bites * SHAPE_BY_BITE.size) / (maxBites + 1))
|
||||
.coerceIn(0, SHAPE_BY_BITE.lastIndex)
|
||||
|
||||
val baseShape = SHAPE_BY_BITE[visualStage]
|
||||
|
||||
return when (state.getValue(FACING)) {
|
||||
Direction.NORTH -> baseShape
|
||||
Direction.SOUTH -> rotateShape(baseShape, Rotation.CLOCKWISE_180)
|
||||
Direction.WEST -> rotateShape(baseShape, Rotation.COUNTERCLOCKWISE_90)
|
||||
Direction.EAST -> rotateShape(baseShape, Rotation.CLOCKWISE_90)
|
||||
else -> baseShape
|
||||
}
|
||||
}
|
||||
|
||||
private fun rotateShape(shape: VoxelShape, rotation: Rotation): VoxelShape {
|
||||
var newShape = net.minecraft.world.phys.shapes.Shapes.empty()
|
||||
|
||||
for (box in shape.toAabbs()) {
|
||||
val minX = box.minX
|
||||
val minY = box.minY
|
||||
val minZ = box.minZ
|
||||
val maxX = box.maxX
|
||||
val maxY = box.maxY
|
||||
val maxZ = box.maxZ
|
||||
|
||||
val (rMinX, rMinZ, rMaxX, rMaxZ) = when (rotation) {
|
||||
Rotation.NONE -> arrayOf(minX, minZ, maxX, maxZ)
|
||||
Rotation.CLOCKWISE_90 -> arrayOf(minZ, 1.0 - maxX, maxZ, 1.0 - minX)
|
||||
Rotation.CLOCKWISE_180 -> arrayOf(1.0 - maxX, 1.0 - maxZ, 1.0 - minX, 1.0 - minZ)
|
||||
Rotation.COUNTERCLOCKWISE_90 -> arrayOf(1.0 - maxZ, minX, 1.0 - minZ, maxX)
|
||||
}
|
||||
|
||||
val rotatedVoxel = net.minecraft.world.phys.shapes.Shapes.box(rMinX, minY, rMinZ, rMaxX, maxY, rMaxZ)
|
||||
|
||||
newShape = net.minecraft.world.phys.shapes.Shapes.or(newShape, rotatedVoxel)
|
||||
}
|
||||
|
||||
return newShape
|
||||
}
|
||||
|
||||
override fun spawnDestroyParticles(
|
||||
level: Level,
|
||||
player: Player,
|
||||
pos: BlockPos,
|
||||
state: BlockState
|
||||
level: Level,
|
||||
player: Player,
|
||||
pos: BlockPos,
|
||||
state: BlockState
|
||||
) {
|
||||
val blockEntity = level.getBlockEntity(pos) as? CakeBlockEntity
|
||||
val color = blockEntity?.foodColourComponent?.colours?.lastOrNull()
|
||||
@@ -100,5 +162,7 @@ abstract class CakeBlock(settings: Properties): BaseEntityBlock(settings) {
|
||||
}
|
||||
|
||||
fun getBites(level: BlockGetter, pos: BlockPos): Int = (level.getBlockEntity(pos) as? CakeBlockEntity)?.bites ?: 0
|
||||
fun setBites(level: BlockGetter, pos: BlockPos, bites: Int) = (level.getBlockEntity(pos) as? CakeBlockEntity)?.bites = bites
|
||||
fun setBites(level: BlockGetter, pos: BlockPos, bites: Int) {
|
||||
(level.getBlockEntity(pos) as? CakeBlockEntity)?.bites = bites
|
||||
}
|
||||
}
|
||||
@@ -86,15 +86,14 @@ class CandlePokeCakeBlock(settings: Properties) : CakeBlock(settings) {
|
||||
)
|
||||
}
|
||||
|
||||
override fun codec(): MapCodec<out BaseEntityBlock?>? {
|
||||
override fun codec(): MapCodec<out BaseEntityBlock?> {
|
||||
return simpleCodec(::CandlePokeCakeBlock)
|
||||
}
|
||||
|
||||
override fun newBlockEntity(pos: BlockPos, state: BlockState): BlockEntity? {
|
||||
override fun newBlockEntity(pos: BlockPos, state: BlockState): BlockEntity {
|
||||
return CandlePokeCakeBlockEntity(pos, state)
|
||||
}
|
||||
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block?, BlockState?>) {
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
|
||||
super.createBlockStateDefinition(builder)
|
||||
builder.add(LIT, CANDLE_COLOR)
|
||||
}
|
||||
@@ -107,7 +106,7 @@ class CandlePokeCakeBlock(settings: Properties) : CakeBlock(settings) {
|
||||
player: Player,
|
||||
hand: InteractionHand,
|
||||
hitResult: BlockHitResult
|
||||
): ItemInteractionResult? {
|
||||
): ItemInteractionResult {
|
||||
return if (!stack.`is`(Items.FLINT_AND_STEEL) && !stack.`is`(Items.FIRE_CHARGE)) {
|
||||
if (candleHit(hitResult) && stack.isEmpty && state.getValue(LIT) == true) {
|
||||
extinguish(player, state, level, pos)
|
||||
@@ -134,7 +133,7 @@ class CandlePokeCakeBlock(settings: Properties) : CakeBlock(settings) {
|
||||
pos: BlockPos,
|
||||
player: Player,
|
||||
hitResult: BlockHitResult
|
||||
): InteractionResult? {
|
||||
): InteractionResult {
|
||||
val oldCookingComponent = getFoodColourComponent(level, pos)
|
||||
val candle = getCandleByMapColorId(state.getValue(CANDLE_COLOR))
|
||||
|
||||
@@ -175,5 +174,5 @@ class CandlePokeCakeBlock(settings: Properties) : CakeBlock(settings) {
|
||||
level: BlockGetter,
|
||||
pos: BlockPos,
|
||||
context: CollisionContext
|
||||
): VoxelShape? = SHAPE
|
||||
): VoxelShape = SHAPE
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* 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.block
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import net.minecraft.sounds.SoundSource
|
||||
import net.minecraft.world.InteractionResult
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.context.BlockPlaceContext
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.LevelAccessor
|
||||
import net.minecraft.world.level.block.*
|
||||
import net.minecraft.world.level.block.HorizontalDirectionalBlock.FACING
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.StateDefinition
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties.HORIZONTAL_FACING
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED
|
||||
import net.minecraft.world.level.block.state.properties.BooleanProperty
|
||||
import net.minecraft.world.level.gameevent.GameEvent
|
||||
import net.minecraft.world.level.material.FluidState
|
||||
import net.minecraft.world.level.material.Fluids
|
||||
import net.minecraft.world.level.pathfinder.PathComputationType
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import net.minecraft.world.phys.shapes.CollisionContext
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
|
||||
class CopperFanBlock(settings: Properties) : Block(settings), SimpleWaterloggedBlock {
|
||||
init {
|
||||
registerDefaultState(stateDefinition.any()
|
||||
.setValue(HORIZONTAL_FACING, Direction.NORTH)
|
||||
.setValue(ACTIVE, false)
|
||||
.setValue(WATERLOGGED, false)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getStateForPlacement(ctx: BlockPlaceContext): BlockState? {
|
||||
var blockState = defaultBlockState().setValue(ACTIVE, false)
|
||||
.setValue(WATERLOGGED, ctx.level.getFluidState(ctx.clickedPos).type == Fluids.WATER)
|
||||
val worldView = ctx.level
|
||||
val blockPos = ctx.clickedPos
|
||||
ctx.nearestLookingDirections.forEach { direction ->
|
||||
if (direction.axis.isHorizontal) {
|
||||
blockState = blockState.setValue(FACING, direction.opposite) as BlockState
|
||||
if (blockState.canSurvive(worldView, blockPos)) {
|
||||
return blockState
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
|
||||
builder.add(HORIZONTAL_FACING)
|
||||
builder.add(ACTIVE)
|
||||
builder.add(WATERLOGGED)
|
||||
}
|
||||
|
||||
override fun getShape(
|
||||
state: BlockState,
|
||||
blockGetter: BlockGetter,
|
||||
pos: BlockPos,
|
||||
collisionContext: CollisionContext
|
||||
): VoxelShape {
|
||||
return when (state.getValue(HorizontalDirectionalBlock.FACING)) {
|
||||
Direction.SOUTH -> NS_AABB
|
||||
Direction.WEST -> EW_AABB
|
||||
Direction.EAST -> EW_AABB
|
||||
else -> NS_AABB
|
||||
}
|
||||
}
|
||||
|
||||
override fun useWithoutItem(
|
||||
state: BlockState,
|
||||
level: Level,
|
||||
pos: BlockPos,
|
||||
player: Player,
|
||||
hitResult: BlockHitResult
|
||||
): InteractionResult {
|
||||
if (level.isClientSide) {
|
||||
level.setBlockAndUpdate(pos, state.cycle(ACTIVE))
|
||||
return InteractionResult.SUCCESS
|
||||
} else {
|
||||
this.push(state, level, pos, null as Player?)
|
||||
return InteractionResult.CONSUME
|
||||
}
|
||||
}
|
||||
|
||||
fun push(state: BlockState, level: Level, pos: BlockPos?, player: Player?) {
|
||||
var state = state
|
||||
state = state.cycle(ACTIVE)
|
||||
level.setBlock(pos!!, state, 3)
|
||||
level.gameEvent(player, if (state.getValue(ACTIVE)) GameEvent.BLOCK_ACTIVATE else GameEvent.BLOCK_DEACTIVATE, pos)
|
||||
playSound(level, pos, state, CobblemonSounds.DISPLAY_CASE_PLACE)
|
||||
}
|
||||
|
||||
override fun getFluidState(blockState: BlockState): FluidState? {
|
||||
return if (blockState.getValue(WATERLOGGED)) Fluids.WATER.getSource(false) else super.getFluidState(blockState);
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun rotate(state: BlockState, rotation: Rotation): BlockState {
|
||||
return state.setValue(HORIZONTAL_FACING, rotation.rotate(state.getValue(HORIZONTAL_FACING)))
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun isPathfindable(state: BlockState, type: PathComputationType): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun updateShape(
|
||||
state: BlockState,
|
||||
direction: Direction,
|
||||
neighborState: BlockState,
|
||||
world: LevelAccessor,
|
||||
pos: BlockPos,
|
||||
neighborPos: BlockPos
|
||||
): BlockState {
|
||||
if (state.getValue(WATERLOGGED)) {
|
||||
world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world))
|
||||
}
|
||||
return if (direction == state.getValue(FACING) && !state.canSurvive(world, pos)) Blocks.AIR.defaultBlockState()
|
||||
else super.updateShape(state, direction, neighborState, world, pos, neighborPos)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val CODEC = simpleCodec(::CopperFanBlock)
|
||||
val ACTIVE = BooleanProperty.create("active")
|
||||
|
||||
private val NS_AABB = Shapes.or(
|
||||
Shapes.box(0.125, 0.25, 0.4375, 0.875, 1.0, 0.5625),
|
||||
Shapes.box(0.4375, 0.125, 0.4375, 0.5625, 0.25, 0.5625),
|
||||
Shapes.box(0.3125, 0.0, 0.3125, 0.6875, 0.125, 0.6875)
|
||||
)
|
||||
private val EW_AABB = Shapes.or(
|
||||
Shapes.box(0.4375, 0.25, 0.125, 0.5625, 1.0, 0.875),
|
||||
Shapes.box(0.4375, 0.125, 0.4375, 0.5625, 0.25, 0.5625),
|
||||
Shapes.box(0.3125, 0.0, 0.3125, 0.6875, 0.125, 0.6875)
|
||||
)
|
||||
|
||||
fun playSound(world: Level, pos: BlockPos, state: BlockState, sound: SoundEvent) {
|
||||
var d = pos.x.toDouble() + 0.5
|
||||
val e = pos.y.toDouble() + 0.5
|
||||
var f = pos.z.toDouble() + 0.5
|
||||
val direction = state.getValue(BlockStateProperties.HORIZONTAL_FACING)
|
||||
d += direction.stepX.toDouble() * 0.5
|
||||
f += direction.stepZ.toDouble() * 0.5
|
||||
world.playSound(
|
||||
null,
|
||||
d,
|
||||
e,
|
||||
f,
|
||||
sound,
|
||||
SoundSource.BLOCKS,
|
||||
0.5f,
|
||||
world.random.nextFloat() * 0.1f + 0.9f
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
//TODO Get it to be a cleanly looping sound, and get Sterr to make a proper sound for it
|
||||
/* override fun animateTick(state: BlockState, level: Level, pos: BlockPos, random: RandomSource) {
|
||||
if ((state.getValue(ACTIVE))) {
|
||||
if (random.nextInt(6) == 0) {
|
||||
level.playLocalSound(
|
||||
pos.x.toDouble() + 0.5,
|
||||
pos.y.toDouble() + 0.5,
|
||||
pos.z.toDouble() + 0.5,
|
||||
CobblemonSounds.EVOLUTION_NOTIFICATION,
|
||||
SoundSource.BLOCKS,
|
||||
1f,
|
||||
1f,
|
||||
false
|
||||
)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
* 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.block
|
||||
|
||||
import com.cobblemon.mod.common.block.entity.CopperFridgeBlockEntity
|
||||
import com.cobblemon.mod.common.util.*
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.util.StringRepresentable
|
||||
import net.minecraft.world.Containers
|
||||
import net.minecraft.world.InteractionResult
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.monster.piglin.PiglinAi
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.context.BlockPlaceContext
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.LevelAccessor
|
||||
import net.minecraft.world.level.LevelReader
|
||||
import net.minecraft.world.level.block.*
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.StateDefinition
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED
|
||||
import net.minecraft.world.level.block.state.properties.EnumProperty
|
||||
import net.minecraft.world.level.material.FluidState
|
||||
import net.minecraft.world.level.material.Fluids
|
||||
import net.minecraft.world.level.pathfinder.PathComputationType
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import net.minecraft.world.phys.shapes.CollisionContext
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
|
||||
class CopperFridgeBlock(properties: Properties): BaseEntityBlock(properties), SimpleWaterloggedBlock {
|
||||
companion object {
|
||||
val CODEC = simpleCodec(::CopperFridgeBlock)
|
||||
val PART = EnumProperty.create("part", CopperFridgePart::class.java)
|
||||
|
||||
private val NORTH_AABB_TOP = Shapes.or(
|
||||
Shapes.box(0.0, 0.0, 0.0625, 1.0, 1.0, 1.0),
|
||||
Shapes.box(0.25, 0.125, 0.0, 0.375, 0.3125, 0.0625),
|
||||
Shapes.box(0.625, 0.125, 0.0, 0.75, 0.3125, 0.0625)
|
||||
)
|
||||
|
||||
private val SOUTH_AABB_TOP = Shapes.or(
|
||||
Shapes.box(0.0, 0.0, 0.0, 1.0, 1.0, 0.9375),
|
||||
Shapes.box(0.625, 0.125, 0.9375, 0.75, 0.3125, 1.0),
|
||||
Shapes.box(0.25, 0.125, 0.9375, 0.375, 0.3125, 1.0)
|
||||
)
|
||||
|
||||
private val WEST_AABB_TOP = Shapes.or(
|
||||
Shapes.box(0.0625, 0.0, 0.0, 1.0, 1.0, 1.0),
|
||||
Shapes.box(0.0, 0.125, 0.625, 0.0625, 0.3125, 0.75),
|
||||
Shapes.box(0.0, 0.125, 0.25, 0.0625, 0.3125, 0.375)
|
||||
)
|
||||
|
||||
private val EAST_AABB_TOP = Shapes.or(
|
||||
Shapes.box(0.0, 0.0, 0.0, 0.9375, 1.0, 1.0),
|
||||
Shapes.box(0.9375, 0.125, 0.25, 1.0, 0.3125, 0.375),
|
||||
Shapes.box(0.9375, 0.125, 0.625, 1.0, 0.3125, 0.75)
|
||||
)
|
||||
|
||||
private val NORTH_AABB_BOTTOM = Shapes.or(
|
||||
Shapes.box(0.0, 0.0625, 0.0625, 1.0, 1.0, 1.0),
|
||||
Shapes.box(0.0625, 0.0, 0.125, 0.9375, 0.0625, 0.9375)
|
||||
)
|
||||
|
||||
private val SOUTH_AABB_BOTTOM = Shapes.or(
|
||||
Shapes.box(0.0, 0.0625, 0.0, 1.0, 1.0, 0.9375),
|
||||
Shapes.box(0.0625, 0.0, 0.0625, 0.9375, 0.0625, 0.875)
|
||||
)
|
||||
|
||||
private val WEST_AABB_BOTTOM = Shapes.or(
|
||||
Shapes.box(0.0625, 0.0625, 0.0, 1.0, 1.0, 1.0),
|
||||
Shapes.box(0.125, 0.0, 0.0625, 0.9375, 0.0625, 0.9375)
|
||||
)
|
||||
|
||||
private val EAST_AABB_BOTTOM = Shapes.or(
|
||||
Shapes.box(0.0, 0.0625, 0.0, 0.9375, 1.0, 1.0),
|
||||
Shapes.box(0.0625, 0.0, 0.0625, 0.875, 0.0625, 0.9375)
|
||||
)
|
||||
}
|
||||
|
||||
enum class CopperFridgePart(private val label: String) : StringRepresentable {
|
||||
TOP("top"),
|
||||
BOTTOM("bottom");
|
||||
override fun getSerializedName(): String = label
|
||||
}
|
||||
|
||||
init {
|
||||
registerDefaultState(stateDefinition.any()
|
||||
.setValue(HorizontalDirectionalBlock.FACING, Direction.NORTH)
|
||||
.setValue(PART, CopperFridgePart.BOTTOM)
|
||||
.setValue(WATERLOGGED, false)
|
||||
)
|
||||
}
|
||||
|
||||
override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState) = if (blockState.getValue(PART) == CopperFridgePart.BOTTOM) CopperFridgeBlockEntity(blockPos, blockState) else null
|
||||
|
||||
override fun getName(): MutableComponent {
|
||||
return Component.translatable("block.cobblemon.copper_fridge")
|
||||
}
|
||||
|
||||
override fun getShape(
|
||||
blockState: BlockState,
|
||||
blockGetter: BlockGetter,
|
||||
blockPos: BlockPos,
|
||||
collisionContext: CollisionContext
|
||||
): VoxelShape {
|
||||
return if (blockState.getValue(PART) == CopperFridgePart.TOP) {
|
||||
when (blockState.getValue(HorizontalDirectionalBlock.FACING)) {
|
||||
Direction.SOUTH -> SOUTH_AABB_TOP
|
||||
Direction.WEST -> WEST_AABB_TOP
|
||||
Direction.EAST -> EAST_AABB_TOP
|
||||
else -> NORTH_AABB_TOP
|
||||
}
|
||||
} else {
|
||||
when (blockState.getValue(HorizontalDirectionalBlock.FACING)) {
|
||||
Direction.SOUTH -> SOUTH_AABB_BOTTOM
|
||||
Direction.WEST -> WEST_AABB_BOTTOM
|
||||
Direction.EAST -> EAST_AABB_BOTTOM
|
||||
else -> NORTH_AABB_BOTTOM
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getPositionOfOtherPart(state: BlockState, pos: BlockPos): BlockPos {
|
||||
return if (state.getValue(PART) == CopperFridgePart.BOTTOM) {
|
||||
pos.above()
|
||||
} else {
|
||||
pos.below()
|
||||
}
|
||||
}
|
||||
|
||||
fun getBasePosition(state: BlockState, pos: BlockPos): BlockPos {
|
||||
return if (isBase(state)) {
|
||||
pos
|
||||
} else {
|
||||
pos.below()
|
||||
}
|
||||
}
|
||||
|
||||
private fun isBase(state: BlockState): Boolean = state.getValue(PART) == CopperFridgePart.BOTTOM
|
||||
|
||||
override fun setPlacedBy(
|
||||
world: Level,
|
||||
pos: BlockPos,
|
||||
state: BlockState,
|
||||
placer: LivingEntity?,
|
||||
itemStack: ItemStack
|
||||
) {
|
||||
world.setBlock(pos.above(),
|
||||
state
|
||||
.setValue(PART, CopperFridgePart.TOP)
|
||||
.setValue(WATERLOGGED, world.getFluidState((pos.above())).type == Fluids.WATER)
|
||||
, 3)
|
||||
world.blockUpdated(pos, Blocks.AIR)
|
||||
state.updateNeighbourShapes(world, pos, 3)
|
||||
}
|
||||
|
||||
override fun getStateForPlacement(blockPlaceContext: BlockPlaceContext): BlockState? {
|
||||
val abovePosition = blockPlaceContext.clickedPos.above()
|
||||
val world = blockPlaceContext.level
|
||||
if (world.getBlockState(abovePosition).canBeReplaced(blockPlaceContext) && !world.isOutsideBuildHeight(abovePosition)) {
|
||||
return defaultBlockState()
|
||||
.setValue(HorizontalDirectionalBlock.FACING, blockPlaceContext.horizontalDirection.opposite)
|
||||
.setValue(PART, CopperFridgePart.BOTTOM)
|
||||
.setValue(WATERLOGGED, blockPlaceContext.level.getFluidState(blockPlaceContext.clickedPos).type == Fluids.WATER)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
override fun canSurvive(state: BlockState, world: LevelReader, pos: BlockPos): Boolean {
|
||||
val blockPos = pos.below()
|
||||
val blockState = world.getBlockState(blockPos)
|
||||
return if (state.getValue(PART) == CopperFridgePart.BOTTOM) blockState.isFaceSturdy(world, blockPos, Direction.UP) else blockState.`is`(this)// todo (techdaan): ensure this is the right mapping
|
||||
}
|
||||
|
||||
override fun playerWillDestroy(world: Level, pos: BlockPos, state: BlockState, player: Player): BlockState {
|
||||
if (!world.isClientSide && player?.isCreative == true) {
|
||||
var blockPos: BlockPos = BlockPos.ZERO
|
||||
var blockState: BlockState = state
|
||||
val part = state.getValue(PART)
|
||||
if (part == CopperFridgePart.TOP && world.getBlockState(pos.below().also { blockPos = it }).also { blockState = it }.`is`(state.block) && blockState.getValue(PART) == CopperFridgePart.BOTTOM) {
|
||||
val blockState2 = if (blockState.fluidState.`is`(Fluids.WATER)) Blocks.WATER.defaultBlockState() else Blocks.AIR.defaultBlockState()
|
||||
world.setBlock(blockPos, blockState2, UPDATE_ALL or UPDATE_SUPPRESS_DROPS)
|
||||
world.levelEvent(player, LevelEvent.PARTICLES_DESTROY_BLOCK, blockPos, getId(blockState))
|
||||
}
|
||||
}
|
||||
return super.playerWillDestroy(world, pos, state, player)
|
||||
}
|
||||
|
||||
override fun codec() = CODEC
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun isPathfindable(
|
||||
blockState: BlockState,
|
||||
pathComputationType: PathComputationType
|
||||
): Boolean = false
|
||||
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
|
||||
builder.add(HorizontalDirectionalBlock.FACING)
|
||||
builder.add(PART)
|
||||
builder.add(WATERLOGGED)
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun rotate(blockState: BlockState, rotation: Rotation) =
|
||||
blockState.setValue(
|
||||
HorizontalDirectionalBlock.FACING, rotation.rotate(blockState.getValue(
|
||||
HorizontalDirectionalBlock.FACING)))
|
||||
|
||||
override fun onRemove(state: BlockState, world: Level, pos: BlockPos, newState: BlockState, moved: Boolean) {
|
||||
if (!state.`is`(newState.block)) {
|
||||
Containers.dropContentsOnDestroy(state, newState, world, pos)
|
||||
super.onRemove(state, world, pos, newState, moved)
|
||||
}
|
||||
}
|
||||
|
||||
override fun hasAnalogOutputSignal(state: BlockState): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getAnalogOutputSignal(state: BlockState, world: Level, pos: BlockPos): Int {
|
||||
return AbstractContainerMenu.getRedstoneSignalFromBlockEntity(world.getBlockEntity(pos))
|
||||
}
|
||||
|
||||
override fun useWithoutItem(
|
||||
state: BlockState,
|
||||
world: Level,
|
||||
pos: BlockPos,
|
||||
player: Player,
|
||||
hit: BlockHitResult
|
||||
): InteractionResult {
|
||||
val basePos = getBasePosition(state, pos)
|
||||
// Remove any duplicate block entities that may exist
|
||||
world.getBlockEntity(basePos.above())?.setRemoved()
|
||||
val baseEntity = world.getBlockEntity(basePos)
|
||||
if (baseEntity !is CopperFridgeBlockEntity) return InteractionResult.SUCCESS
|
||||
|
||||
player.openMenu(baseEntity)
|
||||
if (!player.level().isClientSide) {
|
||||
PiglinAi.angerNearbyPiglins(player, true)
|
||||
}
|
||||
return InteractionResult.SUCCESS
|
||||
}
|
||||
|
||||
override fun getRenderShape(state: BlockState) = RenderShape.ENTITYBLOCK_ANIMATED
|
||||
|
||||
override fun getFluidState(state: BlockState): FluidState? {
|
||||
return if (state.getValue(WATERLOGGED)) {
|
||||
Fluids.WATER.getSource(false)
|
||||
} else super.getFluidState(state)
|
||||
}
|
||||
|
||||
enum class Type(val poserId: ResourceLocation) : StringRepresentable {
|
||||
RED(cobblemonResource("copper_fridge"));
|
||||
|
||||
override fun getSerializedName(): String = name.lowercase()
|
||||
|
||||
companion object {
|
||||
val CODEC = StringRepresentable.fromValues(::values)
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateShape(
|
||||
state: BlockState,
|
||||
direction: Direction,
|
||||
neighborState: BlockState,
|
||||
world: LevelAccessor,
|
||||
pos: BlockPos,
|
||||
neighborPos: BlockPos
|
||||
): BlockState {
|
||||
if (state.getValue(WATERLOGGED)) {
|
||||
world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world))
|
||||
}
|
||||
|
||||
val isFridge = neighborState.`is`(this)
|
||||
val part = state.getValue(PART)
|
||||
if (!isFridge && part == CopperFridgePart.TOP && neighborPos == pos.below()) {
|
||||
return Blocks.AIR.defaultBlockState()
|
||||
} else if (!isFridge && part == CopperFridgePart.BOTTOM && neighborPos == pos.above()) {
|
||||
return Blocks.AIR.defaultBlockState()
|
||||
}
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
override fun tick(state: BlockState, world: ServerLevel, pos: BlockPos, random: RandomSource) {
|
||||
val blockEntity = world.getBlockEntity(pos) as? CopperFridgeBlockEntity ?: return
|
||||
blockEntity.tick()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.block
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.world.item.context.BlockPlaceContext
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.LevelAccessor
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.HorizontalDirectionalBlock.FACING
|
||||
import net.minecraft.world.level.block.Rotation
|
||||
import net.minecraft.world.level.block.SimpleWaterloggedBlock
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.StateDefinition
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties.HORIZONTAL_FACING
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED
|
||||
import net.minecraft.world.level.material.FluidState
|
||||
import net.minecraft.world.level.material.Fluids
|
||||
import net.minecraft.world.level.pathfinder.PathComputationType
|
||||
import net.minecraft.world.phys.shapes.CollisionContext
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
|
||||
class CopperMowerBlock(settings: Properties) : Block(settings), SimpleWaterloggedBlock {
|
||||
init {
|
||||
registerDefaultState(stateDefinition.any()
|
||||
.setValue(HORIZONTAL_FACING, Direction.NORTH)
|
||||
.setValue(WATERLOGGED, false)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getStateForPlacement(ctx: BlockPlaceContext): BlockState? {
|
||||
var blockState = defaultBlockState()
|
||||
.setValue(WATERLOGGED, ctx.level.getFluidState(ctx.clickedPos).type == Fluids.WATER)
|
||||
val worldView = ctx.level
|
||||
val blockPos = ctx.clickedPos
|
||||
ctx.nearestLookingDirections.forEach { direction ->
|
||||
if (direction.axis.isHorizontal) {
|
||||
blockState = blockState.setValue(FACING, direction.opposite) as BlockState
|
||||
if (blockState.canSurvive(worldView, blockPos)) {
|
||||
return blockState
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
|
||||
builder.add(HORIZONTAL_FACING)
|
||||
builder.add(WATERLOGGED)
|
||||
}
|
||||
|
||||
override fun getShape(
|
||||
state: BlockState,
|
||||
blockGetter: BlockGetter,
|
||||
pos: BlockPos,
|
||||
collisionContext: CollisionContext
|
||||
): VoxelShape {
|
||||
return when (state.getValue(FACING)) {
|
||||
Direction.EAST -> EAST_OUTLINE
|
||||
Direction.SOUTH -> SOUTH_OUTLINE
|
||||
Direction.WEST -> WEST_OUTLINE
|
||||
else -> NORTH_OUTLINE
|
||||
}
|
||||
}
|
||||
|
||||
override fun getFluidState(blockState: BlockState): FluidState? {
|
||||
return if (blockState.getValue(WATERLOGGED)) Fluids.WATER.getSource(false) else super.getFluidState(blockState);
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun rotate(state: BlockState, rotation: Rotation): BlockState {
|
||||
return state.setValue(HORIZONTAL_FACING, rotation.rotate(state.getValue(HORIZONTAL_FACING)))
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun isPathfindable(state: BlockState, type: PathComputationType): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun updateShape(
|
||||
state: BlockState,
|
||||
direction: Direction,
|
||||
neighborState: BlockState,
|
||||
world: LevelAccessor,
|
||||
pos: BlockPos,
|
||||
neighborPos: BlockPos
|
||||
): BlockState {
|
||||
if (state.getValue(WATERLOGGED)) {
|
||||
world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world))
|
||||
}
|
||||
return if (direction == state.getValue(FACING) && !state.canSurvive(world, pos)) Blocks.AIR.defaultBlockState()
|
||||
else super.updateShape(state, direction, neighborState, world, pos, neighborPos)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val CODEC = simpleCodec(::CopperMowerBlock)
|
||||
|
||||
val SOUTH_OUTLINE = Shapes.or(
|
||||
Shapes.box(0.0625, 0.0, 0.0, 0.9375, 0.625, 0.375),
|
||||
Shapes.box(0.1875, 0.0, 0.375, 0.8125, 0.375, 1.0),
|
||||
Shapes.box(0.8125, 0.0, 0.5, 0.875, 0.3125, 0.8125),
|
||||
Shapes.box(0.125, 0.0, 0.5, 0.1875, 0.3125, 0.8125)
|
||||
)
|
||||
val NORTH_OUTLINE = Shapes.or(
|
||||
Shapes.box(0.0625, 0.0, 0.625, 0.9375, 0.625, 1.0),
|
||||
Shapes.box(0.1875, 0.0, 0.0, 0.8125, 0.375, 0.625),
|
||||
Shapes.box(0.125, 0.0, 0.1875, 0.1875, 0.3125, 0.5),
|
||||
Shapes.box(0.8125, 0.0, 0.1875, 0.875, 0.3125, 0.5)
|
||||
)
|
||||
val WEST_OUTLINE = Shapes.or(
|
||||
Shapes.box(0.625, 0.0, 0.0625, 1.0, 0.625, 0.9375),
|
||||
Shapes.box(0.0, 0.0, 0.1875, 0.625, 0.375, 0.8125),
|
||||
Shapes.box(0.1875, 0.0, 0.8125, 0.5, 0.3125, 0.875),
|
||||
Shapes.box(0.1875, 0.0, 0.125, 0.5, 0.3125, 0.1875),
|
||||
)
|
||||
val EAST_OUTLINE = Shapes.or(
|
||||
Shapes.box(0.0, 0.0, 0.0625, 0.375, 0.625, 0.9375),
|
||||
Shapes.box(0.375, 0.0, 0.1875, 1.0, 0.375, 0.8125),
|
||||
Shapes.box(0.5, 0.0, 0.125, 0.8125, 0.3125, 0.1875),
|
||||
Shapes.box(0.5, 0.0, 0.8125, 0.8125, 0.3125, 0.875)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* 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.block
|
||||
|
||||
import com.cobblemon.mod.common.block.entity.CopperOvenBlockEntity
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.mojang.serialization.MapCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.util.StringRepresentable
|
||||
import net.minecraft.world.Containers
|
||||
import net.minecraft.world.InteractionResult
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.monster.piglin.PiglinAi
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.context.BlockPlaceContext
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.LevelAccessor
|
||||
import net.minecraft.world.level.block.*
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.StateDefinition
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties.HORIZONTAL_FACING
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED
|
||||
import net.minecraft.world.level.material.FluidState
|
||||
import net.minecraft.world.level.material.Fluids
|
||||
import net.minecraft.world.level.pathfinder.PathComputationType
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import net.minecraft.world.phys.shapes.CollisionContext
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
|
||||
@Suppress("OVERRIDE_DEPRECATION")
|
||||
class CopperOvenBlock(settings: Properties) : BaseEntityBlock(settings),
|
||||
SimpleWaterloggedBlock {
|
||||
|
||||
init {
|
||||
registerDefaultState(stateDefinition.any()
|
||||
.setValue(HORIZONTAL_FACING, Direction.SOUTH)
|
||||
.setValue(WATERLOGGED, false))
|
||||
}
|
||||
|
||||
companion object {
|
||||
val CODEC: MapCodec<CopperOvenBlock> = RecordCodecBuilder.mapCodec {
|
||||
it.group(propertiesCodec()).apply(it, ::CopperOvenBlock)
|
||||
}
|
||||
|
||||
val SOUTH_OUTLINE = Shapes.or(
|
||||
Shapes.box(0.0625, 0.0, 0.125, 0.9375, 0.625, 0.8125)
|
||||
)
|
||||
val NORTH_OUTLINE = Shapes.or(
|
||||
Shapes.box(0.0625, 0.0, 0.1875, 0.9375, 0.625, 0.875)
|
||||
)
|
||||
val WEST_OUTLINE = Shapes.or(
|
||||
Shapes.box(0.1875, 0.0, 0.0625, 0.875, 0.625, 0.9375)
|
||||
)
|
||||
val EAST_OUTLINE = Shapes.or(
|
||||
Shapes.box(0.125, 0.0, 0.0625, 0.8125, 0.625, 0.9375)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getShape(
|
||||
state: BlockState,
|
||||
world: BlockGetter,
|
||||
pos: BlockPos,
|
||||
context: CollisionContext
|
||||
): VoxelShape {
|
||||
return when (state.getValue(HorizontalDirectionalBlock.FACING)) {
|
||||
Direction.NORTH -> NORTH_OUTLINE
|
||||
Direction.EAST -> EAST_OUTLINE
|
||||
Direction.WEST -> WEST_OUTLINE
|
||||
else -> SOUTH_OUTLINE
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateShape(
|
||||
state: BlockState,
|
||||
direction: Direction,
|
||||
neighborState: BlockState,
|
||||
world: LevelAccessor,
|
||||
pos: BlockPos,
|
||||
neighborPos: BlockPos
|
||||
): BlockState {
|
||||
if (state.getValue(WATERLOGGED)) world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world))
|
||||
return super.updateShape(state, direction, neighborState, world, pos, neighborPos)
|
||||
}
|
||||
|
||||
override fun getFluidState(state: BlockState): FluidState {
|
||||
return if (state.getValue(WATERLOGGED)) {
|
||||
Fluids.WATER.getSource(false)
|
||||
} else super.getFluidState(state)
|
||||
}
|
||||
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
|
||||
super.createBlockStateDefinition(builder)
|
||||
builder.add(HORIZONTAL_FACING)
|
||||
builder.add(WATERLOGGED)
|
||||
}
|
||||
|
||||
override fun newBlockEntity(pos: BlockPos, state: BlockState) = CopperOvenBlockEntity(pos, state)
|
||||
|
||||
private val facingToYaw: HashMap<Direction, Float> = hashMapOf(
|
||||
Direction.NORTH to -179.0F,
|
||||
Direction.WEST to 90.0F,
|
||||
Direction.SOUTH to 0.0F,
|
||||
Direction.EAST to -90.0F
|
||||
)
|
||||
|
||||
override fun getName(): MutableComponent {
|
||||
return Component.translatable("block.cobblemon.copper_oven")
|
||||
}
|
||||
|
||||
override fun playerWillDestroy(world: Level, pos: BlockPos, state: BlockState, player: Player): BlockState {
|
||||
if (!world.isClientSide) {}
|
||||
return super.playerWillDestroy(world, pos, state, player)
|
||||
}
|
||||
|
||||
override fun onRemove(
|
||||
state: BlockState,
|
||||
world: Level,
|
||||
pos: BlockPos,
|
||||
newState: BlockState,
|
||||
moved: Boolean
|
||||
) {
|
||||
Containers.dropContentsOnDestroy(state, newState, world, pos)
|
||||
super.onRemove(state, world, pos, newState, moved)
|
||||
}
|
||||
|
||||
override fun useWithoutItem(
|
||||
state: BlockState,
|
||||
world: Level,
|
||||
pos: BlockPos,
|
||||
player: Player,
|
||||
hit: BlockHitResult
|
||||
): InteractionResult {
|
||||
val entity = world.getBlockEntity(pos) as? CopperOvenBlockEntity ?: return InteractionResult.FAIL
|
||||
player.openMenu(entity)
|
||||
if (!player.level().isClientSide) {
|
||||
PiglinAi.angerNearbyPiglins(player, true)
|
||||
}
|
||||
return InteractionResult.SUCCESS
|
||||
}
|
||||
|
||||
override fun getRenderShape(state: BlockState) = RenderShape.ENTITYBLOCK_ANIMATED
|
||||
|
||||
override fun getStateForPlacement(blockPlaceContext: BlockPlaceContext): BlockState {
|
||||
return defaultBlockState()
|
||||
.setValue(HorizontalDirectionalBlock.FACING, blockPlaceContext.horizontalDirection.opposite)
|
||||
.setValue(WATERLOGGED, blockPlaceContext.level.getFluidState(blockPlaceContext.clickedPos).type == Fluids.WATER)
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun rotate(state: BlockState, rotation: Rotation): BlockState {
|
||||
return state.setValue(
|
||||
HORIZONTAL_FACING, rotation.rotate(
|
||||
state.getValue(HORIZONTAL_FACING) as Direction
|
||||
)
|
||||
) as BlockState
|
||||
}
|
||||
|
||||
override fun hasAnalogOutputSignal(state: BlockState): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getAnalogOutputSignal(state: BlockState, world: Level, pos: BlockPos): Int {
|
||||
return AbstractContainerMenu.getRedstoneSignalFromBlockEntity(world.getBlockEntity(pos))
|
||||
}
|
||||
|
||||
override fun mirror(state: BlockState, mirror: Mirror): BlockState {
|
||||
return state.rotate(mirror.getRotation(state.getValue(HORIZONTAL_FACING) as Direction))
|
||||
}
|
||||
|
||||
enum class Type(val poserId: ResourceLocation) : StringRepresentable {
|
||||
RED(cobblemonResource("copper_oven"));
|
||||
|
||||
override fun getSerializedName(): String = name.lowercase()
|
||||
|
||||
companion object {
|
||||
val CODEC = StringRepresentable.fromValues(::values)
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun isPathfindable(state: BlockState, type: PathComputationType): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun codec(): MapCodec<out BaseEntityBlock> {
|
||||
return CODEC
|
||||
}
|
||||
|
||||
override fun setPlacedBy(
|
||||
world: Level,
|
||||
pos: BlockPos,
|
||||
state: BlockState,
|
||||
placer: LivingEntity?,
|
||||
itemStack: ItemStack
|
||||
) {
|
||||
//Theoretically this is no longer needed according to https://fabricmc.net/2024/04/19/1205.html
|
||||
/*
|
||||
val blockEntity = world.getBlockEntity(pos)
|
||||
if (itemStack.get(DataComponentTypes.CUSTOM_NAME) != && blockEntity is GildedChestBlockEntity) {
|
||||
blockEntity.customName = itemStack.name
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
override fun tick(state: BlockState, world: ServerLevel, pos: BlockPos, random: RandomSource) {
|
||||
val blockEntity = world.getBlockEntity(pos) as? CopperOvenBlockEntity ?: return
|
||||
blockEntity.tick()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* 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.block
|
||||
|
||||
import com.cobblemon.mod.common.block.entity.CopperWasherBlockEntity
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.mojang.serialization.MapCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.util.StringRepresentable
|
||||
import net.minecraft.world.Containers
|
||||
import net.minecraft.world.InteractionResult
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.monster.piglin.PiglinAi
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.context.BlockPlaceContext
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.LevelAccessor
|
||||
import net.minecraft.world.level.block.*
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.StateDefinition
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties.HORIZONTAL_FACING
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED
|
||||
import net.minecraft.world.level.material.FluidState
|
||||
import net.minecraft.world.level.material.Fluids
|
||||
import net.minecraft.world.level.pathfinder.PathComputationType
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import net.minecraft.world.phys.shapes.CollisionContext
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
|
||||
@Suppress("OVERRIDE_DEPRECATION")
|
||||
class CopperWasherBlock(settings: Properties) : BaseEntityBlock(settings),
|
||||
SimpleWaterloggedBlock {
|
||||
|
||||
init {
|
||||
registerDefaultState(stateDefinition.any()
|
||||
.setValue(HORIZONTAL_FACING, Direction.SOUTH)
|
||||
.setValue(WATERLOGGED, false))
|
||||
}
|
||||
|
||||
companion object {
|
||||
val CODEC: MapCodec<CopperWasherBlock> = RecordCodecBuilder.mapCodec {
|
||||
it.group(propertiesCodec()).apply(it, ::CopperWasherBlock)
|
||||
}
|
||||
|
||||
private val NORTH_OUTLINE = Shapes.or(
|
||||
Shapes.box(0.0625, 0.0, 0.125, 0.9375, 0.875, 1.0),
|
||||
Shapes.box(0.25, 0.125, 0.0625, 0.75, 0.625, 0.125),
|
||||
Shapes.box(0.9375, 0.125, 0.6875, 1.0, 0.375, 0.9375)
|
||||
)
|
||||
private val SOUTH_OUTLINE = Shapes.or(
|
||||
Shapes.box(0.0625, 0.0, 0.0, 0.9375, 0.875, 0.875),
|
||||
Shapes.box(0.25, 0.125, 0.875, 0.75, 0.625, 0.9375),
|
||||
Shapes.box(0.0, 0.125, 0.0625, 0.0625, 0.375, 0.3125)
|
||||
)
|
||||
private val WEST_OUTLINE = Shapes.or(
|
||||
Shapes.box(0.125, 0.0, 0.0625, 1.0, 0.875, 0.9375),
|
||||
Shapes.box(0.0625, 0.125, 0.25, 0.125, 0.625, 0.75),
|
||||
Shapes.box(0.6875, 0.125, 0.0, 0.9375, 0.375, 0.0625)
|
||||
)
|
||||
private val EAST_OUTLINE = Shapes.or(
|
||||
Shapes.box(0.0, 0.0, 0.0625, 0.875, 0.875, 0.9375),
|
||||
Shapes.box(0.875, 0.125, 0.25, 0.9375, 0.625, 0.75),
|
||||
Shapes.box(0.0625, 0.125, 0.9375, 0.3125, 0.375, 1.0)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getShape(
|
||||
state: BlockState,
|
||||
world: BlockGetter,
|
||||
pos: BlockPos,
|
||||
context: CollisionContext
|
||||
): VoxelShape {
|
||||
return when (state.getValue(HorizontalDirectionalBlock.FACING)) {
|
||||
Direction.NORTH -> NORTH_OUTLINE
|
||||
Direction.EAST -> EAST_OUTLINE
|
||||
Direction.WEST -> WEST_OUTLINE
|
||||
else -> SOUTH_OUTLINE
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateShape(
|
||||
state: BlockState,
|
||||
direction: Direction,
|
||||
neighborState: BlockState,
|
||||
world: LevelAccessor,
|
||||
pos: BlockPos,
|
||||
neighborPos: BlockPos
|
||||
): BlockState {
|
||||
if (state.getValue(WATERLOGGED)) world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world))
|
||||
return super.updateShape(state, direction, neighborState, world, pos, neighborPos)
|
||||
}
|
||||
|
||||
override fun getFluidState(state: BlockState): FluidState {
|
||||
return if (state.getValue(WATERLOGGED)) {
|
||||
Fluids.WATER.getSource(false)
|
||||
} else super.getFluidState(state)
|
||||
}
|
||||
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
|
||||
super.createBlockStateDefinition(builder)
|
||||
builder.add(HORIZONTAL_FACING)
|
||||
builder.add(WATERLOGGED)
|
||||
}
|
||||
|
||||
override fun newBlockEntity(pos: BlockPos, state: BlockState) = CopperWasherBlockEntity(pos, state)
|
||||
|
||||
private val facingToYaw: HashMap<Direction, Float> = hashMapOf(
|
||||
Direction.NORTH to -179.0F,
|
||||
Direction.WEST to 90.0F,
|
||||
Direction.SOUTH to 0.0F,
|
||||
Direction.EAST to -90.0F
|
||||
)
|
||||
|
||||
override fun getName(): MutableComponent {
|
||||
return Component.translatable("block.cobblemon.copper_washer")
|
||||
}
|
||||
|
||||
override fun playerWillDestroy(world: Level, pos: BlockPos, state: BlockState, player: Player): BlockState {
|
||||
if (!world.isClientSide) {}
|
||||
return super.playerWillDestroy(world, pos, state, player)
|
||||
}
|
||||
|
||||
override fun onRemove(
|
||||
state: BlockState,
|
||||
world: Level,
|
||||
pos: BlockPos,
|
||||
newState: BlockState,
|
||||
moved: Boolean
|
||||
) {
|
||||
Containers.dropContentsOnDestroy(state, newState, world, pos)
|
||||
super.onRemove(state, world, pos, newState, moved)
|
||||
}
|
||||
|
||||
override fun useWithoutItem(
|
||||
state: BlockState,
|
||||
world: Level,
|
||||
pos: BlockPos,
|
||||
player: Player,
|
||||
hit: BlockHitResult
|
||||
): InteractionResult {
|
||||
val entity = world.getBlockEntity(pos) as? CopperWasherBlockEntity ?: return InteractionResult.FAIL
|
||||
player.openMenu(entity)
|
||||
if (!player.level().isClientSide) {
|
||||
PiglinAi.angerNearbyPiglins(player, true)
|
||||
}
|
||||
return InteractionResult.SUCCESS
|
||||
}
|
||||
|
||||
override fun getRenderShape(state: BlockState) = RenderShape.ENTITYBLOCK_ANIMATED
|
||||
|
||||
override fun getStateForPlacement(blockPlaceContext: BlockPlaceContext): BlockState {
|
||||
return defaultBlockState()
|
||||
.setValue(HorizontalDirectionalBlock.FACING, blockPlaceContext.horizontalDirection.opposite)
|
||||
.setValue(WATERLOGGED, blockPlaceContext.level.getFluidState(blockPlaceContext.clickedPos).type == Fluids.WATER)
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun rotate(state: BlockState, rotation: Rotation): BlockState {
|
||||
return state.setValue(
|
||||
HORIZONTAL_FACING, rotation.rotate(
|
||||
state.getValue(HORIZONTAL_FACING) as Direction
|
||||
)
|
||||
) as BlockState
|
||||
}
|
||||
|
||||
override fun hasAnalogOutputSignal(state: BlockState): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun getAnalogOutputSignal(state: BlockState, world: Level, pos: BlockPos): Int {
|
||||
return AbstractContainerMenu.getRedstoneSignalFromBlockEntity(world.getBlockEntity(pos))
|
||||
}
|
||||
|
||||
override fun mirror(state: BlockState, mirror: Mirror): BlockState {
|
||||
return state.rotate(mirror.getRotation(state.getValue(HORIZONTAL_FACING) as Direction))
|
||||
}
|
||||
|
||||
enum class Type(val poserId: ResourceLocation) : StringRepresentable {
|
||||
RED(cobblemonResource("copper_washer"));
|
||||
|
||||
override fun getSerializedName(): String = name.lowercase()
|
||||
|
||||
companion object {
|
||||
val CODEC = StringRepresentable.fromValues(::values)
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun isPathfindable(state: BlockState, type: PathComputationType): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun codec(): MapCodec<out BaseEntityBlock> {
|
||||
return CODEC
|
||||
}
|
||||
|
||||
override fun setPlacedBy(
|
||||
world: Level,
|
||||
pos: BlockPos,
|
||||
state: BlockState,
|
||||
placer: LivingEntity?,
|
||||
itemStack: ItemStack
|
||||
) {
|
||||
//Theoretically this is no longer needed according to https://fabricmc.net/2024/04/19/1205.html
|
||||
/*
|
||||
val blockEntity = world.getBlockEntity(pos)
|
||||
if (itemStack.get(DataComponentTypes.CUSTOM_NAME) != && blockEntity is GildedChestBlockEntity) {
|
||||
blockEntity.customName = itemStack.name
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
override fun tick(state: BlockState, world: ServerLevel, pos: BlockPos, random: RandomSource) {
|
||||
val blockEntity = world.getBlockEntity(pos) as? CopperWasherBlockEntity ?: return
|
||||
blockEntity.tick()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.block
|
||||
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.core.dispenser.DispenseItemBehavior
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.level.block.DispenserBlock
|
||||
|
||||
object DispenserBehaviorRegistry {
|
||||
private val behaviors = mutableMapOf<Item, DispenseItemBehavior>()
|
||||
|
||||
fun register(items: List<Item>, behaviorProvider: (Item) -> DispenseItemBehavior) {
|
||||
for (item in items) {
|
||||
behaviors[item] = behaviorProvider(item)
|
||||
}
|
||||
}
|
||||
|
||||
fun applyBehaviors() {
|
||||
behaviors.forEach { (item, behavior) ->
|
||||
DispenserBlock.registerBehavior(item, behavior)
|
||||
}
|
||||
}
|
||||
|
||||
fun registerDispenserBehaviors() {
|
||||
register(listOf(Items.GLASS_BOTTLE)) { SaccharineHoneyLogBlock.createBehavior() }
|
||||
register(listOf(Items.HONEY_BOTTLE)) { SaccharineLogBlock.createBehavior() }
|
||||
register(listOf(Items.HONEY_BOTTLE, Items.GLASS_BOTTLE)) { item -> SaccharineLeafBlock.createBehavior(item)}
|
||||
applyBehaviors()
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.block
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonBlockTags
|
||||
import com.mojang.serialization.MapCodec
|
||||
@@ -16,9 +17,8 @@ import net.minecraft.core.Direction
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.tags.FluidTags
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.util.StringRepresentable
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.context.BlockPlaceContext
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.ItemLike
|
||||
import net.minecraft.world.level.Level
|
||||
@@ -31,6 +31,7 @@ import net.minecraft.world.level.block.SimpleWaterloggedBlock
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.StateDefinition
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties
|
||||
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf
|
||||
import net.minecraft.world.level.block.state.properties.EnumProperty
|
||||
import net.minecraft.world.level.block.state.properties.IntegerProperty
|
||||
import net.minecraft.world.level.material.FluidState
|
||||
@@ -45,13 +46,13 @@ class HeartyGrainsBlock(settings: Properties) : CropBlock(settings), SimpleWater
|
||||
|
||||
override fun getMaxAge(): Int = MATURE_AGE
|
||||
|
||||
private val ageAfterHarvest = 3
|
||||
private val ageAfterHarvest = 4
|
||||
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
|
||||
builder.add(AGE, PART, WATERLOGGED)
|
||||
builder.add(AGE, HALF, WATERLOGGED)
|
||||
}
|
||||
|
||||
override fun getBaseSeedId(): ItemLike = CobblemonItems.Hearty_Grains
|
||||
override fun getBaseSeedId(): ItemLike = CobblemonItems.HEARTY_GRAINS
|
||||
|
||||
override fun getShape(state: BlockState, world: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape {
|
||||
return AGE_TO_SHAPE[this.getAge(state)]
|
||||
@@ -62,45 +63,48 @@ class HeartyGrainsBlock(settings: Properties) : CropBlock(settings), SimpleWater
|
||||
}
|
||||
|
||||
override fun randomTick(state: BlockState, world: ServerLevel, pos: BlockPos, random: RandomSource) {
|
||||
if (state.getValue(PART) == Part.UPPER || this.isMaxAge(state) || !canGrow(world, pos)) return
|
||||
if (state.getValue(HALF) == DoubleBlockHalf.UPPER || !canGrow(world, pos, state)) return
|
||||
|
||||
val lightLevel = world.getMaxLocalRawBrightness(pos)
|
||||
if (lightLevel >= 9 && random.nextInt(7) == 0) {
|
||||
val newAge = state.getValue(AGE) + 1
|
||||
world.setBlock(pos, state.setValue(AGE, newAge), UPDATE_CLIENTS)
|
||||
|
||||
if (newAge == MATURE_AGE) {
|
||||
val abovePos = pos.above()
|
||||
if (world.getBlockState(abovePos).isAir) {
|
||||
world.setBlock(
|
||||
abovePos,
|
||||
this.defaultBlockState().setValue(AGE, newAge).setValue(PART, Part.UPPER),
|
||||
UPDATE_CLIENTS
|
||||
)
|
||||
}
|
||||
}
|
||||
if (hasSufficientLight(world, pos) && random.nextInt(7) == 0) {
|
||||
grow(world, pos, state, 1)
|
||||
}
|
||||
}
|
||||
|
||||
private fun canGrow(world: LevelReader, pos: BlockPos): Boolean {
|
||||
return canSurvive(defaultBlockState().setValue(PART, Part.LOWER), world, pos)
|
||||
override fun getStateForPlacement(context: BlockPlaceContext): BlockState? {
|
||||
val fluidState = context.level.getFluidState(context.clickedPos)
|
||||
return this.defaultBlockState()
|
||||
.setValue(
|
||||
WATERLOGGED,
|
||||
fluidState.type === Fluids.WATER
|
||||
)
|
||||
}
|
||||
|
||||
private fun canGrow(world: LevelReader, pos: BlockPos, state: BlockState): Boolean {
|
||||
return !this.isMaxAge(state) && canSurvive(state, world, pos)
|
||||
}
|
||||
|
||||
private fun canGrowInto(world: LevelReader, pos: BlockPos): Boolean {
|
||||
val blockState = world.getBlockState(pos)
|
||||
return blockState.isAir || blockState.`is`(CobblemonBlocks.HEARTY_GRAINS)
|
||||
}
|
||||
|
||||
override fun playerWillDestroy(world: Level, pos: BlockPos, state: BlockState, player: Player): BlockState {
|
||||
if (state.getValue(PART) == Part.UPPER && state.block is HeartyGrainsBlock) {
|
||||
val belowPos = pos.below()
|
||||
val belowState = world.getBlockState(belowPos)
|
||||
world.destroyBlock(pos, true) // Break the lower block without drops
|
||||
world.setBlock(
|
||||
belowPos,
|
||||
belowState.setValue(AGE, ageAfterHarvest), // Reset age to simulate regrowth preparation
|
||||
UPDATE_CLIENTS
|
||||
)
|
||||
} else if (state.getValue(PART) == Part.LOWER) {
|
||||
val abovePos = pos.above()
|
||||
val aboveState = world.getBlockState(abovePos)
|
||||
if (aboveState.block is HeartyGrainsBlock && aboveState.getValue(PART) == Part.UPPER) {
|
||||
world.destroyBlock(abovePos, true) // Break the upper block without drops
|
||||
if (!world.isClientSide) {
|
||||
if (state.getValue(HALF) == DoubleBlockHalf.UPPER) {
|
||||
val belowPos = pos.below()
|
||||
val belowState = world.getBlockState(belowPos)
|
||||
world.destroyBlock(pos, true) // Break the lower block without drops
|
||||
world.setBlock(
|
||||
belowPos,
|
||||
belowState.setValue(AGE, ageAfterHarvest), // Reset age to simulate regrowth preparation
|
||||
UPDATE_CLIENTS
|
||||
)
|
||||
} else if (state.getValue(HALF) == DoubleBlockHalf.LOWER) {
|
||||
val abovePos = pos.above()
|
||||
val aboveState = world.getBlockState(abovePos)
|
||||
if (aboveState.block is HeartyGrainsBlock && aboveState.getValue(HALF) == DoubleBlockHalf.UPPER) {
|
||||
world.destroyBlock(abovePos, true) // Break the upper block without drops
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.playerWillDestroy(world, pos, state, player)
|
||||
@@ -117,32 +121,53 @@ class HeartyGrainsBlock(settings: Properties) : CropBlock(settings), SimpleWater
|
||||
if (state.getValue(WATERLOGGED)) {
|
||||
world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world))
|
||||
}
|
||||
return if (!canSurvive(state, world, pos)) Blocks.AIR.defaultBlockState() else super.updateShape(
|
||||
state,
|
||||
direction,
|
||||
neighborState,
|
||||
world,
|
||||
pos,
|
||||
neighborPos
|
||||
val doubleBlockHalf = state.getValue(HALF)
|
||||
return if (direction.axis !== Direction.Axis.Y || doubleBlockHalf == DoubleBlockHalf.LOWER != (direction == Direction.UP) ||
|
||||
neighborState.`is`(this) && neighborState.getValue(HALF) != doubleBlockHalf) {
|
||||
if (doubleBlockHalf == DoubleBlockHalf.LOWER && direction == Direction.DOWN && !state.canSurvive(world, pos))
|
||||
Blocks.AIR.defaultBlockState()
|
||||
else super.updateShape(state, direction, neighborState, world, pos, neighborPos)
|
||||
} else {
|
||||
Blocks.AIR.defaultBlockState()
|
||||
}
|
||||
}
|
||||
|
||||
override fun isValidBonemealTarget(level: LevelReader, pos: BlockPos, state: BlockState): Boolean {
|
||||
val posAndState = getLowerHalf(level, pos, state)
|
||||
return if (posAndState == null) false else this.canGrow(
|
||||
level,
|
||||
posAndState.first,
|
||||
posAndState.second
|
||||
)
|
||||
}
|
||||
|
||||
override fun isValidBonemealTarget(world: LevelReader, pos: BlockPos, state: BlockState): Boolean {
|
||||
return !this.isMaxAge(state) && state.getValue(PART) == Part.LOWER
|
||||
override fun performBonemeal(level: ServerLevel, random: RandomSource, pos: BlockPos, state: BlockState) {
|
||||
val posAndState = getLowerHalf(level, pos, state)
|
||||
if (posAndState != null) {
|
||||
grow(level, posAndState.first, posAndState.second, getBonemealAgeIncrease(level))
|
||||
}
|
||||
}
|
||||
|
||||
override fun growCrops(world: Level, pos: BlockPos, state: BlockState) {
|
||||
if (!canGrow(world, pos)) return
|
||||
fun grow(world: Level, pos: BlockPos, state: BlockState, increment: Int) {
|
||||
if (!canGrow(world, pos, state)) return
|
||||
|
||||
val newAge = (this.getAge(state) + this.getBonemealAgeIncrease(world)).coerceAtMost(this.maxAge)
|
||||
val newAge = (this.getAge(state) + increment).coerceAtMost(this.maxAge)
|
||||
world.setBlock(pos, state.setValue(this.ageProperty, newAge), UPDATE_CLIENTS)
|
||||
|
||||
if (newAge == MATURE_AGE && state.getValue(PART) == Part.LOWER) {
|
||||
if (newAge >= 5) {
|
||||
val abovePos = pos.above()
|
||||
if (world.getBlockState(abovePos).isAir) {
|
||||
val stateAbove = world.getBlockState(abovePos)
|
||||
if (stateAbove.isAir) {
|
||||
world.setBlock(
|
||||
abovePos,
|
||||
this.defaultBlockState().setValue(AGE, newAge).setValue(PART, Part.UPPER),
|
||||
this.defaultBlockState().setValue(AGE, newAge).setValue(HALF, DoubleBlockHalf.UPPER),
|
||||
UPDATE_CLIENTS
|
||||
)
|
||||
}
|
||||
else if (stateAbove.getValue(HALF) == DoubleBlockHalf.UPPER) {
|
||||
world.setBlock(
|
||||
abovePos,
|
||||
stateAbove.setValue(AGE, newAge),
|
||||
UPDATE_CLIENTS
|
||||
)
|
||||
}
|
||||
@@ -152,63 +177,81 @@ class HeartyGrainsBlock(settings: Properties) : CropBlock(settings), SimpleWater
|
||||
override fun getBonemealAgeIncrease(world: Level): Int = 1
|
||||
|
||||
override fun canSurvive(state: BlockState, world: LevelReader, pos: BlockPos): Boolean {
|
||||
return when (state.getValue(PART)) {
|
||||
Part.LOWER -> {
|
||||
val floor = world.getBlockState(pos.below())
|
||||
val fluidState = world.getFluidState(pos)
|
||||
return when (state.getValue(HALF)) {
|
||||
DoubleBlockHalf.LOWER -> {
|
||||
val floorBlock = pos.below()
|
||||
val floor = world.getBlockState(floorBlock)
|
||||
|
||||
// Check if bottom part is submerged in water
|
||||
val isSubmergedInWater = fluidState.`is`(FluidTags.WATER) && fluidState.isSource
|
||||
val fluidState = world.getFluidState(pos)
|
||||
if (fluidState.`is`(FluidTags.WATER) && fluidState.isSource)
|
||||
return floor.`is`(CobblemonBlockTags.HEARTY_GRAINS_WATER_PLANTABLE) && canGrowInto(world, pos.above())
|
||||
|
||||
// Check for adjacency to water
|
||||
val isNearWater = BlockPos.betweenClosed(pos.offset(-1, 0, -1), pos.offset(1, 0, 1))
|
||||
.any { world.getFluidState(it).`is`(FluidTags.WATER) }
|
||||
// check if water is adjacent
|
||||
var waterNearby = false
|
||||
for (i in -1..1) {
|
||||
for (j in -1..1) {
|
||||
val fluidState = world.getFluidState(floorBlock.offset(i, 0, j))
|
||||
if (fluidState.`is`(FluidTags.WATER) && fluidState.isSource) {
|
||||
waterNearby = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check waterlogging state
|
||||
val isWaterlogged = state.getValue(WATERLOGGED)
|
||||
|
||||
// Check for valid soil or survival conditions
|
||||
isSubmergedInWater || isWaterlogged || isNearWater || floor.`is`(CobblemonBlockTags.HEARTY_GRAINS_PLANTABLE) || floor.`is`(Blocks.MUD) || floor.`is`(Blocks.FARMLAND)
|
||||
waterNearby && floor.`is`(CobblemonBlockTags.HEARTY_GRAINS_LAND_PLANTABLE) && canGrowInto(world, pos.above())
|
||||
}
|
||||
Part.UPPER -> {
|
||||
val below = world.getBlockState(pos.below())
|
||||
below.block is HeartyGrainsBlock && below.getValue(PART) == Part.LOWER
|
||||
DoubleBlockHalf.UPPER -> {
|
||||
getLowerHalf(world, pos, state) != null
|
||||
// Upper part survives only if the lower part is valid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getLowerHalf(level: LevelReader, pos: BlockPos, state: BlockState): Pair<BlockPos, BlockState>? {
|
||||
if (isLower(state)) {
|
||||
return Pair(pos, state)
|
||||
} else {
|
||||
val blockPos = pos.below()
|
||||
val blockState = level.getBlockState(blockPos)
|
||||
return if (isLower(blockState)) Pair(
|
||||
blockPos,
|
||||
blockState
|
||||
) else null
|
||||
}
|
||||
}
|
||||
|
||||
private fun isLower(state: BlockState): Boolean =
|
||||
state.`is`(CobblemonBlocks.HEARTY_GRAINS) && state.getValue(HALF) == DoubleBlockHalf.LOWER
|
||||
|
||||
|
||||
|
||||
override fun codec(): MapCodec<out CropBlock> = CODEC
|
||||
|
||||
companion object {
|
||||
val CODEC = simpleCodec(::HeartyGrainsBlock)
|
||||
const val MATURE_AGE = 4
|
||||
const val MATURE_AGE = 7
|
||||
val WATERLOGGED = BlockStateProperties.WATERLOGGED
|
||||
val AGE: IntegerProperty = BlockStateProperties.AGE_4
|
||||
val PART: EnumProperty<Part> = EnumProperty.create("part", Part::class.java)
|
||||
val AGE: IntegerProperty = BlockStateProperties.AGE_7
|
||||
val HALF: EnumProperty<DoubleBlockHalf> = BlockStateProperties.DOUBLE_BLOCK_HALF
|
||||
|
||||
val AGE_TO_SHAPE = arrayOf(
|
||||
box(2.0, 0.0, 0.0, 16.0, 17.0, 16.0), // Stage 1
|
||||
box(2.0, 0.0, 0.0, 16.0, 17.0, 16.0), // Stage 2
|
||||
box(2.0, 0.0, 0.0, 16.0, 17.0, 16.0), // Stage 3
|
||||
box(2.0, 0.0, 0.0, 16.0, 17.0, 16.0), // Stage 4 (Bottom)
|
||||
box(2.0, 0.0, 0.0, 16.0, 17.0, 16.0) // Stage 5 (Bottom)
|
||||
box(0.0, 0.0, 0.0, 16.0, 3.0, 16.0), // Stage 0
|
||||
box(0.0, 0.0, 0.0, 16.0, 5.0, 16.0), // Stage 1
|
||||
box(0.0, 0.0, 0.0, 16.0, 8.0, 16.0), // Stage 2
|
||||
box(0.0, 0.0, 0.0, 16.0, 10.0, 16.0), // Stage 3
|
||||
box(0.0, 0.0, 0.0, 16.0, 16.0, 16.0), // Stage 4
|
||||
box(0.0, 0.0, 0.0, 16.0, 16.0, 16.0), // Stage 5
|
||||
box(0.0, 0.0, 0.0, 16.0, 16.0, 16.0), // Stage 6
|
||||
box(0.0, 0.0, 0.0, 16.0, 16.0, 16.0) // Stage 7
|
||||
)
|
||||
}
|
||||
|
||||
enum class Part : StringRepresentable {
|
||||
LOWER, UPPER;
|
||||
|
||||
override fun getSerializedName(): String = name.lowercase()
|
||||
}
|
||||
|
||||
init {
|
||||
this.registerDefaultState(
|
||||
this.stateDefinition.any()
|
||||
.setValue(AGE, 0)
|
||||
.setValue(PART, Part.LOWER)
|
||||
.setValue(HALF, DoubleBlockHalf.LOWER)
|
||||
.setValue(WATERLOGGED, false)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ import net.minecraft.world.level.gameevent.GameEvent
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
|
||||
class PokeCakeBlock(settings: Properties): CakeBlock(settings) {
|
||||
override fun codec(): MapCodec<out BaseEntityBlock?>? {
|
||||
override fun codec(): MapCodec<out BaseEntityBlock?> {
|
||||
return simpleCodec(::PokeCakeBlock)
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ class PokeCakeBlock(settings: Properties): CakeBlock(settings) {
|
||||
pos: BlockPos,
|
||||
player: Player,
|
||||
hitResult: BlockHitResult
|
||||
): InteractionResult? {
|
||||
): InteractionResult {
|
||||
if (level.isClientSide) {
|
||||
if (eat(level, pos, player).consumesAction()) {
|
||||
return InteractionResult.SUCCESS
|
||||
@@ -84,7 +84,7 @@ class PokeCakeBlock(settings: Properties): CakeBlock(settings) {
|
||||
player: Player,
|
||||
hand: InteractionHand,
|
||||
hitResult: BlockHitResult
|
||||
): ItemInteractionResult? {
|
||||
): ItemInteractionResult {
|
||||
val item = stack.item
|
||||
val block = state.block as? PokeCakeBlock
|
||||
|
||||
|
||||
@@ -19,7 +19,12 @@ import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
import net.minecraft.sounds.SoundSource
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.InteractionResult
|
||||
import net.minecraft.world.entity.EquipmentSlot
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.LevelAccessor
|
||||
import net.minecraft.world.level.LevelReader
|
||||
@@ -29,6 +34,7 @@ import net.minecraft.world.level.block.BonemealableBlock
|
||||
import net.minecraft.world.level.block.RenderShape
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.gameevent.GameEvent
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
|
||||
@Suppress("OVERRIDE_DEPRECATION", "UNUSED_PARAMETER", "MemberVisibilityCanBePrivate", "DEPRECATION")
|
||||
abstract class RootBlock(settings: Properties) : Block(settings), BonemealableBlock, ShearableBlock {
|
||||
@@ -42,6 +48,23 @@ abstract class RootBlock(settings: Properties) : Block(settings), BonemealableBl
|
||||
}
|
||||
}
|
||||
|
||||
override fun useWithoutItem(
|
||||
state: BlockState,
|
||||
world: Level,
|
||||
pos: BlockPos,
|
||||
player: Player,
|
||||
blockHitResult: BlockHitResult
|
||||
): InteractionResult {
|
||||
val stack = player.getItemInHand(InteractionHand.MAIN_HAND)
|
||||
if (stack.`is`(Items.SHEARS)) {
|
||||
this.attemptShear(world, state, pos) {
|
||||
stack.hurtAndBreak(1, player, EquipmentSlot.MAINHAND)
|
||||
}
|
||||
return InteractionResult.sidedSuccess(world.isClientSide)
|
||||
}
|
||||
return super.useWithoutItem(state, world, pos, player, blockHitResult)
|
||||
}
|
||||
|
||||
fun hasReachedSpreadCap(world: Level, pos: BlockPos): Boolean {
|
||||
var nearby = 0
|
||||
val nearbyPositions = BlockPos.betweenClosed(pos.offset(-4, -1, -4), pos.offset(4, 1, 4)).iterator()
|
||||
@@ -67,7 +90,8 @@ abstract class RootBlock(settings: Properties) : Block(settings), BonemealableBl
|
||||
pos: BlockPos,
|
||||
neighborPos: BlockPos
|
||||
): BlockState {
|
||||
return if (direction == Direction.UP && !this.canSurvive(state, world, pos)) Blocks.AIR.defaultBlockState() else super.updateShape(state, direction, neighborState, world, pos, neighborPos)
|
||||
return if (direction == Direction.UP && !this.canSurvive(state, world, pos)) Blocks.AIR.defaultBlockState()
|
||||
else super.updateShape(state, direction, neighborState, world, pos, neighborPos)
|
||||
}
|
||||
|
||||
override fun isValidBonemealTarget(world: LevelReader, pos: BlockPos, state: BlockState) = this.canSpread(world, pos, state)
|
||||
@@ -117,6 +141,7 @@ abstract class RootBlock(settings: Properties) : Block(settings), BonemealableBl
|
||||
popResource(world, pos, shearedDrop)
|
||||
}
|
||||
world.gameEvent(null, GameEvent.SHEAR, pos)
|
||||
successCallback.invoke()
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -150,12 +175,12 @@ abstract class RootBlock(settings: Properties) : Block(settings), BonemealableBl
|
||||
/**
|
||||
* Picks the [BlockState] that results from a spread of this block.
|
||||
*
|
||||
* @param random The [Random] instance used during a spread attempt.
|
||||
* @param random The [RandomSource] instance used during a spread attempt.
|
||||
* @return The [BlockState] that will represent the spread root.
|
||||
*/
|
||||
protected fun spreadingRoot(random: RandomSource): BlockState =
|
||||
if (random.nextFloat() < Cobblemon.config.energyRootChance) CobblemonBlocks.ENERGY_ROOT.defaultBlockState()
|
||||
else this.defaultBlockState()
|
||||
else CobblemonBlocks.BIG_ROOT.defaultBlockState()
|
||||
|
||||
/**
|
||||
* Checks if the given coordinates allow for a root to be placed with some context.
|
||||
@@ -169,7 +194,7 @@ abstract class RootBlock(settings: Properties) : Block(settings), BonemealableBl
|
||||
protected fun canGoOn(state: BlockState, world: LevelReader, pos: BlockPos, ceilingValidator: (ceiling: BlockState) -> Boolean): Boolean {
|
||||
val up = pos.above()
|
||||
val upState = world.getBlockState(up)
|
||||
return upState.isFaceSturdy(world, up, Direction.DOWN) && ceilingValidator(upState) // todo (techdaan): ensure this is the right mapping
|
||||
return upState.isFaceSturdy(world, up, Direction.DOWN) && ceilingValidator(upState)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,84 +8,120 @@
|
||||
|
||||
package com.cobblemon.mod.common.block
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.core.dispenser.DispenseItemBehavior
|
||||
import net.minecraft.world.Containers
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.ItemInteractionResult
|
||||
import net.minecraft.world.entity.item.ItemEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.LevelAccessor
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.DispenserBlock
|
||||
import net.minecraft.world.level.block.RotatedPillarBlock
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.StateDefinition
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties
|
||||
import net.minecraft.world.level.block.state.properties.EnumProperty
|
||||
import net.minecraft.world.level.material.PushReaction
|
||||
import net.minecraft.world.level.gameevent.GameEvent
|
||||
import net.minecraft.world.level.pathfinder.PathComputationType
|
||||
import net.minecraft.world.level.storage.loot.LootParams
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import net.minecraft.world.phys.shapes.CollisionContext
|
||||
import net.minecraft.world.phys.shapes.EntityCollisionContext
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
|
||||
class SaccharineHoneyLogBlock(properties: Properties) : RotatedPillarBlock(properties) {
|
||||
|
||||
init {
|
||||
this.registerDefaultState(
|
||||
this.stateDefinition.any()
|
||||
.setValue(AXIS, Direction.Axis.Y)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getShape(
|
||||
override fun useItemOn(
|
||||
stack: ItemStack,
|
||||
state: BlockState,
|
||||
level: BlockGetter,
|
||||
level: Level,
|
||||
pos: BlockPos,
|
||||
context: CollisionContext
|
||||
): VoxelShape {
|
||||
return SHAPE
|
||||
}
|
||||
player: Player,
|
||||
hand: InteractionHand,
|
||||
hitResult: BlockHitResult
|
||||
): ItemInteractionResult? {
|
||||
val itemStack = player.getItemInHand(hand)
|
||||
if (itemStack.`is`(Items.GLASS_BOTTLE)) {
|
||||
if (!level.isClientSide) {
|
||||
// Replace the honey with the block variant
|
||||
val newState = CobblemonBlocks.SACCHARINE_LOG.defaultBlockState()
|
||||
.setValue(RotatedPillarBlock.AXIS, state.getValue(RotatedPillarBlock.AXIS))
|
||||
level.setBlock(pos, newState, 3)
|
||||
level.gameEvent(null, GameEvent.BLOCK_CHANGE, pos)
|
||||
|
||||
override fun getCollisionShape(
|
||||
state: BlockState,
|
||||
level: BlockGetter,
|
||||
pos: BlockPos,
|
||||
context: CollisionContext
|
||||
): VoxelShape {
|
||||
if (context is EntityCollisionContext && (context.entity as? ItemEntity)?.item?.`is`(CobblemonItemTags.APRICORNS) == true) {
|
||||
return Shapes.empty()
|
||||
// Consume glass bottle
|
||||
if (!player.isCreative) {
|
||||
itemStack.shrink(1)
|
||||
|
||||
// Give Honey bottle
|
||||
val honeyBottle = ItemStack(Items.HONEY_BOTTLE)
|
||||
if (!player.addItem(honeyBottle)) {
|
||||
player.drop(honeyBottle, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ItemInteractionResult.SUCCESS
|
||||
}
|
||||
return super.getCollisionShape(state, level, pos, context)
|
||||
return super.useItemOn(stack, state, level, pos, player, hand, hitResult)
|
||||
}
|
||||
|
||||
override fun updateShape(
|
||||
state: BlockState,
|
||||
direction: Direction,
|
||||
neighborState: BlockState,
|
||||
level: LevelAccessor,
|
||||
pos: BlockPos,
|
||||
neighborPos: BlockPos
|
||||
): BlockState {
|
||||
return if (!state.canSurvive(level, pos)) {
|
||||
Blocks.AIR.defaultBlockState()
|
||||
} else {
|
||||
super.updateShape(state, direction, neighborState, level, pos, neighborPos)
|
||||
}
|
||||
}
|
||||
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
|
||||
builder.add(AXIS)
|
||||
}
|
||||
|
||||
override fun isPathfindable(
|
||||
state: BlockState,
|
||||
type: PathComputationType
|
||||
): Boolean = false
|
||||
|
||||
companion object {
|
||||
val AXIS: EnumProperty<Direction.Axis> = BlockStateProperties.AXIS
|
||||
|
||||
private val SHAPE: VoxelShape = Shapes.block()
|
||||
|
||||
fun createBehavior(): DispenseItemBehavior {
|
||||
return DispenseItemBehavior { source, stack ->
|
||||
val level = source.level
|
||||
val pos = source.pos.relative(source.state.getValue(DispenserBlock.FACING))
|
||||
val blockState = level.getBlockState(pos)
|
||||
|
||||
if (blockState.block is SaccharineHoneyLogBlock) {
|
||||
val newState = CobblemonBlocks.SACCHARINE_LOG.defaultBlockState()
|
||||
.setValue(AXIS, blockState.getValue(AXIS))
|
||||
level.setBlock(pos, newState, 3)
|
||||
level.gameEvent(null, GameEvent.BLOCK_CHANGE, pos)
|
||||
stack.shrink(1)
|
||||
|
||||
val dispenserEntity = source.blockEntity
|
||||
if (dispenserEntity != null) {
|
||||
val honeyBottle = ItemStack(Items.HONEY_BOTTLE)
|
||||
var added = false
|
||||
|
||||
for (i in 0 until dispenserEntity.containerSize) {
|
||||
val slotStack = dispenserEntity.getItem(i)
|
||||
|
||||
if (slotStack.isEmpty) {
|
||||
dispenserEntity.setItem(i, honeyBottle.copy())
|
||||
added = true
|
||||
break
|
||||
} else if (slotStack.`is`(Items.HONEY_BOTTLE) && slotStack.count < slotStack.maxStackSize) {
|
||||
slotStack.grow(1)
|
||||
added = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!added) {
|
||||
Containers.dropItemStack(
|
||||
level,
|
||||
source.pos.x.toDouble(), source.pos.y.toDouble(), source.pos.z.toDouble(), honeyBottle
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
stack
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,31 +11,31 @@ package com.cobblemon.mod.common.block
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.core.dispenser.DispenseItemBehavior
|
||||
import net.minecraft.core.particles.ParticleTypes
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.tags.BlockTags
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.world.Containers
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.ItemInteractionResult
|
||||
import net.minecraft.world.entity.item.ItemEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.item.context.BlockPlaceContext
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.LevelAccessor
|
||||
import net.minecraft.world.level.LevelReader
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.BonemealableBlock
|
||||
import net.minecraft.world.level.block.LeavesBlock
|
||||
import net.minecraft.world.level.block.*
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.StateDefinition
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties
|
||||
import net.minecraft.world.level.block.state.properties.BooleanProperty
|
||||
import net.minecraft.world.level.block.state.properties.IntegerProperty
|
||||
import net.minecraft.world.level.gameevent.GameEvent
|
||||
import net.minecraft.world.level.material.Fluids
|
||||
import net.minecraft.world.level.pathfinder.PathComputationType
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
@@ -84,7 +84,7 @@ class SaccharineLeafBlock(settings: Properties) : LeavesBlock(settings), Bonemea
|
||||
if (belowAge < MAX_AGE) {
|
||||
changeAge(state, -1)
|
||||
changeAge(belowState, 1)
|
||||
}
|
||||
}
|
||||
break
|
||||
} else {
|
||||
break
|
||||
@@ -130,7 +130,7 @@ class SaccharineLeafBlock(settings: Properties) : LeavesBlock(settings), Bonemea
|
||||
override fun animateTick(state: BlockState, level: Level, pos: BlockPos, random: RandomSource) {
|
||||
|
||||
val particleCount = random.nextInt(3)
|
||||
|
||||
|
||||
if (state.getValue(AGE) == 2) {
|
||||
repeat(particleCount) {
|
||||
spawnHoneyParticles(level, pos, state, 0.75f)
|
||||
@@ -218,12 +218,14 @@ class SaccharineLeafBlock(settings: Properties) : LeavesBlock(settings), Bonemea
|
||||
// give player honey bottle for now
|
||||
player.addItem(Items.HONEY_BOTTLE.defaultInstance)
|
||||
level.setBlock(pos, state.setValue(AGE, 0), 2)
|
||||
level.gameEvent(null, GameEvent.BLOCK_CHANGE, pos)
|
||||
} else if (isHoneyBottle && !isAtMaxAge(state)) {
|
||||
// decrement stack if not in creative mode
|
||||
if (!player.isCreative)
|
||||
itemStack.shrink(1)
|
||||
|
||||
|
||||
level.setBlock(pos, state.setValue(AGE, 2), 2)
|
||||
level.gameEvent(null, GameEvent.BLOCK_CHANGE, pos)
|
||||
}
|
||||
|
||||
if (state.getValue(AGE) != MAX_AGE) {
|
||||
@@ -235,13 +237,28 @@ class SaccharineLeafBlock(settings: Properties) : LeavesBlock(settings), Bonemea
|
||||
}
|
||||
|
||||
private fun isAtMaxAge(state: BlockState) = state.getValue(AGE) == MAX_AGE
|
||||
private fun isAtMinAge(state: BlockState) = state.getValue(AGE) >= MIN_AGE
|
||||
private fun isAtMinAge(state: BlockState) = state.getValue(AGE) == MIN_AGE
|
||||
|
||||
private fun changeAge(state: BlockState, value: Int): BlockState {
|
||||
val newAge = (state.getValue(AGE) + value).coerceIn(MIN_AGE, MAX_AGE)
|
||||
return state.setValue(AGE, newAge)
|
||||
}
|
||||
|
||||
override fun spawnDestroyParticles(level: Level, player: Player, pos: BlockPos, state: BlockState) {
|
||||
if (isAtMinAge(state)) {
|
||||
super.spawnDestroyParticles(level, player, pos, state)
|
||||
return
|
||||
} else {
|
||||
// TODO: Change to Yellow Leaves in stead of concrete
|
||||
val particle = Blocks.YELLOW_CONCRETE_POWDER.defaultBlockState()
|
||||
level.levelEvent(
|
||||
LevelEvent.PARTICLES_DESTROY_BLOCK,
|
||||
pos,
|
||||
Block.getId(particle)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/*override fun onBlockBreakStart(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity) {
|
||||
if (state.get(AGE) != MAX_AGE) {
|
||||
return super.onBlockBreakStart(state, world, pos, player)
|
||||
@@ -260,6 +277,63 @@ class SaccharineLeafBlock(settings: Properties) : LeavesBlock(settings), Bonemea
|
||||
const val DISTANCE_MAX = 7
|
||||
|
||||
private val SHAPE: VoxelShape = box(0.0, 0.0, 0.0, 16.0, 16.0, 16.0)
|
||||
|
||||
fun createBehavior(item: Item): DispenseItemBehavior {
|
||||
return DispenseItemBehavior { source, stack ->
|
||||
val level = source.level
|
||||
val facing = source.state.getValue(DispenserBlock.FACING)
|
||||
val pos = source.pos.relative(facing)
|
||||
val blockState = level.getBlockState(pos)
|
||||
|
||||
if (blockState.block is SaccharineLeafBlock) {
|
||||
val currentAge = blockState.getValue(AGE)
|
||||
val newAge = when {
|
||||
item == Items.HONEY_BOTTLE && currentAge < MAX_AGE -> (currentAge + 2).coerceAtMost(MAX_AGE)
|
||||
item == Items.GLASS_BOTTLE && currentAge > MIN_AGE -> (currentAge - 2).coerceAtLeast(MIN_AGE)
|
||||
else -> currentAge
|
||||
}
|
||||
|
||||
if (newAge != currentAge) {
|
||||
level.setBlock(pos, blockState.setValue(AGE, newAge), 3)
|
||||
level.gameEvent(null, GameEvent.BLOCK_CHANGE, pos)
|
||||
stack.shrink(1)
|
||||
|
||||
val dispenserEntity = source.blockEntity
|
||||
if (dispenserEntity != null) {
|
||||
val outputItem = if (item == Items.HONEY_BOTTLE) Items.GLASS_BOTTLE else Items.HONEY_BOTTLE
|
||||
val outputStack = ItemStack(outputItem)
|
||||
var added = false
|
||||
|
||||
for (i in 0 until dispenserEntity.containerSize) {
|
||||
val slotStack = dispenserEntity.getItem(i)
|
||||
|
||||
if (slotStack.isEmpty) {
|
||||
dispenserEntity.setItem(i, outputStack.copy())
|
||||
added = true
|
||||
break
|
||||
} else if (slotStack.`is`(outputItem) && slotStack.count < slotStack.maxStackSize) {
|
||||
slotStack.grow(1)
|
||||
added = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!added) {
|
||||
Containers.dropItemStack(
|
||||
level,
|
||||
source.pos.x.toDouble(),
|
||||
source.pos.y.toDouble(),
|
||||
source.pos.z.toDouble(),
|
||||
outputStack
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stack
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,16 +9,13 @@
|
||||
package com.cobblemon.mod.common.block
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.core.dispenser.DispenseItemBehavior
|
||||
import net.minecraft.world.Containers
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.InteractionResult
|
||||
import net.minecraft.world.ItemInteractionResult
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.item.ItemEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.ItemStack
|
||||
@@ -26,14 +23,16 @@ import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.LevelAccessor
|
||||
import net.minecraft.world.level.block.*
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.DispenserBlock
|
||||
import net.minecraft.world.level.block.RotatedPillarBlock
|
||||
import net.minecraft.world.level.block.entity.DispenserBlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.StateDefinition
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties
|
||||
import net.minecraft.world.level.block.state.properties.EnumProperty
|
||||
import net.minecraft.world.level.block.state.properties.IntegerProperty
|
||||
import net.minecraft.world.level.material.PushReaction
|
||||
import net.minecraft.world.level.gameevent.GameEvent
|
||||
import net.minecraft.world.level.pathfinder.PathComputationType
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import net.minecraft.world.phys.shapes.CollisionContext
|
||||
@@ -43,53 +42,6 @@ import net.minecraft.world.phys.shapes.VoxelShape
|
||||
|
||||
class SaccharineLogBlock(properties: Properties) : RotatedPillarBlock(properties) {
|
||||
|
||||
init {
|
||||
this.registerDefaultState(
|
||||
this.stateDefinition.any()
|
||||
.setValue(AXIS, Direction.Axis.Y)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getShape(
|
||||
state: BlockState,
|
||||
level: BlockGetter,
|
||||
pos: BlockPos,
|
||||
context: CollisionContext
|
||||
): VoxelShape {
|
||||
return SHAPE
|
||||
}
|
||||
|
||||
override fun getCollisionShape(
|
||||
state: BlockState,
|
||||
level: BlockGetter,
|
||||
pos: BlockPos,
|
||||
context: CollisionContext
|
||||
): VoxelShape {
|
||||
if (context is EntityCollisionContext && (context.entity as? ItemEntity)?.item?.`is`(CobblemonItemTags.APRICORNS) == true) {
|
||||
return Shapes.empty()
|
||||
}
|
||||
return super.getCollisionShape(state, level, pos, context)
|
||||
}
|
||||
|
||||
override fun updateShape(
|
||||
state: BlockState,
|
||||
direction: Direction,
|
||||
neighborState: BlockState,
|
||||
level: LevelAccessor,
|
||||
pos: BlockPos,
|
||||
neighborPos: BlockPos
|
||||
): BlockState {
|
||||
return if (!state.canSurvive(level, pos)) {
|
||||
Blocks.AIR.defaultBlockState()
|
||||
} else {
|
||||
super.updateShape(state, direction, neighborState, level, pos, neighborPos)
|
||||
}
|
||||
}
|
||||
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
|
||||
builder.add(AXIS)
|
||||
}
|
||||
|
||||
override fun useItemOn(
|
||||
stack: ItemStack,
|
||||
state: BlockState,
|
||||
@@ -106,6 +58,7 @@ class SaccharineLogBlock(properties: Properties) : RotatedPillarBlock(properties
|
||||
val newState = CobblemonBlocks.SACCHARINE_HONEY_LOG.defaultBlockState()
|
||||
.setValue(RotatedPillarBlock.AXIS, state.getValue(RotatedPillarBlock.AXIS))
|
||||
level.setBlock(pos, newState, 3)
|
||||
level.gameEvent(null, GameEvent.BLOCK_CHANGE, pos)
|
||||
|
||||
// Consume honey bottle
|
||||
if (!player.isCreative) {
|
||||
@@ -123,15 +76,57 @@ class SaccharineLogBlock(properties: Properties) : RotatedPillarBlock(properties
|
||||
return super.useItemOn(stack, state, level, pos, player, hand, hitResult)
|
||||
}
|
||||
|
||||
|
||||
override fun isPathfindable(
|
||||
state: BlockState,
|
||||
type: PathComputationType
|
||||
): Boolean = false
|
||||
|
||||
companion object {
|
||||
val AXIS: EnumProperty<Direction.Axis> = BlockStateProperties.AXIS
|
||||
|
||||
private val SHAPE: VoxelShape = Shapes.block()
|
||||
|
||||
fun createBehavior(): DispenseItemBehavior {
|
||||
return DispenseItemBehavior { source, stack ->
|
||||
val level = source.level
|
||||
val facing = source.state.getValue(DispenserBlock.FACING)
|
||||
val pos = source.pos.relative(facing)
|
||||
val blockState = level.getBlockState(pos)
|
||||
|
||||
if (blockState.block is SaccharineLogBlock) {
|
||||
val newState = CobblemonBlocks.SACCHARINE_HONEY_LOG.defaultBlockState()
|
||||
.setValue(AXIS, blockState.getValue(AXIS))
|
||||
level.setBlock(pos, newState, 3)
|
||||
level.gameEvent(null, GameEvent.BLOCK_CHANGE, pos)
|
||||
|
||||
stack.shrink(1)
|
||||
|
||||
val dispenserEntity = source.blockEntity
|
||||
if (dispenserEntity != null) {
|
||||
val glassBottle = ItemStack(Items.GLASS_BOTTLE)
|
||||
var added = false
|
||||
|
||||
for (i in 0 until dispenserEntity.containerSize) {
|
||||
val slotStack = dispenserEntity.getItem(i)
|
||||
|
||||
if (slotStack.isEmpty) {
|
||||
dispenserEntity.setItem(i, glassBottle.copy())
|
||||
added = true
|
||||
break
|
||||
} else if (slotStack.`is`(Items.GLASS_BOTTLE) && slotStack.count < slotStack.maxStackSize) {
|
||||
slotStack.grow(1)
|
||||
added = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!added) {
|
||||
Containers.dropItemStack(
|
||||
level,
|
||||
source.pos.x.toDouble(), source.pos.y.toDouble(), source.pos.z.toDouble(), glassBottle
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stack
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,115 +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.block
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.InteractionResult
|
||||
import net.minecraft.world.ItemInteractionResult
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.item.ItemEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.LevelAccessor
|
||||
import net.minecraft.world.level.block.*
|
||||
import net.minecraft.world.level.block.RotatedPillarBlock
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.StateDefinition
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties
|
||||
import net.minecraft.world.level.block.state.properties.EnumProperty
|
||||
import net.minecraft.world.level.block.state.properties.IntegerProperty
|
||||
import net.minecraft.world.level.material.PushReaction
|
||||
import net.minecraft.world.level.pathfinder.PathComputationType
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import net.minecraft.world.phys.shapes.CollisionContext
|
||||
import net.minecraft.world.phys.shapes.EntityCollisionContext
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
|
||||
class SaccharineStrippedLogBlock(properties: Properties) : RotatedPillarBlock(properties) {
|
||||
|
||||
private var owner: LivingEntity? = null
|
||||
|
||||
init {
|
||||
this.registerDefaultState(
|
||||
this.stateDefinition.any()
|
||||
.setValue(AXIS, Direction.Axis.Y)
|
||||
)
|
||||
}
|
||||
|
||||
override fun setPlacedBy(
|
||||
level: Level,
|
||||
pos: BlockPos,
|
||||
state: BlockState,
|
||||
placer: LivingEntity?,
|
||||
itemStack: ItemStack
|
||||
) {
|
||||
owner = placer
|
||||
super.setPlacedBy(level, pos, state, placer, itemStack)
|
||||
}
|
||||
|
||||
override fun getShape(
|
||||
state: BlockState,
|
||||
level: BlockGetter,
|
||||
pos: BlockPos,
|
||||
context: CollisionContext
|
||||
): VoxelShape {
|
||||
return SHAPE
|
||||
}
|
||||
|
||||
override fun getCollisionShape(
|
||||
state: BlockState,
|
||||
level: BlockGetter,
|
||||
pos: BlockPos,
|
||||
context: CollisionContext
|
||||
): VoxelShape {
|
||||
if (context is EntityCollisionContext && (context.entity as? ItemEntity)?.item?.`is`(CobblemonItemTags.APRICORNS) == true) {
|
||||
return Shapes.empty()
|
||||
}
|
||||
return super.getCollisionShape(state, level, pos, context)
|
||||
}
|
||||
|
||||
override fun updateShape(
|
||||
state: BlockState,
|
||||
direction: Direction,
|
||||
neighborState: BlockState,
|
||||
level: LevelAccessor,
|
||||
pos: BlockPos,
|
||||
neighborPos: BlockPos
|
||||
): BlockState {
|
||||
return if (!state.canSurvive(level, pos)) {
|
||||
Blocks.AIR.defaultBlockState()
|
||||
} else {
|
||||
super.updateShape(state, direction, neighborState, level, pos, neighborPos)
|
||||
}
|
||||
}
|
||||
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
|
||||
builder.add(AXIS)
|
||||
}
|
||||
|
||||
override fun isPathfindable(
|
||||
state: BlockState,
|
||||
type: PathComputationType
|
||||
): Boolean = false
|
||||
|
||||
companion object {
|
||||
val AXIS: EnumProperty<Direction.Axis> = BlockStateProperties.AXIS
|
||||
|
||||
private val SHAPE: VoxelShape = Shapes.block()
|
||||
}
|
||||
}
|
||||
+29
-12
@@ -12,9 +12,7 @@ import com.cobblemon.mod.common.CobblemonBlockEntities
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.block.entity.CampfireBlockEntity
|
||||
import com.cobblemon.mod.common.block.entity.CampfireBlockEntity.Companion.PREVIEW_ITEM_SLOT
|
||||
import com.cobblemon.mod.common.block.entity.DisplayCaseBlockEntity
|
||||
import com.cobblemon.mod.common.item.CampfirePotItem
|
||||
import com.cobblemon.mod.common.item.PokeBallItem
|
||||
import com.cobblemon.mod.common.util.playSoundServer
|
||||
import com.cobblemon.mod.common.util.toVec3d
|
||||
import com.mojang.serialization.MapCodec
|
||||
@@ -28,7 +26,7 @@ import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.InteractionResult
|
||||
import net.minecraft.world.entity.item.ItemEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.BlockItem
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.context.BlockPlaceContext
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
@@ -62,6 +60,7 @@ class CampfireBlock(settings: Properties) : BaseEntityBlock(settings), SimpleWat
|
||||
val ITEM_DIRECTION = DirectionProperty.create("item_facing")
|
||||
val LIT = BlockStateProperties.LIT
|
||||
var SOUL = BooleanProperty.create("soul")
|
||||
val POWERED = BlockStateProperties.POWERED
|
||||
|
||||
private val campfireAABB = Shapes.box(0.0, 0.0, 0.0, 1.0, 0.4375, 1.0)
|
||||
private val AABB = Shapes.or(
|
||||
@@ -79,7 +78,8 @@ class CampfireBlock(settings: Properties) : BaseEntityBlock(settings), SimpleWat
|
||||
.setValue(FACING, Direction.NORTH)
|
||||
.setValue(LIT, true)
|
||||
.setValue(SOUL, false)
|
||||
.setValue(ITEM_DIRECTION, Direction.NORTH))
|
||||
.setValue(ITEM_DIRECTION, Direction.NORTH)
|
||||
.setValue(POWERED, false))
|
||||
}
|
||||
|
||||
override fun getStateForPlacement(ctx: BlockPlaceContext): BlockState? {
|
||||
@@ -198,7 +198,7 @@ class CampfireBlock(settings: Properties) : BaseEntityBlock(settings), SimpleWat
|
||||
}
|
||||
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
|
||||
builder.add(FACING, ITEM_DIRECTION, LIT, SOUL)
|
||||
builder.add(FACING, ITEM_DIRECTION, LIT, SOUL, POWERED)
|
||||
}
|
||||
|
||||
override fun updateShape(
|
||||
@@ -215,13 +215,8 @@ class CampfireBlock(settings: Properties) : BaseEntityBlock(settings), SimpleWat
|
||||
|
||||
override fun getRenderShape(state: BlockState) = RenderShape.MODEL
|
||||
|
||||
override fun getAnalogOutputSignal(state: BlockState, world: Level, pos: BlockPos): Int {
|
||||
val stack = (world.getBlockEntity(pos) as DisplayCaseBlockEntity).getStack()
|
||||
|
||||
if (stack.isEmpty) return 0
|
||||
if (stack.item is PokeBallItem) return 3
|
||||
if (stack.item is BlockItem) return 2
|
||||
return 1
|
||||
override fun getAnalogOutputSignal(state: BlockState, level: Level, pos: BlockPos): Int {
|
||||
return AbstractContainerMenu.getRedstoneSignalFromBlockEntity(level.getBlockEntity(pos))
|
||||
}
|
||||
|
||||
override fun hasAnalogOutputSignal(state: BlockState): Boolean = true
|
||||
@@ -304,4 +299,26 @@ class CampfireBlock(settings: Properties) : BaseEntityBlock(settings), SimpleWat
|
||||
override fun getCloneItemStack(level: LevelReader, pos: BlockPos, state: BlockState): ItemStack {
|
||||
return if (state.getValue(SOUL)) ItemStack(Blocks.SOUL_CAMPFIRE) else ItemStack(Blocks.CAMPFIRE)
|
||||
}
|
||||
|
||||
override fun neighborChanged(
|
||||
state: BlockState,
|
||||
level: Level,
|
||||
pos: BlockPos,
|
||||
neighborBlock: Block,
|
||||
neighborPos: BlockPos,
|
||||
movedByPiston: Boolean
|
||||
) {
|
||||
super.neighborChanged(state, level, pos, neighborBlock, neighborPos, movedByPiston)
|
||||
val isPowered = level.hasNeighborSignal(pos)
|
||||
val blockEntity = level.getBlockEntity(pos) as? CampfireBlockEntity ?: return
|
||||
|
||||
if (isPowered != state.getValue(POWERED)) {
|
||||
level.setBlock(pos, state.setValue(POWERED, isPowered), UPDATE_ALL)
|
||||
blockEntity.toggleLid(!isPowered, pos)
|
||||
}
|
||||
}
|
||||
|
||||
override fun isSignalSource(state: BlockState): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
+15
-1
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.CobblemonMenuType
|
||||
import com.cobblemon.mod.common.CobblemonRecipeTypes
|
||||
import com.cobblemon.mod.common.api.cooking.Seasonings
|
||||
import com.cobblemon.mod.common.block.entity.CampfireBlockEntity
|
||||
import com.cobblemon.mod.common.client.tooltips.itemTakesSeasoningData
|
||||
import com.cobblemon.mod.common.item.crafting.CookingPotRecipe
|
||||
import com.cobblemon.mod.common.item.crafting.CookingPotRecipeBase
|
||||
import net.minecraft.recipebook.ServerPlaceRecipe
|
||||
@@ -109,11 +110,15 @@ class CookingPotMenu : RecipeBookMenu<CraftingInput, CookingPotRecipeBase>, Cont
|
||||
}
|
||||
|
||||
override fun handlePlacement(placeAll: Boolean, recipe: RecipeHolder<*>, player: ServerPlayer) {
|
||||
// Check if the recipe value implements CookingPotRecipeBase
|
||||
val recipeValue = recipe.value()
|
||||
if (recipeValue is CookingPotRecipeBase) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val castedRecipe = recipe as RecipeHolder<CookingPotRecipeBase>
|
||||
|
||||
// Save seasoning contents in case the next recipe absorbs seasoning data
|
||||
val seasoningSlots = CampfireBlockEntity.SEASONING_SLOTS
|
||||
val preservedSeasonings = seasoningSlots.map { container.getItem(it).copy() }
|
||||
|
||||
this.beginPlacingRecipe()
|
||||
try {
|
||||
val serverPlaceRecipe = ServerPlaceRecipe(this)
|
||||
@@ -121,6 +126,15 @@ class CookingPotMenu : RecipeBookMenu<CraftingInput, CookingPotRecipeBase>, Cont
|
||||
} finally {
|
||||
this.finishPlacingRecipe(castedRecipe)
|
||||
}
|
||||
|
||||
// Check if new result item supports seasoning
|
||||
val result = castedRecipe.value().result
|
||||
if (itemTakesSeasoningData(result)) {
|
||||
seasoningSlots.forEachIndexed { index, slot ->
|
||||
container.setItem(slot, preservedSeasonings[index])
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
throw IllegalArgumentException("Unsupported recipe type: ${recipeValue::class.java.name}")
|
||||
}
|
||||
|
||||
+3
-1
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.block.campfirepot
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonItemComponents
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import net.minecraft.sounds.SoundSource
|
||||
import net.minecraft.world.entity.player.Player
|
||||
@@ -23,8 +24,9 @@ class CookingPotResultSlot(
|
||||
) : Slot(container, index, x, y) {
|
||||
|
||||
override fun onTake(player: Player, stack: ItemStack) {
|
||||
val menu = player.containerMenu
|
||||
stack.set(CobblemonItemComponents.CRAFTED, true)
|
||||
|
||||
val menu = player.containerMenu
|
||||
if (menu is CookingPotMenu) {
|
||||
menu.broadcastChanges()
|
||||
player.playNotifySound(CobblemonSounds.CAMPFIRE_POT_USE, SoundSource.MASTER, 1.0f, 1.0f)
|
||||
|
||||
@@ -343,16 +343,9 @@ class BerryBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(Cobblemon
|
||||
world.setBlock(pos, newState, UPDATE_CLIENTS)
|
||||
world.gameEvent(player, GameEvent.BLOCK_CHANGE, pos)
|
||||
resetGrowTimers(pos, newState)
|
||||
|
||||
// Notify top block too since we want observers to work there too
|
||||
val abovePos = pos.above()
|
||||
val aboveState = world.getBlockState(abovePos)
|
||||
if (!aboveState.isAir) {
|
||||
world.sendBlockUpdated(abovePos, aboveState, aboveState, Block.UPDATE_CLIENTS)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
//Using a similar approach to ComputerCraft, implement this client side
|
||||
interface RenderState : AutoCloseable {
|
||||
var needsRebuild: Boolean
|
||||
|
||||
@@ -115,7 +115,7 @@ open class CakeBlockEntity(
|
||||
return ClientboundBlockEntityDataPacket.create(this)
|
||||
}
|
||||
|
||||
override fun getUpdateTag(registries: HolderLookup.Provider): CompoundTag? {
|
||||
override fun getUpdateTag(registries: HolderLookup.Provider): CompoundTag {
|
||||
val tag = CompoundTag()
|
||||
saveAdditional(tag, registries)
|
||||
return tag
|
||||
|
||||
+67
-26
@@ -12,7 +12,7 @@ import com.cobblemon.mod.common.CobblemonBlockEntities
|
||||
import com.cobblemon.mod.common.CobblemonRecipeTypes
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.cooking.getColourMixFromSeasonings
|
||||
import com.cobblemon.mod.common.block.PotComponent
|
||||
import com.cobblemon.mod.common.item.components.PotComponent
|
||||
import com.cobblemon.mod.common.block.campfirepot.CookingPotMenu
|
||||
import com.cobblemon.mod.common.client.particle.BedrockParticleOptionsRepository
|
||||
import com.cobblemon.mod.common.client.particle.ParticleStorm
|
||||
@@ -20,10 +20,10 @@ import com.cobblemon.mod.common.client.render.MatrixWrapper
|
||||
import com.cobblemon.mod.common.client.sound.BlockEntitySoundTracker
|
||||
import com.cobblemon.mod.common.client.sound.instances.CancellableSoundInstance
|
||||
import com.cobblemon.mod.common.item.crafting.CookingPotRecipeBase
|
||||
import com.cobblemon.mod.common.util.activateNearbyObservers
|
||||
import com.cobblemon.mod.common.util.playSoundServer
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap
|
||||
import java.util.Optional
|
||||
import net.minecraft.client.multiplayer.ClientLevel
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
@@ -41,11 +41,7 @@ import net.minecraft.world.ContainerHelper
|
||||
import net.minecraft.world.WorldlyContainer
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.StackedContents
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraft.world.inventory.ContainerData
|
||||
import net.minecraft.world.inventory.CraftingContainer
|
||||
import net.minecraft.world.inventory.RecipeCraftingHolder
|
||||
import net.minecraft.world.inventory.StackedContentsCompatible
|
||||
import net.minecraft.world.inventory.*
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.item.crafting.CraftingInput
|
||||
@@ -56,9 +52,10 @@ import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.entity.BaseContainerBlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.gameevent.GameEvent
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import org.joml.Vector4f
|
||||
import kotlin.compareTo
|
||||
import java.util.*
|
||||
|
||||
class CampfireBlockEntity(pos: BlockPos, state: BlockState) : BaseContainerBlockEntity(
|
||||
CobblemonBlockEntities.CAMPFIRE,
|
||||
@@ -95,14 +92,17 @@ class CampfireBlockEntity(pos: BlockPos, state: BlockState) : BaseContainerBlock
|
||||
val isSoundActive = BlockEntitySoundTracker.isActive(pos, campfireBlockEntity.runningSound.location)
|
||||
|
||||
if (isLit && !isSoundActive) {
|
||||
BlockEntitySoundTracker.play(pos, CancellableSoundInstance(campfireBlockEntity.runningSound, pos, true, 0.8f, 1.0f))
|
||||
BlockEntitySoundTracker.play(
|
||||
pos,
|
||||
CancellableSoundInstance(campfireBlockEntity.runningSound, pos, true, 0.8f, 1.0f)
|
||||
)
|
||||
} else if (!isLit && isSoundActive) {
|
||||
BlockEntitySoundTracker.stop(pos, campfireBlockEntity.runningSound.location)
|
||||
}
|
||||
|
||||
campfireBlockEntity.brothColor =
|
||||
getColourMixFromSeasonings(campfireBlockEntity.getSeasonings())
|
||||
?: BASE_BROTH_COLOR
|
||||
?: BASE_BROTH_COLOR
|
||||
|
||||
campfireBlockEntity.bubbleColor =
|
||||
getColourMixFromSeasonings(campfireBlockEntity.getSeasonings(), true)
|
||||
@@ -111,15 +111,20 @@ class CampfireBlockEntity(pos: BlockPos, state: BlockState) : BaseContainerBlock
|
||||
if (campfireBlockEntity.particleCooldown > 0) {
|
||||
campfireBlockEntity.particleCooldown--
|
||||
} else {
|
||||
if (isLit) {
|
||||
if (isLit) {
|
||||
val position = Vec3(pos.x + 0.5, pos.y + 0.5375, pos.z + 0.5)
|
||||
|
||||
campfireBlockEntity.particleEntityHandler(
|
||||
position = position,
|
||||
level = level,
|
||||
particle = ResourceLocation("cobblemon", if (campfireBlockEntity.getSeasonings().isEmpty()) "broth_bubbles_basic" else "broth_bubbles")
|
||||
particle = ResourceLocation(
|
||||
"cobblemon",
|
||||
if (campfireBlockEntity.getSeasonings()
|
||||
.isEmpty()
|
||||
) "broth_bubbles_basic" else "broth_bubbles"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
campfireBlockEntity.particleCooldown = 20
|
||||
}
|
||||
@@ -163,7 +168,11 @@ class CampfireBlockEntity(pos: BlockPos, state: BlockState) : BaseContainerBlock
|
||||
}
|
||||
|
||||
if (!resultSlotItem.isEmpty) {
|
||||
if (!ItemStack.isSameItemSameComponents(resultSlotItem, cookedItem) || resultSlotItem.count >= resultSlotItem.maxStackSize) {
|
||||
if (!ItemStack.isSameItemSameComponents(
|
||||
resultSlotItem,
|
||||
cookedItem
|
||||
) || resultSlotItem.count >= resultSlotItem.maxStackSize
|
||||
) {
|
||||
campfireBlockEntity.cookingProgress = 0
|
||||
return
|
||||
}
|
||||
@@ -196,18 +205,19 @@ class CampfireBlockEntity(pos: BlockPos, state: BlockState) : BaseContainerBlock
|
||||
}
|
||||
|
||||
private val runningSound = CobblemonSounds.CAMPFIRE_POT_COOK
|
||||
private var cookingProgress : Int = 0
|
||||
private var cookingTotalTime : Int = COOKING_TOTAL_TIME
|
||||
private var isLidOpen : Boolean = true
|
||||
private var items : NonNullList<ItemStack> = NonNullList.withSize(ITEMS_SIZE, ItemStack.EMPTY)
|
||||
private var cookingProgress: Int = 0
|
||||
private var cookingTotalTime: Int = COOKING_TOTAL_TIME
|
||||
private var isLidOpen: Boolean = true
|
||||
private var items: NonNullList<ItemStack> = NonNullList.withSize(ITEMS_SIZE, ItemStack.EMPTY)
|
||||
private val recipesUsed: Object2IntOpenHashMap<ResourceLocation> = Object2IntOpenHashMap()
|
||||
private val quickCheck: RecipeManager.CachedCheck<CraftingInput, *> = RecipeManager.createCheck(CobblemonRecipeTypes.COOKING_POT_COOKING)
|
||||
private val quickCheck: RecipeManager.CachedCheck<CraftingInput, *> =
|
||||
RecipeManager.createCheck(CobblemonRecipeTypes.COOKING_POT_COOKING)
|
||||
private var potComponent: PotComponent? = null
|
||||
private var particleCooldown: Int = 0
|
||||
var brothColor: Int = BASE_BROTH_COLOR
|
||||
var bubbleColor: Int = 0xFFFFFF
|
||||
|
||||
var dataAccess : ContainerData = object : ContainerData {
|
||||
var dataAccess: ContainerData = object : ContainerData {
|
||||
override fun get(index: Int): Int {
|
||||
return when (index) {
|
||||
COOKING_PROGRESS_INDEX -> this@CampfireBlockEntity.cookingProgress
|
||||
@@ -235,15 +245,16 @@ class CampfireBlockEntity(pos: BlockPos, state: BlockState) : BaseContainerBlock
|
||||
val matrix = PoseStack()
|
||||
wrapper.updateMatrix(matrix.last().pose())
|
||||
wrapper.updatePosition(position)
|
||||
val effect = BedrockParticleOptionsRepository.getEffect(particle) ?: throw IllegalStateException("Particle with resource location $particle not found")
|
||||
val effect = BedrockParticleOptionsRepository.getEffect(particle)
|
||||
?: throw IllegalStateException("Particle with resource location $particle not found")
|
||||
|
||||
val particleStorm = ParticleStorm(
|
||||
effect,
|
||||
wrapper,
|
||||
wrapper,
|
||||
level as ClientLevel,
|
||||
sourceAlive = { cookingProgress > 0 },
|
||||
sourceVisible = { cookingProgress > 0 },
|
||||
sourceAlive = { cookingProgress > 0 },
|
||||
sourceVisible = { cookingProgress > 0 },
|
||||
getParticleColor = {
|
||||
val red = FastColor.ARGB32.red(bubbleColor) / 255F
|
||||
val green = FastColor.ARGB32.green(bubbleColor) / 255F
|
||||
@@ -268,6 +279,7 @@ class CampfireBlockEntity(pos: BlockPos, state: BlockState) : BaseContainerBlock
|
||||
// Replace with empty bucket
|
||||
setItem(i, ItemStack(Items.BUCKET))
|
||||
}
|
||||
|
||||
Items.HONEY_BOTTLE -> {
|
||||
// TODO: Currently eats the empty bottles until the honey bottle stack is empty, replace with better system later.
|
||||
itemInSlot.shrink(1)
|
||||
@@ -275,6 +287,7 @@ class CampfireBlockEntity(pos: BlockPos, state: BlockState) : BaseContainerBlock
|
||||
setItem(i, ItemStack.EMPTY)
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
// Decrease the stack size by 1
|
||||
itemInSlot.shrink(1)
|
||||
@@ -323,9 +336,7 @@ class CampfireBlockEntity(pos: BlockPos, state: BlockState) : BaseContainerBlock
|
||||
}
|
||||
|
||||
override fun getContainerSize() = this.items.size
|
||||
override fun getSlotsForFace(side: Direction) = intArrayOf(0, 1, 2)
|
||||
override fun canPlaceItemThroughFace(index: Int, itemStack: ItemStack, direction: Direction?) = false
|
||||
override fun canTakeItemThroughFace(index: Int, stack: ItemStack, direction: Direction) = false
|
||||
override fun getSlotsForFace(side: Direction) = (0..12).toList().toIntArray()
|
||||
|
||||
override fun setRecipeUsed(recipe: RecipeHolder<*>?) {
|
||||
if (recipe != null) {
|
||||
@@ -413,4 +424,34 @@ class CampfireBlockEntity(pos: BlockPos, state: BlockState) : BaseContainerBlock
|
||||
BlockEntitySoundTracker.stop(blockPos, runningSound.location)
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleLid(isOpen: Boolean, blockPos: BlockPos) {
|
||||
this.isLidOpen = isOpen
|
||||
level?.let { lvl ->
|
||||
lvl.activateNearbyObservers(blockPos)
|
||||
lvl.playSoundServer(
|
||||
position = blockPos.center,
|
||||
sound = if (isOpen) CobblemonSounds.CAMPFIRE_POT_OPEN else CobblemonSounds.CAMPFIRE_POT_CLOSE
|
||||
)
|
||||
lvl.gameEvent(
|
||||
null,
|
||||
if (isOpen) GameEvent.BLOCK_OPEN else GameEvent.BLOCK_CLOSE,
|
||||
blockPos
|
||||
)
|
||||
}
|
||||
setChanged()
|
||||
}
|
||||
|
||||
override fun canTakeItemThroughFace(index: Int, stack: ItemStack, direction: Direction): Boolean {
|
||||
return index == RESULT_SLOT
|
||||
}
|
||||
|
||||
override fun canPlaceItemThroughFace(index: Int, itemStack: ItemStack, direction: Direction?): Boolean {
|
||||
return when (direction) {
|
||||
Direction.UP -> SEASONING_SLOTS.contains(index)
|
||||
else -> CRAFTING_GRID_SLOTS.contains(index)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* 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.block.entity
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlockEntities
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.block.chest.GildedState
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.core.HolderLookup
|
||||
import net.minecraft.core.NonNullList
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import net.minecraft.sounds.SoundSource
|
||||
import net.minecraft.world.ContainerHelper
|
||||
import net.minecraft.world.WorldlyContainer
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraft.world.inventory.ChestMenu
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.entity.ContainerOpenersCounter
|
||||
import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties
|
||||
|
||||
class CopperFridgeBlockEntity(pos: BlockPos, state: BlockState) : RandomizableContainerBlockEntity(CobblemonBlockEntities.COPPER_FRIDGE, pos, state), WorldlyContainer {
|
||||
var inventoryContents: NonNullList<ItemStack> = NonNullList.withSize(NUM_SLOTS, ItemStack.EMPTY)
|
||||
val posableState: GildedState = GildedState()
|
||||
|
||||
private val stateManager: ContainerOpenersCounter = object : ContainerOpenersCounter() {
|
||||
override fun onOpen(world: Level, pos: BlockPos, state: BlockState) {
|
||||
playSound(world, pos, state, CobblemonSounds.GILDED_CHEST_OPEN)
|
||||
}
|
||||
|
||||
override fun onClose(world: Level, pos: BlockPos, state: BlockState) {
|
||||
playSound(world, pos, state, CobblemonSounds.GILDED_CHEST_CLOSE)
|
||||
}
|
||||
|
||||
override fun openerCountChanged(
|
||||
world: Level,
|
||||
pos: BlockPos,
|
||||
state: BlockState,
|
||||
oldViewerCount: Int,
|
||||
newViewerCount: Int
|
||||
) {
|
||||
this@CopperFridgeBlockEntity.onViewerCountUpdate(world, pos, state, oldViewerCount, newViewerCount)
|
||||
}
|
||||
|
||||
override fun isOwnContainer(player: Player): Boolean {
|
||||
if (player.containerMenu is ChestMenu) {
|
||||
val inventory = (player.containerMenu as ChestMenu).container
|
||||
return inventory === this@CopperFridgeBlockEntity
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
override fun getContainerSize() = NUM_SLOTS
|
||||
|
||||
override fun getDefaultName() = Component.translatable("block.cobblemon.copper_fridge")
|
||||
|
||||
override fun createMenu(syncId: Int, playerInventory: Inventory): AbstractContainerMenu =
|
||||
ChestMenu.sixRows(syncId, playerInventory, this)
|
||||
|
||||
override fun getItems() = inventoryContents
|
||||
|
||||
override fun startOpen(player: Player) {
|
||||
if (!this.remove && !player.isSpectator) {
|
||||
stateManager.incrementOpeners(player, level, blockPos, blockState)
|
||||
}
|
||||
}
|
||||
|
||||
override fun stopOpen(player: Player) {
|
||||
if (!this.remove && !player.isSpectator) {
|
||||
stateManager.decrementOpeners(player, level, blockPos, blockState)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSlotsForFace(side: Direction): IntArray {
|
||||
return IntArray(NUM_SLOTS) { it }
|
||||
}
|
||||
|
||||
override fun canPlaceItemThroughFace(slot: Int, stack: ItemStack, dir: Direction?): Boolean {
|
||||
return dir != Direction.DOWN
|
||||
}
|
||||
|
||||
override fun canTakeItemThroughFace(slot: Int, stack: ItemStack, dir: Direction): Boolean {
|
||||
return dir == Direction.DOWN
|
||||
}
|
||||
|
||||
override fun stillValid(player: Player) = !player.isSpectator
|
||||
|
||||
override fun setItems(inventory: NonNullList<ItemStack>) {
|
||||
inventoryContents = inventory
|
||||
}
|
||||
|
||||
companion object {
|
||||
val NUM_SLOTS = 54
|
||||
fun playSound(world: Level, pos: BlockPos, state: BlockState, sound: SoundEvent) {
|
||||
var d = pos.x.toDouble() + 0.5
|
||||
val e = pos.y.toDouble() + 0.5
|
||||
var f = pos.z.toDouble() + 0.5
|
||||
val direction = state.getValue(BlockStateProperties.HORIZONTAL_FACING)
|
||||
d += direction.stepX.toDouble() * 0.5
|
||||
f += direction.stepZ.toDouble() * 0.5
|
||||
world.playSound(
|
||||
null,
|
||||
d,
|
||||
e,
|
||||
f,
|
||||
sound,
|
||||
SoundSource.BLOCKS,
|
||||
0.5f,
|
||||
world.random.nextFloat() * 0.1f + 0.9f
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun triggerEvent(type: Int, data: Int): Boolean {
|
||||
if (type == 1) {
|
||||
val isNowOpen = data > 0
|
||||
val wasOpen = posableState.currentPose == "open"
|
||||
val model = posableState.currentModel ?: return true
|
||||
if (isNowOpen && !wasOpen) {
|
||||
model.moveToPose(posableState, model.poses["open"]!!)
|
||||
} else if (!isNowOpen && wasOpen) {
|
||||
model.moveToPose(posableState, model.poses["closed"]!!)
|
||||
}
|
||||
return true
|
||||
}
|
||||
return super.triggerEvent(type, data)
|
||||
}
|
||||
|
||||
fun onViewerCountUpdate(world: Level, pos: BlockPos, state: BlockState, oldViewerCount: Int, newViewerCount: Int) {
|
||||
val block = state.block
|
||||
world.blockEvent(pos, block, 1, newViewerCount)
|
||||
}
|
||||
|
||||
override fun saveAdditional(nbt: CompoundTag, registryLookup: HolderLookup.Provider) {
|
||||
super.saveAdditional(nbt, registryLookup)
|
||||
if (!trySaveLootTable(nbt)) {
|
||||
ContainerHelper.saveAllItems(nbt, inventoryContents, registryLookup)
|
||||
}
|
||||
}
|
||||
|
||||
override fun loadAdditional(nbt: CompoundTag, registryLookup: HolderLookup.Provider) {
|
||||
super.loadAdditional(nbt, registryLookup)
|
||||
inventoryContents= NonNullList.withSize(containerSize, ItemStack.EMPTY)
|
||||
if (!tryLoadLootTable(nbt)) {
|
||||
ContainerHelper.loadAllItems(nbt, inventoryContents, registryLookup)
|
||||
}
|
||||
}
|
||||
|
||||
fun tick() {
|
||||
if (!this.remove) {
|
||||
stateManager.recheckOpeners(level, blockPos, this.blockState)
|
||||
}
|
||||
}
|
||||
}
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* 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.block.entity
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlockEntities
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.block.chest.GildedState
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.core.HolderLookup
|
||||
import net.minecraft.core.NonNullList
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import net.minecraft.sounds.SoundSource
|
||||
import net.minecraft.world.ContainerHelper
|
||||
import net.minecraft.world.WorldlyContainer
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraft.world.inventory.ChestMenu
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.entity.ContainerOpenersCounter
|
||||
import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties
|
||||
|
||||
class CopperOvenBlockEntity(pos: BlockPos, state: BlockState) : RandomizableContainerBlockEntity(CobblemonBlockEntities.COPPER_OVEN, pos, state), WorldlyContainer {
|
||||
var inventoryContents: NonNullList<ItemStack> = NonNullList.withSize(NUM_SLOTS, ItemStack.EMPTY)
|
||||
val posableState: GildedState = GildedState()
|
||||
|
||||
private val stateManager: ContainerOpenersCounter = object : ContainerOpenersCounter() {
|
||||
override fun onOpen(world: Level, pos: BlockPos, state: BlockState) {
|
||||
playSound(world, pos, state, CobblemonSounds.GILDED_CHEST_OPEN)
|
||||
}
|
||||
|
||||
override fun onClose(world: Level, pos: BlockPos, state: BlockState) {
|
||||
playSound(world, pos, state, CobblemonSounds.GILDED_CHEST_CLOSE)
|
||||
}
|
||||
|
||||
override fun openerCountChanged(
|
||||
world: Level,
|
||||
pos: BlockPos,
|
||||
state: BlockState,
|
||||
oldViewerCount: Int,
|
||||
newViewerCount: Int
|
||||
) {
|
||||
this@CopperOvenBlockEntity.onViewerCountUpdate(world, pos, state, oldViewerCount, newViewerCount)
|
||||
}
|
||||
|
||||
override fun isOwnContainer(player: Player): Boolean {
|
||||
if (player.containerMenu is ChestMenu) {
|
||||
val inventory = (player.containerMenu as ChestMenu).container
|
||||
return inventory === this@CopperOvenBlockEntity
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
override fun getContainerSize() = NUM_SLOTS
|
||||
|
||||
override fun getDefaultName() = Component.translatable("block.cobblemon.copper_oven")
|
||||
|
||||
override fun createMenu(syncId: Int, playerInventory: Inventory): AbstractContainerMenu =
|
||||
ChestMenu.threeRows(syncId, playerInventory, this)
|
||||
|
||||
override fun getItems() = inventoryContents
|
||||
|
||||
override fun startOpen(player: Player) {
|
||||
if (!this.remove && !player.isSpectator) {
|
||||
stateManager.incrementOpeners(player, level, blockPos, blockState)
|
||||
}
|
||||
}
|
||||
|
||||
override fun stopOpen(player: Player) {
|
||||
if (!this.remove && !player.isSpectator) {
|
||||
stateManager.decrementOpeners(player, level, blockPos, blockState)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSlotsForFace(side: Direction): IntArray {
|
||||
return IntArray(NUM_SLOTS) { it }
|
||||
}
|
||||
|
||||
override fun canPlaceItemThroughFace(slot: Int, stack: ItemStack, dir: Direction?): Boolean {
|
||||
return dir != Direction.DOWN
|
||||
}
|
||||
|
||||
override fun canTakeItemThroughFace(slot: Int, stack: ItemStack, dir: Direction): Boolean {
|
||||
return dir == Direction.DOWN
|
||||
}
|
||||
|
||||
override fun stillValid(player: Player) = !player.isSpectator
|
||||
|
||||
override fun setItems(inventory: NonNullList<ItemStack>) {
|
||||
inventoryContents = inventory
|
||||
}
|
||||
|
||||
companion object {
|
||||
val NUM_SLOTS = 27
|
||||
fun playSound(world: Level, pos: BlockPos, state: BlockState, sound: SoundEvent) {
|
||||
var d = pos.x.toDouble() + 0.5
|
||||
val e = pos.y.toDouble() + 0.5
|
||||
var f = pos.z.toDouble() + 0.5
|
||||
val direction = state.getValue(BlockStateProperties.HORIZONTAL_FACING)
|
||||
d += direction.stepX.toDouble() * 0.5
|
||||
f += direction.stepZ.toDouble() * 0.5
|
||||
world.playSound(
|
||||
null,
|
||||
d,
|
||||
e,
|
||||
f,
|
||||
sound,
|
||||
SoundSource.BLOCKS,
|
||||
0.5f,
|
||||
world.random.nextFloat() * 0.1f + 0.9f
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun triggerEvent(type: Int, data: Int): Boolean {
|
||||
if (type == 1) {
|
||||
val isNowOpen = data > 0
|
||||
val wasOpen = posableState.currentPose == "open"
|
||||
val model = posableState.currentModel ?: return true
|
||||
if (isNowOpen && !wasOpen) {
|
||||
model.moveToPose(posableState, model.poses["open"]!!)
|
||||
} else if (!isNowOpen && wasOpen) {
|
||||
model.moveToPose(posableState, model.poses["closed"]!!)
|
||||
}
|
||||
return true
|
||||
}
|
||||
return super.triggerEvent(type, data)
|
||||
}
|
||||
|
||||
fun onViewerCountUpdate(world: Level, pos: BlockPos, state: BlockState, oldViewerCount: Int, newViewerCount: Int) {
|
||||
val block = state.block
|
||||
world.blockEvent(pos, block, 1, newViewerCount)
|
||||
}
|
||||
|
||||
override fun saveAdditional(nbt: CompoundTag, registryLookup: HolderLookup.Provider) {
|
||||
super.saveAdditional(nbt, registryLookup)
|
||||
if (!trySaveLootTable(nbt)) {
|
||||
ContainerHelper.saveAllItems(nbt, inventoryContents, registryLookup)
|
||||
}
|
||||
}
|
||||
|
||||
override fun loadAdditional(nbt: CompoundTag, registryLookup: HolderLookup.Provider) {
|
||||
super.loadAdditional(nbt, registryLookup)
|
||||
inventoryContents= NonNullList.withSize(containerSize, ItemStack.EMPTY)
|
||||
if (!tryLoadLootTable(nbt)) {
|
||||
ContainerHelper.loadAllItems(nbt, inventoryContents, registryLookup)
|
||||
}
|
||||
}
|
||||
|
||||
fun tick() {
|
||||
if (!this.remove) {
|
||||
stateManager.recheckOpeners(level, blockPos, this.blockState)
|
||||
}
|
||||
}
|
||||
}
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* 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.block.entity
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlockEntities
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.block.chest.GildedState
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.core.HolderLookup
|
||||
import net.minecraft.core.NonNullList
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import net.minecraft.sounds.SoundSource
|
||||
import net.minecraft.world.ContainerHelper
|
||||
import net.minecraft.world.WorldlyContainer
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraft.world.inventory.ChestMenu
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.entity.ContainerOpenersCounter
|
||||
import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties
|
||||
|
||||
class CopperWasherBlockEntity(pos: BlockPos, state: BlockState) : RandomizableContainerBlockEntity(CobblemonBlockEntities.COPPER_WASHER, pos, state), WorldlyContainer {
|
||||
var inventoryContents: NonNullList<ItemStack> = NonNullList.withSize(NUM_SLOTS, ItemStack.EMPTY)
|
||||
val posableState: GildedState = GildedState()
|
||||
|
||||
private val stateManager: ContainerOpenersCounter = object : ContainerOpenersCounter() {
|
||||
override fun onOpen(world: Level, pos: BlockPos, state: BlockState) {
|
||||
playSound(world, pos, state, CobblemonSounds.GILDED_CHEST_OPEN)
|
||||
}
|
||||
|
||||
override fun onClose(world: Level, pos: BlockPos, state: BlockState) {
|
||||
playSound(world, pos, state, CobblemonSounds.GILDED_CHEST_CLOSE)
|
||||
}
|
||||
|
||||
override fun openerCountChanged(
|
||||
world: Level,
|
||||
pos: BlockPos,
|
||||
state: BlockState,
|
||||
oldViewerCount: Int,
|
||||
newViewerCount: Int
|
||||
) {
|
||||
this@CopperWasherBlockEntity.onViewerCountUpdate(world, pos, state, oldViewerCount, newViewerCount)
|
||||
}
|
||||
|
||||
override fun isOwnContainer(player: Player): Boolean {
|
||||
if (player.containerMenu is ChestMenu) {
|
||||
val inventory = (player.containerMenu as ChestMenu).container
|
||||
return inventory === this@CopperWasherBlockEntity
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
override fun getContainerSize() = NUM_SLOTS
|
||||
|
||||
override fun getDefaultName() = Component.translatable("block.cobblemon.copper_washer")
|
||||
|
||||
override fun createMenu(syncId: Int, playerInventory: Inventory): AbstractContainerMenu =
|
||||
ChestMenu.threeRows(syncId, playerInventory, this)
|
||||
|
||||
override fun getItems() = inventoryContents
|
||||
|
||||
override fun startOpen(player: Player) {
|
||||
if (!this.remove && !player.isSpectator) {
|
||||
stateManager.incrementOpeners(player, level, blockPos, blockState)
|
||||
}
|
||||
}
|
||||
|
||||
override fun stopOpen(player: Player) {
|
||||
if (!this.remove && !player.isSpectator) {
|
||||
stateManager.decrementOpeners(player, level, blockPos, blockState)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSlotsForFace(side: Direction): IntArray {
|
||||
return IntArray(NUM_SLOTS) { it }
|
||||
}
|
||||
|
||||
override fun canPlaceItemThroughFace(slot: Int, stack: ItemStack, dir: Direction?): Boolean {
|
||||
return dir != Direction.DOWN
|
||||
}
|
||||
|
||||
override fun canTakeItemThroughFace(slot: Int, stack: ItemStack, dir: Direction): Boolean {
|
||||
return dir == Direction.DOWN
|
||||
}
|
||||
|
||||
override fun stillValid(player: Player) = !player.isSpectator
|
||||
|
||||
override fun setItems(inventory: NonNullList<ItemStack>) {
|
||||
inventoryContents = inventory
|
||||
}
|
||||
|
||||
companion object {
|
||||
val NUM_SLOTS = 27
|
||||
fun playSound(world: Level, pos: BlockPos, state: BlockState, sound: SoundEvent) {
|
||||
var d = pos.x.toDouble() + 0.5
|
||||
val e = pos.y.toDouble() + 0.5
|
||||
var f = pos.z.toDouble() + 0.5
|
||||
val direction = state.getValue(BlockStateProperties.HORIZONTAL_FACING)
|
||||
d += direction.stepX.toDouble() * 0.5
|
||||
f += direction.stepZ.toDouble() * 0.5
|
||||
world.playSound(
|
||||
null,
|
||||
d,
|
||||
e,
|
||||
f,
|
||||
sound,
|
||||
SoundSource.BLOCKS,
|
||||
0.5f,
|
||||
world.random.nextFloat() * 0.1f + 0.9f
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun triggerEvent(type: Int, data: Int): Boolean {
|
||||
if (type == 1) {
|
||||
val isNowOpen = data > 0
|
||||
val wasOpen = posableState.currentPose == "open"
|
||||
val model = posableState.currentModel ?: return true
|
||||
if (isNowOpen && !wasOpen) {
|
||||
model.moveToPose(posableState, model.poses["open"]!!)
|
||||
} else if (!isNowOpen && wasOpen) {
|
||||
model.moveToPose(posableState, model.poses["closed"]!!)
|
||||
}
|
||||
return true
|
||||
}
|
||||
return super.triggerEvent(type, data)
|
||||
}
|
||||
|
||||
fun onViewerCountUpdate(world: Level, pos: BlockPos, state: BlockState, oldViewerCount: Int, newViewerCount: Int) {
|
||||
val block = state.block
|
||||
world.blockEvent(pos, block, 1, newViewerCount)
|
||||
}
|
||||
|
||||
override fun saveAdditional(nbt: CompoundTag, registryLookup: HolderLookup.Provider) {
|
||||
super.saveAdditional(nbt, registryLookup)
|
||||
if (!trySaveLootTable(nbt)) {
|
||||
ContainerHelper.saveAllItems(nbt, inventoryContents, registryLookup)
|
||||
}
|
||||
}
|
||||
|
||||
override fun loadAdditional(nbt: CompoundTag, registryLookup: HolderLookup.Provider) {
|
||||
super.loadAdditional(nbt, registryLookup)
|
||||
inventoryContents= NonNullList.withSize(containerSize, ItemStack.EMPTY)
|
||||
if (!tryLoadLootTable(nbt)) {
|
||||
ContainerHelper.loadAllItems(nbt, inventoryContents, registryLookup)
|
||||
}
|
||||
}
|
||||
|
||||
fun tick() {
|
||||
if (!this.remove) {
|
||||
stateManager.recheckOpeners(level, blockPos, this.blockState)
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -16,6 +16,7 @@ import com.cobblemon.mod.common.advancement.CobblemonCriteria
|
||||
import com.cobblemon.mod.common.api.pasture.PastureLinkManager
|
||||
import com.cobblemon.mod.common.api.scheduling.afterOnServer
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.api.text.textClickHandlers
|
||||
import com.cobblemon.mod.common.block.PastureBlock
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormEntityParticlePacket
|
||||
@@ -96,6 +97,15 @@ class PokemonPastureBlockEntity(pos: BlockPos, state: BlockState) :
|
||||
if (blockEntity.ticksUntilCheck <= 0) {
|
||||
blockEntity.checkPokemon()
|
||||
}
|
||||
|
||||
// for every tethered pokemon tick metabolism if fullness is above 0
|
||||
val tetheredPokemonList = blockEntity.tetheredPokemon.filter { it.getPokemon() != null }
|
||||
for (tetheredPokemon in tetheredPokemonList) {
|
||||
val pokemon = tetheredPokemon.getPokemon()!!
|
||||
if (pokemon.currentFullness > 0) {
|
||||
pokemon.tickMetabolism()
|
||||
}
|
||||
}
|
||||
blockEntity.togglePastureOn(blockEntity.getInRangeViewerCount(world, blockEntity.blockPos) > 0)
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -118,17 +118,17 @@ class RestorationTankBlockEntity(
|
||||
}
|
||||
|
||||
override fun getSlotsForFace(side: Direction): IntArray {
|
||||
return if (side == Direction.DOWN) intArrayOf(0, 1, 2, 3, 4, 5, 6, 7) else intArrayOf()
|
||||
return intArrayOf(0, 1, 2, 3, 4, 5, 6, 7)
|
||||
}
|
||||
|
||||
override fun canPlaceItemThroughFace(slot: Int, stack: ItemStack, direction: Direction?): Boolean {
|
||||
if (tankEntity.multiblockStructure is FossilMultiblockStructure) {
|
||||
if (direction != Direction.DOWN) {
|
||||
val structure = tankEntity.multiblockStructure as FossilMultiblockStructure
|
||||
val canUtilize = stack?.let { NaturalMaterials.isNaturalMaterial(it) } == true
|
||||
val canUtilize = stack.let { NaturalMaterials.isNaturalMaterial(it) }
|
||||
&& structure.organicMaterialInside < FossilMultiblockStructure.MATERIAL_TO_START
|
||||
&& structure.hasCreatedPokemon
|
||||
val returnItem = NaturalMaterials.getReturnItem(stack!!) ?: return canUtilize
|
||||
&& !structure.hasCreatedPokemon
|
||||
val returnItem = NaturalMaterials.getReturnItem(stack) ?: return canUtilize
|
||||
if (canUtilize) {
|
||||
// See if there's room
|
||||
for (i in items.indices) {
|
||||
|
||||
Loaded 100 of 1646 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user