mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-11-07 16:58:53 -05:00
Compare commits
320
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
149c1f85e0 | ||
|
|
0725fa83d6 | ||
|
|
1f5bb78684 | ||
|
|
87c21d8906 | ||
|
|
cadaf00d08 | ||
|
|
30404192bd | ||
|
|
5b3566a2b5 | ||
|
|
1feeab6f87 | ||
|
|
99e0a26d7b | ||
|
|
71753df513 | ||
|
|
729f080f6e | ||
|
|
13eb57afb1 | ||
|
|
72b6cb06ff | ||
|
|
74a57eb972 | ||
|
|
7246c7f8e6 | ||
|
|
cd05f741ae | ||
|
|
00222d929d | ||
|
|
b8f4637cb3 | ||
|
|
9f572250f5 | ||
|
|
0927d6fa43 | ||
|
|
a293b3d71f | ||
|
|
162b1cc68f | ||
|
|
67f906dec2 | ||
|
|
0570afbe05 | ||
|
|
dfba2d27ab | ||
|
|
9c7cd4b616 | ||
|
|
9fe0e9c87e | ||
|
|
bd0e5a44bd | ||
|
|
229ec4176b | ||
|
|
323413efdc | ||
|
|
a309cc2522 | ||
|
|
cb782a2aa1 | ||
|
|
2c58dcb8ef | ||
|
|
d91cd4322c | ||
|
|
e48e492392 | ||
|
|
1f93994eba | ||
|
|
5210121b3d | ||
|
|
7fa3bf24d1 | ||
|
|
1128d7edf3 | ||
|
|
eef50a7237 | ||
|
|
f4140a097d | ||
|
|
b79dbcca80 | ||
|
|
5ac12a897a | ||
|
|
ae5f7c83f2 | ||
|
|
f14de9ab58 | ||
|
|
8a1c846c2c | ||
|
|
459e7d3490 | ||
|
|
5a9be8944f | ||
|
|
3bb941b087 | ||
|
|
384b496d76 | ||
|
|
4caa736e0b | ||
|
|
c3e9051918 | ||
|
|
fe940caafc | ||
|
|
c9d148ec9c | ||
|
|
e611bf4a77 | ||
|
|
8093822140 | ||
|
|
f695ec15f9 | ||
|
|
1f6c791ce6 | ||
|
|
570805fdf1 | ||
|
|
ddecb08bc7 | ||
|
|
a1b930a21f | ||
|
|
7728ff3892 | ||
|
|
0b38e063d2 | ||
|
|
4d7cfcdf61 | ||
|
|
e56dd6ef64 | ||
|
|
236b98fa78 | ||
|
|
ac61e0d4d0 | ||
|
|
d8956fd66f | ||
|
|
ffe005511d | ||
|
|
1e634a20b8 | ||
|
|
50a5a78dd4 | ||
|
|
76c2654399 | ||
|
|
f9f4745e93 | ||
|
|
c700674289 | ||
|
|
c4f0032eee | ||
|
|
d92986016b | ||
|
|
ab57e01242 | ||
|
|
0da1c740a4 | ||
|
|
a7979aa80c | ||
|
|
397d3c618d | ||
|
|
066a6b56f7 | ||
|
|
29f6feab6c | ||
|
|
ea5d3ae40f | ||
|
|
59804a4e08 | ||
|
|
072c67acad | ||
|
|
60bbe221de | ||
|
|
5f06dc214b | ||
|
|
7687833add | ||
|
|
a6607e585b | ||
|
|
20584f4507 | ||
|
|
9660f1f724 | ||
|
|
c8cbace800 | ||
|
|
a616a24923 | ||
|
|
12035dd589 | ||
|
|
9627b80b01 | ||
|
|
4e9cecc854 | ||
|
|
9d4b19b185 | ||
|
|
aee96d06aa | ||
|
|
23e3c585f7 | ||
|
|
c22a88079f | ||
|
|
2225402082 | ||
|
|
9197207431 | ||
|
|
47c7f7079c | ||
|
|
eb0c1dddfd | ||
|
|
e3dbfe6ff8 | ||
|
|
fac207f36b | ||
|
|
379e794848 | ||
|
|
9081a4b131 | ||
|
|
dc6d75b8ee | ||
|
|
bb297a4448 | ||
|
|
a93922c438 | ||
|
|
f7d21c80d7 | ||
|
|
9248d26fd4 | ||
|
|
cb9ba82fcc | ||
|
|
b5ac54cd16 | ||
|
|
dc703e67f7 | ||
|
|
0930721865 | ||
|
|
644ff1772e | ||
|
|
3c7e0bebb6 | ||
|
|
0c0eea3876 | ||
|
|
5535140bb7 | ||
|
|
f9dd1448e5 | ||
|
|
ecf5d57ad2 | ||
|
|
8663888abc | ||
|
|
f452cd9a05 | ||
|
|
4fe9cd7fd6 | ||
|
|
9b0ca1c16b | ||
|
|
052ff59f57 | ||
|
|
40e5ef1c46 | ||
|
|
5025977d23 | ||
|
|
922006afe7 | ||
|
|
46cc7cb04d | ||
|
|
fa3e3bbb1b | ||
|
|
afbdcce337 | ||
|
|
2c1d11ed11 | ||
|
|
b88adf0479 | ||
|
|
b1066671f5 | ||
|
|
387e85d4ad | ||
|
|
1fa113f5ac | ||
|
|
77ab58d823 | ||
|
|
1a9e736d8b | ||
|
|
f680682f61 | ||
|
|
4d93d1244d | ||
|
|
6a7d5d2133 | ||
|
|
98397cd1da | ||
|
|
fc5a610394 | ||
|
|
504df5d998 | ||
|
|
3b4d3ebf50 | ||
|
|
aa39c1906e | ||
|
|
2e460e2ca2 | ||
|
|
a07ff7f442 | ||
|
|
5374569ea1 | ||
|
|
af9c1196bf | ||
|
|
09d5543469 | ||
|
|
49e4dd0298 | ||
|
|
c8e408c50a | ||
|
|
e8a0467643 | ||
|
|
2dd0b66b83 | ||
|
|
68374017e1 | ||
|
|
120520f51d | ||
|
|
e8dea9773a | ||
|
|
7b31e6bcc4 | ||
|
|
c6ffca639f | ||
|
|
c491a1f7ca | ||
|
|
0b333b743d | ||
|
|
95e79865e5 | ||
|
|
0e2860cd90 | ||
|
|
3259bf032c | ||
|
|
116205cdf1 | ||
|
|
43277d18dc | ||
|
|
86153419ee | ||
|
|
2b4d9c451c | ||
|
|
7f0e2fa9d8 | ||
|
|
e165095bd5 | ||
|
|
b8708d6e10 | ||
|
|
ef536390ca | ||
|
|
28befab173 | ||
|
|
c142439d5b | ||
|
|
1ca7335654 | ||
|
|
9197d9cdcd | ||
|
|
f75813e64d | ||
|
|
1f617c76a4 | ||
|
|
ebf573aa7a | ||
|
|
75363da470 | ||
|
|
cce4b932cc | ||
|
|
0973e1ced0 | ||
|
|
e7b5c84024 | ||
|
|
4001cc2a89 | ||
|
|
6e57d77d10 | ||
|
|
2206d96a6e | ||
|
|
33f05858f1 | ||
|
|
8443b88c16 | ||
|
|
a4f204a5a3 | ||
|
|
31b6be2164 | ||
|
|
0dbf73067b | ||
|
|
775703e1f5 | ||
|
|
bcdfef4886 | ||
|
|
a19adb463b | ||
|
|
b71208299f | ||
|
|
136b5824b0 | ||
|
|
5004edbbb6 | ||
|
|
d8bdd6329a | ||
|
|
82d56637a0 | ||
|
|
7232a43816 | ||
|
|
098eb7d14b | ||
|
|
835b70ed48 | ||
|
|
9d828a86fb | ||
|
|
910551ee70 | ||
|
|
9beee548d4 | ||
|
|
bacc482bf0 | ||
|
|
edb3f906f8 | ||
|
|
4171bf341b | ||
|
|
f9189b265f | ||
|
|
6f3894f27b | ||
|
|
bbc9a5e62e | ||
|
|
94765da04a | ||
|
|
8caa82f123 | ||
|
|
8e1fcc6f14 | ||
|
|
21c4d0233d | ||
|
|
2f87d53af6 | ||
|
|
131ef31492 | ||
|
|
b6b067b1d3 | ||
|
|
546f10eca7 | ||
|
|
542839ba69 | ||
|
|
efab1bba08 | ||
|
|
8f986bc326 | ||
|
|
e155d32aaf | ||
|
|
743e0b7d66 | ||
|
|
1518d703f9 | ||
|
|
af9d851d67 | ||
|
|
20ca91f1c9 | ||
|
|
6fb3c0e49a | ||
|
|
5cb4ff5f5f | ||
|
|
d035c08a5c | ||
|
|
fda7b13f50 | ||
|
|
fb4aaed220 | ||
|
|
c5e1b37ead | ||
|
|
2be9d303ea | ||
|
|
99ac6d213a | ||
|
|
f595724971 | ||
|
|
0511ba147b | ||
|
|
760f48d850 | ||
|
|
bf296b4921 | ||
|
|
6f4aae8b7d | ||
|
|
01e5e74e64 | ||
|
|
b6565a5dee | ||
|
|
49886389cf | ||
|
|
61d53f3052 | ||
|
|
4221993f7d | ||
|
|
a616c25c8c | ||
|
|
6ce4bf5673 | ||
|
|
1b652ba99f | ||
|
|
11b59df386 | ||
|
|
ac2b068bf3 | ||
|
|
8e8f346e52 | ||
|
|
b426df7271 | ||
|
|
1543e06a06 | ||
|
|
d7b4ccb1e5 | ||
|
|
dedd449329 | ||
|
|
38c589658f | ||
|
|
2f961bd7bf | ||
|
|
b72244a986 | ||
|
|
6710f25190 | ||
|
|
4089e5d7a9 | ||
|
|
0a49b5b17b | ||
|
|
34c40de429 | ||
|
|
6d02144401 | ||
|
|
561687ce0f | ||
|
|
49c22f951d | ||
|
|
a94cbc4eae | ||
|
|
20973c6724 | ||
|
|
bf10a4dcef | ||
|
|
565987a780 | ||
|
|
4f9a6c8e98 | ||
|
|
3a3e92d441 | ||
|
|
bc0dc809f9 | ||
|
|
92310847aa | ||
|
|
5bdc59830c | ||
|
|
17f524d3da | ||
|
|
4d0de2bb45 | ||
|
|
b3b8f56bb8 | ||
|
|
f036b83693 | ||
|
|
73fb31c2fc | ||
|
|
381787f39d | ||
|
|
5083af626c | ||
|
|
137bb37c29 | ||
|
|
eec578b312 | ||
|
|
b6abe9711d | ||
|
|
38c2e0d194 | ||
|
|
69566a97ca | ||
|
|
6866e9af9b | ||
|
|
e45f2c6261 | ||
|
|
d9bea49567 | ||
|
|
235b753a25 | ||
|
|
3d48432390 | ||
|
|
7b03940dab | ||
|
|
8d5d37c750 | ||
|
|
cdb9c80c0e | ||
|
|
a77f035617 | ||
|
|
2cb942a24b | ||
|
|
c79cb5731e | ||
|
|
4760bb15a4 | ||
|
|
aac881f23c | ||
|
|
da19c51566 | ||
|
|
37dd354155 | ||
|
|
acb1ebda19 | ||
|
|
5dddc05626 | ||
|
|
99890671bd | ||
|
|
9451ac5f46 | ||
|
|
a8e4e21ba1 | ||
|
|
f555ba3703 | ||
|
|
37677b3730 | ||
|
|
2a298b2268 | ||
|
|
ad3f94fb80 | ||
|
|
719660798e | ||
|
|
8d973a09e1 | ||
|
|
3579a86cde | ||
|
|
ba96a6a205 | ||
|
|
f07d2a9a9a | ||
|
|
2469067fd4 |
No files matched your search
+13
-199
@@ -1,215 +1,29 @@
|
||||
# Changelog
|
||||
## [1.8.2 (October 11th, 2026)](#1-8-2)
|
||||
## [1.8.5 (MONTH xth, 2026)](#1-8-5)
|
||||
|
||||
### Additions
|
||||
- The following items can now be placed on the ground as blocks:
|
||||
- King's Rock, Galarica Cuff, Unremarkable Teacup, Masterpiece Teacup, Chipped Pot, Cracked Pot, Sachet, Metal Powder, Quick Powder, Bright Powder, Soft Sand, Electirizer, Magmarizer, Icy Rock, Heat Rock, Smooth Rock, Damp Rock, Destiny Knot, Luminous Moss, Never-Melt Ice, Wide Lens, Scope Lens, and Zoom Lens.
|
||||
- I wasn't finished. Iron Ball, Metal Coat, Throat Spray, Terrain Extender, Medicinal Brew, Moomoo Milk, HP Up, Protein, Iron, Carbos, Calcium, Zinc, PP Up, PP Max, Upgrade, Dubious Disc, and Loaded Dice.
|
||||
- The following items can now be placed on various surfaces:
|
||||
- Galarica Wreath, Magnet, Flame Orb, Life Orb, Toxic Orb, Light Ball, and Smoke Ball.
|
||||
- The following items can now be placed as blocks and have additional functionality:
|
||||
- Ring Target, Metronome, and Eject Button.
|
||||
- The following items can now be worn by Players and Pokémon:
|
||||
- Galarica Wreath, Cleanse Tag, Spell Tag, Sharp Beak, Covert Cloak, Shell Helmet, and Never-Melt Ice.
|
||||
- Wearable items can now be equipped by a player by holding it and right-clicking (or whatever you've rebound use/interact to).
|
||||
- Wearable items that can be placed down are exempt from this behaviour.
|
||||
- Mint Leaves can now be placed on the ground as Leaf Litter, or in Flower Pots.
|
||||
- The recall animation now renders the ball in hand with the player's arm raised.
|
||||
- Added Oricorio Flowers.
|
||||
- Added Terrain Plants, four plants grown from Electric, Grassy, Misty, and Psychic Seeds, which glow under specific environmental conditions and can be farmed for more of their seeds.
|
||||
- Berries can now be placed in Flower Pots.
|
||||
- The evolution tree for a Pokémon can now be viewed in the Pokédex, showing the Pokémon's full family line and what's needed to evolve into each stage.
|
||||
- Added custom sounds to a bunch of items that can be placed as blocks: liquid bottles, pill bottles, powders, and dice.
|
||||
- Added paper as a new cosmetic item for Pikachu.
|
||||
- Burmy changes its cloak after a battle it took part in, based on the biome.
|
||||
- Trash Cloak in the Deep Dark, Nether and End.
|
||||
- Plant Cloak in lush biomes such as forests, jungles, plains and swamps.
|
||||
- Sandy Cloak in sandy biomes, beaches and caves.
|
||||
|
||||
### Pokémon Added
|
||||
#### Generation 4
|
||||
- Snover
|
||||
- Abomasnow
|
||||
- Burmy
|
||||
- Wormadam
|
||||
- Mothim
|
||||
|
||||
#### Generation 5
|
||||
- Tympole
|
||||
- Palpitoad
|
||||
- Seismitoad
|
||||
|
||||
#### Generation 6
|
||||
- Helioptile
|
||||
- Heliolisk
|
||||
|
||||
#### Generation 7
|
||||
- Grubbin
|
||||
- Charjabug
|
||||
- Vikavolt
|
||||
- Minior
|
||||
|
||||
#### Generation 8
|
||||
- Eternatus
|
||||
|
||||
#### Generation 9
|
||||
- Greavard
|
||||
- Houndstone
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
- Sudowoodo
|
||||
- Spheal
|
||||
- Cacnea
|
||||
- Cacturne
|
||||
- Binacle
|
||||
- Barbaracle
|
||||
- Glimmet
|
||||
- Glimmora
|
||||
- Deerling
|
||||
- Sawsbuck (All forms)
|
||||
- Absol
|
||||
- Poliwag
|
||||
- Politoed
|
||||
- Ekans
|
||||
- Oddish
|
||||
- Gloom
|
||||
- Vileplume
|
||||
- Bellossom
|
||||
- Shroomish
|
||||
- Chespin
|
||||
- Quilladin
|
||||
- Chesnaught
|
||||
- Fennekin
|
||||
- Braixen
|
||||
- Delphox
|
||||
- Froakie
|
||||
- Frogadier
|
||||
- Greninja
|
||||
- Shinx
|
||||
- Luxio
|
||||
- Luxray
|
||||
- Slakoth
|
||||
- Riolu
|
||||
- Lucario
|
||||
- Corsola
|
||||
- Mime Jr.
|
||||
|
||||
### Animation updates for the following Pokémon
|
||||
- Treecko (New Shoulder Mount!)
|
||||
- Bonsly (New Shoulder Mount!)
|
||||
- Sudowoodo
|
||||
- Cacnea
|
||||
- Cacturne
|
||||
- Ekans
|
||||
- Arbok
|
||||
- Oddish
|
||||
- Gloom
|
||||
- Vileplume
|
||||
- Bellossom
|
||||
- Pichu
|
||||
- Pikachu
|
||||
- Raichu (+ Alolan)
|
||||
- Greninja
|
||||
- Slakoth
|
||||
- Added the `healersSetSpawn` gamerule. When enabled, using a healing machine will set your spawnpoint.
|
||||
- A Pokémon holding a Power item now gains 1 point in the corresponding riding stat every two minutes while being ridden. The interval is configurable, and can be disabled with `-1`.
|
||||
- Added sounds to Gigaton Hammer and Pyro Ball
|
||||
- Added stepsounds to Venusaur, Blastoise, Dewgong, Rhydon, Rhyhorn, Parasect and Mr. Mime.
|
||||
|
||||
### Changes
|
||||
- Slowed the speed of Type Gem growth, and revamped their generation to grow in a more crystal-like shape.
|
||||
- Terrain Seeds can now be planted.
|
||||
- Terrain Seeds are now consumed during PvP and NPC battles.
|
||||
- Glow Item Frames can be crafted using Bright Powder as an alternative to Glow Ink Sacs.
|
||||
- Bright Powder can be used on Signs and Hanging Signs to make text glow, as an alternative to Glow Ink Sacs.
|
||||
- Updated various recipes to display in Recipe Groups within the Recipe Book.
|
||||
- Updated most recipes to display more logically and consistently within the Recipe Book's categories.
|
||||
- Updated the following recipes
|
||||
- Never-Melt Ice, Focus Sash, Blunder Policy, Weakness Policy, Blank TM.
|
||||
- Made ride rotations less jittery in multiplayer.
|
||||
- Changes Disc Shelf TMs to use textures instead of tinting and overlays to line up with item display.
|
||||
- Blank TM can now be inserted into the Disc Shelf.
|
||||
- Added a TM creative tab.
|
||||
- Made regional and Vivillon split-evo locations mutually exclusive.
|
||||
- Vivillon's patterns are now viewable as forms with form names and unique Pokédex entries displayed.
|
||||
- Item evolutions now unlock **all** locked evolutions whose requirements are met instead of stopping after the first.
|
||||
- Exceptions being "forced" evolutions which stop after the first one.
|
||||
- Removed Mega Drain as a TM.
|
||||
- PokeSnacks (and other area spawns) will now start the vertical offset checking from the center rather than base coordinate
|
||||
- This will help PokeSnacks to work inside caves or tighter spaces better.
|
||||
- Amethyst now grows from Typegem core blocks like typegems do
|
||||
- Updated the recipe category for the Create compatibility EXP Candy recipe
|
||||
- Added No Man's Lands' Honeyed Apple to the Leaves Leftovers tag
|
||||
|
||||
### Fixes
|
||||
- Type Gem blocks now properly generate clusters off of the block.
|
||||
- Correctly grant "They're Minerals!" advancement when planting a Type Gem.
|
||||
- Shoulder mounted Pokémon now follow player body animations, improving their positioning with custom player animations and default actions.
|
||||
- Shoulder mounted Pokémon now sit slightly higher with chest armor equipped for better alignment, with a configurable blacklist.
|
||||
- Type Gem Blocks now have advancements to give you the recipe in the recipe book (the data for the advancements were inside the recipes somehow??).
|
||||
- Some other recipes without advancements have also been corrected.
|
||||
- Corrected the TM Recipes for Charge Beam and Payday.
|
||||
- Starter Screen Categories will no longer stop rendering if they are bigger than the viewport and you are not viewing the top or bottom edges.
|
||||
- The Random Starter option no longer runs off into other categories or becomes unaccessible due to scroll limits if it causes a new row.
|
||||
- Mochi and Feathers no longer drop glass bottles on use.
|
||||
- Fixed a rare set of concurrency bugs related to reloading packs on NeoForge; fixes a ModernFix compatibility issue.
|
||||
- Removed unnecessary conditions for Mimikyu's standing pose. Hopefully fixes the rare instance of it using its shoulder animations during battle in multiplayer scenarios.
|
||||
- Fixed Rockruff line not blinking.
|
||||
- Fixed Flygon sometimes using its running animation instead of walking.
|
||||
- Fixed Bramblin always sleeping outside of battle.
|
||||
- Fixed Dragonair using its battle idle as a normal idle.
|
||||
- Fixed Lycanroc's head movement.
|
||||
- Added head movement to Archaludon.
|
||||
- Fixed Duraludon line not having any sleep animations.
|
||||
- Fixed Diglett line not having their faint animations.
|
||||
- Fixed Kingambit moving its legs while walking.
|
||||
- Fixed Alolan Diglett's cry not playing.
|
||||
- Fixed shiny alpha Snorlax using the non-shiny texture.
|
||||
- Fixed Crabominable's head breaking when looking around.
|
||||
- Fixed Shiny Dipplin and Hydrapple's textures.
|
||||
- Various structure fixes.
|
||||
- Fixed shiny Pokémon under certain circumstances forgetting taught TMs.
|
||||
- Fixed certain Pokémon sounds sometimes being doubled when played at specific times in their animations.
|
||||
- Fixed ball capture beam origin coming from behind the ball.
|
||||
- Fixed Safari Ball catch rate outside of battle.
|
||||
- Fixed alpha eye (and other) particles not respecting the client particle density setting in video options.
|
||||
- Fixed the TM Machine UI not closing when player is moving away from it.
|
||||
- Moved the config category for alpha/shiny chance config fields for fossil machine and honey log slathering to Spawning.
|
||||
- Fixed crashes for addon species with non-Cobblemon namespaces in evolution, fishing bait, and Pokédex lookups.
|
||||
- Bees will now grow Apricorns and the Galarica Nut Bush, which were in the bee growables tag but never handled, and correctly spend their nectar when they do.
|
||||
- Saccharine Leaves can now be bone mealed.
|
||||
- Fixed equipping a stack of wearable items instead of one item of a stack.
|
||||
- Fixed TM stack consumption in TM Machine screen when a player teaches a move to a Pokémon.
|
||||
- Fixed every Miltank giving mushroom stew, not only mushroom variants.
|
||||
- Medicinal Leeks can now be eaten when they aren't being planted, matching their food properties.
|
||||
- Sweeping attacks no longer set owned Pokémon on fire (e.g. with Fire Aspect) or knock them back. Friendly Fire is now off.
|
||||
- Fixed Pokémon not losing their previous form's signature moves when changing forms (e.g. Rotom keeping Overheat after leaving its Heat form).
|
||||
- Form-specific moves gained from a form change are now only granted if the Pokémon is high enough level to learn them, and no longer create duplicates in benched moves.
|
||||
- Spinda now learns Teeter Dance at level 32 instead of via TM.
|
||||
- Fixed Oricorio Pa'u form description in the Pokédex.
|
||||
- Fixed PC playing sound on close when opened via command.
|
||||
- Fixed Ponigiri food values for AppleSkin integration
|
||||
- Fixed errors emitted by typos in Parched Peat bog structure files
|
||||
|
||||
### Developer
|
||||
- Evolution requirements can now set `pokedexIcon` and `pokedexTooltip` directly in their JSON to control how they're shown on the Pokédex's evolution tree, for example:
|
||||
```json
|
||||
{
|
||||
"variant": "attack_defence_ratio",
|
||||
"pokedexIcon": "minecraft:diamond_sword",
|
||||
"pokedexTooltip": "cobblemon.ui.pokedex.requirement.attack_defence_ratio.tooltip"
|
||||
}
|
||||
```
|
||||
- Fixed the wrong order of operations in the code flow prior to the `FOSSIL_REVIVED` event causing Pokémon to appear without the entity link.
|
||||
- Fixed TestPartySlot command not correctly comparing the provided spec with the target Pokémon.
|
||||
|
||||
### Molang & Datapacks
|
||||
- A new `negate` variant for evolution requirements has been added, which will negate (invert) the provided inner condition.
|
||||
- Added Molang functions for individual Pokédex ids, wherein a subdex is passed in as a string to `dex_caught_count` etc.
|
||||
- Added a `battle_ended` callback, backed by the new `BATTLE_ENDED` event, which fires whenever a battle ends for any reason, alongside a multitude of flags not previously covered by `BATTLE_VICTORY`.
|
||||
- Added `battle_pokemon` to battle actor structs and `has_faced_opponents` to battle Pokémon structs.
|
||||
- Added the `cobblemon:form_change/bagworm_cloak/plant_cloak`, `sandy_cloak` and `trash_cloak` biome tags, which control Burmy's cloak after battle.
|
||||
- `q.is_standing_on_blocks` now properly checks for non-full blocks like slabs, Mud or Soul Sand
|
||||
- Added Molang functions to play footstep sounds based on the corresponding surface. These are intended to be used by Pokémon animations.
|
||||
- Pokémon can now have their Minecraft footstep sounds silenced in their poser. This doesn't affect emitting game events.
|
||||
|
||||
### Particles
|
||||
|
||||
#### New Move Animations
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
- Brazilian Portuguese
|
||||
- Canadian French
|
||||
- Japanese
|
||||
- Korean
|
||||
- Russian
|
||||
- Ukrainian
|
||||
@@ -0,0 +1,2 @@
|
||||
Spec Doc: https://docs.google.com/document/d/1hEKKrT4JEagJBykx-k9K2BoeNxiMGahUWXnf8YQ85xo/edit?tab=t.0
|
||||
Marshal: dhi_holo
|
||||
@@ -36,6 +36,7 @@
|
||||
- Added `cobblemon:catch_alpha_pokemon` advancement trigger and `totalAlphaCaptureCount` stat for captured Alpha Pokémon.
|
||||
|
||||
### New rideable Pokémon
|
||||
- Pidgeot
|
||||
- Crobat
|
||||
- Skarmory
|
||||
- Milotic
|
||||
@@ -106,7 +107,9 @@
|
||||
- Avalugg (Hisuian Form)
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
|
||||
- Pidgey
|
||||
- Pidgeotto
|
||||
- Pidgeot
|
||||
- Sandshrew
|
||||
- Sandslash
|
||||
- Nidoking
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
# Changelog
|
||||
## [1.8.2 (October 11th, 2026)](#1-8-2)
|
||||
|
||||
### Additions
|
||||
- The following items can now be placed on the ground as blocks:
|
||||
- King's Rock, Galarica Cuff, Unremarkable Teacup, Masterpiece Teacup, Chipped Pot, Cracked Pot, Sachet, Metal Powder, Quick Powder, Bright Powder, Soft Sand, Electirizer, Magmarizer, Icy Rock, Heat Rock, Smooth Rock, Damp Rock, Destiny Knot, Luminous Moss, Never-Melt Ice, Wide Lens, Scope Lens, and Zoom Lens.
|
||||
- I wasn't finished. Iron Ball, Metal Coat, Throat Spray, Terrain Extender, Medicinal Brew, Moomoo Milk, HP Up, Protein, Iron, Carbos, Calcium, Zinc, PP Up, PP Max, Upgrade, Dubious Disc, and Loaded Dice.
|
||||
- The following items can now be placed on various surfaces:
|
||||
- Galarica Wreath, Magnet, Flame Orb, Life Orb, Toxic Orb, Light Ball, and Smoke Ball.
|
||||
- The following items can now be placed as blocks and have additional functionality:
|
||||
- Ring Target, Metronome, and Eject Button.
|
||||
- The following items can now be worn by Players and Pokémon:
|
||||
- Galarica Wreath, Cleanse Tag, Spell Tag, Sharp Beak, Covert Cloak, Shell Helmet, and Never-Melt Ice.
|
||||
- Wearable items can now be equipped by a player by holding it and right-clicking (or whatever you've rebound use/interact to).
|
||||
- Wearable items that can be placed down are exempt from this behaviour.
|
||||
- Mint Leaves can now be placed on the ground as Leaf Litter, or in Flower Pots.
|
||||
- The recall animation now renders the ball in hand with the player's arm raised.
|
||||
- Added Oricorio Flowers.
|
||||
- Added Terrain Plants, four plants grown from Electric, Grassy, Misty, and Psychic Seeds, which glow under specific environmental conditions and can be farmed for more of their seeds.
|
||||
- Berries can now be placed in Flower Pots.
|
||||
- The evolution tree for a Pokémon can now be viewed in the Pokédex, showing the Pokémon's full family line and what's needed to evolve into each stage.
|
||||
- Added custom sounds to a bunch of items that can be placed as blocks: liquid bottles, pill bottles, powders, and dice.
|
||||
- Added paper as a new cosmetic item for Pikachu.
|
||||
- Burmy changes its cloak after a battle it took part in, based on the biome.
|
||||
- Trash Cloak in the Deep Dark, Nether and End.
|
||||
- Plant Cloak in lush biomes such as forests, jungles, plains and swamps.
|
||||
- Sandy Cloak in sandy biomes, beaches and caves.
|
||||
|
||||
### Pokémon Added
|
||||
#### Generation 4
|
||||
- Snover
|
||||
- Abomasnow
|
||||
- Burmy
|
||||
- Wormadam
|
||||
- Mothim
|
||||
|
||||
#### Generation 5
|
||||
- Tympole
|
||||
- Palpitoad
|
||||
- Seismitoad
|
||||
|
||||
#### Generation 6
|
||||
- Helioptile
|
||||
- Heliolisk
|
||||
|
||||
#### Generation 7
|
||||
- Grubbin
|
||||
- Charjabug
|
||||
- Vikavolt
|
||||
- Minior
|
||||
|
||||
#### Generation 8
|
||||
- Eternatus
|
||||
|
||||
#### Generation 9
|
||||
- Greavard
|
||||
- Houndstone
|
||||
|
||||
### Model updates for the following Pokémon
|
||||
- Sudowoodo
|
||||
- Spheal
|
||||
- Cacnea
|
||||
- Cacturne
|
||||
- Binacle
|
||||
- Barbaracle
|
||||
- Glimmet
|
||||
- Glimmora
|
||||
- Deerling
|
||||
- Sawsbuck (All forms)
|
||||
- Absol
|
||||
- Poliwag
|
||||
- Politoed
|
||||
- Ekans
|
||||
- Oddish
|
||||
- Gloom
|
||||
- Vileplume
|
||||
- Bellossom
|
||||
- Shroomish
|
||||
- Chespin
|
||||
- Quilladin
|
||||
- Chesnaught
|
||||
- Fennekin
|
||||
- Braixen
|
||||
- Delphox
|
||||
- Froakie
|
||||
- Frogadier
|
||||
- Greninja
|
||||
- Shinx
|
||||
- Luxio
|
||||
- Luxray
|
||||
- Slakoth
|
||||
- Riolu
|
||||
- Lucario
|
||||
- Corsola
|
||||
- Mime Jr.
|
||||
|
||||
### Animation updates for the following Pokémon
|
||||
- Treecko (New Shoulder Mount!)
|
||||
- Bonsly (New Shoulder Mount!)
|
||||
- Sudowoodo
|
||||
- Cacnea
|
||||
- Cacturne
|
||||
- Ekans
|
||||
- Arbok
|
||||
- Oddish
|
||||
- Gloom
|
||||
- Vileplume
|
||||
- Bellossom
|
||||
- Pichu
|
||||
- Pikachu
|
||||
- Raichu (+ Alolan)
|
||||
- Greninja
|
||||
- Slakoth
|
||||
|
||||
### Changes
|
||||
- Slowed the speed of Type Gem growth, and revamped their generation to grow in a more crystal-like shape.
|
||||
- Terrain Seeds can now be planted.
|
||||
- Terrain Seeds are now consumed during PvP and NPC battles.
|
||||
- Glow Item Frames can be crafted using Bright Powder as an alternative to Glow Ink Sacs.
|
||||
- Bright Powder can be used on Signs and Hanging Signs to make text glow, as an alternative to Glow Ink Sacs.
|
||||
- Updated various recipes to display in Recipe Groups within the Recipe Book.
|
||||
- Updated most recipes to display more logically and consistently within the Recipe Book's categories.
|
||||
- Updated the following recipes
|
||||
- Never-Melt Ice, Focus Sash, Blunder Policy, Weakness Policy, Blank TM.
|
||||
- Made ride rotations less jittery in multiplayer.
|
||||
- Changes Disc Shelf TMs to use textures instead of tinting and overlays to line up with item display.
|
||||
- Blank TM can now be inserted into the Disc Shelf.
|
||||
- Added a TM creative tab.
|
||||
- Made regional and Vivillon split-evo locations mutually exclusive.
|
||||
- Vivillon's patterns are now viewable as forms with form names and unique Pokédex entries displayed.
|
||||
- Item evolutions now unlock **all** locked evolutions whose requirements are met instead of stopping after the first.
|
||||
- Exceptions being "forced" evolutions which stop after the first one.
|
||||
- Removed Mega Drain as a TM.
|
||||
- PokeSnacks (and other area spawns) will now start the vertical offset checking from the center rather than base coordinate
|
||||
- This will help PokeSnacks to work inside caves or tighter spaces better.
|
||||
|
||||
### Fixes
|
||||
- Type Gem blocks now properly generate clusters off of the block.
|
||||
- Correctly grant "They're Minerals!" advancement when planting a Type Gem.
|
||||
- Shoulder mounted Pokémon now follow player body animations, improving their positioning with custom player animations and default actions.
|
||||
- Shoulder mounted Pokémon now sit slightly higher with chest armor equipped for better alignment, with a configurable blacklist.
|
||||
- Type Gem Blocks now have advancements to give you the recipe in the recipe book (the data for the advancements were inside the recipes somehow??).
|
||||
- Some other recipes without advancements have also been corrected.
|
||||
- Corrected the TM Recipes for Charge Beam and Payday.
|
||||
- Starter Screen Categories will no longer stop rendering if they are bigger than the viewport and you are not viewing the top or bottom edges.
|
||||
- The Random Starter option no longer runs off into other categories or becomes unaccessible due to scroll limits if it causes a new row.
|
||||
- Mochi and Feathers no longer drop glass bottles on use.
|
||||
- Fixed a rare set of concurrency bugs related to reloading packs on NeoForge; fixes a ModernFix compatibility issue.
|
||||
- Removed unnecessary conditions for Mimikyu's standing pose. Hopefully fixes the rare instance of it using its shoulder animations during battle in multiplayer scenarios.
|
||||
- Fixed Rockruff line not blinking.
|
||||
- Fixed Flygon sometimes using its running animation instead of walking.
|
||||
- Fixed Bramblin always sleeping outside of battle.
|
||||
- Fixed Dragonair using its battle idle as a normal idle.
|
||||
- Fixed Lycanroc's head movement.
|
||||
- Added head movement to Archaludon.
|
||||
- Fixed Duraludon line not having any sleep animations.
|
||||
- Fixed Diglett line not having their faint animations.
|
||||
- Fixed Kingambit moving its legs while walking.
|
||||
- Fixed Alolan Diglett's cry not playing.
|
||||
- Fixed shiny alpha Snorlax using the non-shiny texture.
|
||||
- Fixed Crabominable's head breaking when looking around.
|
||||
- Fixed Shiny Dipplin and Hydrapple's textures.
|
||||
- Various structure fixes.
|
||||
- Fixed shiny Pokémon under certain circumstances forgetting taught TMs.
|
||||
- Fixed certain Pokémon sounds sometimes being doubled when played at specific times in their animations.
|
||||
- Fixed ball capture beam origin coming from behind the ball.
|
||||
- Fixed Safari Ball catch rate outside of battle.
|
||||
- Fixed alpha eye (and other) particles not respecting the client particle density setting in video options.
|
||||
- Fixed the TM Machine UI not closing when player is moving away from it.
|
||||
- Moved the config category for alpha/shiny chance config fields for fossil machine and honey log slathering to Spawning.
|
||||
- Fixed crashes for addon species with non-Cobblemon namespaces in evolution, fishing bait, and Pokédex lookups.
|
||||
- Bees will now grow Apricorns and the Galarica Nut Bush, which were in the bee growables tag but never handled, and correctly spend their nectar when they do.
|
||||
- Saccharine Leaves can now be bone mealed.
|
||||
- Fixed equipping a stack of wearable items instead of one item of a stack.
|
||||
- Fixed TM stack consumption in TM Machine screen when a player teaches a move to a Pokémon.
|
||||
- Fixed every Miltank giving mushroom stew, not only mushroom variants.
|
||||
- Medicinal Leeks can now be eaten when they aren't being planted, matching their food properties.
|
||||
- Sweeping attacks no longer set owned Pokémon on fire (e.g. with Fire Aspect) or knock them back. Friendly Fire is now off.
|
||||
- Fixed Pokémon not losing their previous form's signature moves when changing forms (e.g. Rotom keeping Overheat after leaving its Heat form).
|
||||
- Form-specific moves gained from a form change are now only granted if the Pokémon is high enough level to learn them, and no longer create duplicates in benched moves.
|
||||
- Spinda now learns Teeter Dance at level 32 instead of via TM.
|
||||
- Fixed Oricorio Pa'u form description in the Pokédex.
|
||||
- Fixed PC playing sound on close when opened via command.
|
||||
|
||||
### Developer
|
||||
- Evolution requirements can now set `pokedexIcon` and `pokedexTooltip` directly in their JSON to control how they're shown on the Pokédex's evolution tree, for example:
|
||||
```json
|
||||
{
|
||||
"variant": "attack_defence_ratio",
|
||||
"pokedexIcon": "minecraft:diamond_sword",
|
||||
"pokedexTooltip": "cobblemon.ui.pokedex.requirement.attack_defence_ratio.tooltip"
|
||||
}
|
||||
```
|
||||
- Fixed the wrong order of operations in the code flow prior to the `FOSSIL_REVIVED` event causing Pokémon to appear without the entity link.
|
||||
- Fixed TestPartySlot command not correctly comparing the provided spec with the target Pokémon.
|
||||
|
||||
### Molang & Datapacks
|
||||
- A new `negate` variant for evolution requirements has been added, which will negate (invert) the provided inner condition.
|
||||
- Added Molang functions for individual Pokédex ids, wherein a subdex is passed in as a string to `dex_caught_count` etc.
|
||||
- Added a `battle_ended` callback, backed by the new `BATTLE_ENDED` event, which fires whenever a battle ends for any reason, alongside a multitude of flags not previously covered by `BATTLE_VICTORY`.
|
||||
- Added `battle_pokemon` to battle actor structs and `has_faced_opponents` to battle Pokémon structs.
|
||||
- Added the `cobblemon:form_change/bagworm_cloak/plant_cloak`, `sandy_cloak` and `trash_cloak` biome tags, which control Burmy's cloak after battle.
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
- Brazilian Portuguese
|
||||
- Canadian French
|
||||
- Japanese
|
||||
- Korean
|
||||
- Russian
|
||||
- Ukrainian
|
||||
@@ -0,0 +1,107 @@
|
||||
# Changelog
|
||||
## [1.8.3 (October 25th, 2026)](#1-8-3)
|
||||
|
||||
### Additions
|
||||
- Added compatability with AppleSkin.
|
||||
|
||||
### New Rideable Pokémon
|
||||
- Vikavolt
|
||||
- Fearow
|
||||
|
||||
### Particles
|
||||
## New Move Animations
|
||||
- Water Shuriken
|
||||
|
||||
### Cries added/updated for the following Pokémon
|
||||
- Hoppip
|
||||
- Skiploom
|
||||
- Jumpluff
|
||||
- Houndour
|
||||
- Houndoom
|
||||
- Wurmple
|
||||
- Silcoon
|
||||
- Beautifly
|
||||
- Cascoon
|
||||
- Dustox
|
||||
- Surskit
|
||||
- Masquerain
|
||||
- Torkoal
|
||||
- Starly
|
||||
- Staravia
|
||||
- Staraptor
|
||||
- Combee
|
||||
- Vespiquen
|
||||
- Dusknoir
|
||||
- Helioptile
|
||||
- Heliolisk
|
||||
- Grubbin
|
||||
- Charjabug
|
||||
- Vikavolt
|
||||
- Applin (updated)
|
||||
- Flapple (updated)
|
||||
- Appletun
|
||||
- Runerigus
|
||||
- Dipplin
|
||||
|
||||
### Animation updates for the following Pokémon
|
||||
- Vikavolt
|
||||
- Magby
|
||||
- Magmar
|
||||
- Ninetales (+ Alolan)
|
||||
- Spearow
|
||||
- Fearow
|
||||
- Squawkabilly
|
||||
- Mudkip
|
||||
- Marshtomp
|
||||
- Swampert
|
||||
|
||||
### Changes
|
||||
- Changed the Misc icon in the Campfire Pot Recipe Book to Health Candy.
|
||||
- Moved EXP Candies from the Medicine recipe book category to the Misc category.
|
||||
- Removed Dynamic Lights data from the Magmarizer item for consistency with the block.
|
||||
- Added `doPokemonPredation` game rule, which controls aggressiveness of Pokémon with the `hate_entity` brain task defined.
|
||||
- Added `predation_chance` server config value, which controls the possibility of attacking the hated entity found in `hate_entity` brain tasks.
|
||||
- Prehistoric Eroded Pillar generates slightly more frequently.
|
||||
- Togekiss was changed from a jet-style mount to bird-style.
|
||||
|
||||
### Fixes
|
||||
- Fixed datapacks with item interaction evolutions that don't specify an item crashing the world on load.
|
||||
- Fixed the Pokédex evolution tree crashing when a datapack's dex entry is missing an evolution's form.
|
||||
- Fixed the Pokédex evolution tree crashing with a stack overflow on evolutions that loop back on themselves.
|
||||
- Fixed the Pokédex evolution tree crashing when looking at a dex that is not part of the "National Dex" aggregate.
|
||||
- Fixed some display names in the Pokédex evolution tree having unintended font colours.
|
||||
- Fixed evolution trees not building properly when a Pokémon has several Pokédex entries for different regions.
|
||||
- Fixed form-changing evolutions sometimes resolving to the source form in the Pokédex evolution tree.
|
||||
- Broken datapack evolutions are now logged and skipped in the Pokédex evolution tree instead of crashing.
|
||||
- Fixed the `alpha` property having no tab completion in commands such as `/pokespawn`, `/pokegive` and `/pokeedit`, and added the missing `dmax_level`, `gmax_factor` and `tradable` aliases to tab completion.
|
||||
- Fixed friendship booster items not being recognised as such.
|
||||
- Fixed conflicts with other mods that would make use of recipe books in certain ways (Farmer's Delight Cooking Pot).
|
||||
- Fixed Pokémon battles stalling when a sidemod cancels the `THROWN_POKEBALL_HIT` hit event.
|
||||
- Fixed choice feature tab completion in `spawnpokemon/pokegive/pokeedit` commands.
|
||||
- Fixed MoLang that's targeting players intermittedly failing when they have died, requiring them to relog.
|
||||
- Fixed a NeoForge bug where none of the Cobblemon plants/berries could be placed into pots.
|
||||
- Fixed party overlay not hiding when the player opens the Pokédex scanner.
|
||||
- Fixed `hate_entity` task focusing on its own entity, therefore enabling deadly warfare between Zangoose and Seviper.
|
||||
- Prehistoric Frozen Pond, Prehistoric Frozen Spike, and Prehistoric Lush Den now actually generate (oops).
|
||||
- Fixed Frogadier floating in its `battle_idle` animation.
|
||||
- Fixed absence or incorrect mergers in spawning conditions, causing the max height/depth of conditions to use the min value instead.
|
||||
- Added stricter riding checks on server side to prevent possible packet forgery when a player tries to ride Pokémon.
|
||||
- Fixed Pokémon cries and animation sounds played from GUIs, such as the starter selection screen and the Pokédex, being tied to the Master volume slider instead of Friendly Creatures.
|
||||
- Fixed Archeops T-posing during its `air_cry` animation.
|
||||
|
||||
### Developer
|
||||
- Bumped NeoForge to `21.1.195` to get access to MixinExtras `0.5` and the expressions annotation.
|
||||
- New Platform Event `PLAYER_RESPAWN` which is fired when a player respawns (either through death or returning from the end).
|
||||
- Platform Events `SERVER_PLAYER_TICK_PRE` and `SERVER_PLAYER_TICK_POST` no longer fire when the player is dead.
|
||||
- It is now tied much closer to the actual entity rather than the player or their connection.
|
||||
|
||||
### Molang & Datapacks
|
||||
- Fixed `q.pokemon.nature` returning class instance instead of proper string value (`cobblemon:adamant`).
|
||||
- Fixed `q.entity.is_looking_at` result being always `1` for whatever entity passed as the target parameter.
|
||||
- Added hate chance optional parameter to `hate_entity` task. `1.0` will make an entity always attack the target.
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
- Russian
|
||||
- Japanese
|
||||
- Brazilian Portuguese
|
||||
@@ -0,0 +1,25 @@
|
||||
# Changelog
|
||||
## [1.8.4 (October 27th, 2026)](#1-8-4)
|
||||
|
||||
### Changes
|
||||
- The Froakie line now blinks. The world will never be the same.
|
||||
|
||||
### Fixes
|
||||
- Fixed heaps of spawns not working. This was caused by us missing something before release. RIP.
|
||||
- Fixed a crash caused by Fearow blinking while you're riding one. Makes sense to me.
|
||||
- Fixed Minior's "Shields Down" ability being very broken.
|
||||
- Fixed Dusclops using Squirtle's cry sound (lol).
|
||||
- Fixed blank Cooking Pot recipe book entries and missing tabs on Fabric.
|
||||
- Fixed a hitbox issue with placeable Orb held items attached to a ceiling.
|
||||
- Fixed something sneaky. I'll tell you about it later.
|
||||
|
||||
### Molang & Datapacks
|
||||
- Added `q.target_fainted` function to move action effects that checks if any opponents fainted from the move.
|
||||
|
||||
### Particles
|
||||
- Updated Water Shuriken effect to be timed better when the opponent faints.
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
- Korean
|
||||
- Simplified Chinese
|
||||
@@ -15,6 +15,7 @@ import com.cobblemon.mod.common.api.riding.RidingStyle;
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawner;
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.PlayerSpawnerFactory;
|
||||
import com.cobblemon.mod.common.api.stats.CobblemonStats;
|
||||
import com.cobblemon.mod.common.block.HealingMachineBlock;
|
||||
import com.cobblemon.mod.common.duck.ServerLevelDuck;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
|
||||
@@ -22,10 +23,14 @@ import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
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.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
@@ -33,6 +38,9 @@ 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.Optional;
|
||||
|
||||
@Mixin(ServerPlayer.class)
|
||||
public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
|
||||
@@ -142,4 +150,17 @@ public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
|
||||
((ServerLevelDuck) this.serverLevel()).cobblemon$getLevelResourceLocation()
|
||||
);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "findRespawnAndUseSpawnBlock(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/core/BlockPos;FZZ)Ljava/util/Optional;",
|
||||
at = @At(value = "HEAD"),
|
||||
cancellable = true
|
||||
)
|
||||
private static void cobblemon$useHealthStationAsRespawn(ServerLevel level, BlockPos pos, float angle, boolean forced, boolean keepInventory, CallbackInfoReturnable<Optional<ServerPlayer.RespawnPosAngle>> cir) {
|
||||
BlockState state = level.getBlockState(pos);
|
||||
Block block = state.getBlock();
|
||||
if (block instanceof HealingMachineBlock && HealingMachineBlock.Companion.canSetSpawn(level)) {
|
||||
cir.setReturnValue(HealingMachineBlock.Companion.findStandUpPosition(EntityType.PLAYER, level, pos).map((vec3) -> ServerPlayer.RespawnPosAngle.of(vec3, pos)));
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-17
@@ -16,6 +16,7 @@ import com.cobblemon.mod.common.item.crafting.CookingPotShapelessRecipe;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.client.ClientRecipeBook;
|
||||
import net.minecraft.client.RecipeBookCategories;
|
||||
import net.minecraft.client.gui.screens.recipebook.RecipeCollection;
|
||||
@@ -63,23 +64,12 @@ public abstract class ClientRecipeBookMixin {
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "setupCollections", at = @At("RETURN"))
|
||||
private void addCustomAggregateCategories(Iterable<RecipeHolder<?>> recipes, RegistryAccess registryAccess, CallbackInfo ci) {
|
||||
Map<RecipeBookCategories, List<List<RecipeHolder<?>>>> map = categorizeAndGroupRecipes(recipes);
|
||||
Map<RecipeBookCategories, List<RecipeCollection>> map2 = Maps.newHashMap();
|
||||
ImmutableList.Builder<RecipeCollection> builder = ImmutableList.builder();
|
||||
|
||||
map.forEach((recipeBookCategories, list) -> {
|
||||
List<RecipeCollection> collections = list.stream()
|
||||
.map(listx -> new RecipeCollection(registryAccess, listx))
|
||||
.peek(builder::add)
|
||||
.collect(ImmutableList.toImmutableList());
|
||||
map2.put(recipeBookCategories, collections);
|
||||
});
|
||||
RecipeBookCategories.AGGREGATE_CATEGORIES.forEach((recipeBookCategories, list) -> map2.put(recipeBookCategories, (List) list.stream().flatMap((recipeBookCategoriesx) -> ((List) map2.getOrDefault(recipeBookCategoriesx, ImmutableList.of())).stream()).collect(ImmutableList.toImmutableList())));
|
||||
@Inject(method = "setupCollections",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lcom/google/common/collect/ImmutableMap;copyOf(Ljava/util/Map;)Lcom/google/common/collect/ImmutableMap;"
|
||||
))
|
||||
private void addCustomAggregateCategories(Iterable<RecipeHolder<?>> recipes, RegistryAccess registryAccess, CallbackInfo ci, @Local(ordinal = 1) Map<RecipeBookCategories, List<RecipeCollection>> map2) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
+13
-43
@@ -9,55 +9,25 @@
|
||||
package com.cobblemon.mod.common.mixin.client;
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonRecipeCategories;
|
||||
import net.minecraft.client.ClientRecipeBook;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import com.llamalad7.mixinextras.expression.Definition;
|
||||
import com.llamalad7.mixinextras.expression.Expression;
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.client.RecipeBookCategories;
|
||||
import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent;
|
||||
import net.minecraft.client.gui.screens.recipebook.RecipeBookPage;
|
||||
import net.minecraft.client.gui.screens.recipebook.RecipeBookTabButton;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(RecipeBookComponent.class)
|
||||
public class RecipeBookComponentMixin {
|
||||
|
||||
@Shadow private ClientRecipeBook book;
|
||||
|
||||
@Shadow protected Minecraft minecraft;
|
||||
|
||||
@Shadow private int width;
|
||||
|
||||
@Shadow private int xOffset;
|
||||
|
||||
@Shadow private int height;
|
||||
|
||||
@Shadow @Final private RecipeBookPage recipeBookPage;
|
||||
|
||||
@Inject(method = "updateTabs", at = @At("HEAD"), cancellable = true)
|
||||
private void customUpdateTabs(CallbackInfo ci) {
|
||||
RecipeBookComponent instance = (RecipeBookComponent) (Object) this;
|
||||
int i = (width - 147) / 2 - xOffset - 30;
|
||||
int j = (height - 166) / 2 + 3;
|
||||
int k = 27;
|
||||
int l = 0;
|
||||
|
||||
for (RecipeBookTabButton recipeBookTabButton : instance.tabButtons) {
|
||||
RecipeBookCategories recipeBookCategories = recipeBookTabButton.getCategory();
|
||||
if (recipeBookCategories != RecipeBookCategories.CRAFTING_SEARCH && recipeBookCategories != RecipeBookCategories.FURNACE_SEARCH && recipeBookCategories != CobblemonRecipeCategories.COOKING_POT_SEARCH.toVanillaCategory()) {
|
||||
if (recipeBookTabButton.updateVisibility(book)) {
|
||||
recipeBookTabButton.setPosition(i, j + 27 * l++);
|
||||
recipeBookTabButton.startAnimation(minecraft);
|
||||
}
|
||||
} else {
|
||||
recipeBookTabButton.visible = true;
|
||||
recipeBookTabButton.setPosition(i, j + k * l++);
|
||||
}
|
||||
}
|
||||
|
||||
ci.cancel();
|
||||
@Definition(id = "recipeBookCategories", local = @Local(type = RecipeBookCategories.class))
|
||||
@Definition(id = "FURNACE_SEARCH", field = "Lnet/minecraft/client/RecipeBookCategories;FURNACE_SEARCH:Lnet/minecraft/client/RecipeBookCategories;")
|
||||
@Expression("recipeBookCategories != FURNACE_SEARCH")
|
||||
@ModifyExpressionValue(
|
||||
method = "updateTabs",
|
||||
at = @At(value = "MIXINEXTRAS:EXPRESSION")
|
||||
)
|
||||
private boolean notCookingPotSearch(boolean original, @Local RecipeBookCategories recipeBookCategories) {
|
||||
return original && recipeBookCategories != CobblemonRecipeCategories.COOKING_POT_SEARCH.toVanillaCategory();
|
||||
}
|
||||
}
|
||||
@@ -260,6 +260,9 @@ object Cobblemon {
|
||||
RequestManager.onLogoff(it.player)
|
||||
serverPlayerStructs.remove(it.player.uuid)
|
||||
}
|
||||
PlatformEvents.PLAYER_RESPAWN.subscribe {
|
||||
serverPlayerStructs.remove(it.player.uuid)
|
||||
}
|
||||
PlatformEvents.PLAYER_DEATH.subscribe {
|
||||
PCLinkManager.removeLink(it.player.uuid)
|
||||
battleRegistry.getBattleByParticipatingPlayer(it.player)?.stop()
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
|
||||
package com.cobblemon.mod.common
|
||||
|
||||
import com.cobblemon.mod.common.block.appliances.CopperFridgeBlockEntity
|
||||
import com.cobblemon.mod.common.block.appliances.CopperMowerBlockEntity
|
||||
import com.cobblemon.mod.common.block.appliances.CopperWasherBlockEntity
|
||||
import com.cobblemon.mod.common.block.entity.*
|
||||
import com.cobblemon.mod.common.block.habitat.HabitatBlockEntity
|
||||
import com.cobblemon.mod.common.block.multiblock.FossilMultiblockBuilder
|
||||
@@ -126,4 +129,49 @@ object CobblemonBlockEntities : PlatformRegistry<Registry<BlockEntityType<*>>, R
|
||||
CobblemonBlocks.MISTLEAF
|
||||
).build(null)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val COPPER_FRIDGE: BlockEntityType<CopperFridgeBlockEntity> = this.create(
|
||||
"copper_fridge",
|
||||
BlockEntityType.Builder.of(::CopperFridgeBlockEntity,
|
||||
CobblemonBlocks.COPPER_FRIDGE,
|
||||
CobblemonBlocks.EXPOSED_COPPER_FRIDGE,
|
||||
CobblemonBlocks.WEATHERED_COPPER_FRIDGE,
|
||||
CobblemonBlocks.OXIDIZED_COPPER_FRIDGE,
|
||||
CobblemonBlocks.WAXED_COPPER_FRIDGE,
|
||||
CobblemonBlocks.WAXED_EXPOSED_COPPER_FRIDGE,
|
||||
CobblemonBlocks.WAXED_WEATHERED_COPPER_FRIDGE,
|
||||
CobblemonBlocks.WAXED_OXIDIZED_COPPER_FRIDGE
|
||||
).build(null)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val COPPER_WASHER: BlockEntityType<CopperWasherBlockEntity> = this.create(
|
||||
"copper_washer",
|
||||
BlockEntityType.Builder.of(::CopperWasherBlockEntity,
|
||||
CobblemonBlocks.COPPER_WASHER,
|
||||
CobblemonBlocks.EXPOSED_COPPER_WASHER,
|
||||
CobblemonBlocks.WEATHERED_COPPER_WASHER,
|
||||
CobblemonBlocks.OXIDIZED_COPPER_WASHER,
|
||||
CobblemonBlocks.WAXED_COPPER_WASHER,
|
||||
CobblemonBlocks.WAXED_EXPOSED_COPPER_WASHER,
|
||||
CobblemonBlocks.WAXED_WEATHERED_COPPER_WASHER,
|
||||
CobblemonBlocks.WAXED_OXIDIZED_COPPER_WASHER
|
||||
).build(null)
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val COPPER_MOWER: BlockEntityType<CopperMowerBlockEntity> = this.create(
|
||||
"copper_mower",
|
||||
BlockEntityType.Builder.of(::CopperMowerBlockEntity,
|
||||
CobblemonBlocks.COPPER_MOWER,
|
||||
CobblemonBlocks.EXPOSED_COPPER_MOWER,
|
||||
CobblemonBlocks.WEATHERED_COPPER_MOWER,
|
||||
CobblemonBlocks.OXIDIZED_COPPER_MOWER,
|
||||
CobblemonBlocks.WAXED_COPPER_MOWER,
|
||||
CobblemonBlocks.WAXED_EXPOSED_COPPER_MOWER,
|
||||
CobblemonBlocks.WAXED_WEATHERED_COPPER_MOWER,
|
||||
CobblemonBlocks.WAXED_OXIDIZED_COPPER_MOWER
|
||||
).build(null)
|
||||
)
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.api.apricorn.Apricorn
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.block.*
|
||||
import com.cobblemon.mod.common.block.LecternBlock
|
||||
import com.cobblemon.mod.common.block.appliances.*
|
||||
import com.cobblemon.mod.common.block.MintBlock.MintType
|
||||
import com.cobblemon.mod.common.block.campfirepot.CampfireBlock
|
||||
import com.cobblemon.mod.common.block.campfirepot.CampfirePotBlock
|
||||
@@ -28,12 +29,7 @@ import com.cobblemon.mod.common.block.sign.CobblemonWallHangingSignBlock
|
||||
import com.cobblemon.mod.common.block.sign.CobblemonWallSignBlock
|
||||
import com.cobblemon.mod.common.block.tmmachine.TMMachineBlock
|
||||
import com.cobblemon.mod.common.block.general.MintLitterBlock
|
||||
import com.cobblemon.mod.common.mixin.invoker.BlocksInvoker
|
||||
import com.cobblemon.mod.common.mixin.invoker.DoorBlockInvoker
|
||||
import com.cobblemon.mod.common.mixin.invoker.FireBlockInvoker
|
||||
import com.cobblemon.mod.common.mixin.invoker.PressurePlateBlockInvoker
|
||||
import com.cobblemon.mod.common.mixin.invoker.StairsBlockInvoker
|
||||
import com.cobblemon.mod.common.mixin.invoker.TrapdoorBlockInvoker
|
||||
import com.cobblemon.mod.common.mixin.invoker.*
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.core.BlockPos
|
||||
@@ -792,6 +788,9 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
@JvmField
|
||||
val RESTORATION_TANK = create("restoration_tank", RestorationTankBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.GLASS).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops().strength(5.0F, 6.0F).noOcclusion()))
|
||||
|
||||
@JvmField
|
||||
val ROTOM_MONITOR = create("rotom_data_monitor", RotomMonitorBlock(BlockBehaviour.Properties.ofFullCopy(MONITOR)))
|
||||
|
||||
@JvmField
|
||||
val HEALING_MACHINE = create("healing_machine", HealingMachineBlock(BlockBehaviour.Properties.of().mapColor(MapColor.METAL).sound(SoundType.METAL).pushReaction(PushReaction.BLOCK).strength(2F).noOcclusion().lightLevel { if (it.getValue(HealingMachineBlock.CHARGE_LEVEL) >= HealingMachineBlock.MAX_CHARGE_LEVEL) 12 else 5 }))
|
||||
|
||||
@@ -821,6 +820,94 @@ 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).requiresCorrectToolForDrops()))
|
||||
|
||||
//Rotom Blocks
|
||||
//Oven
|
||||
@JvmField
|
||||
val COPPER_OVEN = create("copper_oven", WeatheringCopperOvenBlock(WeatheringCopper.WeatherState.UNAFFECTED, BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_ORANGE).requiresCorrectToolForDrops().strength(3.0f, 6.0f).sound(
|
||||
CobblemonSounds.APPLIANCE_BLOCK_SOUNDS).pushReaction(PushReaction.BLOCK)))
|
||||
@JvmField
|
||||
val EXPOSED_COPPER_OVEN = create("exposed_copper_oven", WeatheringCopperOvenBlock(WeatheringCopper.WeatherState.EXPOSED, BlockBehaviour.Properties.ofFullCopy(COPPER_OVEN).mapColor(MapColor.TERRACOTTA_LIGHT_GRAY)))
|
||||
@JvmField
|
||||
val WEATHERED_COPPER_OVEN = create("weathered_copper_oven", WeatheringCopperOvenBlock(WeatheringCopper.WeatherState.WEATHERED, BlockBehaviour.Properties.ofFullCopy(COPPER_OVEN).mapColor(MapColor.WARPED_STEM)))
|
||||
@JvmField
|
||||
val OXIDIZED_COPPER_OVEN = create("oxidized_copper_oven", WeatheringCopperOvenBlock(WeatheringCopper.WeatherState.OXIDIZED, BlockBehaviour.Properties.ofFullCopy(COPPER_OVEN).mapColor(MapColor.WARPED_NYLIUM)))
|
||||
@JvmField
|
||||
val WAXED_COPPER_OVEN = create("waxed_copper_oven", CopperOvenBlock(BlockBehaviour.Properties.ofFullCopy(COPPER_OVEN)))
|
||||
@JvmField
|
||||
val WAXED_EXPOSED_COPPER_OVEN = create("waxed_exposed_copper_oven", CopperOvenBlock(BlockBehaviour.Properties.ofFullCopy(EXPOSED_COPPER_OVEN)))
|
||||
@JvmField
|
||||
val WAXED_WEATHERED_COPPER_OVEN = create("waxed_weathered_copper_oven", CopperOvenBlock(BlockBehaviour.Properties.ofFullCopy(WEATHERED_COPPER_OVEN)))
|
||||
@JvmField
|
||||
val WAXED_OXIDIZED_COPPER_OVEN = create("waxed_oxidized_copper_oven", CopperOvenBlock(BlockBehaviour.Properties.ofFullCopy(OXIDIZED_COPPER_OVEN)))
|
||||
//Washer
|
||||
@JvmField
|
||||
val COPPER_WASHER = create("copper_washer", WeatheringCopperWasherBlock(WeatheringCopper.WeatherState.UNAFFECTED, BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_ORANGE).requiresCorrectToolForDrops().strength(3.0f, 6.0f).sound(CobblemonSounds.APPLIANCE_BLOCK_SOUNDS).pushReaction(PushReaction.BLOCK)))
|
||||
@JvmField
|
||||
val EXPOSED_COPPER_WASHER = create("exposed_copper_washer", WeatheringCopperWasherBlock(WeatheringCopper.WeatherState.EXPOSED, BlockBehaviour.Properties.ofFullCopy(COPPER_WASHER).mapColor(MapColor.TERRACOTTA_LIGHT_GRAY)))
|
||||
@JvmField
|
||||
val WEATHERED_COPPER_WASHER = create("weathered_copper_washer", WeatheringCopperWasherBlock(WeatheringCopper.WeatherState.WEATHERED, BlockBehaviour.Properties.ofFullCopy(COPPER_WASHER).mapColor(MapColor.WARPED_STEM)))
|
||||
@JvmField
|
||||
val OXIDIZED_COPPER_WASHER = create("oxidized_copper_washer", WeatheringCopperWasherBlock(WeatheringCopper.WeatherState.OXIDIZED, BlockBehaviour.Properties.ofFullCopy(COPPER_WASHER).mapColor(MapColor.WARPED_NYLIUM)))
|
||||
@JvmField
|
||||
val WAXED_COPPER_WASHER = create("waxed_copper_washer", CopperWasherBlock(BlockBehaviour.Properties.ofFullCopy(COPPER_WASHER)))
|
||||
@JvmField
|
||||
val WAXED_EXPOSED_COPPER_WASHER = create("waxed_exposed_copper_washer", CopperWasherBlock(BlockBehaviour.Properties.ofFullCopy(EXPOSED_COPPER_WASHER)))
|
||||
@JvmField
|
||||
val WAXED_WEATHERED_COPPER_WASHER = create("waxed_weathered_copper_washer", CopperWasherBlock(BlockBehaviour.Properties.ofFullCopy(WEATHERED_COPPER_WASHER)))
|
||||
@JvmField
|
||||
val WAXED_OXIDIZED_COPPER_WASHER = create("waxed_oxidized_copper_washer", CopperWasherBlock(BlockBehaviour.Properties.ofFullCopy(OXIDIZED_COPPER_WASHER)))
|
||||
//Fan
|
||||
@JvmField
|
||||
val COPPER_FAN = create("copper_fan", WeatheringCopperFanBlock(WeatheringCopper.WeatherState.UNAFFECTED, BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_ORANGE).requiresCorrectToolForDrops().strength(3.0f, 6.0f).sound(CobblemonSounds.APPLIANCE_BLOCK_SOUNDS).pushReaction(PushReaction.DESTROY)))
|
||||
@JvmField
|
||||
val EXPOSED_COPPER_FAN = create("exposed_copper_fan", WeatheringCopperFanBlock(WeatheringCopper.WeatherState.EXPOSED, BlockBehaviour.Properties.ofFullCopy(COPPER_FAN).mapColor(MapColor.TERRACOTTA_LIGHT_GRAY)))
|
||||
@JvmField
|
||||
val WEATHERED_COPPER_FAN = create("weathered_copper_fan", WeatheringCopperFanBlock(WeatheringCopper.WeatherState.WEATHERED, BlockBehaviour.Properties.ofFullCopy(COPPER_FAN).mapColor(MapColor.WARPED_STEM)))
|
||||
@JvmField
|
||||
val OXIDIZED_COPPER_FAN = create("oxidized_copper_fan", WeatheringCopperFanBlock(WeatheringCopper.WeatherState.OXIDIZED, BlockBehaviour.Properties.ofFullCopy(COPPER_FAN).mapColor(MapColor.WARPED_NYLIUM)))
|
||||
@JvmField
|
||||
val WAXED_COPPER_FAN = create("waxed_copper_fan", CopperFanBlock(BlockBehaviour.Properties.ofFullCopy(COPPER_FAN)))
|
||||
@JvmField
|
||||
val WAXED_EXPOSED_COPPER_FAN = create("waxed_exposed_copper_fan", CopperFanBlock(BlockBehaviour.Properties.ofFullCopy(EXPOSED_COPPER_FAN)))
|
||||
@JvmField
|
||||
val WAXED_WEATHERED_COPPER_FAN = create("waxed_weathered_copper_fan", CopperFanBlock(BlockBehaviour.Properties.ofFullCopy(WEATHERED_COPPER_FAN)))
|
||||
@JvmField
|
||||
val WAXED_OXIDIZED_COPPER_FAN = create("waxed_oxidized_copper_fan", CopperFanBlock(BlockBehaviour.Properties.ofFullCopy(OXIDIZED_COPPER_FAN)))
|
||||
//Mower
|
||||
@JvmField
|
||||
val COPPER_MOWER = create("copper_mower", WeatheringCopperMowerBlock(WeatheringCopper.WeatherState.UNAFFECTED, BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_ORANGE).requiresCorrectToolForDrops().strength(3.0f, 6.0f).sound(CobblemonSounds.APPLIANCE_BLOCK_SOUNDS).pushReaction(PushReaction.NORMAL)))
|
||||
@JvmField
|
||||
val EXPOSED_COPPER_MOWER = create("exposed_copper_mower", WeatheringCopperMowerBlock(WeatheringCopper.WeatherState.EXPOSED, BlockBehaviour.Properties.ofFullCopy(COPPER_MOWER).mapColor(MapColor.TERRACOTTA_LIGHT_GRAY)))
|
||||
@JvmField
|
||||
val WEATHERED_COPPER_MOWER = create("weathered_copper_mower", WeatheringCopperMowerBlock(WeatheringCopper.WeatherState.WEATHERED, BlockBehaviour.Properties.ofFullCopy(COPPER_MOWER).mapColor(MapColor.WARPED_STEM)))
|
||||
@JvmField
|
||||
val OXIDIZED_COPPER_MOWER = create("oxidized_copper_mower", WeatheringCopperMowerBlock(WeatheringCopper.WeatherState.OXIDIZED, BlockBehaviour.Properties.ofFullCopy(COPPER_MOWER).mapColor(MapColor.WARPED_NYLIUM)))
|
||||
@JvmField
|
||||
val WAXED_COPPER_MOWER = create("waxed_copper_mower", CopperMowerBlock(BlockBehaviour.Properties.ofFullCopy(COPPER_MOWER)))
|
||||
@JvmField
|
||||
val WAXED_EXPOSED_COPPER_MOWER = create("waxed_exposed_copper_mower", CopperMowerBlock(BlockBehaviour.Properties.ofFullCopy(EXPOSED_COPPER_MOWER)))
|
||||
@JvmField
|
||||
val WAXED_WEATHERED_COPPER_MOWER = create("waxed_weathered_copper_mower", CopperMowerBlock(BlockBehaviour.Properties.ofFullCopy(WEATHERED_COPPER_MOWER)))
|
||||
@JvmField
|
||||
val WAXED_OXIDIZED_COPPER_MOWER = create("waxed_oxidized_copper_mower", CopperMowerBlock(BlockBehaviour.Properties.ofFullCopy(OXIDIZED_COPPER_MOWER)))
|
||||
//Fridge
|
||||
@JvmField
|
||||
val COPPER_FRIDGE = create("copper_fridge", WeatheringCopperFridgeBlock(WeatheringCopper.WeatherState.UNAFFECTED, BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_ORANGE).requiresCorrectToolForDrops().strength(3.0f, 6.0f).sound(CobblemonSounds.APPLIANCE_BLOCK_SOUNDS).pushReaction(PushReaction.BLOCK)))
|
||||
@JvmField
|
||||
val EXPOSED_COPPER_FRIDGE = create("exposed_copper_fridge", WeatheringCopperFridgeBlock(WeatheringCopper.WeatherState.EXPOSED, BlockBehaviour.Properties.ofFullCopy(COPPER_FRIDGE).mapColor(MapColor.TERRACOTTA_LIGHT_GRAY)))
|
||||
@JvmField
|
||||
val WEATHERED_COPPER_FRIDGE = create("weathered_copper_fridge", WeatheringCopperFridgeBlock(WeatheringCopper.WeatherState.WEATHERED, BlockBehaviour.Properties.ofFullCopy(COPPER_FRIDGE).mapColor(MapColor.WARPED_STEM)))
|
||||
@JvmField
|
||||
val OXIDIZED_COPPER_FRIDGE = create("oxidized_copper_fridge", WeatheringCopperFridgeBlock(WeatheringCopper.WeatherState.OXIDIZED, BlockBehaviour.Properties.ofFullCopy(COPPER_FRIDGE).mapColor(MapColor.WARPED_NYLIUM)))
|
||||
@JvmField
|
||||
val WAXED_COPPER_FRIDGE = create("waxed_copper_fridge", CopperFridgeBlock(BlockBehaviour.Properties.ofFullCopy(COPPER_FRIDGE)))
|
||||
@JvmField
|
||||
val WAXED_EXPOSED_COPPER_FRIDGE = create("waxed_exposed_copper_fridge", CopperFridgeBlock(BlockBehaviour.Properties.ofFullCopy(EXPOSED_COPPER_FRIDGE)))
|
||||
@JvmField
|
||||
val WAXED_WEATHERED_COPPER_FRIDGE = create("waxed_weathered_copper_fridge", CopperFridgeBlock(BlockBehaviour.Properties.ofFullCopy(WEATHERED_COPPER_FRIDGE)))
|
||||
@JvmField
|
||||
val WAXED_OXIDIZED_COPPER_FRIDGE = create("waxed_oxidized_copper_fridge", CopperFridgeBlock(BlockBehaviour.Properties.ofFullCopy(OXIDIZED_COPPER_FRIDGE)))
|
||||
|
||||
// TODO after 1.7
|
||||
// @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)))
|
||||
@@ -845,54 +932,34 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
@JvmField
|
||||
val PEP_UP_FLOWER = this.create("pep_up_flower", FlowerBlock(MobEffects.LEVITATION, 10F, BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).noCollission().instabreak().sound(SoundType.GRASS).offsetType(BlockBehaviour.OffsetType.XZ).pushReaction(PushReaction.DESTROY)))
|
||||
@JvmField
|
||||
val POTTED_PEP_UP_FLOWER = this.create("potted_pep_up_flower", BlocksInvoker.createFlowerPotBlock(PEP_UP_FLOWER))
|
||||
@JvmField
|
||||
val HEARTY_GRAINS = this.create("hearty_grains", HeartyGrainsBlock(BlockBehaviour.Properties.of().pushReaction(PushReaction.DESTROY).ignitedByLava().mapColor(MapColor.PLANT).noCollission().randomTicks().instabreak()))
|
||||
|
||||
@JvmField
|
||||
val GALARICA_NUT_BUSH = this.create("galarica_nut_bush", NutBushBlock(BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).randomTicks().noCollission().sound(SoundType.SWEET_BERRY_BUSH).pushReaction(PushReaction.DESTROY)))
|
||||
|
||||
@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 RED_MINT_LEAF_LITTER = this.mintLitter("red_mint_leaf_litter", MapColor.COLOR_RED)
|
||||
@JvmField
|
||||
val POTTED_RED_MINT = this.pottedPlant("potted_red_mint", RED_MINT_LEAF_LITTER)
|
||||
val POTTED_RED_MINT = this.flowerPot("potted_red_mint", RED_MINT_LEAF_LITTER)
|
||||
@JvmField
|
||||
val BLUE_MINT_LEAF_LITTER = this.mintLitter("blue_mint_leaf_litter", MapColor.COLOR_BLUE)
|
||||
@JvmField
|
||||
val POTTED_BLUE_MINT = this.pottedPlant("potted_blue_mint", BLUE_MINT_LEAF_LITTER)
|
||||
val POTTED_BLUE_MINT = this.flowerPot("potted_blue_mint", BLUE_MINT_LEAF_LITTER)
|
||||
@JvmField
|
||||
val CYAN_MINT_LEAF_LITTER = this.mintLitter("cyan_mint_leaf_litter", MapColor.COLOR_CYAN)
|
||||
@JvmField
|
||||
val POTTED_CYAN_MINT = this.pottedPlant("potted_cyan_mint", CYAN_MINT_LEAF_LITTER)
|
||||
val POTTED_CYAN_MINT = this.flowerPot("potted_cyan_mint", CYAN_MINT_LEAF_LITTER)
|
||||
@JvmField
|
||||
val PINK_MINT_LEAF_LITTER = this.mintLitter("pink_mint_leaf_litter", MapColor.COLOR_PINK)
|
||||
@JvmField
|
||||
val POTTED_PINK_MINT = this.pottedPlant("potted_pink_mint", PINK_MINT_LEAF_LITTER)
|
||||
val POTTED_PINK_MINT = this.flowerPot("potted_pink_mint", PINK_MINT_LEAF_LITTER)
|
||||
@JvmField
|
||||
val GREEN_MINT_LEAF_LITTER = this.mintLitter("green_mint_leaf_litter", MapColor.COLOR_GREEN)
|
||||
@JvmField
|
||||
val POTTED_GREEN_MINT = this.pottedPlant("potted_green_mint", GREEN_MINT_LEAF_LITTER)
|
||||
val POTTED_GREEN_MINT = this.flowerPot("potted_green_mint", GREEN_MINT_LEAF_LITTER)
|
||||
@JvmField
|
||||
val WHITE_MINT_LEAF_LITTER = this.mintLitter("white_mint_leaf_litter", MapColor.SNOW)
|
||||
@JvmField
|
||||
val POTTED_WHITE_MINT = this.pottedPlant("potted_white_mint", WHITE_MINT_LEAF_LITTER)
|
||||
val POTTED_WHITE_MINT = this.flowerPot("potted_white_mint", WHITE_MINT_LEAF_LITTER)
|
||||
|
||||
@JvmField
|
||||
val LOBAILA = this.create("lobaila", LobailaFlowerBlock(BlockBehaviour.Properties.of().mapColor(MapColor.PLANT).noCollission().instabreak().sound(SoundType.GRASS).offsetType(BlockBehaviour.OffsetType.XZ).ignitedByLava().pushReaction(PushReaction.DESTROY)))
|
||||
@@ -946,6 +1013,57 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
SACCHARINE_LOG to STRIPPED_SACCHARINE_LOG,
|
||||
SACCHARINE_LOG_SLATHERED to STRIPPED_SACCHARINE_LOG
|
||||
)
|
||||
/**Same idea as above, but for Copper Oxidation over time (or when inverted, scraping with an axe)*/
|
||||
fun oxidizingBlocks(): Map<Block, Block> = mapOf(
|
||||
//Ovens
|
||||
COPPER_OVEN to EXPOSED_COPPER_OVEN,
|
||||
EXPOSED_COPPER_OVEN to WEATHERED_COPPER_OVEN,
|
||||
WEATHERED_COPPER_OVEN to OXIDIZED_COPPER_OVEN,
|
||||
//Washers
|
||||
COPPER_WASHER to EXPOSED_COPPER_WASHER,
|
||||
EXPOSED_COPPER_WASHER to WEATHERED_COPPER_WASHER,
|
||||
WEATHERED_COPPER_WASHER to OXIDIZED_COPPER_WASHER,
|
||||
//Fans
|
||||
COPPER_FAN to EXPOSED_COPPER_FAN,
|
||||
EXPOSED_COPPER_FAN to WEATHERED_COPPER_FAN,
|
||||
WEATHERED_COPPER_FAN to OXIDIZED_COPPER_FAN,
|
||||
//Fridges
|
||||
COPPER_FRIDGE to EXPOSED_COPPER_FRIDGE,
|
||||
EXPOSED_COPPER_FRIDGE to WEATHERED_COPPER_FRIDGE,
|
||||
WEATHERED_COPPER_FRIDGE to OXIDIZED_COPPER_FRIDGE,
|
||||
//Mowers
|
||||
COPPER_MOWER to EXPOSED_COPPER_MOWER,
|
||||
EXPOSED_COPPER_MOWER to WEATHERED_COPPER_MOWER,
|
||||
WEATHERED_COPPER_MOWER to OXIDIZED_COPPER_MOWER
|
||||
)
|
||||
/**Same idea as above, but for waxing blocks with Honeycomb (or unwaxing them with an axe)*/
|
||||
fun waxingBlocks(): Map<Block, Block> = mapOf(
|
||||
//Ovens
|
||||
COPPER_OVEN to WAXED_COPPER_OVEN,
|
||||
EXPOSED_COPPER_OVEN to WAXED_EXPOSED_COPPER_OVEN,
|
||||
WEATHERED_COPPER_OVEN to WAXED_WEATHERED_COPPER_OVEN,
|
||||
OXIDIZED_COPPER_OVEN to WAXED_OXIDIZED_COPPER_OVEN,
|
||||
//Washers
|
||||
COPPER_WASHER to WAXED_COPPER_WASHER,
|
||||
EXPOSED_COPPER_WASHER to WAXED_EXPOSED_COPPER_WASHER,
|
||||
WEATHERED_COPPER_WASHER to WAXED_WEATHERED_COPPER_WASHER,
|
||||
OXIDIZED_COPPER_WASHER to WAXED_OXIDIZED_COPPER_WASHER,
|
||||
//Fans
|
||||
COPPER_FAN to WAXED_COPPER_FAN,
|
||||
EXPOSED_COPPER_FAN to WAXED_EXPOSED_COPPER_FAN,
|
||||
WEATHERED_COPPER_FAN to WAXED_WEATHERED_COPPER_FAN,
|
||||
OXIDIZED_COPPER_FAN to WAXED_OXIDIZED_COPPER_FAN,
|
||||
//Fridges
|
||||
COPPER_FRIDGE to WAXED_COPPER_FRIDGE,
|
||||
EXPOSED_COPPER_FRIDGE to WAXED_EXPOSED_COPPER_FRIDGE,
|
||||
WEATHERED_COPPER_FRIDGE to WAXED_WEATHERED_COPPER_FRIDGE,
|
||||
OXIDIZED_COPPER_FRIDGE to WAXED_OXIDIZED_COPPER_FRIDGE,
|
||||
//Mowers
|
||||
COPPER_MOWER to WAXED_COPPER_MOWER,
|
||||
EXPOSED_COPPER_MOWER to WAXED_EXPOSED_COPPER_MOWER,
|
||||
WEATHERED_COPPER_MOWER to WAXED_WEATHERED_COPPER_MOWER,
|
||||
OXIDIZED_COPPER_MOWER to WAXED_OXIDIZED_COPPER_MOWER
|
||||
)
|
||||
|
||||
private fun apricornBlock(name: String, apricorn: Apricorn): ApricornBlock = this.create(name, ApricornBlock(BlockBehaviour.Properties.of().mapColor(apricorn.mapColor()).randomTicks().strength(Blocks.OAK_LOG.defaultDestroyTime(), Blocks.OAK_LOG.explosionResistance).sound(SoundType.WOOD).noOcclusion(), apricorn))
|
||||
|
||||
@@ -1104,145 +1222,163 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
//val BINDING_SOIL = this.create("binding_soil", BindingSoilBlock(BlockBehaviour.Properties.of()))
|
||||
|
||||
@JvmField
|
||||
val POTTED_AGUAV_BERRY = this.create("potted_aguav_berry", BlocksInvoker.createFlowerPotBlock(AGUAV_BERRY))
|
||||
val POTTED_AGUAV_BERRY = this.flowerPot("potted_aguav_berry", AGUAV_BERRY)
|
||||
@JvmField
|
||||
val POTTED_APICOT_BERRY = this.create("potted_apicot_berry", BlocksInvoker.createFlowerPotBlock(APICOT_BERRY))
|
||||
val POTTED_APICOT_BERRY = this.flowerPot("potted_apicot_berry", APICOT_BERRY)
|
||||
@JvmField
|
||||
val POTTED_ASPEAR_BERRY = this.create("potted_aspear_berry", BlocksInvoker.createFlowerPotBlock(ASPEAR_BERRY))
|
||||
val POTTED_ASPEAR_BERRY = this.flowerPot("potted_aspear_berry", ASPEAR_BERRY)
|
||||
@JvmField
|
||||
val POTTED_BABIRI_BERRY = this.create("potted_babiri_berry", BlocksInvoker.createFlowerPotBlock(BABIRI_BERRY))
|
||||
val POTTED_BABIRI_BERRY = this.flowerPot("potted_babiri_berry", BABIRI_BERRY)
|
||||
@JvmField
|
||||
val POTTED_BELUE_BERRY = this.create("potted_belue_berry", BlocksInvoker.createFlowerPotBlock(BELUE_BERRY))
|
||||
val POTTED_BELUE_BERRY = this.flowerPot("potted_belue_berry", BELUE_BERRY)
|
||||
@JvmField
|
||||
val POTTED_BLUK_BERRY = this.create("potted_bluk_berry", BlocksInvoker.createFlowerPotBlock(BLUK_BERRY))
|
||||
val POTTED_BLUK_BERRY = this.flowerPot("potted_bluk_berry", BLUK_BERRY)
|
||||
@JvmField
|
||||
val POTTED_CHARTI_BERRY = this.create("potted_charti_berry", BlocksInvoker.createFlowerPotBlock(CHARTI_BERRY))
|
||||
val POTTED_CHARTI_BERRY = this.flowerPot("potted_charti_berry", CHARTI_BERRY)
|
||||
@JvmField
|
||||
val POTTED_CHERI_BERRY = this.create("potted_cheri_berry", BlocksInvoker.createFlowerPotBlock(CHERI_BERRY))
|
||||
val POTTED_CHERI_BERRY = this.flowerPot("potted_cheri_berry", CHERI_BERRY)
|
||||
@JvmField
|
||||
val POTTED_CHESTO_BERRY = this.create("potted_chesto_berry", BlocksInvoker.createFlowerPotBlock(CHESTO_BERRY))
|
||||
val POTTED_CHESTO_BERRY = this.flowerPot("potted_chesto_berry", CHESTO_BERRY)
|
||||
@JvmField
|
||||
val POTTED_CHILAN_BERRY = this.create("potted_chilan_berry", BlocksInvoker.createFlowerPotBlock(CHILAN_BERRY))
|
||||
val POTTED_CHILAN_BERRY = this.flowerPot("potted_chilan_berry", CHILAN_BERRY)
|
||||
@JvmField
|
||||
val POTTED_CHOPLE_BERRY = this.create("potted_chople_berry", BlocksInvoker.createFlowerPotBlock(CHOPLE_BERRY))
|
||||
val POTTED_CHOPLE_BERRY = this.flowerPot("potted_chople_berry", CHOPLE_BERRY)
|
||||
@JvmField
|
||||
val POTTED_COBA_BERRY = this.create("potted_coba_berry", BlocksInvoker.createFlowerPotBlock(COBA_BERRY))
|
||||
val POTTED_COBA_BERRY = this.flowerPot("potted_coba_berry", COBA_BERRY)
|
||||
@JvmField
|
||||
val POTTED_COLBUR_BERRY = this.create("potted_colbur_berry", BlocksInvoker.createFlowerPotBlock(COLBUR_BERRY))
|
||||
val POTTED_COLBUR_BERRY = this.flowerPot("potted_colbur_berry", COLBUR_BERRY)
|
||||
@JvmField
|
||||
val POTTED_CORNN_BERRY = this.create("potted_cornn_berry", BlocksInvoker.createFlowerPotBlock(CORNN_BERRY))
|
||||
val POTTED_CORNN_BERRY = this.flowerPot("potted_cornn_berry", CORNN_BERRY)
|
||||
@JvmField
|
||||
val POTTED_CUSTAP_BERRY = this.create("potted_custap_berry", BlocksInvoker.createFlowerPotBlock(CUSTAP_BERRY))
|
||||
val POTTED_CUSTAP_BERRY = this.flowerPot("potted_custap_berry", CUSTAP_BERRY)
|
||||
@JvmField
|
||||
val POTTED_DURIN_BERRY = this.create("potted_durin_berry", BlocksInvoker.createFlowerPotBlock(DURIN_BERRY))
|
||||
val POTTED_DURIN_BERRY = this.flowerPot("potted_durin_berry", DURIN_BERRY)
|
||||
@JvmField
|
||||
val POTTED_EGGANT_BERRY = this.create("potted_eggant_berry", BlocksInvoker.createFlowerPotBlock(EGGANT_BERRY))
|
||||
val POTTED_EGGANT_BERRY = this.flowerPot("potted_eggant_berry", EGGANT_BERRY)
|
||||
@JvmField
|
||||
val POTTED_ENIGMA_BERRY = this.create("potted_enigma_berry", BlocksInvoker.createFlowerPotBlock(ENIGMA_BERRY))
|
||||
val POTTED_ENIGMA_BERRY = this.flowerPot("potted_enigma_berry", ENIGMA_BERRY)
|
||||
@JvmField
|
||||
val POTTED_FIGY_BERRY = this.create("potted_figy_berry", BlocksInvoker.createFlowerPotBlock(FIGY_BERRY))
|
||||
val POTTED_FIGY_BERRY = this.flowerPot("potted_figy_berry", FIGY_BERRY)
|
||||
@JvmField
|
||||
val POTTED_GANLON_BERRY = this.create("potted_ganlon_berry", BlocksInvoker.createFlowerPotBlock(GANLON_BERRY))
|
||||
val POTTED_GANLON_BERRY = this.flowerPot("potted_ganlon_berry", GANLON_BERRY)
|
||||
@JvmField
|
||||
val POTTED_GREPA_BERRY = this.create("potted_grepa_berry", BlocksInvoker.createFlowerPotBlock(GREPA_BERRY))
|
||||
val POTTED_GREPA_BERRY = this.flowerPot("potted_grepa_berry", GREPA_BERRY)
|
||||
@JvmField
|
||||
val POTTED_HABAN_BERRY = this.create("potted_haban_berry", BlocksInvoker.createFlowerPotBlock(HABAN_BERRY))
|
||||
val POTTED_HABAN_BERRY = this.flowerPot("potted_haban_berry", HABAN_BERRY)
|
||||
@JvmField
|
||||
val POTTED_HONDEW_BERRY = this.create("potted_hondew_berry", BlocksInvoker.createFlowerPotBlock(HONDEW_BERRY))
|
||||
val POTTED_HONDEW_BERRY = this.flowerPot("potted_hondew_berry", HONDEW_BERRY)
|
||||
@JvmField
|
||||
val POTTED_HOPO_BERRY = this.create("potted_hopo_berry", BlocksInvoker.createFlowerPotBlock(HOPO_BERRY))
|
||||
val POTTED_HOPO_BERRY = this.flowerPot("potted_hopo_berry", HOPO_BERRY)
|
||||
@JvmField
|
||||
val POTTED_IAPAPA_BERRY = this.create("potted_iapapa_berry", BlocksInvoker.createFlowerPotBlock(IAPAPA_BERRY))
|
||||
val POTTED_IAPAPA_BERRY = this.flowerPot("potted_iapapa_berry", IAPAPA_BERRY)
|
||||
@JvmField
|
||||
val POTTED_JABOCA_BERRY = this.create("potted_jaboca_berry", BlocksInvoker.createFlowerPotBlock(JABOCA_BERRY))
|
||||
val POTTED_JABOCA_BERRY = this.flowerPot("potted_jaboca_berry", JABOCA_BERRY)
|
||||
@JvmField
|
||||
val POTTED_KASIB_BERRY = this.create("potted_kasib_berry", BlocksInvoker.createFlowerPotBlock(KASIB_BERRY))
|
||||
val POTTED_KASIB_BERRY = this.flowerPot("potted_kasib_berry", KASIB_BERRY)
|
||||
@JvmField
|
||||
val POTTED_KEBIA_BERRY = this.create("potted_kebia_berry", BlocksInvoker.createFlowerPotBlock(KEBIA_BERRY))
|
||||
val POTTED_KEBIA_BERRY = this.flowerPot("potted_kebia_berry", KEBIA_BERRY)
|
||||
@JvmField
|
||||
val POTTED_KEE_BERRY = this.create("potted_kee_berry", BlocksInvoker.createFlowerPotBlock(KEE_BERRY))
|
||||
val POTTED_KEE_BERRY = this.flowerPot("potted_kee_berry", KEE_BERRY)
|
||||
@JvmField
|
||||
val POTTED_KELPSY_BERRY = this.create("potted_kelpsy_berry", BlocksInvoker.createFlowerPotBlock(KELPSY_BERRY))
|
||||
val POTTED_KELPSY_BERRY = this.flowerPot("potted_kelpsy_berry", KELPSY_BERRY)
|
||||
@JvmField
|
||||
val POTTED_LANSAT_BERRY = this.create("potted_lansat_berry", BlocksInvoker.createFlowerPotBlock(LANSAT_BERRY))
|
||||
val POTTED_LANSAT_BERRY = this.flowerPot("potted_lansat_berry", LANSAT_BERRY)
|
||||
@JvmField
|
||||
val POTTED_LEPPA_BERRY = this.create("potted_leppa_berry", BlocksInvoker.createFlowerPotBlock(LEPPA_BERRY))
|
||||
val POTTED_LEPPA_BERRY = this.flowerPot("potted_leppa_berry", LEPPA_BERRY)
|
||||
@JvmField
|
||||
val POTTED_LIECHI_BERRY = this.create("potted_liechi_berry", BlocksInvoker.createFlowerPotBlock(LIECHI_BERRY))
|
||||
val POTTED_LIECHI_BERRY = this.flowerPot("potted_liechi_berry", LIECHI_BERRY)
|
||||
@JvmField
|
||||
val POTTED_LUM_BERRY = this.create("potted_lum_berry", BlocksInvoker.createFlowerPotBlock(LUM_BERRY))
|
||||
val POTTED_LUM_BERRY = this.flowerPot("potted_lum_berry", LUM_BERRY)
|
||||
@JvmField
|
||||
val POTTED_MAGO_BERRY = this.create("potted_mago_berry", BlocksInvoker.createFlowerPotBlock(MAGO_BERRY))
|
||||
val POTTED_MAGO_BERRY = this.flowerPot("potted_mago_berry", MAGO_BERRY)
|
||||
@JvmField
|
||||
val POTTED_MAGOST_BERRY = this.create("potted_magost_berry", BlocksInvoker.createFlowerPotBlock(MAGOST_BERRY))
|
||||
val POTTED_MAGOST_BERRY = this.flowerPot("potted_magost_berry", MAGOST_BERRY)
|
||||
@JvmField
|
||||
val POTTED_MARANGA_BERRY = this.create("potted_maranga_berry", BlocksInvoker.createFlowerPotBlock(MARANGA_BERRY))
|
||||
val POTTED_MARANGA_BERRY = this.flowerPot("potted_maranga_berry", MARANGA_BERRY)
|
||||
@JvmField
|
||||
val POTTED_MICLE_BERRY = this.create("potted_micle_berry", BlocksInvoker.createFlowerPotBlock(MICLE_BERRY))
|
||||
val POTTED_MICLE_BERRY = this.flowerPot("potted_micle_berry", MICLE_BERRY)
|
||||
@JvmField
|
||||
val POTTED_NANAB_BERRY = this.create("potted_nanab_berry", BlocksInvoker.createFlowerPotBlock(NANAB_BERRY))
|
||||
val POTTED_NANAB_BERRY = this.flowerPot("potted_nanab_berry", NANAB_BERRY)
|
||||
@JvmField
|
||||
val POTTED_NOMEL_BERRY = this.create("potted_nomel_berry", BlocksInvoker.createFlowerPotBlock(NOMEL_BERRY))
|
||||
val POTTED_NOMEL_BERRY = this.flowerPot("potted_nomel_berry", NOMEL_BERRY)
|
||||
@JvmField
|
||||
val POTTED_OCCA_BERRY = this.create("potted_occa_berry", BlocksInvoker.createFlowerPotBlock(OCCA_BERRY))
|
||||
val POTTED_OCCA_BERRY = this.flowerPot("potted_occa_berry", OCCA_BERRY)
|
||||
@JvmField
|
||||
val POTTED_ORAN_BERRY = this.create("potted_oran_berry", BlocksInvoker.createFlowerPotBlock(ORAN_BERRY))
|
||||
val POTTED_ORAN_BERRY = this.flowerPot("potted_oran_berry", ORAN_BERRY)
|
||||
@JvmField
|
||||
val POTTED_PAMTRE_BERRY = this.create("potted_pamtre_berry", BlocksInvoker.createFlowerPotBlock(PAMTRE_BERRY))
|
||||
val POTTED_PAMTRE_BERRY = this.flowerPot("potted_pamtre_berry", PAMTRE_BERRY)
|
||||
@JvmField
|
||||
val POTTED_PASSHO_BERRY = this.create("potted_passho_berry", BlocksInvoker.createFlowerPotBlock(PASSHO_BERRY))
|
||||
val POTTED_PASSHO_BERRY = this.flowerPot("potted_passho_berry", PASSHO_BERRY)
|
||||
@JvmField
|
||||
val POTTED_PAYAPA_BERRY = this.create("potted_payapa_berry", BlocksInvoker.createFlowerPotBlock(PAYAPA_BERRY))
|
||||
val POTTED_PAYAPA_BERRY = this.flowerPot("potted_payapa_berry", PAYAPA_BERRY)
|
||||
@JvmField
|
||||
val POTTED_PECHA_BERRY = this.create("potted_pecha_berry", BlocksInvoker.createFlowerPotBlock(PECHA_BERRY))
|
||||
val POTTED_PECHA_BERRY = this.flowerPot("potted_pecha_berry", PECHA_BERRY)
|
||||
@JvmField
|
||||
val POTTED_PERSIM_BERRY = this.create("potted_persim_berry", BlocksInvoker.createFlowerPotBlock(PERSIM_BERRY))
|
||||
val POTTED_PERSIM_BERRY = this.flowerPot("potted_persim_berry", PERSIM_BERRY)
|
||||
@JvmField
|
||||
val POTTED_PETAYA_BERRY = this.create("potted_petaya_berry", BlocksInvoker.createFlowerPotBlock(PETAYA_BERRY))
|
||||
val POTTED_PETAYA_BERRY = this.flowerPot("potted_petaya_berry", PETAYA_BERRY)
|
||||
@JvmField
|
||||
val POTTED_PINAP_BERRY = this.create("potted_pinap_berry", BlocksInvoker.createFlowerPotBlock(PINAP_BERRY))
|
||||
val POTTED_PINAP_BERRY = this.flowerPot("potted_pinap_berry", PINAP_BERRY)
|
||||
@JvmField
|
||||
val POTTED_POMEG_BERRY = this.create("potted_pomeg_berry", BlocksInvoker.createFlowerPotBlock(POMEG_BERRY))
|
||||
val POTTED_POMEG_BERRY = this.flowerPot("potted_pomeg_berry", POMEG_BERRY)
|
||||
@JvmField
|
||||
val POTTED_QUALOT_BERRY = this.create("potted_qualot_berry", BlocksInvoker.createFlowerPotBlock(QUALOT_BERRY))
|
||||
val POTTED_QUALOT_BERRY = this.flowerPot("potted_qualot_berry", QUALOT_BERRY)
|
||||
@JvmField
|
||||
val POTTED_RABUTA_BERRY = this.create("potted_rabuta_berry", BlocksInvoker.createFlowerPotBlock(RABUTA_BERRY))
|
||||
val POTTED_RABUTA_BERRY = this.flowerPot("potted_rabuta_berry", RABUTA_BERRY)
|
||||
@JvmField
|
||||
val POTTED_RAWST_BERRY = this.create("potted_rawst_berry", BlocksInvoker.createFlowerPotBlock(RAWST_BERRY))
|
||||
val POTTED_RAWST_BERRY = this.flowerPot("potted_rawst_berry", RAWST_BERRY)
|
||||
@JvmField
|
||||
val POTTED_RAZZ_BERRY = this.create("potted_razz_berry", BlocksInvoker.createFlowerPotBlock(RAZZ_BERRY))
|
||||
val POTTED_RAZZ_BERRY = this.flowerPot("potted_razz_berry", RAZZ_BERRY)
|
||||
@JvmField
|
||||
val POTTED_RINDO_BERRY = this.create("potted_rindo_berry", BlocksInvoker.createFlowerPotBlock(RINDO_BERRY))
|
||||
val POTTED_RINDO_BERRY = this.flowerPot("potted_rindo_berry", RINDO_BERRY)
|
||||
@JvmField
|
||||
val POTTED_ROSELI_BERRY = this.create("potted_roseli_berry", BlocksInvoker.createFlowerPotBlock(ROSELI_BERRY))
|
||||
val POTTED_ROSELI_BERRY = this.flowerPot("potted_roseli_berry", ROSELI_BERRY)
|
||||
@JvmField
|
||||
val POTTED_ROWAP_BERRY = this.create("potted_rowap_berry", BlocksInvoker.createFlowerPotBlock(ROWAP_BERRY))
|
||||
val POTTED_ROWAP_BERRY = this.flowerPot("potted_rowap_berry", ROWAP_BERRY)
|
||||
@JvmField
|
||||
val POTTED_SALAC_BERRY = this.create("potted_salac_berry", BlocksInvoker.createFlowerPotBlock(SALAC_BERRY))
|
||||
val POTTED_SALAC_BERRY = this.flowerPot("potted_salac_berry", SALAC_BERRY)
|
||||
@JvmField
|
||||
val POTTED_SHUCA_BERRY = this.create("potted_shuca_berry", BlocksInvoker.createFlowerPotBlock(SHUCA_BERRY))
|
||||
val POTTED_SHUCA_BERRY = this.flowerPot("potted_shuca_berry", SHUCA_BERRY)
|
||||
@JvmField
|
||||
val POTTED_SITRUS_BERRY = this.create("potted_sitrus_berry", BlocksInvoker.createFlowerPotBlock(SITRUS_BERRY))
|
||||
val POTTED_SITRUS_BERRY = this.flowerPot("potted_sitrus_berry", SITRUS_BERRY)
|
||||
@JvmField
|
||||
val POTTED_SPELON_BERRY = this.create("potted_spelon_berry", BlocksInvoker.createFlowerPotBlock(SPELON_BERRY))
|
||||
val POTTED_SPELON_BERRY = this.flowerPot("potted_spelon_berry", SPELON_BERRY)
|
||||
@JvmField
|
||||
val POTTED_STARF_BERRY = this.create("potted_starf_berry", BlocksInvoker.createFlowerPotBlock(STARF_BERRY))
|
||||
val POTTED_STARF_BERRY = this.flowerPot("potted_starf_berry", STARF_BERRY)
|
||||
@JvmField
|
||||
val POTTED_TAMATO_BERRY = this.create("potted_tamato_berry", BlocksInvoker.createFlowerPotBlock(TAMATO_BERRY))
|
||||
val POTTED_TAMATO_BERRY = this.flowerPot("potted_tamato_berry", TAMATO_BERRY)
|
||||
@JvmField
|
||||
val POTTED_TANGA_BERRY = this.create("potted_tanga_berry", BlocksInvoker.createFlowerPotBlock(TANGA_BERRY))
|
||||
val POTTED_TANGA_BERRY = this.flowerPot("potted_tanga_berry", TANGA_BERRY)
|
||||
@JvmField
|
||||
val POTTED_TOUGA_BERRY = this.create("potted_touga_berry", BlocksInvoker.createFlowerPotBlock(TOUGA_BERRY))
|
||||
val POTTED_TOUGA_BERRY = this.flowerPot("potted_touga_berry", TOUGA_BERRY)
|
||||
@JvmField
|
||||
val POTTED_WACAN_BERRY = this.create("potted_wacan_berry", BlocksInvoker.createFlowerPotBlock(WACAN_BERRY))
|
||||
val POTTED_WACAN_BERRY = this.flowerPot("potted_wacan_berry", WACAN_BERRY)
|
||||
@JvmField
|
||||
val POTTED_WATMEL_BERRY = this.create("potted_watmel_berry", BlocksInvoker.createFlowerPotBlock(WATMEL_BERRY))
|
||||
val POTTED_WATMEL_BERRY = this.flowerPot("potted_watmel_berry", WATMEL_BERRY)
|
||||
@JvmField
|
||||
val POTTED_WEPEAR_BERRY = this.create("potted_wepear_berry", BlocksInvoker.createFlowerPotBlock(WEPEAR_BERRY))
|
||||
val POTTED_WEPEAR_BERRY = this.flowerPot("potted_wepear_berry", WEPEAR_BERRY)
|
||||
@JvmField
|
||||
val POTTED_WIKI_BERRY = this.create("potted_wiki_berry", BlocksInvoker.createFlowerPotBlock(WIKI_BERRY))
|
||||
val POTTED_WIKI_BERRY = this.flowerPot("potted_wiki_berry", WIKI_BERRY)
|
||||
@JvmField
|
||||
val POTTED_YACHE_BERRY = this.create("potted_yache_berry", BlocksInvoker.createFlowerPotBlock(YACHE_BERRY))
|
||||
val POTTED_YACHE_BERRY = this.flowerPot("potted_yache_berry", YACHE_BERRY)
|
||||
@JvmField
|
||||
val POTTED_PEP_UP_FLOWER = this.flowerPot("potted_pep_up_flower", PEP_UP_FLOWER)
|
||||
@JvmField
|
||||
val POTTED_RED_APRICORN_SAPLING = this.flowerPot("potted_red_apricorn_sapling", RED_APRICORN_SAPLING)
|
||||
@JvmField
|
||||
val POTTED_YELLOW_APRICORN_SAPLING = this.flowerPot("potted_yellow_apricorn_sapling", YELLOW_APRICORN_SAPLING)
|
||||
@JvmField
|
||||
val POTTED_GREEN_APRICORN_SAPLING = this.flowerPot("potted_green_apricorn_sapling", GREEN_APRICORN_SAPLING)
|
||||
@JvmField
|
||||
val POTTED_BLUE_APRICORN_SAPLING = this.flowerPot("potted_blue_apricorn_sapling", BLUE_APRICORN_SAPLING)
|
||||
@JvmField
|
||||
val POTTED_PINK_APRICORN_SAPLING = this.flowerPot("potted_pink_apricorn_sapling", PINK_APRICORN_SAPLING)
|
||||
@JvmField
|
||||
val POTTED_BLACK_APRICORN_SAPLING = this.flowerPot("potted_black_apricorn_sapling", BLACK_APRICORN_SAPLING)
|
||||
@JvmField
|
||||
val POTTED_WHITE_APRICORN_SAPLING = this.flowerPot("potted_white_apricorn_sapling", WHITE_APRICORN_SAPLING)
|
||||
@JvmField
|
||||
val POTTED_SACCHARINE_SAPLING = this.flowerPot("potted_saccharine_sapling", SACCHARINE_SAPLING)
|
||||
|
||||
init {
|
||||
/**
|
||||
@@ -1346,7 +1482,16 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, ResourceKey<Registry<
|
||||
|
||||
fun typeGemClusters() = typeGemClusters.toMap()
|
||||
|
||||
private fun pottedPlant(name: String, flower: Block) = this.create(name, BlocksInvoker.createFlowerPotBlock(flower))
|
||||
private fun flowerPot(name: String, flower: Block) = this.create(
|
||||
name,
|
||||
FlowerPotBlock(
|
||||
flower,
|
||||
BlockBehaviour.Properties.of()
|
||||
.instabreak()
|
||||
.noOcclusion()
|
||||
.pushReaction(PushReaction.DESTROY)
|
||||
)
|
||||
)
|
||||
|
||||
private fun mintLitter(name: String, color: MapColor) = this.create(
|
||||
name,
|
||||
|
||||
@@ -454,6 +454,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val DAMAGED_MONITOR = blockItem("damaged_monitor", CobblemonBlocks.DAMAGED_MONITOR)
|
||||
@JvmField
|
||||
val ROTOM_MONITOR = blockItem("rotom_data_monitor", CobblemonBlocks.ROTOM_MONITOR)
|
||||
@JvmField
|
||||
val HEALING_MACHINE = blockItem("healing_machine", CobblemonBlocks.HEALING_MACHINE, Rarity.UNCOMMON)
|
||||
@JvmField
|
||||
val PC = blockItem("pc", CobblemonBlocks.PC)
|
||||
@@ -1517,6 +1519,87 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, ResourceKey<Registry<It
|
||||
@JvmField
|
||||
val BLANK_TM = this.create("blank_tm", CobblemonItem(Item.Properties()))
|
||||
|
||||
@JvmField
|
||||
val COPPER_OVEN = this.create("copper_oven", BlockItem(CobblemonBlocks.COPPER_OVEN, Item.Properties()))
|
||||
@JvmField
|
||||
val EXPOSED_COPPER_OVEN = this.create("exposed_copper_oven", BlockItem(CobblemonBlocks.EXPOSED_COPPER_OVEN, Item.Properties()))
|
||||
@JvmField
|
||||
val WEATHERED_COPPER_OVEN = this.create("weathered_copper_oven", BlockItem(CobblemonBlocks.WEATHERED_COPPER_OVEN, Item.Properties()))
|
||||
@JvmField
|
||||
val OXIDIZED_COPPER_OVEN = this.create("oxidized_copper_oven", BlockItem(CobblemonBlocks.OXIDIZED_COPPER_OVEN, Item.Properties()))
|
||||
@JvmField
|
||||
val WAXED_COPPER_OVEN = this.create("waxed_copper_oven", BlockItem(CobblemonBlocks.WAXED_COPPER_OVEN, Item.Properties()))
|
||||
@JvmField
|
||||
val WAXED_EXPOSED_COPPER_OVEN = this.create("waxed_exposed_copper_oven", BlockItem(CobblemonBlocks.WAXED_EXPOSED_COPPER_OVEN, Item.Properties()))
|
||||
@JvmField
|
||||
val WAXED_WEATHERED_COPPER_OVEN = this.create("waxed_weathered_copper_oven", BlockItem(CobblemonBlocks.WAXED_WEATHERED_COPPER_OVEN, Item.Properties()))
|
||||
@JvmField
|
||||
val WAXED_OXIDIZED_COPPER_OVEN = this.create("waxed_oxidized_copper_oven", BlockItem(CobblemonBlocks.WAXED_OXIDIZED_COPPER_OVEN, Item.Properties()))
|
||||
@JvmField
|
||||
val COPPER_WASHER = this.create("copper_washer", BlockItem(CobblemonBlocks.COPPER_WASHER, Item.Properties()))
|
||||
@JvmField
|
||||
val EXPOSED_COPPER_WASHER = this.create("exposed_copper_washer", BlockItem(CobblemonBlocks.EXPOSED_COPPER_WASHER, Item.Properties()))
|
||||
@JvmField
|
||||
val WEATHERED_COPPER_WASHER = this.create("weathered_copper_washer", BlockItem(CobblemonBlocks.WEATHERED_COPPER_WASHER, Item.Properties()))
|
||||
@JvmField
|
||||
val OXIDIZED_COPPER_WASHER = this.create("oxidized_copper_washer", BlockItem(CobblemonBlocks.OXIDIZED_COPPER_WASHER, Item.Properties()))
|
||||
@JvmField
|
||||
val WAXED_COPPER_WASHER = this.create("waxed_copper_washer", BlockItem(CobblemonBlocks.WAXED_COPPER_WASHER, Item.Properties()))
|
||||
@JvmField
|
||||
val WAXED_EXPOSED_COPPER_WASHER = this.create("waxed_exposed_copper_washer", BlockItem(CobblemonBlocks.WAXED_EXPOSED_COPPER_WASHER, Item.Properties()))
|
||||
@JvmField
|
||||
val WAXED_WEATHERED_COPPER_WASHER = this.create("waxed_weathered_copper_washer", BlockItem(CobblemonBlocks.WAXED_WEATHERED_COPPER_WASHER, Item.Properties()))
|
||||
@JvmField
|
||||
val WAXED_OXIDIZED_COPPER_WASHER = this.create("waxed_oxidized_copper_washer", BlockItem(CobblemonBlocks.WAXED_OXIDIZED_COPPER_WASHER, Item.Properties()))
|
||||
@JvmField
|
||||
val COPPER_FAN = this.create("copper_fan", BlockItem(CobblemonBlocks.COPPER_FAN, Item.Properties()))
|
||||
@JvmField
|
||||
val EXPOSED_COPPER_FAN = this.create("exposed_copper_fan", BlockItem(CobblemonBlocks.EXPOSED_COPPER_FAN, Item.Properties()))
|
||||
@JvmField
|
||||
val WEATHERED_COPPER_FAN = this.create("weathered_copper_fan", BlockItem(CobblemonBlocks.WEATHERED_COPPER_FAN, Item.Properties()))
|
||||
@JvmField
|
||||
val OXIDIZED_COPPER_FAN = this.create("oxidized_copper_fan", BlockItem(CobblemonBlocks.OXIDIZED_COPPER_FAN, Item.Properties()))
|
||||
@JvmField
|
||||
val WAXED_COPPER_FAN = this.create("waxed_copper_fan", BlockItem(CobblemonBlocks.WAXED_COPPER_FAN, Item.Properties()))
|
||||
@JvmField
|
||||
val WAXED_EXPOSED_COPPER_FAN = this.create("waxed_exposed_copper_fan", BlockItem(CobblemonBlocks.WAXED_EXPOSED_COPPER_FAN, Item.Properties()))
|
||||
@JvmField
|
||||
val WAXED_WEATHERED_COPPER_FAN = this.create("waxed_weathered_copper_fan", BlockItem(CobblemonBlocks.WAXED_WEATHERED_COPPER_FAN, Item.Properties()))
|
||||
@JvmField
|
||||
val WAXED_OXIDIZED_COPPER_FAN = this.create("waxed_oxidized_copper_fan", BlockItem(CobblemonBlocks.WAXED_OXIDIZED_COPPER_FAN, Item.Properties()))
|
||||
@JvmField
|
||||
val COPPER_MOWER = this.create("copper_mower", BlockItem(CobblemonBlocks.COPPER_MOWER, Item.Properties()))
|
||||
@JvmField
|
||||
val EXPOSED_COPPER_MOWER = this.create("exposed_copper_mower", BlockItem(CobblemonBlocks.EXPOSED_COPPER_MOWER, Item.Properties()))
|
||||
@JvmField
|
||||
val WEATHERED_COPPER_MOWER = this.create("weathered_copper_mower", BlockItem(CobblemonBlocks.WEATHERED_COPPER_MOWER, Item.Properties()))
|
||||
@JvmField
|
||||
val OXIDIZED_COPPER_MOWER = this.create("oxidized_copper_mower", BlockItem(CobblemonBlocks.OXIDIZED_COPPER_MOWER, Item.Properties()))
|
||||
@JvmField
|
||||
val WAXED_COPPER_MOWER = this.create("waxed_copper_mower", BlockItem(CobblemonBlocks.WAXED_COPPER_MOWER, Item.Properties()))
|
||||
@JvmField
|
||||
val WAXED_EXPOSED_COPPER_MOWER = this.create("waxed_exposed_copper_mower", BlockItem(CobblemonBlocks.WAXED_EXPOSED_COPPER_MOWER, Item.Properties()))
|
||||
@JvmField
|
||||
val WAXED_WEATHERED_COPPER_MOWER = this.create("waxed_weathered_copper_mower", BlockItem(CobblemonBlocks.WAXED_WEATHERED_COPPER_MOWER, Item.Properties()))
|
||||
@JvmField
|
||||
val WAXED_OXIDIZED_COPPER_MOWER = this.create("waxed_oxidized_copper_mower", BlockItem(CobblemonBlocks.WAXED_OXIDIZED_COPPER_MOWER, Item.Properties()))
|
||||
@JvmField
|
||||
val COPPER_FRIDGE = this.create("copper_fridge", BlockItem(CobblemonBlocks.COPPER_FRIDGE, Item.Properties()))
|
||||
@JvmField
|
||||
val EXPOSED_COPPER_FRIDGE = this.create("exposed_copper_fridge", BlockItem(CobblemonBlocks.EXPOSED_COPPER_FRIDGE, Item.Properties()))
|
||||
@JvmField
|
||||
val WEATHERED_COPPER_FRIDGE = this.create("weathered_copper_fridge", BlockItem(CobblemonBlocks.WEATHERED_COPPER_FRIDGE, Item.Properties()))
|
||||
@JvmField
|
||||
val OXIDIZED_COPPER_FRIDGE = this.create("oxidized_copper_fridge", BlockItem(CobblemonBlocks.OXIDIZED_COPPER_FRIDGE, Item.Properties()))
|
||||
@JvmField
|
||||
val WAXED_COPPER_FRIDGE = this.create("waxed_copper_fridge", BlockItem(CobblemonBlocks.WAXED_COPPER_FRIDGE, Item.Properties()))
|
||||
@JvmField
|
||||
val WAXED_EXPOSED_COPPER_FRIDGE = this.create("waxed_exposed_copper_fridge", BlockItem(CobblemonBlocks.WAXED_EXPOSED_COPPER_FRIDGE, Item.Properties()))
|
||||
@JvmField
|
||||
val WAXED_WEATHERED_COPPER_FRIDGE = this.create("waxed_weathered_copper_fridge", BlockItem(CobblemonBlocks.WAXED_WEATHERED_COPPER_FRIDGE, Item.Properties()))
|
||||
@JvmField
|
||||
val WAXED_OXIDIZED_COPPER_FRIDGE = this.create("waxed_oxidized_copper_fridge", BlockItem(CobblemonBlocks.WAXED_OXIDIZED_COPPER_FRIDGE, Item.Properties()))
|
||||
|
||||
// Type Gems
|
||||
@JvmField
|
||||
val NORMAL_GEM = this.create("normal_gem", GemItem(Item.Properties(), CobblemonBlocks.TYPE_GEM_CLUSTER_NORMAL))
|
||||
|
||||
@@ -12,6 +12,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.item.crafting.washer.WasherRecipe
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import net.minecraft.core.Registry
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
@@ -26,7 +27,9 @@ object CobblemonRecipeSerializers : PlatformRegistry<Registry<RecipeSerializer<*
|
||||
val COOKING_POT_SHAPELESS: RecipeSerializer<*> = register("cobblemon:cooking_pot_shapeless", CookingPotShapelessRecipe.Serializer())
|
||||
|
||||
val BREWING_STAND: RecipeSerializer<*> = register("cobblemon:brewing_stand", BrewingStandRecipe.Serializer())
|
||||
|
||||
|
||||
val WASHER: RecipeSerializer<*> = register("cobblemon:washer", WasherRecipe.Serializer())
|
||||
|
||||
override val registry: Registry<RecipeSerializer<*>>
|
||||
get() = BuiltInRegistries.RECIPE_SERIALIZER
|
||||
override val resourceKey: ResourceKey<Registry<RecipeSerializer<*>>>
|
||||
|
||||
@@ -12,6 +12,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.item.crafting.washer.WasherRecipe
|
||||
import com.cobblemon.mod.common.platform.PlatformRegistry
|
||||
import net.minecraft.core.Registry
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
@@ -26,7 +27,9 @@ object CobblemonRecipeTypes : PlatformRegistry<Registry<RecipeType<*>>, Resource
|
||||
val COOKING_POT_SHAPELESS: RecipeType<CookingPotShapelessRecipe> = register("cobblemon:cooking_pot_shapeless")
|
||||
|
||||
val BREWING_STAND: RecipeType<BrewingStandRecipe> = register("cobblemon:brewing_stand")
|
||||
|
||||
|
||||
val WASHER: RecipeType<WasherRecipe> = register("cobblemon:washer")
|
||||
|
||||
override val registry: Registry<RecipeType<*>>
|
||||
get() = BuiltInRegistries.RECIPE_TYPE
|
||||
override val resourceKey: ResourceKey<Registry<RecipeType<*>>>
|
||||
|
||||
@@ -404,6 +404,17 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
@JvmField
|
||||
val IMPACT_WATER = this.create("impact.water")
|
||||
|
||||
@JvmField
|
||||
val APPLIANCE_STEP = this.create("block.appliance.roto_appliance_step")
|
||||
@JvmField
|
||||
val APPLIANCE_PLACE = this.create("block.appliance.roto_appliance_place")
|
||||
@JvmField
|
||||
val APPLIANCE_HIT = this.create("block.appliance.roto_appliance_hit")
|
||||
@JvmField
|
||||
val APPLIANCE_BREAK = this.create("block.appliance.roto_appliance_break")
|
||||
@JvmField
|
||||
val MOWER_CUT = this.create("block.appliance.roto_mower_cut")
|
||||
|
||||
// Note to self or whoever's peeking, block sounds have to be at 1.1f pitch
|
||||
// For some reason, the game pitches them down and compensating for it here returns them to normal
|
||||
@JvmField
|
||||
@@ -424,6 +435,15 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, ResourceKey<Regi
|
||||
TUMBLESTONE_STEP
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val APPLIANCE_BLOCK_SOUNDS = SoundType(1f, 1.1f,
|
||||
APPLIANCE_BREAK,
|
||||
APPLIANCE_STEP,
|
||||
APPLIANCE_PLACE,
|
||||
APPLIANCE_HIT,
|
||||
APPLIANCE_STEP
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val TYPE_GEM_BLOCK_BREAK = this.create("block.type_gem_block.break")
|
||||
@JvmField
|
||||
|
||||
+31
-7
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.api.ai.config.task
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.ai.BehaviourConfigurationContext
|
||||
import com.cobblemon.mod.common.api.ai.ExpressionOrEntityVariable
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMostSpecificMoLangValue
|
||||
@@ -17,6 +18,7 @@ import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.mainThreadRuntime
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.withQueryValue
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
|
||||
import com.mojang.datafixers.util.Either
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.ai.behavior.BehaviorControl
|
||||
@@ -34,6 +36,8 @@ import net.minecraft.world.entity.ai.sensing.SensorType
|
||||
class HateEntityTaskConfig : SingleTaskConfig {
|
||||
val entityCondition: Expression = "true".asExpression()
|
||||
val range: ExpressionOrEntityVariable = Either.left("24".asExpression())
|
||||
val chance: Float = Cobblemon.config.predationChance
|
||||
private val coercedChance = chance.coerceIn(0f, 1f)
|
||||
|
||||
override fun getVariables(entity: LivingEntity, behaviourConfigurationContext: BehaviourConfigurationContext) = emptyList<MoLangConfigVariable>()
|
||||
override fun createTask(
|
||||
@@ -43,24 +47,44 @@ class HateEntityTaskConfig : SingleTaskConfig {
|
||||
val range = range.resolveFloat(behaviourConfigurationContext.runtime)
|
||||
behaviourConfigurationContext.addMemories(
|
||||
MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES,
|
||||
MemoryModuleType.ANGRY_AT
|
||||
MemoryModuleType.ANGRY_AT,
|
||||
MemoryModuleType.ATTACK_TARGET
|
||||
)
|
||||
behaviourConfigurationContext.addSensors(SensorType.NEAREST_LIVING_ENTITIES)
|
||||
return BehaviorBuilder.create { instance ->
|
||||
instance.group(
|
||||
instance.present(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES),
|
||||
instance.registered(MemoryModuleType.ANGRY_AT)
|
||||
).apply(instance) { entities, angryAt ->
|
||||
instance.registered(MemoryModuleType.ANGRY_AT),
|
||||
instance.registered(MemoryModuleType.ATTACK_TARGET),
|
||||
).apply(instance) { entities, angryAt, attackTarget ->
|
||||
Trigger { world, entity, _ ->
|
||||
val target = instance.get(entities).findClosest {
|
||||
mainThreadRuntime.withQueryValue("entity", entity.asMostSpecificMoLangValue())
|
||||
// bail if gamerule is disabled
|
||||
if (!world.gameRules.getBoolean(CobblemonGameRules.DO_POKEMON_PREDATION)) return@Trigger false
|
||||
val target = instance.get(entities).findClosest { hated ->
|
||||
mainThreadRuntime.withQueryValue("entity", hated.asMostSpecificMoLangValue())
|
||||
return@findClosest mainThreadRuntime.resolveBoolean(entityCondition)
|
||||
}.orElse(null)
|
||||
|
||||
var shouldTrigger = false
|
||||
if (target != null && target.distanceTo(entity) <= range) {
|
||||
angryAt.set(target.uuid)
|
||||
shouldTrigger = when {
|
||||
// set always attacking if activity chance is equal to 1.0
|
||||
coercedChance == 1f -> {
|
||||
angryAt.set(target.uuid)
|
||||
attackTarget.set(target)
|
||||
true
|
||||
}
|
||||
// roll the dice in other way
|
||||
coercedChance != 1f && world.random.nextFloat() < coercedChance -> {
|
||||
angryAt.set(target.uuid)
|
||||
attackTarget.set(target)
|
||||
true
|
||||
}
|
||||
// fallback to peaceful behavior in unattended cases
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
return@Trigger true
|
||||
return@Trigger shouldTrigger
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,6 +239,10 @@ open class PokemonBattle(
|
||||
}
|
||||
|
||||
fun writeShowdownAction(vararg messages: String) {
|
||||
if (messages.any { it.contains("\n") || it.contains("\r") }) {
|
||||
LOGGER.warn("Refusing to forward Showdown action with an embedded line break for battle {}: {}", battleId, messages.joinToString(" | "))
|
||||
return
|
||||
}
|
||||
log(messages.joinToString("\n"))
|
||||
ShowdownService.service.send(battleId, messages.toList().toTypedArray())
|
||||
}
|
||||
|
||||
+2
-2
@@ -98,14 +98,14 @@ object LivingEntityMoLangFunctions : AbstractMoLangFunctionHolder<LivingEntity>(
|
||||
val targetEntity = params.get<MoValue>(0)
|
||||
val maxDistance = params.getDoubleOrNull(1)?.toFloat() ?: 2.0F
|
||||
|
||||
val entity =
|
||||
val target =
|
||||
if (targetEntity is ObjectValue<*> && targetEntity.obj is Entity) {
|
||||
targetEntity.obj as Entity
|
||||
} else {
|
||||
return@isLookingAt DoubleValue.ZERO
|
||||
}
|
||||
|
||||
DoubleValue(entity.isLookingAt(entity, maxDistance))
|
||||
DoubleValue(entity.isLookingAt(target, maxDistance))
|
||||
}
|
||||
functions["is_living_entity"] = { DoubleValue.ONE }
|
||||
functions["is_flying"] = { DoubleValue(entity.isFallFlying) }
|
||||
|
||||
+1
-1
@@ -212,7 +212,7 @@ object PokemonMoLangFunctions : AbstractMoLangFunctionHolder<Pokemon>() {
|
||||
// Lol. Lmao, even.
|
||||
// TO-DO: Subscribe to [PokemonSpecies.observable].
|
||||
functions["pre_evolution"] = { pokemon.species.preEvolution ?: DoubleValue.ZERO }
|
||||
functions["nature"] = { StringValue(pokemon.nature.toString()) }
|
||||
functions["nature"] = { StringValue(pokemon.nature.name.toString()) }
|
||||
functions["is_wild"] = { DoubleValue(pokemon.entity?.let { it.ownerUUID == null } == true) }
|
||||
functions["is_shiny"] = { DoubleValue(pokemon.shiny) }
|
||||
functions["is_in_party"] = { DoubleValue(pokemon.storeCoordinates.get()?.store is PartyStore) }
|
||||
|
||||
@@ -10,9 +10,6 @@ package com.cobblemon.mod.common.api.pokedex
|
||||
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.pokedex.def.PokedexDef
|
||||
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
|
||||
import com.cobblemon.mod.common.api.pokedex.entry.PokedexForm
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.reactive.SimpleObservable
|
||||
import com.cobblemon.mod.common.net.messages.client.data.PokedexDexSyncPacket
|
||||
import com.cobblemon.mod.common.util.adapters.CodecBackedAdapter
|
||||
@@ -64,14 +61,6 @@ object Dexes : JsonDataRegistry<PokedexDef> {
|
||||
PokedexDexSyncPacket(dexEntryMap.values).sendToPlayer(player)
|
||||
}
|
||||
|
||||
fun findDexEntryBySpeciesId(regionId: ResourceLocation, speciesId: ResourceLocation): PokedexEntry? {
|
||||
return dexEntryMap[regionId]?.getEntries()?.firstOrNull { it -> it.speciesId == speciesId }
|
||||
}
|
||||
|
||||
fun findDexEntryBySpeciesId(speciesId: ResourceLocation): PokedexEntry? {
|
||||
return findDexEntryBySpeciesId(cobblemonResource("national"), speciesId)
|
||||
}
|
||||
|
||||
fun getFormEquivalents(formName: String): List<String> {
|
||||
val key = equivalentFormsLookup[formName.lowercase()]
|
||||
return equivalentForms[key] ?: listOf(formName.lowercase())
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.pokedex.entry
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.api.data.JsonDataRegistry
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
@@ -72,8 +73,11 @@ object DexEntries : JsonDataRegistry<PokedexEntry> {
|
||||
fun computeEvolutionDisplays() {
|
||||
evolutionDisplays.clear()
|
||||
PokemonSpecies.species.forEach {
|
||||
evolutionDisplays.addAll(buildDisplays(it.standardForm))
|
||||
evolutionDisplays.addAll(it.forms.flatMap { form -> buildDisplays(form) })
|
||||
try {
|
||||
evolutionDisplays.addAll(buildDisplays(it.standardForm) + it.forms.flatMap { form -> buildDisplays(form) })
|
||||
} catch (e: Exception) {
|
||||
Cobblemon.LOGGER.error("Failed to build dex evolution displays for ${it.resourceIdentifier}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,8 +97,10 @@ object DexEntries : JsonDataRegistry<PokedexEntry> {
|
||||
?.let { PokemonSpecies.getByIdentifier(it.asIdentifierDefaultingNamespace()) }
|
||||
?: return@resultLoop
|
||||
|
||||
// Carry the source form's aspects over like a real evolution does (Alola-Bias Pichu -> Alola-Bias Pikachu)
|
||||
val resultForm = resultSpecies.getForm(form.aspects.toSet() + resultProperties.aspects)
|
||||
// The result's own aspects win, otherwise carry the source form's aspects over
|
||||
// like a real evolution does (Alola-Bias Pichu -> Alola-Bias Pikachu)
|
||||
val resultForm = resultSpecies.getForm(resultProperties.aspects).takeIf { it != resultSpecies.standardForm }
|
||||
?: resultSpecies.getForm(form.aspects.toSet() + resultProperties.aspects)
|
||||
val toAspects = resultProperties.aspects + resultForm.aspects
|
||||
val resultRequirements = if (resultProperties === evolution.shedder) {
|
||||
requirements + CobblemonDexEvolutionRequirementDisplay(CobblemonItems.POKE_BALL, lang("ui.pokedex.evolution.shedder.tooltip"))
|
||||
@@ -115,4 +121,4 @@ object DexEntries : JsonDataRegistry<PokedexEntry> {
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
-10
@@ -77,8 +77,8 @@ fun getToolTipHeaderIcon(evolution: Evolution): DexEvolutionRequirementDisplay?
|
||||
}
|
||||
|
||||
|
||||
fun getToolTipHeaderIcon(itemInteractionEvolution: ItemInteractionEvolution): CobblemonDexEvolutionRequirementDisplay {
|
||||
val item = itemInteractionEvolution.requiredContext.items.get().first().value()
|
||||
fun getToolTipHeaderIcon(itemInteractionEvolution: ItemInteractionEvolution): CobblemonDexEvolutionRequirementDisplay? {
|
||||
val item = itemInteractionEvolution.requiredContext.items.orElse(null)?.firstOrNull()?.value() ?: return null
|
||||
return CobblemonDexEvolutionRequirementDisplay(item, lang("ui.pokedex.evolution.item_interact.tooltip", item.description.plainCopy().green()))
|
||||
}
|
||||
|
||||
@@ -87,7 +87,9 @@ fun getToolTipHeaderIcon(tradeEvolution: TradeEvolution): CobblemonDexEvolutionR
|
||||
val tooltip = if (species == null) {
|
||||
lang("ui.pokedex.evolution.trade.tooltip.with_any_species")
|
||||
} else {
|
||||
lang("ui.pokedex.evolution.trade.tooltip.with_species", PokemonSpecies.getByIdentifier(species.asIdentifierDefaultingNamespace())!!.translatedName.green())
|
||||
PokemonSpecies.getByIdentifier(species.asIdentifierDefaultingNamespace())
|
||||
?.let { lang("ui.pokedex.evolution.trade.tooltip.with_species", it.translatedName.plainCopy().green()) }
|
||||
?: lang("ui.pokedex.evolution.trade.tooltip.with_any_species")
|
||||
}
|
||||
return CobblemonDexEvolutionRequirementDisplay(CobblemonItems.LINK_CABLE, tooltip)
|
||||
}
|
||||
@@ -280,7 +282,7 @@ fun buildLevelRequirement(levelRequirement: LevelRequirement): DexEvolutionRequi
|
||||
|
||||
fun buildMoonPhaseRequirement(moonPhaseRequirement: MoonPhaseRequirement): DexEvolutionRequirementDisplay {
|
||||
val icon = Items.CLOCK
|
||||
val moonPhaseComponent = moonPhaseRequirement.moonPhase.displayName().green()
|
||||
val moonPhaseComponent = moonPhaseRequirement.moonPhase.displayName().plainCopy().green()
|
||||
val tooltip = lang("ui.pokedex.requirement.moon_phase.tooltip", moonPhaseComponent)
|
||||
|
||||
return CobblemonDexEvolutionRequirementDisplay(icon, tooltip)
|
||||
@@ -288,7 +290,7 @@ fun buildMoonPhaseRequirement(moonPhaseRequirement: MoonPhaseRequirement): DexEv
|
||||
|
||||
fun buildMoveSetRequirement(moveSetRequirement: MoveSetRequirement): DexEvolutionRequirementDisplay {
|
||||
val icon = CobblemonItems.TECHNICAL_MACHINE
|
||||
val tooltip = lang("ui.pokedex.requirement.has_move.tooltip", moveSetRequirement.move.displayName.green())
|
||||
val tooltip = lang("ui.pokedex.requirement.has_move.tooltip", moveSetRequirement.move.displayName.plainCopy().green())
|
||||
|
||||
return CobblemonDexEvolutionRequirementDisplay(icon, tooltip)
|
||||
}
|
||||
@@ -317,13 +319,13 @@ fun buildMoveTypeRequirement(moveTypeRequirement: MoveTypeRequirement): DexEvolu
|
||||
else -> CobblemonItems.NORMAL_GEM
|
||||
}
|
||||
|
||||
val tooltip = lang("ui.pokedex.requirement.has_move_type.tooltip", moveTypeRequirement.type.displayName.green())
|
||||
val tooltip = lang("ui.pokedex.requirement.has_move_type.tooltip", moveTypeRequirement.type.displayName.plainCopy().green())
|
||||
|
||||
return CobblemonDexEvolutionRequirementDisplay(icon, tooltip)
|
||||
}
|
||||
|
||||
fun buildOwnerHoldsItemRequirement(ownerHoldsItemRequirement: OwnerHoldsItemRequirement): DexEvolutionRequirementDisplay {
|
||||
val item = ownerHoldsItemRequirement.itemCondition.items.get().first().value()
|
||||
fun buildOwnerHoldsItemRequirement(ownerHoldsItemRequirement: OwnerHoldsItemRequirement): DexEvolutionRequirementDisplay? {
|
||||
val item = ownerHoldsItemRequirement.itemCondition.items.orElse(null)?.firstOrNull()?.value() ?: return null
|
||||
val tooltip = lang("ui.pokedex.requirement.owner_held_item.tooltip", item.description.plainCopy().green())
|
||||
|
||||
return CobblemonDexEvolutionRequirementDisplay(item, tooltip)
|
||||
@@ -435,7 +437,7 @@ fun buildStructureRequirement(structureRequirement: StructureRequirement, negate
|
||||
|
||||
fun buildTimeRangeRequirement(timeRangeRequirement: TimeRangeRequirement): DexEvolutionRequirementDisplay? {
|
||||
val icon = Items.CLOCK
|
||||
val timeRangeComponent = timeRangeRequirement.range.displayName() ?: return null
|
||||
val timeRangeComponent = timeRangeRequirement.range.displayName()?.plainCopy() ?: return null
|
||||
val tooltip = lang("ui.pokedex.requirement.time_range.tooltip", timeRangeComponent.green())
|
||||
|
||||
return CobblemonDexEvolutionRequirementDisplay(icon, tooltip)
|
||||
@@ -443,7 +445,7 @@ fun buildTimeRangeRequirement(timeRangeRequirement: TimeRangeRequirement): DexEv
|
||||
|
||||
fun buildUseMoveRequirement(useMoveRequirement: UseMoveRequirement): DexEvolutionRequirementDisplay {
|
||||
val icon = CobblemonItems.CHOICE_BAND
|
||||
val tooltip = lang("ui.pokedex.requirement.use_move.tooltip", useMoveRequirement.move.displayName.green())
|
||||
val tooltip = lang("ui.pokedex.requirement.use_move.tooltip", useMoveRequirement.move.displayName.plainCopy().green())
|
||||
|
||||
return CobblemonDexEvolutionRequirementDisplay(icon, tooltip)
|
||||
}
|
||||
|
||||
@@ -9,9 +9,12 @@
|
||||
package com.cobblemon.mod.common.api.riding.stats
|
||||
|
||||
import com.cobblemon.mod.common.api.cooking.Flavour
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.tags.TagKey
|
||||
import net.minecraft.world.item.Item
|
||||
|
||||
/**
|
||||
* A stat that is used for riding Pokémon. The exact implementation of each of these depends on the [com.cobblemon.mod.common.api.riding.controller.RideController].
|
||||
@@ -20,13 +23,14 @@ import net.minecraft.network.chat.MutableComponent
|
||||
* @since February 17th, 2025
|
||||
*/
|
||||
enum class RidingStat(
|
||||
val flavour: Flavour
|
||||
val flavour: Flavour,
|
||||
val powerItem: TagKey<Item>
|
||||
) {
|
||||
ACCELERATION(Flavour.SPICY),
|
||||
SKILL(Flavour.DRY),
|
||||
SPEED(Flavour.SWEET),
|
||||
STAMINA(Flavour.SOUR),
|
||||
JUMP(Flavour.BITTER);
|
||||
ACCELERATION(Flavour.SPICY, CobblemonItemTags.POWER_BRACER),
|
||||
SKILL(Flavour.DRY, CobblemonItemTags.POWER_BELT),
|
||||
SPEED(Flavour.SWEET, CobblemonItemTags.POWER_ANKLET),
|
||||
STAMINA(Flavour.SOUR, CobblemonItemTags.POWER_WEIGHT),
|
||||
JUMP(Flavour.BITTER, CobblemonItemTags.POWER_BAND);
|
||||
|
||||
companion object {
|
||||
fun getByName(name: String) = RidingStat.entries.firstOrNull { it.name.equals(name, ignoreCase = true) }
|
||||
|
||||
+2
-2
@@ -42,8 +42,8 @@ abstract class AreaTypeSpawningCondition<T : AreaSpawnablePosition> : SpawningCo
|
||||
override fun copyFrom(other: SpawningCondition<*>, merger: Merger) {
|
||||
super.copyFrom(other, merger)
|
||||
if (other is AreaTypeSpawningCondition) {
|
||||
merger.mergeSingle(minHeight, other.minHeight)
|
||||
merger.mergeSingle(maxHeight, other.maxHeight)
|
||||
minHeight = merger.mergeSingle(minHeight, other.minHeight)
|
||||
maxHeight = merger.mergeSingle(maxHeight, other.maxHeight)
|
||||
neededNearbyBlocks = merger.merge(neededNearbyBlocks, other.neededNearbyBlocks)?.toMutableList()
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ abstract class SubmergedTypeSpawningCondition<T : SubmergedSpawnablePosition> :
|
||||
super.copyFrom(other, merger)
|
||||
if (other is SubmergedTypeSpawningCondition) {
|
||||
minDepth = merger.mergeSingle(minDepth, other.minDepth)
|
||||
maxDepth = merger.mergeSingle(minDepth, other.minDepth)
|
||||
maxDepth = merger.mergeSingle(maxDepth, other.maxDepth)
|
||||
fluidIsSource = merger.mergeSingle(fluidIsSource, other.fluidIsSource)
|
||||
fluid = merger.mergeSingle(fluid, other.fluid)
|
||||
}
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ abstract class SurfaceTypeSpawningCondition<T : SurfaceSpawnablePosition> : Area
|
||||
super.copyFrom(other, merger)
|
||||
if (other is SurfaceTypeSpawningCondition) {
|
||||
minDepth = merger.mergeSingle(minDepth, other.minDepth)
|
||||
maxDepth = merger.mergeSingle(minDepth, other.minDepth)
|
||||
maxDepth = merger.mergeSingle(maxDepth, other.maxDepth)
|
||||
fluid = merger.mergeSingle(fluid, other.fluid)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,7 +198,17 @@ interface Spawner {
|
||||
val mid = chunk.getBlockState(startPos)
|
||||
val above = chunk.getBlockState(abovePos)
|
||||
|
||||
return above.isPathfindable(PathComputationType.AIR) && mid.isAir
|
||||
// Above must be non-solid
|
||||
if (!above.isPathfindable(PathComputationType.AIR)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Position must be non-air
|
||||
if (mid.isAir) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun constrainArea(area: SpawningZoneInput): SpawningZoneInput? {
|
||||
|
||||
@@ -120,7 +120,7 @@ object CobblemonItemTags {
|
||||
@JvmField val DESTINY_KNOT = create("held/destiny_knot")
|
||||
@JvmField val EVERSTONE = create("held/everstone")
|
||||
@JvmField val EXPERIENCE_SHARE = create("held/experience_share")
|
||||
@JvmField val IS_FRIENDSHIP_BOOSTER = create("is_friendship_booster")
|
||||
@JvmField val IS_FRIENDSHIP_BOOSTER = create("held/is_friendship_booster")
|
||||
@JvmField val ANY_HELD_ITEM = create("held/is_held_item")
|
||||
@JvmField val BLACKLISTED_ITEMS_TO_HOLD = create("held/blacklisted_items_to_hold")
|
||||
@JvmField val WHITELISTED_ITEMS_TO_HOLD = create("held/whitelisted_items_to_hold")
|
||||
|
||||
@@ -117,6 +117,9 @@ abstract class ShowdownActionResponse(val type: ShowdownActionResponseType) {
|
||||
|
||||
data class MoveActionResponse(var moveName: String, var targetPnx: String? = null, var gimmickID: String? = null): ShowdownActionResponse(ShowdownActionResponseType.MOVE) {
|
||||
override fun isValid(activeBattlePokemon: ActiveBattlePokemon, showdownMoveSet: ShowdownMoveset?, forceSwitch: Boolean): Boolean {
|
||||
// Ensure that the gimmick ID the player is sending is valid
|
||||
gimmickID?.let { if (it !in VALID_GIMMICK_IDS) return false }
|
||||
|
||||
if (forceSwitch || showdownMoveSet == null) {
|
||||
return false
|
||||
}
|
||||
@@ -168,6 +171,10 @@ data class MoveActionResponse(var moveName: String, var targetPnx: String? = nul
|
||||
gimmickID = buffer.readNullable { buffer.readString() }
|
||||
return this
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val VALID_GIMMICK_IDS = ShowdownMoveset.Gimmick.entries.map { it.id }.toSet()
|
||||
}
|
||||
}
|
||||
|
||||
data class HealItemActionResponse(var item: String) : ShowdownActionResponse(ShowdownActionResponseType.FORCE_PASS) {
|
||||
@@ -183,7 +190,8 @@ data class HealItemActionResponse(var item: String) : ShowdownActionResponse(Sho
|
||||
}
|
||||
|
||||
override fun isValid(activeBattlePokemon: ActiveBattlePokemon, showdownMoveSet: ShowdownMoveset?, forceSwitch: Boolean): Boolean {
|
||||
return !forceSwitch
|
||||
// Previously checked for !forceSwitch, excepts in the case of a forceSwitch, this couldn't legally be sent anyway.
|
||||
return false
|
||||
}
|
||||
|
||||
override fun toShowdownString(activeBattlePokemon: ActiveBattlePokemon, showdownMoveSet: ShowdownMoveset?): String {
|
||||
|
||||
+11
-2
@@ -37,7 +37,6 @@ import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
||||
/**
|
||||
* Format: |move|POKEMON|MOVE|TARGET
|
||||
@@ -77,7 +76,7 @@ class MoveInstruction(
|
||||
val pokemonName = userPokemon.getName()
|
||||
ShowdownInterpreter.lastCauser[battle.battleId] = message
|
||||
// For Spread targets the message data only gives the pnx strings. So we can't know what pokemon are actually targeted until the previous messages have been interpreted
|
||||
val spreadTargetPokemon = spreadTargets.map { battle.activePokemon.firstOrNull() { poke -> poke.getPNX() == it }?.battlePokemon }
|
||||
val spreadTargetPokemon = spreadTargets.map { battle.activePokemon.firstOrNull { poke -> poke.getPNX() == it }?.battlePokemon }
|
||||
|
||||
val targetPokemonEntity = targetPokemon?.entity
|
||||
if (targetPokemonEntity != null) {
|
||||
@@ -137,10 +136,20 @@ class MoveInstruction(
|
||||
|
||||
val subsequentInstructions = instructionSet.findInstructionsCausedBy(this)
|
||||
val missedTargets = subsequentInstructions.filterIsInstance<MissInstruction>().mapNotNull { it.target }
|
||||
val faintedTargets = subsequentInstructions.filterIsInstance<FaintInstruction>().map { it.faintingPokemon }
|
||||
val failed = subsequentInstructions.any { it is FailInstruction }
|
||||
val failedTargets = subsequentInstructions.filterIsInstance<FailInstruction>().mapNotNull { it.target }
|
||||
val hitCountInstruction = subsequentInstructions.filterIsInstance<HitCountInstruction>().firstOrNull()
|
||||
|
||||
runtime.environment.query.addFunction("target_fainted") { params ->
|
||||
if (params.params.size == 0) {
|
||||
return@addFunction DoubleValue(faintedTargets.isNotEmpty())
|
||||
} else {
|
||||
val entityUUID = params.getString(0)
|
||||
return@addFunction DoubleValue(faintedTargets.any { it.entity?.stringUUID == entityUUID })
|
||||
}
|
||||
}
|
||||
|
||||
runtime.environment.query.addFunction("missed") { params ->
|
||||
if (params.params.size == 0) {
|
||||
return@addFunction DoubleValue(missedTargets.isNotEmpty())
|
||||
|
||||
@@ -24,6 +24,7 @@ import net.minecraft.network.chat.Component
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.world.InteractionResult
|
||||
import net.minecraft.world.entity.EntityType
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.Item
|
||||
@@ -31,13 +32,9 @@ import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.TooltipFlag
|
||||
import net.minecraft.world.item.context.BlockPlaceContext
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.CollisionGetter
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.BaseEntityBlock
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.HorizontalDirectionalBlock
|
||||
import net.minecraft.world.level.block.Mirror
|
||||
import net.minecraft.world.level.block.RenderShape
|
||||
import net.minecraft.world.level.block.Rotation
|
||||
import net.minecraft.world.level.block.*
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.entity.BlockEntityTicker
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||
@@ -48,9 +45,11 @@ import net.minecraft.world.level.block.state.properties.IntegerProperty
|
||||
import net.minecraft.world.level.block.state.properties.Property
|
||||
import net.minecraft.world.level.pathfinder.PathComputationType
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.CollisionContext
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
import java.util.Optional
|
||||
|
||||
@Suppress("DEPRECATED", "OVERRIDE_DEPRECATION")
|
||||
class HealingMachineBlock(settings: Properties) : BaseEntityBlock(settings) {
|
||||
@@ -79,6 +78,14 @@ class HealingMachineBlock(settings: Properties) : BaseEntityBlock(settings) {
|
||||
const val MAX_CHARGE_LEVEL = 5
|
||||
val CHARGE_LEVEL: IntegerProperty = IntegerProperty.create("charge", 0, MAX_CHARGE_LEVEL + 1)
|
||||
val NATURAL: BooleanProperty = BooleanProperty.create("natural")
|
||||
|
||||
fun canSetSpawn(level: Level): Boolean {
|
||||
return level.gameRules.getBoolean(CobblemonGameRules.HEALER_SET_SPAWN)
|
||||
}
|
||||
|
||||
fun findStandUpPosition(entityType: EntityType<*>, level: CollisionGetter, pos: BlockPos): Optional<Vec3> {
|
||||
return RespawnAnchorBlock.findStandUpPosition(entityType, level, pos) // Exists if we ever want to make something more custom, but anchor block logic should suffice
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
@@ -158,7 +165,12 @@ class HealingMachineBlock(settings: Properties) : BaseEntityBlock(settings) {
|
||||
}
|
||||
val party = serverPlayerEntity.party()
|
||||
val pc = serverPlayerEntity.pc()
|
||||
val healPC = player.level().gameRules.getBoolean(CobblemonGameRules.HEALERS_HEAL_PC);
|
||||
val healPC = player.level().gameRules.getBoolean(CobblemonGameRules.HEALERS_HEAL_PC)
|
||||
|
||||
// Do spawnpoint stuff
|
||||
if (canSetSpawn(world)) {
|
||||
player.setRespawnPosition(world.dimension(), blockPos, player.yRot, false, true)
|
||||
}
|
||||
|
||||
if (party.none() && (!healPC || pc.none())) {
|
||||
player.sendSystemMessage(lang("healingmachine.nopokemon").red(), true)
|
||||
@@ -183,6 +195,7 @@ class HealingMachineBlock(settings: Properties) : BaseEntityBlock(settings) {
|
||||
player.sendSystemMessage(lang("healingmachine.notenoughcharge", "${((neededCharge/party.count())*100f).toInt()}%").red(), true)
|
||||
}
|
||||
party.forEach { it.tryRecallWithAnimation() }
|
||||
|
||||
return InteractionResult.CONSUME
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ import net.minecraft.world.level.block.entity.BlockEntityType
|
||||
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.BooleanProperty
|
||||
import net.minecraft.world.level.block.state.properties.EnumProperty
|
||||
import net.minecraft.world.level.pathfinder.PathComputationType
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
@@ -46,7 +47,10 @@ class MonitorBlock(settings: Properties) : MultiblockBlock(settings) {
|
||||
init {
|
||||
registerDefaultState(stateDefinition.any()
|
||||
.setValue(HORIZONTAL_FACING, Direction.NORTH)
|
||||
.setValue(SCREEN, MonitorScreen.OFF))
|
||||
.setValue(SCREEN, MonitorScreen.OFF)
|
||||
.setValue(NATURAL, false)
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
override fun createMultiBlockEntity(
|
||||
@@ -110,6 +114,7 @@ class MonitorBlock(settings: Properties) : MultiblockBlock(settings) {
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
|
||||
builder.add(HORIZONTAL_FACING)
|
||||
builder.add(SCREEN)
|
||||
builder.add(NATURAL)
|
||||
}
|
||||
|
||||
override fun hasAnalogOutputSignal(state: BlockState): Boolean {
|
||||
@@ -163,6 +168,7 @@ class MonitorBlock(settings: Properties) : MultiblockBlock(settings) {
|
||||
|
||||
//0 is off
|
||||
val SCREEN = EnumProperty.create("screen", MonitorScreen::class.java)
|
||||
val NATURAL = BooleanProperty.create("natural")
|
||||
val HITBOX_SOUTH = Shapes.or(
|
||||
Shapes.box(0.0625, 0.0, 0.0625, 0.9375, 0.375, 0.9375),
|
||||
Shapes.box(0.0625, 0.875, 0.0625, 0.9375, 1.0, 0.9375),
|
||||
|
||||
@@ -30,7 +30,7 @@ class OrbBlock(properties: Properties) : SixFaceRotationalBlock(properties) {
|
||||
|
||||
val FLOOR_NORTH = Shapes.box(0.3125, 0.0, 0.3125, 0.6875, 0.375, 0.6875)
|
||||
val WALL_NORTH = Shapes.box(0.3125, 0.3125, 0.625, 0.6875, 0.6875, 1.0)
|
||||
val CEILING_NORTH = Shapes.box(0.3125, 0.625, 0.375, 0.6875, 1.0, 0.6875)
|
||||
val CEILING_NORTH = Shapes.box(0.3125, 0.625, 0.3125, 0.6875, 1.0, 0.6875)
|
||||
}
|
||||
|
||||
init {
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
package com.cobblemon.mod.common.block
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.scheduling.afterOnServer
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.math.FloatRange
|
||||
import com.cobblemon.mod.common.util.party
|
||||
import com.cobblemon.mod.common.util.toVec3d
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import net.minecraft.sounds.SoundSource
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.world.InteractionResult
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.HorizontalDirectionalBlock
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
/**
|
||||
* A block that can transform into a [PokemonEntity].
|
||||
* Call [spawnPokemon] to spawn.
|
||||
*
|
||||
* @author whatsy
|
||||
*/
|
||||
interface PokemonDisguiseBlock {
|
||||
|
||||
private val facingToYaw: HashMap<Direction, Float>
|
||||
get() = hashMapOf(
|
||||
Direction.NORTH to -179.0F,
|
||||
Direction.WEST to 90.0F,
|
||||
Direction.SOUTH to 0.0F,
|
||||
Direction.EAST to -90.0F
|
||||
)
|
||||
|
||||
/**
|
||||
* An [IntRange] representing the possible level of the spawned Pokémon.
|
||||
*/
|
||||
val levelRange: IntRange
|
||||
|
||||
/**
|
||||
* A [String] representing the [PokemonProperties] of the spawned Pokémon.
|
||||
* Do not include level, scale, shiny, or alpha;
|
||||
* Those are defined using [levelRange], [scaleRange], [shinyRate] and [alphaRate] respectively.
|
||||
*/
|
||||
val pokemonArgs: String
|
||||
|
||||
/**
|
||||
* The chance of the spawned Pokémon being a shiny.
|
||||
* Leave null if impossible.
|
||||
* Defaults to [Cobblemon.config.shinyRate]
|
||||
*/
|
||||
val shinyRate: Float?
|
||||
get() = Cobblemon.config.shinyRate
|
||||
|
||||
/**
|
||||
* The chance of the spawned Pokémon being an Alpha.
|
||||
* Leave null if impossible.
|
||||
* Defaults to null
|
||||
*/
|
||||
val alphaRate: Float?
|
||||
get() = null
|
||||
|
||||
/**
|
||||
* The [BlockState] to replace the block with on interaction.
|
||||
* Defaults to [Blocks.AIR]
|
||||
* Leave null to leave the block unaltered.
|
||||
*
|
||||
* @param originalState The [BlockState] of the block being interacted with. Use to transfer properties to a new block.
|
||||
*/
|
||||
fun getReplacementBlock(originalState: BlockState): BlockState? = Blocks.AIR.defaultBlockState()
|
||||
|
||||
/**
|
||||
* Whether or not a battle should be initiated when the Pokémon spawns.
|
||||
* Defaults to true.
|
||||
* Does not affect players in creative mode.
|
||||
*/
|
||||
val shouldInitiateBattle: Boolean
|
||||
get() = true
|
||||
|
||||
/**
|
||||
* The [SoundEvent], if any, to play when the Pokémon spawns.
|
||||
* Defaults to null.
|
||||
*/
|
||||
val spawnSound: SoundEvent?
|
||||
get() = null
|
||||
|
||||
/**
|
||||
* A [FloatRange] representing the possible scale of the spawned Pokémon.
|
||||
* Defaults to config values.
|
||||
*/
|
||||
val scaleRange: FloatRange
|
||||
get() = FloatRange(Cobblemon.config.pokemonIntrinsicSizeMin, Cobblemon.config.pokemonIntrinsicSizeMax)
|
||||
|
||||
/**
|
||||
* Defines a [Vec3] offset for where the Pokémon will spawn.
|
||||
* Defaults to 0, 0, 0
|
||||
*/
|
||||
val offset: Vec3
|
||||
get() = Vec3(0.0, 0.0, 0.0)
|
||||
|
||||
/**
|
||||
* Returns the direction the Pokémon should be facing upon spawning.
|
||||
* Defaults to the
|
||||
*/
|
||||
fun getPokemonFacing(state: BlockState): Direction
|
||||
|
||||
/**
|
||||
* Spawn a Pokémon from this block.
|
||||
*
|
||||
* @param level The [Level] to spawn this Pokémon in.
|
||||
* @param pos The [BlockPos] to spawn this Pokémon at.
|
||||
* @param state The [BlockState] of the block at time of spawning.
|
||||
* @param player The [ServerPlayer] to initiate the battle against.
|
||||
*/
|
||||
fun spawnPokemon(level: Level, pos: BlockPos, state: BlockState, player: ServerPlayer): InteractionResult {
|
||||
val random = RandomSource.create()
|
||||
val isShiny = shinyRate?.let { random.nextInt(it.toInt()) == 0 } ?: false
|
||||
val isAlpha = alphaRate?.let { random.nextInt(it.toInt()) == 0 } ?: false
|
||||
val properties = "$pokemonArgs lvl=${levelRange.random()} scale_modifier=${scaleRange.random()} alpha=${isAlpha} shiny=${isShiny}"
|
||||
val pokemon = PokemonProperties.parse(properties)
|
||||
val entity = pokemon.createEntity(level)
|
||||
|
||||
// The yaw based on the block's facing direction
|
||||
val yaw = facingToYaw[getPokemonFacing(state)] ?: 0.0F
|
||||
|
||||
entity.entityData.set(PokemonEntity.SPAWN_DIRECTION, yaw)
|
||||
val offsetDir = state.getValue(HorizontalDirectionalBlock.FACING)
|
||||
val vec = pos.toVec3d()
|
||||
.add(offsetDir.stepX * 0.1 + 0.5, 0.0, offsetDir.stepZ * 0.1 + 0.5)
|
||||
.add(offset)
|
||||
entity.moveTo(vec.x, vec.y, vec.z, yaw, entity.xRot)
|
||||
entity.yBodyRot = yaw
|
||||
entity.yBodyRotO = yaw
|
||||
entity.yHeadRot = yaw
|
||||
entity.yHeadRotO = yaw
|
||||
level.addFreshEntity(entity)
|
||||
|
||||
if (getReplacementBlock(state) == Blocks.AIR) {
|
||||
level.removeBlock(pos, false)
|
||||
} else {
|
||||
getReplacementBlock(state)?.let {
|
||||
level.setBlockAndUpdate(pos, it)
|
||||
}
|
||||
}
|
||||
afterOnServer(seconds = 0.1F) {
|
||||
if (player !in player.level().players()) {
|
||||
return@afterOnServer
|
||||
}
|
||||
if (!player.isCreative && shouldInitiateBattle) {
|
||||
entity.forceBattle(player)
|
||||
} else {
|
||||
spawnSound?.let { level.playSound(null, pos, it, SoundSource.NEUTRAL) }
|
||||
}
|
||||
}
|
||||
return InteractionResult.SUCCESS
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.cobblemon.mod.common.block
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlocks
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.block.DamagedMonitorBlock.BrokenMonitorScreen
|
||||
import com.cobblemon.mod.common.block.DamagedMonitorBlock.Companion.HITBOX_EAST
|
||||
import com.cobblemon.mod.common.block.DamagedMonitorBlock.Companion.HITBOX_NORTH
|
||||
import com.cobblemon.mod.common.block.DamagedMonitorBlock.Companion.HITBOX_SOUTH
|
||||
import com.cobblemon.mod.common.block.DamagedMonitorBlock.Companion.HITBOX_WEST
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
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.block.Block
|
||||
import net.minecraft.world.level.block.HorizontalDirectionalBlock
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour
|
||||
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.phys.BlockHitResult
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.CollisionContext
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
|
||||
class RotomMonitorBlock(settings: Properties) : Block(settings), PokemonDisguiseBlock {
|
||||
|
||||
init {
|
||||
registerDefaultState(stateDefinition.any()
|
||||
.setValue(HorizontalDirectionalBlock.FACING, Direction.NORTH)
|
||||
.setValue(MonitorBlock.SCREEN, MonitorBlock.MonitorScreen.OFF)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getStateForPlacement(context: BlockPlaceContext): BlockState? {
|
||||
return defaultBlockState().setValue(HorizontalDirectionalBlock.FACING, context.horizontalDirection)
|
||||
}
|
||||
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block?, BlockState?>) {
|
||||
builder.add(HorizontalDirectionalBlock.FACING)
|
||||
builder.add(MonitorBlock.SCREEN)
|
||||
}
|
||||
|
||||
override fun playerWillDestroy(level: Level, pos: BlockPos, state: BlockState, player: Player): BlockState? {
|
||||
if (!level.isClientSide) {
|
||||
spawnPokemon(level, pos, state, player as ServerPlayer)
|
||||
}
|
||||
return super.playerWillDestroy(level, pos, state, player)
|
||||
}
|
||||
|
||||
override fun getShape(
|
||||
state: BlockState,
|
||||
level: BlockGetter,
|
||||
pos: BlockPos,
|
||||
context: CollisionContext
|
||||
): VoxelShape {
|
||||
return when (state.getValue(HorizontalDirectionalBlock.FACING)) {
|
||||
Direction.WEST -> HITBOX_WEST
|
||||
Direction.EAST -> HITBOX_EAST
|
||||
Direction.SOUTH -> HITBOX_SOUTH
|
||||
else -> HITBOX_NORTH
|
||||
}
|
||||
}
|
||||
|
||||
override fun useWithoutItem(
|
||||
state: BlockState,
|
||||
level: Level,
|
||||
pos: BlockPos,
|
||||
player: Player,
|
||||
hitResult: BlockHitResult
|
||||
): InteractionResult {
|
||||
return if (player is ServerPlayer) {
|
||||
spawnPokemon(level, pos, state, player)
|
||||
} else {
|
||||
InteractionResult.SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
override val levelRange = 35..60
|
||||
override val pokemonArgs = "rotom"
|
||||
override val spawnSound = CobblemonSounds.MONITOR_BREAK
|
||||
override val offset = Vec3(0.0, 1.0, 0.0)
|
||||
override fun getReplacementBlock(originalState: BlockState): BlockState =
|
||||
CobblemonBlocks.MONITOR.defaultBlockState()
|
||||
.setValue(HorizontalDirectionalBlock.FACING, originalState.getValue(HorizontalDirectionalBlock.FACING))
|
||||
.setValue(MonitorBlock.NATURAL, true)
|
||||
override fun getPokemonFacing(state: BlockState): Direction = state.getValue(HORIZONTAL_FACING).opposite
|
||||
}
|
||||
@@ -160,8 +160,8 @@ class TypeGemClusterBlock(
|
||||
&& state.getValue(STAGE) == 3) return false
|
||||
|
||||
val supportPos = pos.relative(state.getValue(FACING).opposite)
|
||||
val supportBlock = level.getBlockState(supportPos).block
|
||||
return CobblemonBlocks.typeGemBlocks().containsValue(supportBlock) || (supportBlock == CobblemonBlocks.TYPE_GEM_CORE) // Cannot grow if not on any gem blocks
|
||||
val supportState = level.getBlockState(supportPos)
|
||||
return supportState.`is`(CobblemonBlockTags.TYPE_GEM_BLOCKS) || supportState.block == CobblemonBlocks.TYPE_GEM_CORE // Cannot grow if not on any gem blocks
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -51,10 +51,20 @@ class TypeGemCoreBlock(properties: Properties) : Block(properties) {
|
||||
ResourceLocation.parse("cobblemon:dragon_gem_block") to CobblemonBlocks.TYPE_GEM_CLUSTER_DRAGON,
|
||||
ResourceLocation.parse("cobblemon:dark_gem_block") to CobblemonBlocks.TYPE_GEM_CLUSTER_DARK,
|
||||
ResourceLocation.parse("cobblemon:steel_gem_block") to CobblemonBlocks.TYPE_GEM_CLUSTER_STEEL,
|
||||
ResourceLocation.parse("cobblemon:fairy_gem_block") to CobblemonBlocks.TYPE_GEM_CLUSTER_FAIRY
|
||||
ResourceLocation.parse("cobblemon:fairy_gem_block") to CobblemonBlocks.TYPE_GEM_CLUSTER_FAIRY,
|
||||
ResourceLocation.parse("minecraft:amethyst_block") to Blocks.SMALL_AMETHYST_BUD
|
||||
)
|
||||
}
|
||||
|
||||
val AMETHYST_STAGES = listOf(
|
||||
Blocks.SMALL_AMETHYST_BUD,
|
||||
Blocks.MEDIUM_AMETHYST_BUD,
|
||||
Blocks.LARGE_AMETHYST_BUD,
|
||||
Blocks.AMETHYST_CLUSTER
|
||||
)
|
||||
|
||||
private fun isAmethystStage(block: Block) = block in AMETHYST_STAGES
|
||||
|
||||
fun getConnectedGemBlocks(level: BlockGetter, pos: BlockPos): List<Pair<BlockState, BlockPos>> {
|
||||
val connectedGems = mutableListOf<Pair<BlockState, BlockPos>>()
|
||||
val visited = mutableSetOf<BlockPos>()
|
||||
@@ -85,12 +95,16 @@ class TypeGemCoreBlock(properties: Properties) : Block(properties) {
|
||||
Direction.entries.forEach {
|
||||
if (random.nextFloat() < Cobblemon.config.typeGemGrowthChance) {
|
||||
val faceState = level.getBlockState(pos.relative(it))
|
||||
val randomGrowthType = decideClusterGrowthType(level, pos)
|
||||
val newState = BLOCK_TO_CLUSTER[BuiltInRegistries.BLOCK.getKey(state.block)]?.defaultBlockState()
|
||||
var newState = BLOCK_TO_CLUSTER[BuiltInRegistries.BLOCK.getKey(state.block)]?.defaultBlockState()
|
||||
?.setValue(DirectionalBlock.FACING, it)
|
||||
?.setValue(GROWTH_TYPE, randomGrowthType)
|
||||
?: return
|
||||
|
||||
if (newState.hasProperty(GROWTH_TYPE)) {
|
||||
newState = newState.setValue(GROWTH_TYPE, decideClusterGrowthType(level, pos))
|
||||
} else if (getConnectedGemBlocks(level, pos).size > Cobblemon.config.typeGemMaxConnected) {
|
||||
return@forEach
|
||||
}
|
||||
|
||||
if (faceState.`is`(Blocks.AIR)) {
|
||||
level.setBlock(pos.relative(it), newState, 3)
|
||||
}
|
||||
@@ -132,7 +146,7 @@ class TypeGemCoreBlock(properties: Properties) : Block(properties) {
|
||||
if (!visited.add(clusterPos)) continue
|
||||
|
||||
val clusterState = level.getBlockState(clusterPos)
|
||||
if (clusterState.block == expectedCluster) {
|
||||
if (clusterState.block == expectedCluster && clusterState.hasProperty(GROWTH_TYPE)) {
|
||||
clusters += clusterState to clusterPos
|
||||
}
|
||||
}
|
||||
@@ -178,13 +192,41 @@ class TypeGemCoreBlock(properties: Properties) : Block(properties) {
|
||||
Direction.entries.forEach { direction ->
|
||||
val relativePos = pos.relative(direction)
|
||||
val relativeState = level.getBlockState(relativePos)
|
||||
val clusterBlock = relativeState.block as? TypeGemClusterBlock ?: return@forEach
|
||||
|
||||
if ((relativeState.getValue(DirectionalBlock.FACING) == direction &&
|
||||
random.nextFloat() < Cobblemon.config.typeGemGrowthChance) || forceGrow
|
||||
) {
|
||||
clusterBlock.advanceGrowth(relativeState, level, relativePos, random)
|
||||
val matchesFace = relativeState.hasProperty(DirectionalBlock.FACING)
|
||||
&& relativeState.getValue(DirectionalBlock.FACING) == direction
|
||||
if (!(forceGrow || (matchesFace && random.nextFloat() < Cobblemon.config.typeGemGrowthChance))) {
|
||||
return@forEach
|
||||
}
|
||||
|
||||
val block = relativeState.block
|
||||
if (block is TypeGemClusterBlock) {
|
||||
block.advanceGrowth(relativeState, level, relativePos, random)
|
||||
} else if (isAmethystStage(block)) {
|
||||
advanceAmethyst(relativeState, level, relativePos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun advanceAmethyst(state: BlockState, level: LevelAccessor, pos: BlockPos) {
|
||||
val facing = state.getValue(DirectionalBlock.FACING)
|
||||
val supportState = level.getBlockState(pos.relative(facing.opposite))
|
||||
if (!supportState.`is`(CobblemonBlockTags.TYPE_GEM_BLOCKS) && supportState.block != CobblemonBlocks.TYPE_GEM_CORE) {
|
||||
return
|
||||
}
|
||||
|
||||
if (state.block != Blocks.AMETHYST_CLUSTER) {
|
||||
val nextStage = AMETHYST_STAGES[AMETHYST_STAGES.indexOf(state.block) + 1]
|
||||
level.setBlock(pos, nextStage.defaultBlockState().setValue(DirectionalBlock.FACING, facing), 3)
|
||||
return
|
||||
}
|
||||
|
||||
// Fully grown clusters mature into amethyst blocks unless boxed in, mirroring stunted type gems
|
||||
val boxedIn = Direction.entries.any { direction ->
|
||||
direction != facing.opposite
|
||||
&& level.getBlockState(pos.relative(direction)).`is`(CobblemonBlockTags.TYPE_GEM_BLOCKS)
|
||||
}
|
||||
if (!boxedIn) {
|
||||
level.setBlock(pos, Blocks.AMETHYST_BLOCK.defaultBlockState(), 3)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* 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.appliances
|
||||
|
||||
import com.cobblemon.mod.common.util.rotateShape
|
||||
import com.mojang.serialization.MapCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
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.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.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.entity.EntityTypeTest
|
||||
import net.minecraft.world.level.material.FluidState
|
||||
import net.minecraft.world.level.material.Fluids
|
||||
import net.minecraft.world.phys.AABB
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.CollisionContext
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
//TODO: All the Fan appliance stuff
|
||||
//TODO: Able to place the Fan on Walls, models and hitbox are there (blockstate would need edits to support it)
|
||||
open class CopperFanBlock(settings: Properties) : HorizontalDirectionalBlock(settings), SimpleWaterloggedBlock {
|
||||
|
||||
companion object {
|
||||
val CODEC: MapCodec<CopperFanBlock> = RecordCodecBuilder.mapCodec {
|
||||
it.group(propertiesCodec()).apply(it, ::CopperFanBlock) }
|
||||
//val FACE = //TODO: Floor/Wall
|
||||
val POWER = BlockStateProperties.POWER;
|
||||
val PUSH = BooleanProperty.create("push")
|
||||
|
||||
val FLOOR_HITBOX = Shapes.or(
|
||||
Shapes.box(0.0625, 0.125, 0.4375, 0.9375, 1.0, 0.5625),
|
||||
Shapes.box(0.375, 0.0, 0.375, 0.625, 0.125, 0.625))
|
||||
val WALL_HITBOX = Shapes.box(0.0625, 0.0625, 0.875, 0.9375, 0.9375, 1.0)
|
||||
}
|
||||
|
||||
init {
|
||||
registerDefaultState(stateDefinition.any()
|
||||
.setValue(HORIZONTAL_FACING, Direction.NORTH)
|
||||
.setValue(WATERLOGGED, false)
|
||||
//.setValue(FACE, AttachFace.FLOOR)
|
||||
.setValue(POWER, 0)
|
||||
.setValue(PUSH, true) //If True, fan pushes entities, If False, fan is cosmetic only
|
||||
)
|
||||
}
|
||||
|
||||
override fun useWithoutItem(
|
||||
state: BlockState,
|
||||
level: Level,
|
||||
pos: BlockPos,
|
||||
player: Player,
|
||||
hitResult: BlockHitResult
|
||||
): InteractionResult {
|
||||
if (!level.isClientSide) {
|
||||
level.setBlockAndUpdate(pos, state.setValue(PUSH, !state.getValue(PUSH)))
|
||||
level.playSound(null, pos, SoundEvents.STONE_BUTTON_CLICK_ON, SoundSource.BLOCKS)
|
||||
}
|
||||
return InteractionResult.SUCCESS
|
||||
}
|
||||
|
||||
override fun codec(): MapCodec<CopperFanBlock> = CODEC
|
||||
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
|
||||
builder.add(HORIZONTAL_FACING, WATERLOGGED, /*FACE,*/ POWER, PUSH)
|
||||
}
|
||||
|
||||
override fun getFluidState(blockState: BlockState): FluidState? = if (blockState.getValue(WATERLOGGED)) Fluids.WATER.getSource(false) else super.getFluidState(blockState)
|
||||
|
||||
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 (state.getValue(HORIZONTAL_FACING).opposite == direction && !state.canSurvive(world, pos)) Blocks.AIR.defaultBlockState()
|
||||
else super.updateShape(state, direction, neighborState, world, pos, neighborPos)
|
||||
}
|
||||
|
||||
override fun getCollisionShape(state: BlockState, level: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape {
|
||||
val direction = state.getValue(HORIZONTAL_FACING)
|
||||
return rotateShape(Direction.NORTH, direction, FLOOR_HITBOX)
|
||||
}
|
||||
|
||||
override fun neighborChanged(
|
||||
state: BlockState,
|
||||
level: Level,
|
||||
pos: BlockPos,
|
||||
neighborBlock: Block,
|
||||
neighborPos: BlockPos,
|
||||
movedByPiston: Boolean
|
||||
) {
|
||||
val power = level.getBestNeighborSignal(pos)
|
||||
if (power != state.getValue(POWER)) {
|
||||
level.setBlock(pos, state.setValue(POWER, power), UPDATE_CLIENTS)
|
||||
if (power > 0) {
|
||||
level.scheduleTick(pos, this, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun tick(state: BlockState, level: ServerLevel, pos: BlockPos, random: RandomSource) {
|
||||
val facing = state.getValue(HORIZONTAL_FACING)
|
||||
val power = state.getValue(POWER)
|
||||
|
||||
if (power == 0) return
|
||||
|
||||
if (state.getValue(PUSH)) {
|
||||
val area = AABB(pos.relative(facing)).expandTowards(
|
||||
facing.stepX.toDouble() * (power - 1),
|
||||
0.0,
|
||||
facing.stepZ.toDouble() * (power - 1)
|
||||
)
|
||||
val entities = level.getEntities(null, area)
|
||||
val pushForce = 0.05
|
||||
entities.forEach { entity ->
|
||||
val motion = entity.deltaMovement
|
||||
entity.setDeltaMovement(
|
||||
motion.x + facing.stepX * pushForce,
|
||||
motion.y,
|
||||
motion.z + facing.stepZ * pushForce
|
||||
)
|
||||
entity.hurtMarked = true
|
||||
}
|
||||
}
|
||||
|
||||
level.scheduleTick(pos, this, 1)
|
||||
}
|
||||
|
||||
override fun getShape(state: BlockState, level: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape {
|
||||
return getCollisionShape(state, level, pos, context)
|
||||
}
|
||||
|
||||
override fun getStateForPlacement(context: BlockPlaceContext): BlockState? {
|
||||
val fluidState = context.level.getFluidState(context.clickedPos)
|
||||
return super.getStateForPlacement(context)?.setValue(HORIZONTAL_FACING, context.horizontalDirection.opposite)?.setValue(WATERLOGGED, fluidState.type === Fluids.WATER)
|
||||
}
|
||||
}
|
||||
+283
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* 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.appliances
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlockEntities
|
||||
import com.cobblemon.mod.common.util.isServerSide
|
||||
import com.cobblemon.mod.common.util.rotateShape
|
||||
import com.mojang.serialization.MapCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
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.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.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.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.entity.BlockEntityTicker
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||
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.block.state.properties.DoubleBlockHalf
|
||||
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.phys.BlockHitResult
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.CollisionContext
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
//TODO: Oxidation/Waxing/Scraping not breaking the blocks
|
||||
//TODO: All the Fridge appliance stuff
|
||||
open class CopperFridgeBlock(settings: Properties) : BaseEntityBlock(settings), SimpleWaterloggedBlock {
|
||||
|
||||
fun getBlockEntity(level: ServerLevel, pos: BlockPos) = level.getBlockEntity(getBottomPos(level, pos)) as CopperFridgeBlockEntity
|
||||
|
||||
companion object {
|
||||
val CODEC: MapCodec<CopperFridgeBlock> = RecordCodecBuilder.mapCodec {
|
||||
it.group(propertiesCodec()).apply(it, ::CopperFridgeBlock) }
|
||||
val HALF: EnumProperty<DoubleBlockHalf> = BlockStateProperties.DOUBLE_BLOCK_HALF
|
||||
val POWERED = BooleanProperty.create("powered")
|
||||
val FACING = HorizontalDirectionalBlock.FACING
|
||||
|
||||
val LOWER_HITBOX = Shapes.or(
|
||||
Shapes.box(0.0625, 0.0, 0.125, 0.9375, 0.0625, 0.9375),
|
||||
Shapes.box(0.0, 0.0625, 0.0625, 1.0, 1.0, 1.0))
|
||||
val UPPER_HITBOX = 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))
|
||||
val UPPER_COLLISSIONBOX = Shapes.box(0.0, 0.0, 0.0625, 1.0, 1.0, 1.0)
|
||||
//The handles get ignored by entity collission, because it feels nicer, but still count as part of the hitbox
|
||||
}
|
||||
|
||||
init {
|
||||
registerDefaultState(stateDefinition.any()
|
||||
.setValue(HORIZONTAL_FACING, Direction.NORTH)
|
||||
.setValue(HALF, DoubleBlockHalf.LOWER)
|
||||
.setValue(WATERLOGGED, false)
|
||||
.setValue(POWERED, false)
|
||||
)
|
||||
}
|
||||
|
||||
override fun codec(): MapCodec<CopperFridgeBlock> = CODEC
|
||||
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
|
||||
builder.add(HORIZONTAL_FACING, HALF, WATERLOGGED, POWERED)
|
||||
}
|
||||
|
||||
override fun getFluidState(blockState: BlockState): FluidState? = if (blockState.getValue(WATERLOGGED)) Fluids.WATER.getSource(false) else super.getFluidState(blockState)
|
||||
|
||||
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.block is CopperFridgeBlock
|
||||
val half = state.getValue(HALF)
|
||||
if (!isFridge && half == DoubleBlockHalf.UPPER && neighborPos == pos.below()) {
|
||||
return Blocks.AIR.defaultBlockState()
|
||||
} else if (!isFridge && half == DoubleBlockHalf.LOWER && neighborPos == pos.above()) {
|
||||
return Blocks.AIR.defaultBlockState()
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
override fun getCollisionShape(state: BlockState, level: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape {
|
||||
val direction = state.getValue(HORIZONTAL_FACING)
|
||||
return if (state.getValue(HALF) == DoubleBlockHalf.LOWER) {
|
||||
rotateShape(Direction.NORTH, direction, LOWER_HITBOX)
|
||||
} else {
|
||||
rotateShape(Direction.NORTH, direction, UPPER_COLLISSIONBOX)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getShape(state: BlockState, level: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape {
|
||||
val direction = state.getValue(HORIZONTAL_FACING)
|
||||
return if (state.getValue(HALF) == DoubleBlockHalf.LOWER) {
|
||||
rotateShape(Direction.NORTH, direction, LOWER_HITBOX)
|
||||
} else {
|
||||
rotateShape(Direction.NORTH, direction, UPPER_HITBOX)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setPlacedBy(world: Level, pos: BlockPos, state: BlockState, placer: LivingEntity?, itemStack: ItemStack) {
|
||||
world.setBlock(pos.above(),
|
||||
state
|
||||
.setValue(HALF, DoubleBlockHalf.UPPER)
|
||||
.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(FACING, blockPlaceContext.horizontalDirection.opposite)
|
||||
.setValue(HALF, DoubleBlockHalf.LOWER)
|
||||
.setValue(WATERLOGGED, blockPlaceContext.level.getFluidState(blockPlaceContext.clickedPos).type == Fluids.WATER)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getRenderShape(state: BlockState) = RenderShape.MODEL
|
||||
|
||||
override fun canSurvive(state: BlockState, world: LevelReader, pos: BlockPos): Boolean {
|
||||
val blockPos = pos.below()
|
||||
val blockState = world.getBlockState(blockPos)
|
||||
return if (state.getValue(HALF) == DoubleBlockHalf.LOWER) blockState.isFaceSturdy(world, blockPos, Direction.UP) else blockState.`is`(this)
|
||||
}
|
||||
|
||||
override fun playerWillDestroy(world: Level, pos: BlockPos, state: BlockState, player: Player): BlockState {
|
||||
if (!world.isClientSide && player.isCreative) {
|
||||
var blockPos: BlockPos = BlockPos.ZERO
|
||||
var blockState: BlockState = state
|
||||
val half = state.getValue(HALF)
|
||||
if (half == DoubleBlockHalf.UPPER && world.getBlockState(pos.below().also { blockPos = it }).also { blockState = it }.`is`(state.block) && blockState.getValue(
|
||||
HALF
|
||||
) == DoubleBlockHalf.LOWER) {
|
||||
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 hasAnalogOutputSignal(state: BlockState) = true
|
||||
|
||||
override fun useItemOn(
|
||||
stack: ItemStack,
|
||||
state: BlockState,
|
||||
level: Level,
|
||||
pos: BlockPos,
|
||||
player: Player,
|
||||
hand: InteractionHand,
|
||||
hitResult: BlockHitResult
|
||||
): ItemInteractionResult {
|
||||
if (level.isServerSide()) {
|
||||
val handStack = player.getItemInHand(hand)
|
||||
val stack = getBlockEntity(level as ServerLevel, pos).theItem
|
||||
|
||||
when (stack.item) {
|
||||
Items.AIR -> {
|
||||
if (handStack.`is`(Items.WATER_BUCKET)) {
|
||||
if (!player.isCreative) player.setItemInHand(hand, Items.BUCKET.defaultInstance)
|
||||
getBlockEntity(level, pos).timer = 100
|
||||
getBlockEntity(level, pos).theItem = Items.WATER_BUCKET.defaultInstance
|
||||
level.playSound(null, pos, SoundEvents.BUCKET_EMPTY, SoundSource.BLOCKS, 1.0f, 1.0f)
|
||||
return ItemInteractionResult.SUCCESS
|
||||
} else {
|
||||
return ItemInteractionResult.FAIL
|
||||
}
|
||||
}
|
||||
|
||||
Items.WATER_BUCKET -> {
|
||||
if (handStack.`is`(Items.BUCKET)) {
|
||||
player.setItemInHand(hand, Items.WATER_BUCKET.defaultInstance)
|
||||
getBlockEntity(level, pos).theItem = Items.AIR.defaultInstance
|
||||
getBlockEntity(level, pos).timer = 0
|
||||
level.playSound(null, pos, SoundEvents.BUCKET_FILL, SoundSource.BLOCKS, 1.0f, 1.0f)
|
||||
return ItemInteractionResult.SUCCESS
|
||||
} else {
|
||||
return ItemInteractionResult.FAIL
|
||||
}
|
||||
}
|
||||
|
||||
Items.ICE -> {
|
||||
val facing = state.getValue(HORIZONTAL_FACING)
|
||||
val spawnPos = getBottomPos(level, pos)
|
||||
val itemEntity =
|
||||
ItemEntity(level, spawnPos.x + 0.5, spawnPos.y + 0.5, spawnPos.z + 0.5, Items.ICE.defaultInstance)
|
||||
itemEntity.deltaMovement = Vec3(facing.stepX.toDouble(), 0.0, facing.stepZ.toDouble()).scale(0.2)
|
||||
level.addFreshEntity(itemEntity)
|
||||
getBlockEntity(level, pos).theItem = Items.AIR.defaultInstance
|
||||
return ItemInteractionResult.SUCCESS
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return if (stack.`is`(Items.WATER_BUCKET)) ItemInteractionResult.SUCCESS
|
||||
else ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION
|
||||
}
|
||||
return ItemInteractionResult.SUCCESS // should not be reachable, but intellij doesnt like that its not there
|
||||
}
|
||||
|
||||
override fun getAnalogOutputSignal(state: BlockState, level: Level, pos: BlockPos): Int {
|
||||
if (level.isClientSide) return 0
|
||||
return when (getBlockEntity(level as ServerLevel, pos).theItem.item) {
|
||||
Items.WATER_BUCKET -> 1
|
||||
Items.ICE -> 2
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
|
||||
override fun tick(state: BlockState, level: ServerLevel, pos: BlockPos, random: RandomSource) {
|
||||
(level.getBlockEntity(pos) as CopperFridgeBlockEntity).processTick()
|
||||
super.tick(state, level, pos, random)
|
||||
}
|
||||
|
||||
override fun newBlockEntity(pos: BlockPos, state: BlockState) = if (state.getValue(HALF) == DoubleBlockHalf.LOWER) CopperFridgeBlockEntity(pos, state) else null
|
||||
|
||||
override fun neighborChanged(
|
||||
state: BlockState,
|
||||
level: Level,
|
||||
pos: BlockPos,
|
||||
neighborBlock: Block,
|
||||
neighborPos: BlockPos,
|
||||
movedByPiston: Boolean
|
||||
) {
|
||||
if (!level.isClientSide) {
|
||||
val otherPos = if (state.getValue(HALF) == DoubleBlockHalf.LOWER) pos.above() else pos.below()
|
||||
val powered = level.hasNeighborSignal(pos) || level.hasNeighborSignal(otherPos)
|
||||
|
||||
if (state.getValue(POWERED) != powered) {
|
||||
level.setBlock(pos, state.setValue(POWERED, powered), 3)
|
||||
}
|
||||
|
||||
val otherState = level.getBlockState(otherPos)
|
||||
if (otherState.`is`(this) && otherState.getValue(POWERED) != powered) {
|
||||
level.setBlock(otherPos, otherState.setValue(POWERED, powered), 3)
|
||||
}
|
||||
}
|
||||
super.neighborChanged(state, level, pos, neighborBlock, neighborPos, movedByPiston)
|
||||
}
|
||||
|
||||
override fun <T : BlockEntity> getTicker(
|
||||
level: Level,
|
||||
state: BlockState,
|
||||
blockEntityType: BlockEntityType<T>
|
||||
): BlockEntityTicker<T>? {
|
||||
return if (level.isClientSide)
|
||||
null
|
||||
else
|
||||
createTickerHelper(blockEntityType, CobblemonBlockEntities.COPPER_FRIDGE, CopperFridgeBlockEntity.TICKER::tick)
|
||||
}
|
||||
|
||||
fun getBottomPos(level: Level, pos: BlockPos) = if (level.getBlockState(pos).getValue(HALF) == DoubleBlockHalf.UPPER) pos.below() else pos
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package com.cobblemon.mod.common.block.appliances
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlockEntities
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.Container
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.entity.BlockEntityTicker
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.ticks.ContainerSingleItem
|
||||
|
||||
class CopperFridgeBlockEntity(val pos: BlockPos, val state: BlockState) : BlockEntity(
|
||||
CobblemonBlockEntities.COPPER_FRIDGE, pos, state
|
||||
), ContainerSingleItem.BlockContainerSingleItem {
|
||||
|
||||
private var item: ItemStack = Items.AIR.defaultInstance
|
||||
var timer: Int = -1
|
||||
|
||||
fun processTick() {
|
||||
val serverLevel = level as? ServerLevel ?: return
|
||||
|
||||
if (item.`is`(Items.ICE) && serverLevel.gameTime % 20L == 0L) {
|
||||
val facing = state.getValue(CopperFridgeBlock.FACING)
|
||||
val particlePosition = Vec3(
|
||||
pos.x + 0.5 + facing.stepX * 0.55,
|
||||
pos.y + 1.0,
|
||||
pos.z + 0.5 + facing.stepZ * 0.55
|
||||
)
|
||||
val packet = SpawnSnowstormParticlePacket(cobblemonResource("rotomfridge_doorready"), particlePosition)
|
||||
|
||||
serverLevel.players()
|
||||
.filter { it.distanceToSqr(particlePosition.x, particlePosition.y, particlePosition.z) <= 32.0 * 32.0 }
|
||||
.forEach { it.sendPacket(packet) }
|
||||
}
|
||||
|
||||
if (!serverLevel.getBlockState(pos).getValue(CopperFridgeBlock.POWERED)) return
|
||||
if (timer > 0) timer--
|
||||
if (timer == 0 && item.item == Items.WATER_BUCKET) {
|
||||
theItem = Items.ICE.defaultInstance
|
||||
timer = -1
|
||||
}
|
||||
}
|
||||
|
||||
override fun getContainerBlockEntity() = this
|
||||
override fun getTheItem() = item
|
||||
|
||||
override fun setTheItem(item: ItemStack) {
|
||||
this.item = item
|
||||
level?.updateNeighborsAt(pos, state.block)
|
||||
}
|
||||
|
||||
override fun canTakeItem(target: Container, slot: Int, stack: ItemStack): Boolean {
|
||||
return stack.item == Items.ICE
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal val TICKER = BlockEntityTicker<CopperFridgeBlockEntity> { level, pos, state, entity ->
|
||||
if (!level.isClientSide) {
|
||||
entity.processTick()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.appliances
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.rotateShape
|
||||
import com.mojang.serialization.MapCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.core.registries.BuiltInRegistries
|
||||
import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.resources.ResourceKey
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.sounds.SoundSource
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.world.entity.item.ItemEntity
|
||||
import net.minecraft.world.item.BlockItem
|
||||
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.block.*
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.StateDefinition
|
||||
import net.minecraft.world.level.block.state.properties.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.material.FluidState
|
||||
import net.minecraft.world.level.material.Fluids
|
||||
import net.minecraft.world.level.storage.loot.LootParams
|
||||
import net.minecraft.world.level.storage.loot.LootTable
|
||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParam
|
||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets
|
||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParams
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.CollisionContext
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
//TODO: All the Mower appliance stuff
|
||||
open class CopperMowerBlock(settings: Properties) : HorizontalDirectionalBlock(settings), SimpleWaterloggedBlock {
|
||||
|
||||
companion object {
|
||||
val CODEC: MapCodec<CopperMowerBlock> = RecordCodecBuilder.mapCodec {
|
||||
it.group(propertiesCodec()).apply(it, ::CopperMowerBlock) }
|
||||
val TRIGGERED = BooleanProperty.create("triggered")
|
||||
|
||||
val COLLISIONBOX = Shapes.or(
|
||||
Shapes.box(0.1875, 0.0, 0.0, 0.8125, 0.375, 0.625),
|
||||
Shapes.box(0.0625, 0.0, 0.625, 0.9375, 0.625, 1.0),
|
||||
Shapes.box(0.125, 0.0, 0.1875, 0.875, 0.3125, 0.5),
|
||||
//The next three lines are just so the handle does have collision, it feels awkward without it but it looks bad as hitbox
|
||||
Shapes.box(0.375, 0.375, 0.375, 0.625, 0.625, 0.5625),
|
||||
Shapes.box(0.4375, 0.5625, 0.5, 0.5625, 0.875, 0.625),
|
||||
Shapes.box(0.25, 0.875, 0.5625, 0.75, 1.0, 0.6875)
|
||||
)
|
||||
val HITBOX = Shapes.or(
|
||||
Shapes.box(0.1875, 0.0, 0.0, 0.8125, 0.375, 0.625),
|
||||
Shapes.box(0.0625, 0.0, 0.625, 0.9375, 0.625, 1.0),
|
||||
Shapes.box(0.125, 0.0, 0.1875, 0.875, 0.3125, 0.5)
|
||||
)
|
||||
}
|
||||
|
||||
init {
|
||||
registerDefaultState(stateDefinition.any()
|
||||
.setValue(HORIZONTAL_FACING, Direction.NORTH)
|
||||
.setValue(WATERLOGGED, false)
|
||||
.setValue(TRIGGERED, false)
|
||||
)
|
||||
}
|
||||
|
||||
override fun neighborChanged(
|
||||
state: BlockState,
|
||||
level: Level,
|
||||
pos: BlockPos,
|
||||
sourceBlock: Block,
|
||||
sourcePos: BlockPos,
|
||||
notify: Boolean
|
||||
) {
|
||||
val powered = level.hasNeighborSignal(pos) || level.hasNeighborSignal(pos.above())
|
||||
val triggered = state.getValue(TRIGGERED)
|
||||
|
||||
if (powered && !triggered) {
|
||||
level.setBlock(pos, state.setValue(TRIGGERED, true), UPDATE_CLIENTS)
|
||||
level.scheduleTick(pos, this, 1)
|
||||
} else if (!powered && triggered) {
|
||||
level.setBlock(pos, state.setValue(TRIGGERED, false), UPDATE_CLIENTS)
|
||||
}
|
||||
}
|
||||
|
||||
override fun hasAnalogOutputSignal(state: BlockState) = true
|
||||
|
||||
override fun tick(state: BlockState, level: ServerLevel, pos: BlockPos, random: RandomSource) {
|
||||
val blockKey = BuiltInRegistries.BLOCK.getKey(level.getBlockState(pos.below()).block)
|
||||
val tableKey = ResourceKey.create(Registries.LOOT_TABLE, cobblemonResource("mower/${blockKey.path}"))
|
||||
val lootTable = level.server.reloadableRegistries().getLootTable(tableKey)
|
||||
if (lootTable == LootTable.EMPTY) return
|
||||
val params = LootParams.Builder(level)
|
||||
.withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(pos.below()))
|
||||
.withParameter(LootContextParams.BLOCK_STATE, level.getBlockState(pos.below()))
|
||||
.withParameter(LootContextParams.TOOL, ItemStack.EMPTY)
|
||||
.create(LootContextParamSets.BLOCK)
|
||||
|
||||
val result = lootTable.getRandomItems(params, random)
|
||||
val block = result.getOrNull(0)?.item as? BlockItem
|
||||
val item = result.getOrNull(1)
|
||||
|
||||
if (block == null || block == Blocks.AIR) {
|
||||
level.destroyBlock(pos.below(), false)
|
||||
} else {
|
||||
level.setBlockAndUpdate(pos.below(), block.block.defaultBlockState())
|
||||
}
|
||||
item?.let {
|
||||
val facing = state.getValue(HORIZONTAL_FACING).opposite
|
||||
val itemEntity =
|
||||
ItemEntity(level,
|
||||
pos.x + 0.5, pos.y + 0.5, pos.z + 0.5,
|
||||
it
|
||||
)
|
||||
itemEntity.deltaMovement = Vec3(facing.stepX.toDouble(), 0.0, facing.stepZ.toDouble()).scale(0.2)
|
||||
level.addFreshEntity(itemEntity)
|
||||
}
|
||||
level.playSound(null, pos, CobblemonSounds.MOWER_CUT, SoundSource.BLOCKS)
|
||||
}
|
||||
|
||||
override fun getRenderShape(state: BlockState) = RenderShape.MODEL
|
||||
|
||||
override fun codec(): MapCodec<CopperMowerBlock> = CODEC
|
||||
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
|
||||
builder.add(HORIZONTAL_FACING, WATERLOGGED, TRIGGERED)
|
||||
}
|
||||
|
||||
override fun getFluidState(blockState: BlockState): FluidState? = if (blockState.getValue(WATERLOGGED)) Fluids.WATER.getSource(false) else super.getFluidState(blockState)
|
||||
|
||||
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 (state.getValue(HORIZONTAL_FACING).opposite == direction && !state.canSurvive(world, pos)) Blocks.AIR.defaultBlockState()
|
||||
else super.updateShape(state, direction, neighborState, world, pos, neighborPos)
|
||||
}
|
||||
|
||||
override fun getCollisionShape(state: BlockState, level: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape {
|
||||
val direction = state.getValue(HORIZONTAL_FACING)
|
||||
return rotateShape(Direction.NORTH, direction, COLLISIONBOX)
|
||||
}
|
||||
|
||||
override fun getShape(state: BlockState, level: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape {
|
||||
val direction = state.getValue(HORIZONTAL_FACING)
|
||||
return rotateShape(Direction.NORTH, direction, HITBOX)
|
||||
}
|
||||
|
||||
override fun getStateForPlacement(context: BlockPlaceContext): BlockState? {
|
||||
val fluidState = context.level.getFluidState(context.clickedPos)
|
||||
return super.getStateForPlacement(context)?.setValue(HORIZONTAL_FACING, context.horizontalDirection.opposite)?.setValue(WATERLOGGED, fluidState.type === Fluids.WATER)
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package com.cobblemon.mod.common.block.appliances
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlockEntities
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
|
||||
class CopperMowerBlockEntity(val pos: BlockPos, val state: BlockState) : BlockEntity(
|
||||
CobblemonBlockEntities.COPPER_MOWER,
|
||||
pos, state
|
||||
) {
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.appliances
|
||||
|
||||
import com.cobblemon.mod.common.util.rotateShape
|
||||
import com.mojang.serialization.MapCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.util.StringRepresentable
|
||||
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.*
|
||||
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.block.state.properties.BooleanProperty
|
||||
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.phys.shapes.CollisionContext
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
//TODO: All the Oven appliance stuff - Good Luck Coders
|
||||
open class CopperOvenBlock(settings: Properties) : HorizontalDirectionalBlock(settings), SimpleWaterloggedBlock {
|
||||
|
||||
companion object {
|
||||
val CODEC: MapCodec<CopperOvenBlock> = RecordCodecBuilder.mapCodec {
|
||||
it.group(propertiesCodec()).apply(it, ::CopperOvenBlock) }
|
||||
val EJECTING = BooleanProperty.create("ejecting")
|
||||
val COOKING = EnumProperty.create("cooking", CookingState::class.java)
|
||||
|
||||
val HITBOX = Shapes.box(0.0625, 0.0, 0.3125, 0.9375, 0.625, 0.9375)
|
||||
}
|
||||
|
||||
init {
|
||||
registerDefaultState(stateDefinition.any()
|
||||
.setValue(HORIZONTAL_FACING, Direction.NORTH)
|
||||
.setValue(WATERLOGGED, false)
|
||||
.setValue(COOKING, CookingState.CLOSED)
|
||||
.setValue(EJECTING, false)
|
||||
)
|
||||
}
|
||||
enum class CookingState : StringRepresentable {
|
||||
CLOSED, //Door is closed
|
||||
OPEN, //Door is open
|
||||
COOKING; //Door is locked closed and the light level is cranked up, as long as the block is powered by redstone. Acts as closed lid in the original Campfire Pot
|
||||
override fun getSerializedName(): String = this.name.lowercase()
|
||||
}
|
||||
|
||||
override fun codec(): MapCodec<CopperOvenBlock> = CODEC
|
||||
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
|
||||
builder.add(HORIZONTAL_FACING, WATERLOGGED, COOKING, EJECTING)
|
||||
}
|
||||
|
||||
override fun getFluidState(blockState: BlockState): FluidState? = if (blockState.getValue(WATERLOGGED)) Fluids.WATER.getSource(false) else super.getFluidState(blockState)
|
||||
|
||||
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 (state.getValue(HORIZONTAL_FACING).opposite == direction && !state.canSurvive(world, pos)) Blocks.AIR.defaultBlockState()
|
||||
else super.updateShape(state, direction, neighborState, world, pos, neighborPos)
|
||||
}
|
||||
|
||||
override fun getCollisionShape(state: BlockState, level: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape {
|
||||
val direction = state.getValue(HORIZONTAL_FACING)
|
||||
return rotateShape(Direction.NORTH, direction, HITBOX)
|
||||
}
|
||||
|
||||
override fun getShape(state: BlockState, level: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape {
|
||||
return getCollisionShape(state, level, pos, context).singleEncompassing()
|
||||
}
|
||||
|
||||
override fun getStateForPlacement(context: BlockPlaceContext): BlockState? {
|
||||
val fluidState = context.level.getFluidState(context.clickedPos)
|
||||
return super.getStateForPlacement(context)?.setValue(HORIZONTAL_FACING, context.horizontalDirection.opposite)?.setValue(WATERLOGGED, fluidState.type === Fluids.WATER)
|
||||
}
|
||||
}
|
||||
+133
@@ -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.appliances
|
||||
|
||||
import com.cobblemon.mod.common.util.isServerSide
|
||||
import com.cobblemon.mod.common.util.rotateShape
|
||||
import com.mojang.serialization.MapCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
import net.minecraft.sounds.SoundSource
|
||||
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.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.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.StateDefinition
|
||||
import net.minecraft.world.level.block.state.properties.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.material.FluidState
|
||||
import net.minecraft.world.level.material.Fluids
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraft.world.phys.shapes.CollisionContext
|
||||
import net.minecraft.world.phys.shapes.Shapes
|
||||
import net.minecraft.world.phys.shapes.VoxelShape
|
||||
|
||||
open class CopperWasherBlock(settings: Properties) : BaseEntityBlock(settings), SimpleWaterloggedBlock {
|
||||
|
||||
companion object {
|
||||
val CODEC: MapCodec<CopperWasherBlock> = RecordCodecBuilder.mapCodec {
|
||||
it.group(propertiesCodec()).apply(it, ::CopperWasherBlock) }
|
||||
val POWERED = BooleanProperty.create("powered")
|
||||
|
||||
val HITBOX = Shapes.box(0.0625, 0.0, 0.125, 0.9375, 1.0, 1.0)
|
||||
}
|
||||
|
||||
init {
|
||||
registerDefaultState(stateDefinition.any()
|
||||
.setValue(HORIZONTAL_FACING, Direction.NORTH)
|
||||
.setValue(WATERLOGGED, false)
|
||||
.setValue(POWERED, false)
|
||||
)
|
||||
}
|
||||
|
||||
override fun codec(): MapCodec<CopperWasherBlock> = CODEC
|
||||
|
||||
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
|
||||
builder.add(HORIZONTAL_FACING, WATERLOGGED, POWERED)
|
||||
}
|
||||
|
||||
override fun getFluidState(blockState: BlockState): FluidState? = if (blockState.getValue(WATERLOGGED)) Fluids.WATER.getSource(false) else super.getFluidState(blockState)
|
||||
|
||||
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 (state.getValue(HORIZONTAL_FACING).opposite == direction && !state.canSurvive(world, pos)) Blocks.AIR.defaultBlockState()
|
||||
else super.updateShape(state, direction, neighborState, world, pos, neighborPos)
|
||||
}
|
||||
|
||||
override fun getCollisionShape(state: BlockState, level: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape {
|
||||
val direction = state.getValue(HORIZONTAL_FACING)
|
||||
return rotateShape(Direction.NORTH, direction, HITBOX)
|
||||
}
|
||||
|
||||
override fun getShape(state: BlockState, level: BlockGetter, pos: BlockPos, context: CollisionContext): VoxelShape {
|
||||
return getCollisionShape(state, level, pos, context).singleEncompassing()
|
||||
}
|
||||
|
||||
override fun getStateForPlacement(context: BlockPlaceContext): BlockState? {
|
||||
val fluidState = context.level.getFluidState(context.clickedPos)
|
||||
return super.getStateForPlacement(context)?.setValue(HORIZONTAL_FACING, context.horizontalDirection.opposite)?.setValue(WATERLOGGED, fluidState.type === Fluids.WATER)
|
||||
}
|
||||
|
||||
override fun newBlockEntity(pos: BlockPos, state: BlockState) = CopperWasherBlockEntity(pos, state)
|
||||
|
||||
override fun getRenderShape(state: BlockState) = RenderShape.MODEL
|
||||
|
||||
override fun hasAnalogOutputSignal(state: BlockState) = true
|
||||
|
||||
override fun getAnalogOutputSignal(state: BlockState, level: Level, pos: BlockPos): Int {
|
||||
return if ((level.getBlockEntity(pos) as CopperWasherBlockEntity).theItem != ItemStack.EMPTY) 1 else 0
|
||||
}
|
||||
|
||||
override fun useItemOn(
|
||||
stack: ItemStack,
|
||||
state: BlockState,
|
||||
level: Level,
|
||||
pos: BlockPos,
|
||||
player: Player,
|
||||
hand: InteractionHand,
|
||||
hitResult: BlockHitResult
|
||||
): ItemInteractionResult {
|
||||
val entity = level.getBlockEntity(pos) as CopperWasherBlockEntity
|
||||
val item = entity.theItem
|
||||
if (item == ItemStack.EMPTY) {
|
||||
if (level.isServerSide()) {
|
||||
entity.theItem = stack.copyWithCount(1)
|
||||
if (!player.isCreative) stack.shrink(1)
|
||||
entity.craft()
|
||||
}
|
||||
return ItemInteractionResult.SUCCESS
|
||||
} else {
|
||||
if (level.isServerSide()) {
|
||||
val facing = state.getValue(HORIZONTAL_FACING)
|
||||
val itemEntity =
|
||||
ItemEntity(level, pos.x + 0.5, pos.y + 0.5, pos.z + 0.5, entity.theItem)
|
||||
itemEntity.deltaMovement = Vec3(facing.stepX.toDouble(), 0.0, facing.stepZ.toDouble()).scale(0.2)
|
||||
level.addFreshEntity(itemEntity)
|
||||
entity.theItem = ItemStack.EMPTY
|
||||
level.playSound(null, pos, SoundEvents.ITEM_FRAME_REMOVE_ITEM, SoundSource.BLOCKS)
|
||||
}
|
||||
return ItemInteractionResult.SUCCESS
|
||||
}
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package com.cobblemon.mod.common.block.appliances
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonBlockEntities
|
||||
import com.cobblemon.mod.common.CobblemonRecipeTypes
|
||||
import com.cobblemon.mod.common.item.crafting.washer.WasherInput
|
||||
import com.cobblemon.mod.common.util.isServerSide
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.ticks.ContainerSingleItem
|
||||
|
||||
class CopperWasherBlockEntity(val pos: BlockPos, val state: BlockState): BlockEntity(
|
||||
CobblemonBlockEntities.COPPER_WASHER,
|
||||
pos, state
|
||||
), ContainerSingleItem.BlockContainerSingleItem {
|
||||
|
||||
private var item: ItemStack = ItemStack.EMPTY
|
||||
|
||||
override fun getContainerBlockEntity() = this
|
||||
override fun getTheItem() = item
|
||||
override fun setTheItem(item: ItemStack) {
|
||||
this.item = item
|
||||
level?.updateNeighborsAt(pos, state.block)
|
||||
}
|
||||
|
||||
fun craft() {
|
||||
val level = level ?: return
|
||||
if (level.isClientSide || theItem.isEmpty) return
|
||||
|
||||
val input = WasherInput(theItem.copyWithCount(1))
|
||||
val recipe = level.recipeManager
|
||||
.getRecipeFor(CobblemonRecipeTypes.WASHER, input, level)
|
||||
.orElse(null) ?: return
|
||||
|
||||
theItem = recipe.value().assemble(input, level.registryAccess())
|
||||
setChanged()
|
||||
level.sendBlockUpdated(worldPosition, blockState, blockState, 3)
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.appliances
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.world.level.block.WeatheringCopper
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
|
||||
class WeatheringCopperFanBlock(val weatherState: WeatheringCopper.WeatherState, properties: Properties) :
|
||||
CopperFanBlock(properties), WeatheringCopper {
|
||||
|
||||
override fun randomTick(state: BlockState?, level: ServerLevel?, pos: BlockPos?, random: RandomSource?) {
|
||||
this.changeOverTime(state, level, pos, random)
|
||||
}
|
||||
|
||||
override fun isRandomlyTicking(state: BlockState): Boolean {
|
||||
return WeatheringCopper.getNext(state.getBlock()).isPresent()
|
||||
}
|
||||
|
||||
override fun getAge(): WeatheringCopper.WeatherState {
|
||||
return this.weatherState
|
||||
}
|
||||
}
|
||||
+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.block.appliances
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.WeatheringCopper
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties
|
||||
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf
|
||||
|
||||
class WeatheringCopperFridgeBlock(val weatherState: WeatheringCopper.WeatherState, properties: Properties) :
|
||||
CopperFridgeBlock(properties), WeatheringCopper {
|
||||
|
||||
override fun randomTick(state: BlockState, level: ServerLevel, pos: BlockPos, random: RandomSource) {
|
||||
if (state.getValue(HALF) == DoubleBlockHalf.LOWER) {
|
||||
this.changeOverTime(state, level, pos, random)
|
||||
}
|
||||
}
|
||||
|
||||
override fun changeOverTime(state: BlockState, level: ServerLevel, pos: BlockPos, random: RandomSource) {
|
||||
val upperPos = pos.above()
|
||||
val upperState = level.getBlockState(upperPos)
|
||||
if (upperState.block != this || upperState.getValue(HALF) != DoubleBlockHalf.UPPER) {
|
||||
return
|
||||
}
|
||||
|
||||
if (random.nextFloat() < 0.05688889F) {
|
||||
getNextState(state, level, pos, random).ifPresent { nextState ->
|
||||
val nextLowerState = nextState.setValue(HALF, DoubleBlockHalf.LOWER)
|
||||
val nextUpperState = nextState
|
||||
.setValue(HALF, DoubleBlockHalf.UPPER)
|
||||
.setValue(FACING, upperState.getValue(FACING))
|
||||
.setValue(BlockStateProperties.WATERLOGGED, upperState.getValue(BlockStateProperties.WATERLOGGED))
|
||||
.setValue(POWERED, upperState.getValue(POWERED))
|
||||
|
||||
level.setBlock(pos, nextLowerState, UPDATE_CLIENTS)
|
||||
level.setBlock(upperPos, nextUpperState, UPDATE_ALL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun isRandomlyTicking(state: BlockState): Boolean {
|
||||
return WeatheringCopper.getNext(state.block).isPresent
|
||||
}
|
||||
|
||||
override fun getAge(): WeatheringCopper.WeatherState {
|
||||
return this.weatherState
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.appliances
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.world.level.block.WeatheringCopper
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
|
||||
class WeatheringCopperMowerBlock(val weatherState: WeatheringCopper.WeatherState, properties: Properties) :
|
||||
CopperMowerBlock(properties), WeatheringCopper {
|
||||
|
||||
override fun randomTick(state: BlockState?, level: ServerLevel?, pos: BlockPos?, random: RandomSource?) {
|
||||
this.changeOverTime(state, level, pos, random)
|
||||
}
|
||||
|
||||
override fun isRandomlyTicking(state: BlockState): Boolean {
|
||||
return WeatheringCopper.getNext(state.getBlock()).isPresent()
|
||||
}
|
||||
|
||||
override fun getAge(): WeatheringCopper.WeatherState {
|
||||
return this.weatherState
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.appliances
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.world.level.block.WeatheringCopper
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
|
||||
class WeatheringCopperOvenBlock(val weatherState: WeatheringCopper.WeatherState, properties: Properties) :
|
||||
CopperOvenBlock(properties), WeatheringCopper {
|
||||
|
||||
override fun randomTick(state: BlockState?, level: ServerLevel?, pos: BlockPos?, random: RandomSource?) {
|
||||
this.changeOverTime(state, level, pos, random)
|
||||
}
|
||||
|
||||
override fun isRandomlyTicking(state: BlockState): Boolean {
|
||||
return WeatheringCopper.getNext(state.getBlock()).isPresent()
|
||||
}
|
||||
|
||||
override fun getAge(): WeatheringCopper.WeatherState {
|
||||
return this.weatherState
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.appliances
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.world.level.block.WeatheringCopper
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
|
||||
class WeatheringCopperWasherBlock(val weatherState: WeatheringCopper.WeatherState, properties: Properties) :
|
||||
CopperWasherBlock(properties), WeatheringCopper {
|
||||
|
||||
override fun randomTick(state: BlockState?, level: ServerLevel?, pos: BlockPos?, random: RandomSource?) {
|
||||
this.changeOverTime(state, level, pos, random)
|
||||
}
|
||||
|
||||
override fun isRandomlyTicking(state: BlockState): Boolean {
|
||||
return WeatheringCopper.getNext(state.getBlock()).isPresent()
|
||||
}
|
||||
|
||||
override fun getAge(): WeatheringCopper.WeatherState {
|
||||
return this.weatherState
|
||||
}
|
||||
}
|
||||
@@ -11,9 +11,11 @@ package com.cobblemon.mod.common.block.chest
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.scheduling.afterOnServer
|
||||
import com.cobblemon.mod.common.block.PokemonDisguiseBlock
|
||||
import com.cobblemon.mod.common.block.entity.GildedChestBlockEntity
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.math.FloatRange
|
||||
import com.cobblemon.mod.common.util.party
|
||||
import com.cobblemon.mod.common.util.toVec3d
|
||||
import com.mojang.serialization.MapCodec
|
||||
@@ -25,6 +27,7 @@ import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import net.minecraft.sounds.SoundSource
|
||||
import net.minecraft.util.RandomSource
|
||||
import net.minecraft.util.StringRepresentable
|
||||
@@ -54,7 +57,7 @@ import net.minecraft.world.phys.shapes.VoxelShape
|
||||
|
||||
@Suppress("OVERRIDE_DEPRECATION")
|
||||
class GildedChestBlock(settings: Properties, val type: Type = Type.RED) : BaseEntityBlock(settings),
|
||||
SimpleWaterloggedBlock {
|
||||
SimpleWaterloggedBlock, PokemonDisguiseBlock {
|
||||
|
||||
init {
|
||||
registerDefaultState(stateDefinition.any()
|
||||
@@ -70,9 +73,6 @@ class GildedChestBlock(settings: Properties, val type: Type = Type.RED) : BaseEn
|
||||
).apply(it, ::GildedChestBlock)
|
||||
}
|
||||
|
||||
val POKEMON_ARGS = "gimmighoul"
|
||||
val LEVEL_RANGE = 5..30
|
||||
|
||||
val SOUTH_OUTLINE = Shapes.or(
|
||||
Shapes.box(0.0, 0.0, 0.25, 1.0, 1.0, 0.9375)
|
||||
)
|
||||
@@ -127,13 +127,6 @@ class GildedChestBlock(settings: Properties, val type: Type = Type.RED) : BaseEn
|
||||
builder.add(WATERLOGGED)
|
||||
}
|
||||
|
||||
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 if (isFake()) Component.translatable("block.cobblemon.gilded_chest") else super.getName()
|
||||
}
|
||||
@@ -149,35 +142,6 @@ class GildedChestBlock(settings: Properties, val type: Type = Type.RED) : BaseEn
|
||||
return super.playerWillDestroy(world, pos, state, player)
|
||||
}
|
||||
|
||||
private fun spawnPokemon(world: Level, pos: BlockPos, state: BlockState, player: ServerPlayer): InteractionResult {
|
||||
val properties = "$POKEMON_ARGS lvl=${LEVEL_RANGE.random()}"
|
||||
val pokemon = PokemonProperties.parse(properties)
|
||||
val entity = pokemon.createEntity(world)
|
||||
|
||||
// The yaw based on the block's facing direction
|
||||
val yaw = facingToYaw[state.getValue(HorizontalDirectionalBlock.FACING)] ?: 0.0F
|
||||
|
||||
entity.entityData.set(PokemonEntity.SPAWN_DIRECTION, yaw)
|
||||
val offsetDir = state.getValue(HorizontalDirectionalBlock.FACING)
|
||||
val vec = pos.toVec3d().add(offsetDir.stepX * 0.1 + 0.5, 0.0, offsetDir.stepZ * 0.1 + 0.5)
|
||||
entity.moveTo(vec.x, vec.y, vec.z, yaw, entity.xRot)
|
||||
world.addFreshEntity(entity)
|
||||
|
||||
world.removeBlock(pos, false)
|
||||
afterOnServer(seconds = 0.1F) {
|
||||
if (player !in player.level().players()) {
|
||||
return@afterOnServer
|
||||
}
|
||||
val party = player.party()
|
||||
if (!player.isCreative) {
|
||||
entity.forceBattle(player)
|
||||
} else {
|
||||
world.playSound(null, pos, CobblemonSounds.GIMMIGHOUL_REVEAL, SoundSource.NEUTRAL)
|
||||
}
|
||||
}
|
||||
return InteractionResult.SUCCESS
|
||||
}
|
||||
|
||||
override fun useWithoutItem(
|
||||
state: BlockState,
|
||||
world: Level,
|
||||
@@ -290,4 +254,10 @@ class GildedChestBlock(settings: Properties, val type: Type = Type.RED) : BaseEn
|
||||
blockEntity.tick()
|
||||
}
|
||||
|
||||
override val levelRange = 5..30
|
||||
override val pokemonArgs = "gimmighoul"
|
||||
override val spawnSound = CobblemonSounds.GIMMIGHOUL_REVEAL
|
||||
override val scaleRange = FloatRange(1f, 1f)
|
||||
override fun getPokemonFacing(state: BlockState): Direction = state.getValue(HORIZONTAL_FACING)
|
||||
override val shinyRate = null
|
||||
}
|
||||
+28
@@ -11,8 +11,11 @@ package com.cobblemon.mod.common.block.dispenser
|
||||
import com.cobblemon.mod.common.block.SaccharineLeafBlock
|
||||
import com.cobblemon.mod.common.block.SaccharineLogBlock
|
||||
import com.cobblemon.mod.common.block.SaccharineLogSlatheredBlock
|
||||
import com.cobblemon.mod.common.block.appliances.CopperFridgeBlock
|
||||
import com.cobblemon.mod.common.mixin.accessor.DispenserBlockAccessor
|
||||
import net.minecraft.core.dispenser.DispenseItemBehavior
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
import net.minecraft.sounds.SoundSource
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.item.alchemy.PotionContents
|
||||
@@ -86,5 +89,30 @@ object DispenserBehaviorRegistry {
|
||||
).item
|
||||
)
|
||||
)
|
||||
register(
|
||||
{ dispenseWaterBucketIntoFridge() },
|
||||
items = listOf(Items.WATER_BUCKET)
|
||||
)
|
||||
}
|
||||
|
||||
private fun dispenseWaterBucketIntoFridge(): DispenseItemBehavior =
|
||||
DispenseItemBehavior { source, stack ->
|
||||
val level = source.level
|
||||
val pos = source.pos.relative(source.state.getValue(DispenserBlock.FACING))
|
||||
val fridge = level.getBlockState(pos).block as? CopperFridgeBlock
|
||||
|
||||
if (fridge == null) {
|
||||
stack
|
||||
} else {
|
||||
val fridgeEntity = fridge.getBlockEntity(level, pos)
|
||||
if (!fridgeEntity.theItem.isEmpty) {
|
||||
stack
|
||||
} else {
|
||||
fridgeEntity.theItem = Items.WATER_BUCKET.defaultInstance
|
||||
fridgeEntity.timer = 100
|
||||
level.playSound(null, pos, SoundEvents.BUCKET_EMPTY, SoundSource.BLOCKS, 1.0f, 1.0f)
|
||||
Items.BUCKET.defaultInstance
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+33
-4
@@ -41,6 +41,7 @@ import net.minecraft.world.Containers
|
||||
import net.minecraft.world.InteractionResult
|
||||
import net.minecraft.world.ItemInteractionResult
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.entity.LightningBolt
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.Pose
|
||||
import net.minecraft.world.entity.item.ItemEntity
|
||||
@@ -617,11 +618,14 @@ open class FossilMultiblockEntity(
|
||||
}
|
||||
|
||||
companion object {
|
||||
val TICKER = BlockEntityTicker<FossilMultiblockEntity> {level, _, _, blockEntity ->
|
||||
if (blockEntity.multiblockStructure != null) return@BlockEntityTicker
|
||||
if(blockEntity.porygonProcess == PorygonProcessType.INACTIVE) return@BlockEntityTicker
|
||||
val TICKER = BlockEntityTicker<FossilMultiblockEntity> { level, _, _, blockEntity ->
|
||||
val serverLevel = level as? ServerLevel ?: return@BlockEntityTicker
|
||||
|
||||
blockEntity.tickPorygon(level)
|
||||
if (blockEntity.checkLightning(serverLevel)) return@BlockEntityTicker
|
||||
if (blockEntity.multiblockStructure != null) return@BlockEntityTicker
|
||||
if (blockEntity.porygonProcess == PorygonProcessType.INACTIVE) return@BlockEntityTicker
|
||||
|
||||
blockEntity.tickPorygon(serverLevel)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -697,4 +701,29 @@ open class FossilMultiblockEntity(
|
||||
//Fallback: If no safe location is found, just spawn it directly in front of the monitor
|
||||
return origin.relative(facing)
|
||||
}
|
||||
|
||||
private var lastLightningBolt: UUID? = null
|
||||
|
||||
fun checkLightning(level: ServerLevel): Boolean {
|
||||
val bolt = level.getEntitiesOfClass(
|
||||
LightningBolt::class.java,
|
||||
AABB.ofSize(blockPos.center, 1.0, 4.0, 1.0)
|
||||
).firstOrNull {
|
||||
(it.blockPosition() == blockPos || it.blockPosition().below() == blockPos) &&
|
||||
it.uuid != lastLightningBolt
|
||||
} ?: return false
|
||||
|
||||
lastLightningBolt = bolt.uuid
|
||||
|
||||
level.setBlockAndUpdate(
|
||||
blockPos,
|
||||
CobblemonBlocks.ROTOM_MONITOR.defaultBlockState()
|
||||
.setValue(
|
||||
HorizontalDirectionalBlock.FACING,
|
||||
level.getBlockState(blockPos).getValue(HorizontalDirectionalBlock.FACING)
|
||||
)
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
@@ -391,7 +391,7 @@ object CobblemonClient {
|
||||
CobblemonBlocks.X_SP_ATK,
|
||||
CobblemonBlocks.X_SP_DEF,
|
||||
CobblemonBlocks.X_SPEED,
|
||||
CobblemonBlocks.TM_MACHINE,
|
||||
CobblemonBlocks.TM_MACHINE,
|
||||
|
||||
CobblemonBlocks.GALARICA_CUFF,
|
||||
CobblemonBlocks.GALARICA_WREATH,
|
||||
@@ -419,7 +419,7 @@ object CobblemonClient {
|
||||
CobblemonBlocks.MOOMOO_MILK,
|
||||
CobblemonBlocks.MEDICINAL_BREW,
|
||||
CobblemonBlocks.TERRAIN_EXTENDER,
|
||||
|
||||
|
||||
CobblemonBlocks.RED_MINT_LEAF_LITTER,
|
||||
CobblemonBlocks.POTTED_RED_MINT,
|
||||
CobblemonBlocks.BLUE_MINT_LEAF_LITTER,
|
||||
@@ -516,7 +516,17 @@ object CobblemonClient {
|
||||
CobblemonBlocks.POTTED_WATMEL_BERRY,
|
||||
CobblemonBlocks.POTTED_WEPEAR_BERRY,
|
||||
CobblemonBlocks.POTTED_WIKI_BERRY,
|
||||
CobblemonBlocks.POTTED_YACHE_BERRY
|
||||
CobblemonBlocks.POTTED_YACHE_BERRY,
|
||||
CobblemonBlocks.SCOPE_LENS,
|
||||
|
||||
CobblemonBlocks.COPPER_FAN,
|
||||
CobblemonBlocks.EXPOSED_COPPER_FAN,
|
||||
CobblemonBlocks.WEATHERED_COPPER_FAN,
|
||||
CobblemonBlocks.OXIDIZED_COPPER_FAN,
|
||||
CobblemonBlocks.WAXED_COPPER_FAN,
|
||||
CobblemonBlocks.WAXED_EXPOSED_COPPER_FAN,
|
||||
CobblemonBlocks.WAXED_WEATHERED_COPPER_FAN,
|
||||
CobblemonBlocks.WAXED_OXIDIZED_COPPER_FAN
|
||||
)
|
||||
|
||||
this.createBoatModelLayers()
|
||||
|
||||
@@ -85,6 +85,7 @@ class PartyOverlay : Gui(Minecraft.getInstance()) {
|
||||
if (HidePartyBinding.shouldHide) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -558,4 +559,4 @@ class PartyOverlay : Gui(Minecraft.getInstance()) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+29
-22
@@ -9,19 +9,11 @@
|
||||
package com.cobblemon.mod.common.client.gui.pokedex.widgets
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonItems
|
||||
import com.cobblemon.mod.common.api.gui.*
|
||||
import com.cobblemon.mod.common.api.pokedex.Dexes
|
||||
import com.cobblemon.mod.common.api.pokedex.PokedexEntryProgress
|
||||
import com.cobblemon.mod.common.api.pokedex.entry.CobblemonBiomeDexEvolutionRequirementDisplay
|
||||
import com.cobblemon.mod.common.api.pokedex.entry.DexEntries
|
||||
import com.cobblemon.mod.common.api.pokedex.entry.DexEvolutionDisplay
|
||||
import com.cobblemon.mod.common.api.pokedex.entry.DexEvolutionRequirementDisplay
|
||||
import com.cobblemon.mod.common.api.pokedex.entry.PokedexEntry
|
||||
import com.cobblemon.mod.common.api.pokedex.entry.PokedexForm
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokedex.entry.*
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.pokemon.evolution.Evolution
|
||||
import com.cobblemon.mod.common.api.text.add
|
||||
import com.cobblemon.mod.common.api.text.bold
|
||||
import com.cobblemon.mod.common.api.text.green
|
||||
@@ -41,7 +33,6 @@ import com.cobblemon.mod.common.client.render.renderScaledGuiItemIcon
|
||||
import com.cobblemon.mod.common.pokemon.FormData
|
||||
import com.cobblemon.mod.common.pokemon.Gender
|
||||
import com.cobblemon.mod.common.pokemon.RenderablePokemon
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import net.minecraft.client.Minecraft
|
||||
@@ -50,6 +41,7 @@ import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.locale.Language
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.chat.MutableComponent
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.tags.TagKey
|
||||
|
||||
class EvolutionTreeWidget(
|
||||
@@ -164,25 +156,28 @@ class EvolutionTreeWidget(
|
||||
var rootSpecies = pokedexEntry
|
||||
var rootForm = pokedexForm
|
||||
var preEvolution = findPreEvolution(rootSpecies, rootForm)
|
||||
// Stop at whatever the dex can't resolve, and at cycles (datapacks)
|
||||
val visited = mutableSetOf(rootSpecies.speciesId to rootForm.displayForm)
|
||||
while (preEvolution != null) {
|
||||
rootSpecies = Dexes.findDexEntryBySpeciesId(preEvolution.fromSpecies)!!
|
||||
rootForm = rootSpecies.forms.first { it.displayForm.equals(preEvolution.fromForm, ignoreCase = true) }
|
||||
val preEvolutionSpecies = DexEntries.entries.values.firstOrNull { it.speciesId == preEvolution.fromSpecies &&
|
||||
it.forms.any {form -> form.displayForm.equals(preEvolution.fromForm, ignoreCase = true)}} ?: break
|
||||
val preEvolutionForm = preEvolutionSpecies.forms.firstOrNull { it.displayForm.equals(preEvolution.fromForm, ignoreCase = true) } ?: break
|
||||
if (!visited.add(preEvolutionSpecies.speciesId to preEvolutionForm.displayForm)) break
|
||||
rootSpecies = preEvolutionSpecies
|
||||
rootForm = preEvolutionForm
|
||||
preEvolution = findPreEvolution(rootSpecies, rootForm)
|
||||
}
|
||||
|
||||
val entry = Dexes.findDexEntryBySpeciesId(rootSpecies.speciesId)
|
||||
?: throw RuntimeException("Root dex entry not found")
|
||||
|
||||
val viewedFormEquivalents = Dexes.getFormEquivalents(pokedexForm.displayForm)
|
||||
viewedForm = PokemonSpecies.getByIdentifier(pokedexEntry.speciesId)
|
||||
?.forms?.firstOrNull { viewedFormEquivalents.contains(it.name.lowercase()) }
|
||||
|
||||
val formEquivalents = Dexes.getFormEquivalents(rootForm.displayForm)
|
||||
val form =
|
||||
entry.forms.firstOrNull { formEquivalents.contains(it.displayForm.lowercase()) } ?:
|
||||
entry.forms.first { it.displayForm.equals("Normal", ignoreCase = true) }
|
||||
rootSpecies.forms.firstOrNull { formEquivalents.contains(it.displayForm.lowercase()) } ?:
|
||||
rootSpecies.forms.first { it.displayForm.equals("Normal", ignoreCase = true) }
|
||||
|
||||
val rootEvolutionNode = buildEvolutionTree(entry, form)
|
||||
val rootEvolutionNode = buildEvolutionTree(rootSpecies, form)
|
||||
|
||||
// val isSameEntry = previousRootPokedexEntry != null && pokedexEntry?.id == previousRootPokedexEntry?.id
|
||||
// val isSameForm =
|
||||
@@ -208,7 +203,7 @@ class EvolutionTreeWidget(
|
||||
|
||||
/** The evolution leading to [form]; the standard form falls back to any form of the species (no evolution leads to regular Vivillon). */
|
||||
private fun findPreEvolution(entry: PokedexEntry, form: PokedexForm): DexEvolutionDisplay? {
|
||||
return DexEntries.evolutionDisplays.firstOrNull { it.toSpecies == entry.speciesId && it.toForm == form.displayForm }
|
||||
return DexEntries.evolutionDisplays.firstOrNull { it.toSpecies == entry.speciesId && form.displayForm.equals(it.toForm, ignoreCase = true) }
|
||||
?: DexEntries.evolutionDisplays.takeIf { form.displayForm.equals("Normal", ignoreCase = true) }
|
||||
?.firstOrNull { it.toSpecies == entry.speciesId }
|
||||
}
|
||||
@@ -230,21 +225,33 @@ class EvolutionTreeWidget(
|
||||
pokedexEntry: PokedexEntry,
|
||||
pokedexForm: PokedexForm,
|
||||
aspects: Set<String> = emptySet(),
|
||||
ancestors: Set<Pair<ResourceLocation, String>> = emptySet(),
|
||||
): EvolutionNode {
|
||||
// Datapack evolutions can loop back (A -> B -> A), so stop at anything already on this branch
|
||||
val path = ancestors + (pokedexEntry.speciesId to pokedexForm.displayForm.lowercase())
|
||||
val discoveryLevel = CobblemonClient.clientPokedexData.getHighestKnowledgeFor(pokedexEntry, pokedexForm, aspects.toMutableSet())
|
||||
|
||||
val formEquivalents = Dexes.getFormEquivalents(pokedexForm.displayForm)
|
||||
val evolutions = DexEntries.evolutionDisplays.filter { it.fromSpecies == pokedexEntry.speciesId && formEquivalents.contains(it.fromForm.lowercase()) }
|
||||
|
||||
val children = evolutions.mapNotNull {
|
||||
val childPokedexEntry = Dexes.findDexEntryBySpeciesId(it.toSpecies)
|
||||
val childPokedexEntry = DexEntries.entries.values.firstOrNull { entry -> entry.speciesId == it.toSpecies &&
|
||||
entry.forms.any {form -> form.displayForm.equals(it.toForm, ignoreCase = true)}}
|
||||
if (childPokedexEntry == null) {
|
||||
Cobblemon.LOGGER.warn("Dex entry not found for species: ${it.toSpecies}")
|
||||
return@mapNotNull null
|
||||
}
|
||||
val formEquivalents = Dexes.getFormEquivalents(it.toForm.lowercase())
|
||||
val childPokedexForm = childPokedexEntry.forms.first { formEquivalents.contains(it.displayForm.lowercase()) }
|
||||
buildEvolutionTree(childPokedexEntry, childPokedexForm, it.toAspects)
|
||||
val childPokedexForm = childPokedexEntry.forms.firstOrNull { formEquivalents.contains(it.displayForm.lowercase()) }
|
||||
if (childPokedexForm == null) {
|
||||
Cobblemon.LOGGER.warn("Dex form ${it.toForm} not found for species: ${it.toSpecies}")
|
||||
return@mapNotNull null
|
||||
}
|
||||
if ((childPokedexEntry.speciesId to childPokedexForm.displayForm.lowercase()) in path) {
|
||||
Cobblemon.LOGGER.warn("Evolution loop found at species: ${it.toSpecies} form: ${it.toForm}")
|
||||
return@mapNotNull null
|
||||
}
|
||||
buildEvolutionTree(childPokedexEntry, childPokedexForm, it.toAspects, path)
|
||||
}
|
||||
|
||||
return EvolutionNode(
|
||||
|
||||
+2
-2
@@ -34,6 +34,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.bedrock.animatio
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.quirk.ModelQuirk
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.quirk.QuirkData
|
||||
import com.cobblemon.mod.common.client.sound.instances.UIEntitySoundInstance
|
||||
import com.cobblemon.mod.common.entity.PosableEntity
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
@@ -44,7 +45,6 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.multiplayer.ClientLevel
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||
import net.minecraft.commands.arguments.item.ItemParser
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import net.minecraft.world.entity.Entity
|
||||
@@ -289,7 +289,7 @@ abstract class PosableState : Schedulable {
|
||||
entity.level().playLocalSound(entity, soundEvent, entity.soundSource, volume, pitch)
|
||||
}
|
||||
} else {
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(soundEvent, volume, pitch))
|
||||
Minecraft.getInstance().soundManager.play(UIEntitySoundInstance(soundEvent, volume, pitch))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -19,6 +19,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Bone
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.repository.RenderContext
|
||||
import com.cobblemon.mod.common.client.sound.instances.AlphaCrySoundInstance
|
||||
import com.cobblemon.mod.common.client.sound.instances.UIEntitySoundInstance
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.effectiveName
|
||||
import com.cobblemon.mod.common.util.genericRuntime
|
||||
@@ -31,7 +32,6 @@ import net.minecraft.client.Minecraft
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.client.multiplayer.ClientLevel
|
||||
import net.minecraft.client.resources.sounds.EntityBoundSoundInstance
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import net.minecraft.world.entity.Entity
|
||||
@@ -121,7 +121,7 @@ class BedrockSoundKeyframe(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(soundEvent, 1F, 1F))
|
||||
Minecraft.getInstance().soundManager.play(UIEntitySoundInstance(soundEvent))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -29,8 +29,8 @@ class FarfetchdGalarianModel(root: ModelPart) : PokemonPosableModel(root), Heade
|
||||
override var portraitScale = 2.6F
|
||||
override var portraitTranslation = Vec3(-0.2, -1.0, 0.0)
|
||||
|
||||
override var profileScale = 1.1F
|
||||
override var profileTranslation = Vec3(-0.1, 0.1, 0.0)
|
||||
override var profileScale = 0.93F
|
||||
override var profileTranslation = Vec3(-0.1, 0.36, 0.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
+2
-2
@@ -28,8 +28,8 @@ class FarfetchdModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame,
|
||||
override var portraitScale = 2.6F
|
||||
override var portraitTranslation = Vec3(-0.2, -1.0, 0.0)
|
||||
|
||||
override var profileScale = 1.1F
|
||||
override var profileTranslation = Vec3(-0.1, 0.1, 0.0)
|
||||
override var profileScale = 0.93F
|
||||
override var profileTranslation = Vec3(-0.1, 0.36, 0.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
+2
-2
@@ -23,8 +23,8 @@ class KabutoModel(root: ModelPart) : PokemonPosableModel(root) {
|
||||
override var portraitScale = 3.3F
|
||||
override var portraitTranslation = Vec3(0.0, -3.3, 0.0)
|
||||
|
||||
override var profileScale = 1.6F
|
||||
override var profileTranslation = Vec3(0.0, -0.6, 0.0)
|
||||
override var profileScale = 1.25F
|
||||
override var profileTranslation = Vec3(0.0, -0.17, 0.0)
|
||||
|
||||
lateinit var standing: CobblemonPose
|
||||
lateinit var walk: CobblemonPose
|
||||
|
||||
+2
-2
@@ -21,8 +21,8 @@ class HoothootModel (root: ModelPart) : PokemonPosableModel(root) {
|
||||
|
||||
override var portraitScale = 2.2F
|
||||
override var portraitTranslation = Vec3(-0.25, -0.9, 0.0)
|
||||
override var profileScale = 1.0F
|
||||
override var profileTranslation = Vec3(0.0, 0.3, 0.0)
|
||||
override var profileScale = 0.82F
|
||||
override var profileTranslation = Vec3(0.0, 0.53, 0.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
+2
-2
@@ -29,8 +29,8 @@ class WooperModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
override var portraitScale = 2.0F
|
||||
override var portraitTranslation = Vec3(-0.15, -0.65, 0.0)
|
||||
|
||||
override var profileScale = 0.9F
|
||||
override var profileTranslation = Vec3(0.0, 0.4, 0.0)
|
||||
override var profileScale = 0.75F
|
||||
override var profileTranslation = Vec3(0.0, 0.6, 0.0)
|
||||
|
||||
lateinit var shoulderLeft: Pose
|
||||
lateinit var shoulderRight: Pose
|
||||
|
||||
+2
-2
@@ -29,8 +29,8 @@ class WooperPaldeanModel(root: ModelPart) : PokemonPosableModel(root), HeadedFra
|
||||
override var portraitScale = 2.0F
|
||||
override var portraitTranslation = Vec3(-0.15, -0.65, 0.0)
|
||||
|
||||
override var profileScale = 0.9F
|
||||
override var profileTranslation = Vec3(0.0, 0.4, 0.0)
|
||||
override var profileScale = 0.75F
|
||||
override var profileTranslation = Vec3(0.0, 0.6, 0.0)
|
||||
|
||||
lateinit var shoulderLeft: Pose
|
||||
lateinit var shoulderRight: Pose
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ class DusclopsModel (root: ModelPart) : PokemonPosableModel(root) {
|
||||
lateinit var battleidle: Pose
|
||||
|
||||
override fun registerPoses() {
|
||||
animations["cry"] = "q.bedrock_stateful('squirtle', 'cry')".asExpressionLike()
|
||||
animations["cry"] = "q.bedrock_stateful('dusclops', 'cry')".asExpressionLike()
|
||||
|
||||
val blink = quirk { bedrockStateful("dusclops", "blink") }
|
||||
|
||||
|
||||
+3
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonP
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
@@ -28,6 +29,8 @@ class MasquerainModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame
|
||||
lateinit var walk: Pose
|
||||
lateinit var standing: Pose
|
||||
override fun registerPoses() {
|
||||
animations["cry"] = "q.bedrock_stateful('masquerain', 'cry')".asExpressionLike()
|
||||
|
||||
val blink = quirk { bedrockStateful("masquerain", "blink") }
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
|
||||
+3
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonP
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.ModelPartTransformation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.isInWater
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
@@ -36,6 +37,8 @@ class SurskitModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
val wateroffset = -8
|
||||
|
||||
override fun registerPoses() {
|
||||
animations["cry"] = "q.bedrock_stateful('surskit', 'cry')".asExpressionLike()
|
||||
|
||||
val blink = quirk { bedrockStateful("surskit", "blink") }
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
|
||||
+3
@@ -14,6 +14,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonP
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.ModelPartTransformation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
@@ -36,6 +37,8 @@ class CombeeModel (root: ModelPart) : PokemonPosableModel(root) {
|
||||
val shoulderZOffset = 8
|
||||
|
||||
override fun registerPoses() {
|
||||
animations["cry"] = "q.bedrock_stateful('combee', 'cry')".asExpressionLike()
|
||||
|
||||
val blink1 = quirk { bedrockStateful("combee", "blink_right") }
|
||||
val blink2 = quirk { bedrockStateful("combee", "blink_gender") }
|
||||
val blink3 = quirk { bedrockStateful("combee", "blink_left") }
|
||||
|
||||
+3
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonP
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
@@ -30,6 +31,8 @@ class VespiquenModel (root: ModelPart) : PokemonPosableModel(root) {
|
||||
lateinit var standing: Pose
|
||||
|
||||
override fun registerPoses() {
|
||||
animations["cry"] = "q.bedrock_stateful('vespiquen', 'cry')".asExpressionLike()
|
||||
|
||||
val blink1 = quirk { bedrockStateful("vespiquen", "blink") }
|
||||
val wingsleep = quirk { bedrockStateful("vespiquen", "sleep_flap") }
|
||||
|
||||
|
||||
-62
@@ -1,62 +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.client.render.models.blockbench.pokemon.gen5
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class SerperiorModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("serperior")
|
||||
override val head = getPart("head_ai")
|
||||
|
||||
override var portraitScale = 2.5F
|
||||
override var portraitTranslation = Vec3(-0.3, 1.25, 0.0)
|
||||
|
||||
override var profileScale = 0.6F
|
||||
override var profileTranslation = Vec3(0.0, 0.8, 0.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
lateinit var sleep: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("serperior", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("serperior", "blink") }
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
animations = arrayOf(bedrock("serperior", "sleep"))
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("serperior", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = PoseType.MOVING_POSES,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("serperior", "ground_walk")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
-70
@@ -1,70 +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.client.render.models.blockbench.pokemon.gen5
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class ServineModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BimanualFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("servine")
|
||||
override val head = getPart("head_ai")
|
||||
override val rightArm = getPart("arm_right")
|
||||
override val leftArm = getPart("arm_left")
|
||||
override val rightLeg = getPart("leg_right")
|
||||
override val leftLeg = getPart("leg_left")
|
||||
|
||||
override var portraitScale = 2.6F
|
||||
override var portraitTranslation = Vec3(-0.15, 0.75, 0.0)
|
||||
override var profileScale = 0.8F
|
||||
override var profileTranslation = Vec3(0.0, 0.55, 0.0)
|
||||
|
||||
lateinit var sleep: Pose
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("servine", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("servine", "blink") }
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
transformTicks = 10,
|
||||
animations = arrayOf(bedrock("servine", "sleep"))
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("servine", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walking",
|
||||
poseTypes = PoseType.MOVING_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("servine", "ground_walk")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
-70
@@ -1,70 +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.client.render.models.blockbench.pokemon.gen5
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BimanualFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class SnivyModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BimanualFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("snivy")
|
||||
override val head = getPart("head_ai")
|
||||
override val rightArm = getPart("arm_right")
|
||||
override val leftArm = getPart("arm_left")
|
||||
override val rightLeg = getPart("leg_right")
|
||||
override val leftLeg = getPart("leg_left")
|
||||
|
||||
override var portraitScale = 2.0F
|
||||
override var portraitTranslation = Vec3(-0.15, 0.32, 0.0)
|
||||
override var profileScale = 0.8F
|
||||
override var profileTranslation = Vec3(0.0, 0.55, 0.0)
|
||||
|
||||
lateinit var sleep: Pose
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("snivy", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("snivy", "blink") }
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
transformTicks = 10,
|
||||
animations = arrayOf(bedrock("snivy", "sleep"))
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("snivy", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walking",
|
||||
poseTypes = PoseType.MOVING_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("snivy", "ground_walk")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -23,7 +23,7 @@ class CarbinkModel (root: ModelPart) : PokemonPosableModel(root) {
|
||||
override var portraitScale = 1.8F
|
||||
override var portraitTranslation = Vec3(0.0, 0.2, 0.0)
|
||||
|
||||
override var profileScale = 0.85F
|
||||
override var profileScale = 0.68F
|
||||
override var profileTranslation = Vec3(0.0, 0.7, 0.0)
|
||||
|
||||
lateinit var standing: CobblemonPose
|
||||
|
||||
-85
@@ -1,85 +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.client.render.models.blockbench.pokemon.gen6
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class GourgeistModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("gourgeist")
|
||||
override val head = getPart("head")
|
||||
|
||||
override var portraitScale = 4.0F
|
||||
override var portraitTranslation = Vec3(-0.1, 0.6, 0.0)
|
||||
|
||||
override var profileScale = 0.8F
|
||||
override var profileTranslation = Vec3(0.0, 0.55, 0.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
lateinit var hovering: Pose
|
||||
lateinit var fly: Pose
|
||||
lateinit var sleep: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("gourgeist", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("gourgeist", "blink") }
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.UI_POSES + PoseType.STAND,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("gourgeist", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseType = PoseType.WALK,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("gourgeist", "ground_walk")
|
||||
)
|
||||
)
|
||||
|
||||
hovering = registerPose(
|
||||
poseName = "hovering",
|
||||
poseType = PoseType.HOVER,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("gourgeist", "air_idle")
|
||||
)
|
||||
)
|
||||
|
||||
fly = registerPose(
|
||||
poseName = "fly",
|
||||
poseType = PoseType.FLY,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("gourgeist", "air_fly")
|
||||
)
|
||||
)
|
||||
|
||||
sleep = registerPose(
|
||||
poseName = "sleep",
|
||||
poseType = PoseType.SLEEP,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("gourgeist", "sleep")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
-77
@@ -1,77 +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.client.render.models.blockbench.pokemon.gen6
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.CobblemonPose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class PumpkabooModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("pumpkaboo")
|
||||
override val head = getPart("head")
|
||||
|
||||
override var portraitScale = 3.5F
|
||||
override var portraitTranslation = Vec3(0.0, -1.5, 0.0)
|
||||
|
||||
override var profileScale = 1.0F
|
||||
override var profileTranslation = Vec3(0.0, 0.25, 0.0)
|
||||
|
||||
lateinit var standing: CobblemonPose
|
||||
lateinit var walk: CobblemonPose
|
||||
lateinit var battleidle: CobblemonPose
|
||||
lateinit var sleep: CobblemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("pumpkaboo", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("pumpkaboo", "blink") }
|
||||
val quirk = quirk { bedrockStateful("pumpkaboo", "quirk_idle") }
|
||||
|
||||
sleep = registerPose(
|
||||
poseName = "sleep",
|
||||
poseType = PoseType.SLEEP,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("pumpkaboo", "sleep")
|
||||
)
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
|
||||
quirks = arrayOf(blink, quirk),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("pumpkaboo", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = PoseType.MOVING_POSES,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("pumpkaboo", "ground_walk")
|
||||
)
|
||||
)
|
||||
|
||||
battleidle = registerPose(
|
||||
poseName = "battleidle",
|
||||
poseTypes = PoseType.STATIONARY_POSES,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
bedrock("pumpkaboo", "battle_idle")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -26,8 +26,8 @@ class ScatterbugModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame
|
||||
override var portraitScale = 2.6F
|
||||
override var portraitTranslation = Vec3(-0.2, -1.9, 0.0)
|
||||
|
||||
override var profileScale = 1.2F
|
||||
override var profileTranslation = Vec3(0.0, 0.05, 0.0)
|
||||
override var profileScale = 0.98F
|
||||
override var profileTranslation = Vec3(0.0, 0.28, 0.0)
|
||||
|
||||
lateinit var standing: CobblemonPose
|
||||
lateinit var walk: CobblemonPose
|
||||
|
||||
+2
-2
@@ -36,8 +36,8 @@ class CharcadetModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame,
|
||||
override var portraitScale = 1.7F
|
||||
override var portraitTranslation = Vec3(-0.15, 0.08, 0.0)
|
||||
|
||||
override var profileScale = 0.8F
|
||||
override var profileTranslation = Vec3(0.0, 0.6, 0.0)
|
||||
override var profileScale = 0.58F
|
||||
override var profileTranslation = Vec3(0.0, 0.91, 0.0)
|
||||
|
||||
lateinit var standing: CobblemonPose
|
||||
lateinit var walking: CobblemonPose
|
||||
|
||||
+2
-2
@@ -35,8 +35,8 @@ class QuaquavalModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame,
|
||||
override var portraitScale = 2.3F
|
||||
override var portraitTranslation = Vec3(-0.42, 3.7, 0.0)
|
||||
|
||||
override var profileScale = 0.32F
|
||||
override var profileTranslation = Vec3(0.0, 1.24, 0.0)
|
||||
override var profileScale = 0.36F
|
||||
override var profileTranslation = Vec3(0.0, 1.19, 0.0)
|
||||
|
||||
lateinit var standing: CobblemonPose
|
||||
lateinit var standing2: CobblemonPose
|
||||
|
||||
-208
@@ -1,208 +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.client.render.models.blockbench.pokemon.gen9
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.WingFlapIdleAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.createTransformation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BiWingedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.ModelPartTransformation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.parabolaFunction
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.sineFunction
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class SquawkabillyModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BiWingedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("squawkabilly")
|
||||
override val head = getPart("head")
|
||||
override val leftWing = getPart("wing_left")
|
||||
override val rightWing = getPart("wing_right")
|
||||
override val leftLeg = getPart("leg_left")
|
||||
override val rightLeg = getPart("leg_right")
|
||||
private val tail = getPart("tail")
|
||||
|
||||
override var portraitScale = 2.0F
|
||||
override var portraitTranslation = Vec3(-0.2, -0.2, 0.0)
|
||||
|
||||
override var profileScale = 0.85F
|
||||
override var profileTranslation = Vec3(0.0, 0.51, 0.0)
|
||||
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
lateinit var hovering: Pose
|
||||
lateinit var flying: Pose
|
||||
lateinit var shoulderLeft: Pose
|
||||
lateinit var shoulderRight: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("squawkabilly", "cry") }
|
||||
|
||||
val shoulderOffsetX = -1.0
|
||||
val shoulderOffsetY = 0
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("squawkabilly", "blink") }
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
quirks = arrayOf(blink),
|
||||
poseTypes = PoseType.UI_POSES + PoseType.STAND,
|
||||
transformTicks = 10,
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("squawkabilly", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
quirks = arrayOf(blink),
|
||||
poseType = PoseType.WALK,
|
||||
transformTicks = 10,
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("squawkabilly", "ground_idle"),
|
||||
rootPart.translation(
|
||||
function = parabolaFunction(
|
||||
peak = -4F,
|
||||
period = 0.4F
|
||||
),
|
||||
timeVariable = { state, _, _ -> state.animationSeconds },
|
||||
axis = ModelPartTransformation.Y_AXIS
|
||||
),
|
||||
head.translation(
|
||||
function = sineFunction(
|
||||
amplitude = (-20F).toRadians(),
|
||||
period = 1F,
|
||||
verticalShift = (-10F).toRadians()
|
||||
),
|
||||
axis = ModelPartTransformation.X_AXIS,
|
||||
timeVariable = { state, _, _ -> state.animationSeconds }
|
||||
),
|
||||
leftLeg.rotation(
|
||||
function = parabolaFunction(
|
||||
tightness = -20F,
|
||||
phaseShift = 0F,
|
||||
verticalShift = (30F).toRadians()
|
||||
),
|
||||
axis = ModelPartTransformation.X_AXIS,
|
||||
timeVariable = { _, _, ageInTicks -> ageInTicks / 20 },
|
||||
),
|
||||
rightLeg.rotation(
|
||||
function = parabolaFunction(
|
||||
tightness = -20F,
|
||||
phaseShift = 0F,
|
||||
verticalShift = (30F).toRadians()
|
||||
),
|
||||
axis = ModelPartTransformation.X_AXIS,
|
||||
timeVariable = { _, _, ageInTicks -> ageInTicks / 20 },
|
||||
),
|
||||
tail.rotation(
|
||||
function = sineFunction(
|
||||
amplitude = (-5F).toRadians(),
|
||||
period = 1F
|
||||
),
|
||||
axis = ModelPartTransformation.X_AXIS,
|
||||
timeVariable = { _, _, ageInTicks -> ageInTicks / 20 },
|
||||
),
|
||||
wingFlap(
|
||||
flapFunction = sineFunction(
|
||||
amplitude = (-5F).toRadians(),
|
||||
period = 0.4F,
|
||||
phaseShift = 0.00F,
|
||||
verticalShift = (-20F).toRadians()
|
||||
),
|
||||
timeVariable = { state, _, _ -> state.animationSeconds },
|
||||
axis = ModelPartTransformation.Z_AXIS
|
||||
),
|
||||
rightWing.translation(
|
||||
function = parabolaFunction(
|
||||
tightness = -10F,
|
||||
phaseShift = 30F,
|
||||
verticalShift = (25F).toRadians()
|
||||
),
|
||||
axis = ModelPartTransformation.Y_AXIS,
|
||||
timeVariable = { _, _, ageInTicks -> ageInTicks / 20 },
|
||||
),
|
||||
leftWing.translation(
|
||||
function = parabolaFunction(
|
||||
tightness = -10F,
|
||||
phaseShift = 30F,
|
||||
verticalShift = (25F).toRadians()
|
||||
),
|
||||
axis = ModelPartTransformation.Y_AXIS,
|
||||
timeVariable = { _, _, ageInTicks -> ageInTicks / 20 },
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
hovering = registerPose(
|
||||
poseName = "hovering",
|
||||
quirks = arrayOf(blink),
|
||||
poseTypes = setOf(PoseType.FLOAT, PoseType.HOVER),
|
||||
transformTicks = 10,
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
WingFlapIdleAnimation(this,
|
||||
flapFunction = sineFunction(verticalShift = -10F.toRadians(), period = 0.9F, amplitude = 0.9F),
|
||||
timeVariable = { state, _, _ -> state.animationSeconds },
|
||||
axis = ModelPartTransformation.Z_AXIS
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
flying = registerPose(
|
||||
poseName = "flying",
|
||||
quirks = arrayOf(blink),
|
||||
poseTypes = setOf(PoseType.FLY, PoseType.SWIM),
|
||||
transformTicks = 10,
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
WingFlapIdleAnimation(this,
|
||||
flapFunction = sineFunction(verticalShift = -14F.toRadians(), period = 0.9F, amplitude = 0.9F),
|
||||
timeVariable = { state, _, _ -> state.animationSeconds },
|
||||
axis = ModelPartTransformation.Z_AXIS
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
shoulderLeft = registerPose(
|
||||
poseType = PoseType.SHOULDER_LEFT,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("squawkabilly", "ground_idle")
|
||||
),
|
||||
transformedParts = arrayOf(
|
||||
rootPart.createTransformation().addPosition(shoulderOffsetX, shoulderOffsetY, 0.0)
|
||||
)
|
||||
)
|
||||
|
||||
shoulderRight = registerPose(
|
||||
poseType = PoseType.SHOULDER_RIGHT,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("squawkabilly", "ground_idle")
|
||||
),
|
||||
transformedParts = arrayOf(
|
||||
rootPart.createTransformation().addPosition(-shoulderOffsetX, shoulderOffsetY, 0.0)
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PosableState<PokemonEntity>
|
||||
// ) = if (state.isNotPosedIn(sleep)) bedrockStateful("squawkabilly", "faint") else null
|
||||
}
|
||||
-6
@@ -322,8 +322,6 @@ object VaryingModelRepository {
|
||||
inbuilt("loudred", :: LoudredModel)
|
||||
inbuilt("exploud", :: ExploudModel)
|
||||
inbuilt("cryogonal", :: CryogonalModel)
|
||||
inbuilt("pumpkaboo", :: PumpkabooModel)
|
||||
inbuilt("gourgeist", :: GourgeistModel)
|
||||
inbuilt("eiscue", :: EiscueModel)
|
||||
inbuilt("wooloo", :: WoolooModel)
|
||||
inbuilt("dubwool", :: DubwoolModel)
|
||||
@@ -340,9 +338,6 @@ object VaryingModelRepository {
|
||||
inbuilt("thwackey", ::ThwackeyModel)
|
||||
inbuilt("rillaboom", ::RillaboomModel)
|
||||
inbuilt("samurott", ::SamurottModel)
|
||||
inbuilt("snivy", ::SnivyModel)
|
||||
inbuilt("servine", ::ServineModel)
|
||||
inbuilt("serperior", ::SerperiorModel)
|
||||
inbuilt("slugma", ::SlugmaModel)
|
||||
inbuilt("magcargo", ::MagcargoModel)
|
||||
inbuilt("slugma_shiny", ::SlugmaShinyModel)
|
||||
@@ -402,7 +397,6 @@ object VaryingModelRepository {
|
||||
inbuilt("bunnelby", ::BunnelbyModel)
|
||||
inbuilt("arrokuda", ::ArrokudaModel)
|
||||
inbuilt("barraskewda", ::BarraskewdaModel)
|
||||
inbuilt("squawkabilly", ::SquawkabillyModel)
|
||||
inbuilt("ponyta_galarian", ::PonytaGalarianModel)
|
||||
inbuilt("rapidash_galarian", ::RapidashGalarianModel)
|
||||
inbuilt("volbeat", ::VolbeatModel)
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.client.sound.instances
|
||||
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance
|
||||
import net.minecraft.client.resources.sounds.SoundInstance
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import net.minecraft.sounds.SoundSource
|
||||
|
||||
/**
|
||||
* Plays a sound for a Pokémon rendered in a GUI, where there is no entity to take the sound source from.
|
||||
* Unlike [SimpleSoundInstance.forUI] this uses [SoundSource.NEUTRAL] so the Friendly Creatures slider applies.
|
||||
*/
|
||||
class UIEntitySoundInstance(sound: SoundEvent, volume: Float = 1F, pitch: Float = 1F) :
|
||||
SimpleSoundInstance(sound.location, SoundSource.NEUTRAL, volume, pitch, SoundInstance.createUnseededRandom(),
|
||||
false, 0, SoundInstance.Attenuation.NONE, 0.0, 0.0, 0.0, true)
|
||||
@@ -47,6 +47,10 @@ class CobblemonConfig {
|
||||
@IntConstraint(min = 0, max = 1000)
|
||||
var maxPokemonFriendship = 255
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "power_item_ride_stat_gain_interval_seconds", SERVER)
|
||||
@IntConstraint(min = -1, max = Int.MAX_VALUE)
|
||||
var powerItemRideStatGainIntervalSeconds = 120
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "announce_drop_items", SERVER)
|
||||
var announceDropItems = true
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "default_drop_item_method", SERVER)
|
||||
@@ -164,6 +168,9 @@ class CobblemonConfig {
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "experience_multiplier", SERVER)
|
||||
var experienceMultiplier = 2F
|
||||
|
||||
@CobblemonConfigField(Category.Pokemon, lang = "predation_chance", SERVER)
|
||||
var predationChance = 0.05F
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "pokemon_per_chunk", SERVER)
|
||||
var pokemonPerChunk = 1F
|
||||
|
||||
|
||||
@@ -269,6 +269,7 @@ class EmptyPokeBallEntity : ThrowableItemProjectile, PosableEntity, WaterDragMod
|
||||
attemptCatch(pokemonEntity)
|
||||
},
|
||||
ifCanceled = {
|
||||
captureFuture.complete(false)
|
||||
drop()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1294,16 +1294,7 @@ open class PokemonEntity(
|
||||
}
|
||||
|
||||
private fun showInteractionWheel(player: ServerPlayer, itemStack: ItemStack) {
|
||||
val canRide = ifRidingAvailableSupply(false) { behaviour, settings, state ->
|
||||
if (platform != PlatformType.NONE) return@ifRidingAvailableSupply false
|
||||
if (tethering != null) return@ifRidingAvailableSupply false;
|
||||
if (seats.isEmpty()) return@ifRidingAvailableSupply false;
|
||||
if ((owner as? ServerPlayer)?.isInBattle() == true) return@ifRidingAvailableSupply false;
|
||||
if (this.owner != player && this.passengers.isEmpty()) return@ifRidingAvailableSupply false;
|
||||
if(pokemon.effectiveScale < Cobblemon.config.minimumRidingScale) return@ifRidingAvailableSupply false;
|
||||
if(beamMode == 3) return@ifRidingAvailableSupply false;
|
||||
return@ifRidingAvailableSupply behaviour.isActive(settings, state, this);
|
||||
}
|
||||
val canRide = isRideableFor(player)
|
||||
if (pokemon.getOwnerPlayer() == player) {
|
||||
val cosmeticItemDefinition = CobblemonCosmeticItems.findValidCosmeticForPokemonAndItem(
|
||||
player.level().registryAccess(),
|
||||
@@ -1325,6 +1316,18 @@ open class PokemonEntity(
|
||||
}
|
||||
}
|
||||
|
||||
fun isRideableFor(player: ServerPlayer): Boolean = ifRidingAvailableSupply(false) canRide@{ behaviour, settings, state ->
|
||||
if (!player.canInteractWithEntity(this, player.entityInteractionRange())) return@canRide false
|
||||
if (platform != PlatformType.NONE) return@canRide false
|
||||
if (tethering != null) return@canRide false
|
||||
if (seats.isEmpty()) return@canRide false
|
||||
if ((owner as? ServerPlayer)?.isInBattle() == true) return@canRide false
|
||||
if (this.owner != player && this.passengers.isEmpty()) return@canRide false
|
||||
if (pokemon.effectiveScale < Cobblemon.config.minimumRidingScale) return@canRide false
|
||||
if (beamMode == 3) return@canRide false
|
||||
return@canRide behaviour.isActive(settings, state, this)
|
||||
}
|
||||
|
||||
override fun getDimensions(pose: Pose): EntityDimensions {
|
||||
val scale = effects.mockEffect?.scale ?: (form.baseScale * pokemon.effectiveScale)
|
||||
var result = this.exposedForm.hitbox.scale(scale)
|
||||
@@ -1606,9 +1609,8 @@ open class PokemonEntity(
|
||||
|| stack.`is`(CobblemonItemTags.WHITELISTED_ITEMS_TO_HOLD)
|
||||
|
||||
fun tryRidingPokemon(player: ServerPlayer): Boolean {
|
||||
if (pokemon.effectiveScale < Cobblemon.config.minimumRidingScale) {
|
||||
return false
|
||||
}
|
||||
if (!isRideableFor(player)) return false
|
||||
|
||||
val event = RidePokemonEvent.Pre(player, this)
|
||||
CobblemonEvents.RIDE_EVENT_PRE.post(event)
|
||||
if (!event.isCanceled) {
|
||||
@@ -2742,4 +2744,9 @@ open class PokemonEntity(
|
||||
}
|
||||
|
||||
fun hasRider() = this.passengers.any { it is LivingEntity }
|
||||
}
|
||||
|
||||
override fun playStepSound(pos: BlockPos, state: BlockState) {
|
||||
if (this.pokemon.species.silenceStepSounds) return
|
||||
super.playStepSound(pos, state)
|
||||
}
|
||||
}
|
||||
+27
@@ -22,6 +22,7 @@ import com.cobblemon.mod.common.api.molang.ObjectValue
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.TickingSpeciesFeature
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.riding.stats.RidingStat
|
||||
import com.cobblemon.mod.common.api.spawning.fishing.FishingSpawnCause.Companion.DROPS_REROLL_ASPECT
|
||||
import com.cobblemon.mod.common.api.tags.CobblemonItemTags
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
@@ -46,10 +47,15 @@ import kotlin.math.*
|
||||
|
||||
/** Handles purely server logic for a Pokémon */
|
||||
class PokemonServerDelegate : PokemonSideDelegate {
|
||||
companion object {
|
||||
private const val RIDE_STAT_GAIN_AMOUNT = 1F
|
||||
}
|
||||
|
||||
lateinit var entity: PokemonEntity
|
||||
var acknowledgedHPValue = -1
|
||||
var acknowledgedLevel = -1
|
||||
val passengerOffsets = mutableMapOf<Int, Vec3>()
|
||||
private var rideStatGainAnchor: Vec3? = null
|
||||
|
||||
/** Mocked properties exposed to the client [PokemonEntity]. */
|
||||
private val mock: PokemonProperties?
|
||||
@@ -355,9 +361,30 @@ class PokemonServerDelegate : PokemonSideDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
val rideStatGainIntervalSeconds = Cobblemon.config.powerItemRideStatGainIntervalSeconds
|
||||
if (rideStatGainIntervalSeconds > 0) {
|
||||
val rideStatGainIntervalTicks = rideStatGainIntervalSeconds * 20L
|
||||
if (entity.level().gameTime % rideStatGainIntervalTicks == 0L) {
|
||||
trainRideStats()
|
||||
}
|
||||
}
|
||||
|
||||
updateTrackedValues()
|
||||
}
|
||||
|
||||
private fun trainRideStats() {
|
||||
val position = entity.position()
|
||||
val anchor = rideStatGainAnchor
|
||||
rideStatGainAnchor = position
|
||||
if (anchor == null || anchor == position || entity.passengers.isEmpty()) return
|
||||
|
||||
val heldItem = entity.pokemon.heldItemNoCopy()
|
||||
if (heldItem.isEmpty) return
|
||||
|
||||
val stat = RidingStat.entries.firstOrNull { heldItem.`is`(it.powerItem) } ?: return
|
||||
entity.pokemon.addRideBoost(stat, RIDE_STAT_GAIN_AMOUNT)
|
||||
}
|
||||
|
||||
fun updateShownItem() {
|
||||
val trackedShownItem = when {
|
||||
// Show Hand Item if Held item is hidden
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.cobblemon.mod.common.item.crafting.washer
|
||||
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.crafting.Ingredient
|
||||
import net.minecraft.world.item.crafting.RecipeInput
|
||||
|
||||
class WasherInput(
|
||||
val item: ItemStack = ItemStack.EMPTY
|
||||
) : RecipeInput {
|
||||
|
||||
override fun getItem(index: Int): ItemStack? {
|
||||
return if (index == 0) item else null
|
||||
}
|
||||
|
||||
override fun size() = 1
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.cobblemon.mod.common.item.crafting.washer
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonRecipeSerializers
|
||||
import com.cobblemon.mod.common.CobblemonRecipeTypes
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.MapCodec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.core.component.DataComponents
|
||||
import net.minecraft.core.HolderLookup
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
import net.minecraft.network.codec.StreamCodec
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.crafting.Ingredient
|
||||
import net.minecraft.world.item.crafting.Recipe
|
||||
import net.minecraft.world.item.crafting.RecipeSerializer
|
||||
import net.minecraft.world.level.Level
|
||||
|
||||
class WasherRecipe(
|
||||
val input: Ingredient,
|
||||
val result: ItemStack,
|
||||
val preserveInputComponents: Boolean = false,
|
||||
val removeDyedColor: Boolean = false
|
||||
) : Recipe<WasherInput> {
|
||||
|
||||
override fun getType() = CobblemonRecipeTypes.WASHER
|
||||
override fun canCraftInDimensions(width: Int, height: Int) = true
|
||||
override fun assemble(input: WasherInput, registries: HolderLookup.Provider): ItemStack {
|
||||
val output = if (preserveInputComponents) {
|
||||
input.item.transmuteCopy(result.item, result.count)
|
||||
} else {
|
||||
result.copy()
|
||||
}
|
||||
if (removeDyedColor) {
|
||||
output.remove(DataComponents.DYED_COLOR)
|
||||
}
|
||||
return output
|
||||
}
|
||||
override fun getSerializer() = CobblemonRecipeSerializers.WASHER
|
||||
override fun getResultItem(registries: HolderLookup.Provider): ItemStack = result.copy()
|
||||
override fun matches(input: WasherInput, level: Level) =
|
||||
this.input.test(input.item) && (!removeDyedColor || input.item.has(DataComponents.DYED_COLOR))
|
||||
|
||||
class Serializer : RecipeSerializer<WasherRecipe> {
|
||||
companion object {
|
||||
val CODEC: MapCodec<WasherRecipe> = RecordCodecBuilder.mapCodec { instance ->
|
||||
instance.group(
|
||||
Ingredient.CODEC.fieldOf("input").forGetter { recipe -> recipe.input },
|
||||
ItemStack.STRICT_CODEC.fieldOf("result").forGetter { recipe -> recipe.result },
|
||||
Codec.BOOL.optionalFieldOf("preserve_input_components", false)
|
||||
.forGetter { recipe -> recipe.preserveInputComponents },
|
||||
Codec.BOOL.optionalFieldOf("remove_dyed_color", false)
|
||||
.forGetter { recipe -> recipe.removeDyedColor }
|
||||
).apply(instance, ::WasherRecipe)
|
||||
}
|
||||
}
|
||||
|
||||
val STREAM_CODEC: StreamCodec<RegistryFriendlyByteBuf, WasherRecipe> =
|
||||
StreamCodec.of(::toNetwork, ::fromNetwork)
|
||||
|
||||
private fun fromNetwork(buffer: RegistryFriendlyByteBuf): WasherRecipe {
|
||||
val input = Ingredient.CONTENTS_STREAM_CODEC.decode(buffer)
|
||||
val result = ItemStack.STREAM_CODEC.decode(buffer)
|
||||
val preserveInputComponents = buffer.readBoolean()
|
||||
val removeDyedColor = buffer.readBoolean()
|
||||
return WasherRecipe(input, result, preserveInputComponents, removeDyedColor)
|
||||
}
|
||||
|
||||
private fun toNetwork(buffer: RegistryFriendlyByteBuf, recipe: WasherRecipe) {
|
||||
Ingredient.CONTENTS_STREAM_CODEC.encode(buffer, recipe.input)
|
||||
ItemStack.STREAM_CODEC.encode(buffer, recipe.result)
|
||||
buffer.writeBoolean(recipe.preserveInputComponents)
|
||||
buffer.writeBoolean(recipe.removeDyedColor)
|
||||
}
|
||||
|
||||
override fun codec() = CODEC
|
||||
override fun streamCodec() = STREAM_CODEC
|
||||
}
|
||||
|
||||
}
|
||||
@@ -394,6 +394,7 @@ object CobblemonItemGroups {
|
||||
entries.accept(CobblemonItems.FOSSIL_ANALYZER)
|
||||
entries.accept(CobblemonItems.MONITOR)
|
||||
entries.accept(CobblemonItems.DAMAGED_MONITOR)
|
||||
entries.accept(CobblemonItems.ROTOM_MONITOR)
|
||||
entries.accept(CobblemonItems.PC)
|
||||
entries.accept(CobblemonItems.HEALING_MACHINE)
|
||||
entries.accept(CobblemonItems.PASTURE)
|
||||
@@ -570,6 +571,47 @@ object CobblemonItemGroups {
|
||||
entries.accept(CobblemonItems.PINK_PLAQUE)
|
||||
|
||||
CobblemonItems.campfire_pots.forEach(entries::accept)
|
||||
|
||||
entries.accept(CobblemonItems.COPPER_OVEN)
|
||||
entries.accept(CobblemonItems.COPPER_WASHER)
|
||||
entries.accept(CobblemonItems.COPPER_FAN)
|
||||
entries.accept(CobblemonItems.COPPER_MOWER)
|
||||
entries.accept(CobblemonItems.COPPER_FRIDGE)
|
||||
entries.accept(CobblemonItems.EXPOSED_COPPER_OVEN)
|
||||
entries.accept(CobblemonItems.EXPOSED_COPPER_WASHER)
|
||||
entries.accept(CobblemonItems.EXPOSED_COPPER_FAN)
|
||||
entries.accept(CobblemonItems.EXPOSED_COPPER_MOWER)
|
||||
entries.accept(CobblemonItems.EXPOSED_COPPER_FRIDGE)
|
||||
entries.accept(CobblemonItems.WEATHERED_COPPER_OVEN)
|
||||
entries.accept(CobblemonItems.WEATHERED_COPPER_WASHER)
|
||||
entries.accept(CobblemonItems.WEATHERED_COPPER_FAN)
|
||||
entries.accept(CobblemonItems.WEATHERED_COPPER_MOWER)
|
||||
entries.accept(CobblemonItems.WEATHERED_COPPER_FRIDGE)
|
||||
entries.accept(CobblemonItems.OXIDIZED_COPPER_OVEN)
|
||||
entries.accept(CobblemonItems.OXIDIZED_COPPER_WASHER)
|
||||
entries.accept(CobblemonItems.OXIDIZED_COPPER_FAN)
|
||||
entries.accept(CobblemonItems.OXIDIZED_COPPER_MOWER)
|
||||
entries.accept(CobblemonItems.OXIDIZED_COPPER_FRIDGE)
|
||||
entries.accept(CobblemonItems.WAXED_COPPER_OVEN)
|
||||
entries.accept(CobblemonItems.WAXED_COPPER_WASHER)
|
||||
entries.accept(CobblemonItems.WAXED_COPPER_FAN)
|
||||
entries.accept(CobblemonItems.WAXED_COPPER_MOWER)
|
||||
entries.accept(CobblemonItems.WAXED_COPPER_FRIDGE)
|
||||
entries.accept(CobblemonItems.WAXED_EXPOSED_COPPER_OVEN)
|
||||
entries.accept(CobblemonItems.WAXED_EXPOSED_COPPER_WASHER)
|
||||
entries.accept(CobblemonItems.WAXED_EXPOSED_COPPER_FAN)
|
||||
entries.accept(CobblemonItems.WAXED_EXPOSED_COPPER_MOWER)
|
||||
entries.accept(CobblemonItems.WAXED_EXPOSED_COPPER_FRIDGE)
|
||||
entries.accept(CobblemonItems.WAXED_WEATHERED_COPPER_OVEN)
|
||||
entries.accept(CobblemonItems.WAXED_WEATHERED_COPPER_WASHER)
|
||||
entries.accept(CobblemonItems.WAXED_WEATHERED_COPPER_FAN)
|
||||
entries.accept(CobblemonItems.WAXED_WEATHERED_COPPER_MOWER)
|
||||
entries.accept(CobblemonItems.WAXED_WEATHERED_COPPER_FRIDGE)
|
||||
entries.accept(CobblemonItems.WAXED_OXIDIZED_COPPER_OVEN)
|
||||
entries.accept(CobblemonItems.WAXED_OXIDIZED_COPPER_WASHER)
|
||||
entries.accept(CobblemonItems.WAXED_OXIDIZED_COPPER_FAN)
|
||||
entries.accept(CobblemonItems.WAXED_OXIDIZED_COPPER_MOWER)
|
||||
entries.accept(CobblemonItems.WAXED_OXIDIZED_COPPER_FRIDGE)
|
||||
}
|
||||
|
||||
private fun consumableEntries(displayContext: ItemDisplayParameters, entries: Output) {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.item.interactive
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonItemComponents
|
||||
import com.cobblemon.mod.common.item.components.FoodComponent
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.sounds.SoundEvent
|
||||
import net.minecraft.sounds.SoundEvents
|
||||
@@ -23,10 +24,15 @@ import net.minecraft.world.level.Level
|
||||
class PonigiriItem : Item(
|
||||
Properties().stacksTo(64)
|
||||
.food(FoodProperties.Builder()
|
||||
.nutrition(2)
|
||||
.saturationModifier(0.55f)
|
||||
.nutrition(NUTRITION)
|
||||
.saturationModifier(SATURATION_MODIFIER)
|
||||
.build())
|
||||
) {
|
||||
companion object {
|
||||
const val NUTRITION = 2
|
||||
const val SATURATION_MODIFIER = 0.55f
|
||||
}
|
||||
|
||||
override fun getName(stack: ItemStack): Component {
|
||||
|
||||
val ingredients = stack.get(CobblemonItemComponents.INGREDIENT)
|
||||
@@ -59,4 +65,9 @@ class PonigiriItem : Item(
|
||||
override fun getEatingSound(): SoundEvent {
|
||||
return SoundEvents.GENERIC_EAT
|
||||
}
|
||||
}
|
||||
|
||||
fun getFoodValues(stack: ItemStack): Pair<Int, Float> {
|
||||
val (hunger, saturation) = stack.getOrDefault(CobblemonItemComponents.FOOD, FoodComponent(NUTRITION, SATURATION_MODIFIER))
|
||||
return hunger to saturation
|
||||
}
|
||||
}
|
||||
+24
@@ -8,9 +8,12 @@
|
||||
|
||||
package com.cobblemon.mod.common.net.serverhandling.battle
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.api.net.ServerNetworkPacketHandler
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.battles.BattleRegistry
|
||||
import com.cobblemon.mod.common.battles.HealItemActionResponse
|
||||
import com.cobblemon.mod.common.battles.MoveActionResponse
|
||||
import com.cobblemon.mod.common.exception.IllegalActionChoiceException
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleMakeChoicePacket
|
||||
import com.cobblemon.mod.common.net.messages.client.battle.BattleQueueRequestPacket
|
||||
@@ -25,6 +28,27 @@ object BattleSelectActionsHandler : ServerNetworkPacketHandler<BattleSelectActio
|
||||
if (!actor.mustChoose) {
|
||||
return
|
||||
}
|
||||
|
||||
// Battle command injection attempt detection
|
||||
packet.showdownActionResponses.asSequence()
|
||||
.flatMap {
|
||||
when (it) {
|
||||
is MoveActionResponse -> sequenceOf(it.moveName, it.targetPnx, it.gimmickID)
|
||||
is HealItemActionResponse -> sequenceOf(it.item)
|
||||
else -> emptySequence()
|
||||
}
|
||||
}
|
||||
.filterNotNull()
|
||||
.firstOrNull { field -> field.any(Char::isISOControl) }
|
||||
?.let {
|
||||
// Escapes control chars as \uXXXX to prevent forging logs.
|
||||
val printable = it.replace(Regex("\\p{Cc}")) { "\\u%04x".format(it.value[0].code) }
|
||||
Cobblemon.LOGGER.warn("Blocked battle command injection from ${player.name.string}: $printable")
|
||||
actor.sendUpdate(BattleQueueRequestPacket(actor.request!!))
|
||||
actor.sendUpdate(BattleMakeChoicePacket())
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
actor.setActionResponses(packet.showdownActionResponses)
|
||||
} catch (e: IllegalActionChoiceException) {
|
||||
|
||||
@@ -55,6 +55,8 @@ object PlatformEvents {
|
||||
@JvmField
|
||||
val CLIENT_PLAYER_LOGOUT = EventObservable<ClientPlayerEvent.Logout>()
|
||||
@JvmField
|
||||
val PLAYER_RESPAWN = EventObservable<ServerPlayerEvent.Respawn>()
|
||||
@JvmField
|
||||
val PLAYER_DEATH = CancelableObservable<ServerPlayerEvent.Death>()
|
||||
@JvmField
|
||||
val RIGHT_CLICK_BLOCK = CancelableObservable<ServerPlayerEvent.RightClickBlock>()
|
||||
|
||||
@@ -50,6 +50,11 @@ interface ServerPlayerEvent {
|
||||
*/
|
||||
data class Logout(override val player: ServerPlayer) : ServerPlayerEvent
|
||||
|
||||
/**
|
||||
* Fired when the [player] respawns (either by coming back from the end or dying).
|
||||
*/
|
||||
data class Respawn(override val player: ServerPlayer) : ServerPlayerEvent
|
||||
|
||||
/**
|
||||
* Fired when the [player] dies.
|
||||
* If canceled the death will be prevented but healing is required in order to not be stuck in a loop.
|
||||
|
||||
@@ -173,6 +173,7 @@ class Species : ShowdownIdentifiable {
|
||||
.addStandardFunctions()
|
||||
.addSpeciesFunctions(this)
|
||||
|
||||
var silenceStepSounds = false
|
||||
|
||||
fun initialize() {
|
||||
Cobblemon.statProvider.provide(this)
|
||||
@@ -256,6 +257,7 @@ class Species : ShowdownIdentifiable {
|
||||
}
|
||||
|
||||
this.riding.encode(buffer)
|
||||
buffer.writeBoolean(this.silenceStepSounds)
|
||||
}
|
||||
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
@@ -299,6 +301,7 @@ class Species : ShowdownIdentifiable {
|
||||
}
|
||||
}
|
||||
this.riding = RidingProperties.decode(buffer)
|
||||
this.silenceStepSounds = buffer.readBoolean()
|
||||
this.initialize()
|
||||
}
|
||||
|
||||
|
||||
+12
-6
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.api.abilities.Abilities
|
||||
import com.cobblemon.mod.common.api.data.DataRegistry
|
||||
import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.api.pokemon.Natures
|
||||
import com.cobblemon.mod.common.api.pokemon.feature.AbstractChoiceSpeciesFeatureProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.properties.CustomPokemonProperty
|
||||
@@ -134,17 +135,18 @@ internal object PropertiesCompletionProvider : DataRegistry {
|
||||
private fun addDefaults() {
|
||||
this.inject(setOf("level", "lvl", "l"), setOf("1", "${Cobblemon.config.maxPokemonLevel}") )
|
||||
this.inject(setOf("shiny", "s"), setOf("yes", "no"))
|
||||
this.inject(setOf("gender"), Gender.values().map { it.name.lowercase() })
|
||||
this.inject(setOf("alpha", "is_alpha"), setOf("yes", "no"))
|
||||
this.inject(setOf("gender"), Gender.entries.map { it.name.lowercase() })
|
||||
this.inject(setOf("friendship"), setOf("0", Cobblemon.config.maxPokemonFriendship.toString()))
|
||||
this.inject(setOf("fullness"), setOf("0", "255"))
|
||||
this.inject(setOf("pokeball"), PokeBalls.all().map { it.name.simplify() })
|
||||
this.inject(setOf("nature"), Natures.all().map { it.name.simplify() })
|
||||
this.inject(setOf("ability"), Abilities.all().map { if (it.name.asIdentifierDefaultingNamespace().namespace == Cobblemon.MODID) it.name.asIdentifierDefaultingNamespace().path else it.name })
|
||||
this.inject(setOf("dmax"), setOf("0", Cobblemon.config.maxDynamaxLevel.toString()))
|
||||
this.inject(setOf("gmax"), setOf("yes", "no"))
|
||||
this.inject(setOf("dmax_level", "dmax"), setOf("0", Cobblemon.config.maxDynamaxLevel.toString()))
|
||||
this.inject(setOf("gmax_factor", "gmax"), setOf("yes", "no"))
|
||||
this.inject(setOf("type", "elemental_type"), ElementalTypes.all().map { it.name })
|
||||
this.inject(setOf("tera_type", "tera"), TeraTypes.map { it.id.simplify() })
|
||||
this.inject(setOf("tradeable"), setOf("yes", "no"))
|
||||
this.inject(setOf("tradeable", "tradable"), setOf("yes", "no"))
|
||||
this.inject(setOf("originaltrainer", "ot"), setOf(""))
|
||||
this.inject(setOf("originaltrainertype", "ottype"), setOf("None", "Player", "NPC"))
|
||||
this.inject(setOf("nickname", "nick"), setOf(""))
|
||||
@@ -164,7 +166,11 @@ internal object PropertiesCompletionProvider : DataRegistry {
|
||||
private fun addCustom() {
|
||||
CustomPokemonProperty.properties.forEach { property ->
|
||||
// We won't tab complete properties that have no key attached to them as it would be fairly hard to determine which one to suggest
|
||||
if (property.needsKey) {
|
||||
if (property.needsKey && property !is AbstractChoiceSpeciesFeatureProvider<*>) {
|
||||
this.inject(property.keys, property.examples())
|
||||
}
|
||||
// Except choice features that fill examples with all available choices - Gito
|
||||
if (property is AbstractChoiceSpeciesFeatureProvider<*>) {
|
||||
this.inject(property.keys, property.examples())
|
||||
}
|
||||
}
|
||||
@@ -175,4 +181,4 @@ internal object PropertiesCompletionProvider : DataRegistry {
|
||||
val suggestions: Collection<String>
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
@@ -234,11 +234,11 @@ fun Entity.isDusk(): Boolean {
|
||||
}
|
||||
|
||||
fun Entity.isStandingOn(blocks: Set<String>, depth: Int = 2): Boolean {
|
||||
for (currentDepth in 1..depth) {
|
||||
val bellowBlockPos = blockPosition().below(currentDepth)
|
||||
for (currentDepth in 0..depth) {
|
||||
val bellowBlockPos = blockPosBelowThatAffectsMyMovement.below(currentDepth)
|
||||
val blockState = level().getBlockState(bellowBlockPos)
|
||||
|
||||
if (blockState.isAir || !blockState.isCollisionShapeFullBlock(level(), bellowBlockPos)) continue
|
||||
if (blockState.isAir) continue
|
||||
|
||||
val elementOrTags = ExtraCodecs.TAG_OR_ELEMENT_ID.listOf().decode(JavaOps.INSTANCE, blocks.toList()).result().get().first
|
||||
elementOrTags.forEach {
|
||||
|
||||
@@ -95,6 +95,8 @@ class FloatRange(override val start: Float, override val endInclusive: Float) :
|
||||
override fun hashCode(): Int = 31 * start.hashCode() + endInclusive.hashCode()
|
||||
|
||||
override fun toString(): String = "$start..$endInclusive"
|
||||
fun random() = Random.nextFloat() * (endInclusive - start) + start
|
||||
|
||||
}
|
||||
|
||||
class DoubleRange(override val start: Double, override val endInclusive: Double) : ClosedFloatingPointRange<Double> {
|
||||
|
||||
+4
-1
@@ -26,5 +26,8 @@ object CobblemonGameRules {
|
||||
val SHINY_STARTERS: GameRules.Key<GameRules.BooleanValue> = Cobblemon.implementation.registerGameRule("doShinyStarters", GameRules.Category.MISC, BooleanRuleInvoker.`cobblemon$create`(false))
|
||||
@JvmField
|
||||
val HEALERS_HEAL_PC: GameRules.Key<GameRules.BooleanValue> = Cobblemon.implementation.registerGameRule("healersHealPC", GameRules.Category.MISC, BooleanRuleInvoker.`cobblemon$create`(false))
|
||||
|
||||
@JvmField
|
||||
val HEALER_SET_SPAWN: GameRules.Key<GameRules.BooleanValue> = Cobblemon.implementation.registerGameRule("healersSetSpawn", GameRules.Category.MISC, BooleanRuleInvoker.`cobblemon$create`(false))
|
||||
@JvmField
|
||||
val DO_POKEMON_PREDATION: GameRules.Key<GameRules.BooleanValue> = Cobblemon.implementation.registerGameRule("doPokemonPredation", GameRules.Category.MOBS, BooleanRuleInvoker.`cobblemon$create`(true))
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"format_version": "1.10.0",
|
||||
"particle_effect": {
|
||||
"description": {
|
||||
"identifier": "cobblemon:rotomfridge_doorready",
|
||||
"basic_render_parameters": {
|
||||
"material": "particles_blend",
|
||||
"texture": "textures/particles/vanilla/generic"
|
||||
}
|
||||
},
|
||||
"curves": {
|
||||
"variable.debrissize": {
|
||||
"type": "linear",
|
||||
"input": "v.particle_age",
|
||||
"horizontal_range": "v.particle_lifetime",
|
||||
"nodes": [0, 1, 0.96, 0.86, 0.7, 0.47, 0]
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_rate_steady": {
|
||||
"spawn_rate": 8,
|
||||
"max_particles": 100
|
||||
},
|
||||
"minecraft:emitter_lifetime_expression": {
|
||||
"activation_expression": 1
|
||||
},
|
||||
"minecraft:emitter_shape_box": {
|
||||
"offset": [0, -1, 0.5],
|
||||
"half_dimensions": [0.5, 0.75, 0],
|
||||
"surface_only": true,
|
||||
"direction": "outwards"
|
||||
},
|
||||
"minecraft:particle_lifetime_expression": {
|
||||
"max_lifetime": "math.random(1.2,2)"
|
||||
},
|
||||
"minecraft:particle_initial_spin": {
|
||||
"rotation": "math.random_integer(0,3)*90"
|
||||
},
|
||||
"minecraft:particle_initial_speed": "math.random(2.5,3.5)*0.1",
|
||||
"minecraft:particle_motion_dynamic": {
|
||||
"linear_acceleration": [0, 0.1, 0],
|
||||
"linear_drag_coefficient": 1
|
||||
},
|
||||
"minecraft:particle_appearance_billboard": {
|
||||
"size": ["0.25*v.debrissize", "0.25*v.debrissize"],
|
||||
"facing_camera_mode": "rotate_xyz",
|
||||
"uv": {
|
||||
"texture_width": 64,
|
||||
"texture_height": 8,
|
||||
"flipbook": {
|
||||
"base_UV": [56, 0],
|
||||
"size_UV": [8, 8],
|
||||
"step_UV": [-8, 0],
|
||||
"frames_per_second": 6,
|
||||
"max_frame": 8
|
||||
}
|
||||
}
|
||||
},
|
||||
"minecraft:particle_motion_collision": {
|
||||
"collision_radius": 0.01
|
||||
},
|
||||
"minecraft:particle_appearance_lighting": {},
|
||||
"minecraft:particle_appearance_tinting": {
|
||||
"color": [0.7098, 0.95294, 1, 0.74902]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"format_version": "1.10.0",
|
||||
"particle_effect": {
|
||||
"description": {
|
||||
"identifier": "cobblemon:watershuriken_actor",
|
||||
"basic_render_parameters": {
|
||||
"material": "particles_blend",
|
||||
"texture": "textures/particles/moves/watershuriken"
|
||||
}
|
||||
},
|
||||
"curves": {
|
||||
"variable.rsize": {
|
||||
"type": "linear",
|
||||
"input": "v.particle_age",
|
||||
"horizontal_range": "v.particle_lifetime",
|
||||
"nodes": [0, 1, 1, 1, 1, 1, 1, 1]
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"trail": {
|
||||
"particle_effect": {
|
||||
"effect": "cobblemon:watershuriken_actortrail",
|
||||
"type": "particle"
|
||||
}
|
||||
},
|
||||
"hit": {
|
||||
"particle_effect": {
|
||||
"effect": "cobblemon:watershuriken_target",
|
||||
"type": "particle"
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"minecraft:emitter_initialization": {
|
||||
"creation_expression": "v.target_deltaz=5;"
|
||||
},
|
||||
"minecraft:emitter_rate_instant": {
|
||||
"num_particles": 1
|
||||
},
|
||||
"minecraft:emitter_lifetime_once": {
|
||||
"active_time": 0.25
|
||||
},
|
||||
"minecraft:emitter_shape_disc": {
|
||||
"offset": [0, 0.02, 0.1],
|
||||
"radius": 0.5,
|
||||
"direction": "outwards"
|
||||
},
|
||||
"minecraft:particle_lifetime_expression": {
|
||||
"max_lifetime": 0.35
|
||||
},
|
||||
"minecraft:particle_lifetime_events": {
|
||||
"timeline": {
|
||||
"0.00": "trail",
|
||||
"0.06": "trail",
|
||||
"0.12": "trail",
|
||||
"0.18": "trail",
|
||||
"0.24": "trail",
|
||||
"0.30": "trail",
|
||||
"0.34": "hit"
|
||||
}
|
||||
},
|
||||
"minecraft:particle_initial_spin": {
|
||||
"rotation": "math.random_integer(0,3)*90"
|
||||
},
|
||||
"minecraft:particle_motion_parametric": {
|
||||
"relative_position": ["-v.target_deltax*(v.particle_age / v.particle_lifetime)", "(v.target_deltay*(v.particle_age / v.particle_lifetime))", "-v.target_deltaz*(v.particle_age / v.particle_lifetime)"]
|
||||
},
|
||||
"minecraft:particle_appearance_billboard": {
|
||||
"size": ["0.4*v.rsize", "0.4*v.rsize"],
|
||||
"facing_camera_mode": "lookat_direction",
|
||||
"direction": {
|
||||
"mode": "custom",
|
||||
"custom_direction": [0, 0, -1]
|
||||
},
|
||||
"uv": {
|
||||
"texture_width": 60,
|
||||
"texture_height": 15,
|
||||
"flipbook": {
|
||||
"base_UV": [0, 0],
|
||||
"size_UV": [15, 15],
|
||||
"step_UV": [15, 0],
|
||||
"frames_per_second": 24,
|
||||
"max_frame": 4,
|
||||
"loop": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loaded 100 of 1553 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user