mirror of
https://gitlab.com/cable-mc/cobblemon.git
synced 2026-10-21 14:46:25 -04:00
Compare commits
316
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b33536e872 | ||
|
|
5957ddae58 | ||
|
|
fcb798161e | ||
|
|
357ac35802 | ||
|
|
25c6fb6d31 | ||
|
|
7fd9b678f1 | ||
|
|
169e06a26f | ||
|
|
ecfc71bfd1 | ||
|
|
f2919aa75d | ||
|
|
336b076eee | ||
|
|
7a970b4bc1 | ||
|
|
1947450d77 | ||
|
|
de94721703 | ||
|
|
c6e217dda7 | ||
|
|
49f4a254d1 | ||
|
|
b0886449bb | ||
|
|
aca61300d6 | ||
|
|
5667ddf6a2 | ||
|
|
702ce3b8f8 | ||
|
|
096136b48e | ||
|
|
25bcd1dec2 | ||
|
|
a9432fc1de | ||
|
|
7ec7152ec3 | ||
|
|
0ac7f664f1 | ||
|
|
4550cf31ed | ||
|
|
4d783b2d15 | ||
|
|
c0fc28d61d | ||
|
|
3701ae7dac | ||
|
|
b4cc95b3bf | ||
|
|
eb83d11952 | ||
|
|
dc2ffa7899 | ||
|
|
a80689609c | ||
|
|
42c2eab418 | ||
|
|
7c1c0dd3c8 | ||
|
|
320f5f7090 | ||
|
|
beed7a322c | ||
|
|
b58e9c6de5 | ||
|
|
3e7ae9750c | ||
|
|
85f80c530e | ||
|
|
1ab5f13704 | ||
|
|
782f0b8a5a | ||
|
|
9dbd27b23c | ||
|
|
2faf669ace | ||
|
|
1c38433dda | ||
|
|
d9d3583cb1 | ||
|
|
dd7edee941 | ||
|
|
616d16e11f | ||
|
|
77a648cebd | ||
|
|
adaa852b59 | ||
|
|
c17c48caec | ||
|
|
f6a833a5fd | ||
|
|
ab3d26dee6 | ||
|
|
37e526614f | ||
|
|
0f3c6d07c8 | ||
|
|
3be4ae8fa6 | ||
|
|
d9b027dd66 | ||
|
|
612b75d3e5 | ||
|
|
bbfe6bd143 | ||
|
|
219fcc369f | ||
|
|
e28eb0e3da | ||
|
|
b3160795fe | ||
|
|
aa68ef640d | ||
|
|
47a6d450cf | ||
|
|
14e4abca27 | ||
|
|
108716eb84 | ||
|
|
8c6ef80cf5 | ||
|
|
2d61cb5979 | ||
|
|
5b8dc82ef2 | ||
|
|
1d3bc137ad | ||
|
|
35e6caf6f2 | ||
|
|
cd827eccbf | ||
|
|
3e89e2b9ad | ||
|
|
f0c0bb2521 | ||
|
|
82c2ce22c1 | ||
|
|
d14a269b29 | ||
|
|
a726408482 | ||
|
|
7e8b972c70 | ||
|
|
15e76629cb | ||
|
|
10c0c188b3 | ||
|
|
fd9d3a3028 | ||
|
|
ba5529e401 | ||
|
|
e0a4a72f9c | ||
|
|
59c922dee0 | ||
|
|
e5dda3e975 | ||
|
|
7d75993562 | ||
|
|
54c64d3dfe | ||
|
|
ddf1396abb | ||
|
|
e3b2220813 | ||
|
|
f982a94ebb | ||
|
|
1c97760188 | ||
|
|
c6d33e6cec | ||
|
|
8e6e1cc3f2 | ||
|
|
ea9654af61 | ||
|
|
b8ccaf9f89 | ||
|
|
dac42f1971 | ||
|
|
09152c7e97 | ||
|
|
f9cddd02a9 | ||
|
|
4920244767 | ||
|
|
9b20a55b69 | ||
|
|
9f1be5feaa | ||
|
|
8ea8968a04 | ||
|
|
efd4f3c623 | ||
|
|
4a06c57a1b | ||
|
|
2ab3d396d2 | ||
|
|
297fa6f9b0 | ||
|
|
455b6bde43 | ||
|
|
b3f32404cb | ||
|
|
8b4326a82d | ||
|
|
fb45d110bc | ||
|
|
a51ccb1a86 | ||
|
|
e3cfb7199d | ||
|
|
3bb61dd649 | ||
|
|
b55d4d576d | ||
|
|
99d818d11e | ||
|
|
48b546fad4 | ||
|
|
2ee04e3b1c | ||
|
|
fbef8ff0dc | ||
|
|
c25a8ca8b5 | ||
|
|
248cc4c5bc | ||
|
|
1bbebfd3ae | ||
|
|
5b5a0afc45 | ||
|
|
d07729abfc | ||
|
|
945c34ccd6 | ||
|
|
01d2350993 | ||
|
|
93b7c421cb | ||
|
|
192542a362 | ||
|
|
8af45c01d8 | ||
|
|
96d508d548 | ||
|
|
a51db63d86 | ||
|
|
f906079a25 | ||
|
|
efd77e1337 | ||
|
|
acc4f341b6 | ||
|
|
567372ef51 | ||
|
|
53b712f8a2 | ||
|
|
d787aabe4e | ||
|
|
327c8b47d1 | ||
|
|
448b02cef9 | ||
|
|
1c669d3eae | ||
|
|
14d6b55989 | ||
|
|
c3d023a56b | ||
|
|
8382e9d904 | ||
|
|
2cf907bec1 | ||
|
|
d167d4c2f2 | ||
|
|
61181f3f1c | ||
|
|
156d193fc8 | ||
|
|
b5b22e2c23 | ||
|
|
e47275236a | ||
|
|
eb96be2eff | ||
|
|
f620f84222 | ||
|
|
2c79a66298 | ||
|
|
27ce289de0 | ||
|
|
bc4076f734 | ||
|
|
b2b5a8f715 | ||
|
|
46764b9fab | ||
|
|
d212cc0ad1 | ||
|
|
600e07fe08 | ||
|
|
4a3f3b0d3f | ||
|
|
bc423515fb | ||
|
|
13e8e39d43 | ||
|
|
8dd6446b6a | ||
|
|
8fc9b46ce7 | ||
|
|
832d315501 | ||
|
|
d4da62adb5 | ||
|
|
f7f6e9d2ee | ||
|
|
8a375d5e81 | ||
|
|
0bb860c9ab | ||
|
|
7616008cd3 | ||
|
|
cf36db419d | ||
|
|
f634d7fae0 | ||
|
|
dddb3b3d48 | ||
|
|
2468f8a8e6 | ||
|
|
c6ce359736 | ||
|
|
e99ba8cd1d | ||
|
|
3f35ca5bd2 | ||
|
|
e053d2864e | ||
|
|
e098426a6d | ||
|
|
069f483552 | ||
|
|
9a8c7dc8bf | ||
|
|
82ba0334a7 | ||
|
|
bfed3ad52f | ||
|
|
149a59ffbf | ||
|
|
a7dd139c14 | ||
|
|
3866e888de | ||
|
|
5089ea5027 | ||
|
|
840762c00d | ||
|
|
b38c44321e | ||
|
|
1ba7ed425e | ||
|
|
9645a1dd17 | ||
|
|
232d871bef | ||
|
|
ce0b5b77bd | ||
|
|
a4f2472431 | ||
|
|
aaae400f0a | ||
|
|
ba42daa83e | ||
|
|
85577259a6 | ||
|
|
5271e09d8d | ||
|
|
c6cb98cabd | ||
|
|
95f56fc1f8 | ||
|
|
a328c54dda | ||
|
|
12db01b7b2 | ||
|
|
93515777b8 | ||
|
|
16e327bd27 | ||
|
|
0edb9ad115 | ||
|
|
8189e5d819 | ||
|
|
72234e6260 | ||
|
|
48e341aca6 | ||
|
|
f2aed673ee | ||
|
|
51d214d45e | ||
|
|
a4619e761b | ||
|
|
fa67e21a76 | ||
|
|
62cccd204a | ||
|
|
ec9c1a0db3 | ||
|
|
d2bbf12598 | ||
|
|
e58ffb9a00 | ||
|
|
0281dd2e94 | ||
|
|
4060472a23 | ||
|
|
58ec5f38ed | ||
|
|
38938b99ac | ||
|
|
ba204b1473 | ||
|
|
fd2de073d9 | ||
|
|
ecec45fb7f | ||
|
|
9889307981 | ||
|
|
9a18dcadd4 | ||
|
|
7e6864764f | ||
|
|
8468d81286 | ||
|
|
e6636bb6af | ||
|
|
78706548ab | ||
|
|
a5184be524 | ||
|
|
da6455fd33 | ||
|
|
7e544346dd | ||
|
|
4812a33169 | ||
|
|
0fbd003cba | ||
|
|
074073a933 | ||
|
|
f82712e6b4 | ||
|
|
5745ff547c | ||
|
|
8f5617c986 | ||
|
|
02f69779a1 | ||
|
|
a2bfc55e96 | ||
|
|
1f9c632883 | ||
|
|
7fecdb1126 | ||
|
|
f88ec39ec7 | ||
|
|
f8b4b2fc2a | ||
|
|
271aef9821 | ||
|
|
ce9970ca1a | ||
|
|
bf47299b2f | ||
|
|
e56b399c59 | ||
|
|
39098134e8 | ||
|
|
0f505ea3f8 | ||
|
|
478859d0ed | ||
|
|
cf95f62185 | ||
|
|
6ba2fc5b65 | ||
|
|
c25724967a | ||
|
|
067e9d42e7 | ||
|
|
0063c8c8af | ||
|
|
ebdffb44e8 | ||
|
|
6cc609fdfc | ||
|
|
864a4f5c09 | ||
|
|
d2f365504b | ||
|
|
48f4790a36 | ||
|
|
024ec427da | ||
|
|
935ea3ad53 | ||
|
|
f270e479e6 | ||
|
|
ce5d3e75a0 | ||
|
|
f7a5bcbd4d | ||
|
|
75b7ca4786 | ||
|
|
dfee92bc1c | ||
|
|
0fd4bd443e | ||
|
|
e26eceeb2a | ||
|
|
51be1364d3 | ||
|
|
27706a766e | ||
|
|
79a4fbcb48 | ||
|
|
53fdce17f8 | ||
|
|
b03e29c5a9 | ||
|
|
3bdf89570a | ||
|
|
0c15a05986 | ||
|
|
bd69670cd2 | ||
|
|
a89f07856a | ||
|
|
8d0fc13e11 | ||
|
|
9fc77832e6 | ||
|
|
fbd928eeaf | ||
|
|
8d0beca2f6 | ||
|
|
9350960457 | ||
|
|
1b3daa2740 | ||
|
|
784f06b9f0 | ||
|
|
6cfe3fd39d | ||
|
|
338cb819af | ||
|
|
1a75d4b2e8 | ||
|
|
5c4c7b2995 | ||
|
|
39e3ca9da8 | ||
|
|
e40164f8cf | ||
|
|
c087cab84a | ||
|
|
bbdc732bd4 | ||
|
|
e9bdd6be11 | ||
|
|
2330aa9512 | ||
|
|
76ec04055a | ||
|
|
7472d3fd0f | ||
|
|
73c842391e | ||
|
|
ce28b96fc8 | ||
|
|
f0b2f71f17 | ||
|
|
e5187f0d0a | ||
|
|
4610870a1d | ||
|
|
5658c12a7d | ||
|
|
c2e6723c3a | ||
|
|
2a31ebf292 | ||
|
|
77f76edfcf | ||
|
|
9684f39c65 | ||
|
|
011995390b | ||
|
|
a2500b7b2d | ||
|
|
811674adb9 | ||
|
|
6ca671c877 | ||
|
|
080ba93d57 | ||
|
|
96d3e39211 | ||
|
|
79c02d386b | ||
|
|
38c0c13121 | ||
|
|
157e211f06 | ||
|
|
e4654cf24d | ||
|
|
e6c54575ee |
+197
-186
@@ -1,62 +1,39 @@
|
||||
# Changelog
|
||||
## [1.8.0 (MONTH Xth, 2026)](#1-8-0)
|
||||
## [1.8.0 - Make Your Move Update (September 6th, 2026)](#1-8-0)
|
||||
#### I think the red eyes mean they're friendly!
|
||||
|
||||
### Additions
|
||||
- Added config options to award experience to fainted Pokémon for opponents they helped defeat (`awardExperienceToFaintedPokemon`) and to still award experience for defeated enemies even after battle loss/forfeit (`awardExperienceOnBattleLoss`)
|
||||
- Party Overlay Exp Gained Animation will now display the amount of EXP the Pokémon gained
|
||||
- Added a toast to notify players of how they can scroll through their party. Did you know you can hold R and scroll instead of using arrow keys??!
|
||||
- Added a new layer property that makes a layer scroll in a direction. "scrolling": {"speedU": 0.1, "speedV": 0.1}
|
||||
- Added missing crops to Botany Pots integration
|
||||
- Added a way to obtain Porygon by inserting the Upgrade or Dubious Disc into a data monitor
|
||||
- Added a new `cobblemon:structure`, which is a feature without any restrictions allowing the Builders to place certain structures in much more specific manner.
|
||||
- Added Configs for Infinite Use TMs and Unlocking all TMs
|
||||
- Added Type Gem blocks
|
||||
- Added Type Gem Clusters
|
||||
- Added TMs
|
||||
- Added TM Machine
|
||||
- Added Deepslate Core Block
|
||||
- Added /givetm Command
|
||||
- Added advancement triggers for learning TMs: `cobblemon:has_learn_specific_tm` (per-TM), `cobblemon:has_learn_all_tm` (all TMs learned), and `cobblemon:tms_learned` (count-based), backed by a new `totalTMLearnedCount` on player advancement data.
|
||||
- Added `cobblemon:catch_alpha_pokemon` advancement trigger and `totalAlphaCaptureCount` tracking for capturing Alpha Pokémon.
|
||||
- Added Move Dex to Pokédex
|
||||
- Added the Habitat Block, a spawner block for servers and adventure maps that controls spawning in an area.
|
||||
- Added Disk Rack for storing disks and being an audio sequencer for Noteblocks
|
||||
- Added intrinsic scaling to all Pokémon (+-5%). Some rendering cases, such as shoulder mounting, revert to 1.0 scaling to preserve animation accuracy.
|
||||
- Added scaling to "baby" Pokémon (smaller (-20%) at level 1 → normally sized at level 10)
|
||||
- Added conditional seats for riding. Seats can be gated by molang such as "is_alpha".
|
||||
- Added Alpha Pokémon
|
||||
- Added alpha scaling (alphas are larger than their normal counterparts)
|
||||
- Alphas will always lead herds and will spawn in herds
|
||||
- Alphas spawn with two random TM moves from their learnset
|
||||
- Alpha Pokémon will always defend themselves from players that attack them
|
||||
- Added alpha level matching and stat boost (based on level)
|
||||
- Added pitch-down and reverb to alpha cries
|
||||
- Added alpha Pokémon bait effect
|
||||
- Added alpha eye rendering including eye overlay, bloom, eye trail, and particles.
|
||||
- Added cobweb block slowness immunity for spider Pokémon
|
||||
- Added 49 new habitat structures. 34 as typical Minecraft structures and 15 as structures that get placed as biome features to allow for more natural placement in generation. Structures placed as biome features will not be able to be located with the `/locate structure` command.
|
||||
- Vanilla village house template pools have been adjusted to account for the new abandoned village structure habitat. Weights have changed within the JSON file for every piece to ensure too many habitats don't generate in a single village.
|
||||
- Alpha Pokémon are bigger, stronger, and more aggressive than regular Pokémon.
|
||||
- They are also scarier.
|
||||
- They always know a TM move and will adapt to be stronger than your party.
|
||||
- Alphas will always lead herds and spawn in herds.
|
||||
- Added alpha Pokémon attraction bait effect to Hopo Berries.
|
||||
- Added intrinsic scaling to all Pokémon (anywhere from 5% smaller to 5% bigger than normal). Some cases, such as shoulder mounting, will not scale so that the shoulder animations don't look silly.
|
||||
- Added scaling to "baby" Pokémon (10% smaller at level 1 → normally sized at level 10).
|
||||
- Added TMs.
|
||||
- Added TM Machine. TMs are made from elemental type gems, and their recipes are unlocked by having Pokémon that know the move.
|
||||
- Added config options for making TMs infinite-use and instant unlocking of all TM recipes.
|
||||
- Added Type Gem blocks as well as crystal clusters and deepslate core blocks that are used for growing elemental type gems.
|
||||
- Added a new Starter Selection menu that looks way better.
|
||||
- Added a "Move Dex" to the Pokédex to help identify what moves a Pokémon can learn and what Pokémon can get a move.
|
||||
- Added the Habitat Block, a spawner block for servers and adventure maps that controls spawning in an area.
|
||||
- Added 49 new habitat structures. In these habitats you will find rarer Pokémon and sometimes different Pokémon will appear on different days.
|
||||
- Added a toast to notify players of how they can scroll through their party. Did you know you can hold R and scroll instead of using arrow keys? It's true!!!
|
||||
- Added a way to obtain Porygon by inserting an Upgrade or Dubious Disc into a data monitor.
|
||||
- Added Disk Rack for storing disks and being an audio sequencer for Noteblocks. What does that have to do with Pokémon? How about you mind your own business!
|
||||
- Added missing crops to Botany Pots integration.
|
||||
- Added conditional seats for riding. Seats can be gated by Molang such as "is_alpha".
|
||||
- Added 10 new ruin structures.
|
||||
- rooted_arch_ruins & crumbling_arch_ruins have been transferred over to biome features, allowing for better placement in generation.
|
||||
- All ruin structures that did not generate with a gimmighoul/gilded chest before will now generate with one.
|
||||
- All ruin structures gilded chest loot tables have been updated to include a guaranteed TM not learned naturally by any Pokémon through their level-up moveset. Each ruin gets its own specific TM, so you can now go hunting ruins to complete your move dex!
|
||||
- All fossil structures have been transferred over to biome features, allowing for better placement in generation.
|
||||
- The prehistoric_underwater_fissure & prehistoric_submerged_impact fossil structures now use the biome tag `#cobblemon:is_temperate_ocean`.
|
||||
- Gimmighoul towers now generate at ground level rather than sinking one block into the ground.
|
||||
- A new shipwreck cove structure called the "magma_shipwreck_cove" has been added.
|
||||
- Shipwreck coves now generate slightly more frequently.
|
||||
- Added equipment loot tables for shipwreck cove enemies.
|
||||
- Maps from abandoned fishing boats leading to shipwreck coves now will skip explored chunks, allowing the player to find more shipwreck coves easier.
|
||||
- The lush shipwreck cove's phantom mob spawner has been replaced with breezes.
|
||||
- The lush shipwreck cove structure itself has been slightly cleaned up to be less noisy with the blocks it is built out of.
|
||||
- All shipwreck coves' spawners have been adjusted to give compatible mobs enchanted iron or diamond armour and weapons while in its ominous state. The armour given to the mobs will also use the automaton trim. We upped the difficulty because it was too easy now that your Pokémon can fight for you.
|
||||
- One TM of the elemental hyper beams has been added as guaranteed loot to the main treasure chest in every shipwreck cove. (Magma cove gets blast burn, lush cove gets frenzy plant, and submerged cove gets hydro cannon)
|
||||
- Added 7 new advancements
|
||||
- Pressing the inventory key now closes the Pokémon interact wheel GUI
|
||||
- Added a new shipwreck cove structure called the Magma Shipwreck Cove.
|
||||
- Added 7 new advancements.
|
||||
- Pokémon cries now play when clicking Pokémon in the summary screen.
|
||||
- Pressing the Summary key while either the starter selection or summary screen are open now closes those screens
|
||||
- Ice type Pokémon are now immune to Packed Snow
|
||||
- Held item visibility can now be controlled by the held_item_visible command argument.
|
||||
- Held item visibility can now be controlled by the `held_item_visible` command argument.
|
||||
- Added config option to disable Pokémon spawning on a per-world basis.
|
||||
- Added config options to award experience to fainted Pokémon for opponents they helped defeat (`awardExperienceToFaintedPokemon`) and to still award experience for defeated enemies even after battle loss/forfeit (`awardExperienceOnBattleLoss`).
|
||||
- Added `/givetm` command.
|
||||
- Added advancement triggers for learning TMs: `cobblemon:has_learn_specific_tm` (per-TM), `cobblemon:has_learn_all_tm` (all TMs learned), and `cobblemon:tms_learned` (count-based), backed by a new `totalTMLearnedCount` on player advancement data.
|
||||
- Added `cobblemon:catch_alpha_pokemon` advancement trigger and `totalAlphaCaptureCount` stat for captured Alpha Pokémon.
|
||||
|
||||
### New rideable Pokémon
|
||||
- Crobat
|
||||
@@ -170,7 +147,6 @@
|
||||
- ... and Substitute
|
||||
|
||||
#### Model changes to the regional bias resource pack:
|
||||
|
||||
- Added Mime Jr. (Galar Bias)
|
||||
- Added Bergmite (Hisui Bias)
|
||||
- Changed models for every existing regional bias
|
||||
@@ -263,14 +239,27 @@
|
||||
- Tail Whip
|
||||
|
||||
### Changes
|
||||
- Stat increase and decrease particles have been changed, with the addition of alpha boost particles.
|
||||
- Dragonite's mailbag cosmetic can now also be obtained with a chest in the cosmetic slot
|
||||
- Adjusted Croagunk's walkspeed
|
||||
- Adjusted Aerodactyl's walkspeed
|
||||
- Sharp Beak can now be crafted
|
||||
- Metal Alloy can now be crafted
|
||||
- Ability Capsules can now be brewed
|
||||
- Using an Ability Capsule will now return an Empty Bottle
|
||||
- Removed the penalty for block destruction speed when on a hover mount, making them better for digging.
|
||||
- Golden Apples can now be crafted using the Applin Apples.
|
||||
- Prismarine Crystals and Amethyst Shards can now be used to craft Pokedexes.
|
||||
- Updated Pokédex Screens item tag to support tagged variants of Redstone and Glowstone Dust.
|
||||
- Sharp Beak can now be crafted using bones and Flying Gems.
|
||||
- Metal Alloy can now be crafted using iron and Thunder Stones.
|
||||
- Ability Capsules can now be brewed from Medicinal Brew and Dragon Breath.
|
||||
- Using an Ability Capsule will now return an Empty Bottle.
|
||||
- Decreased the default pastured wander radius to 32 blocks.
|
||||
- Added alternate versions of the basic PC Wallpapers based on the original design of Cobblemon's PC, before public release.
|
||||
- Rooted Arch Ruins, Crumbling Arch Ruins, and all fossil structures have been improved so that they generate more naturally in terrain.
|
||||
- Gimmighoul towers now generate at ground-level rather than sinking one block into the ground.
|
||||
- All ruin structures that did not generate with a gimmighoul/gilded chest before will now generate with one.
|
||||
- All ruin structures gilded chest loot tables have been updated to include a guaranteed TM not learned naturally by any Pokémon through their level-up moveset. Each ruin gets its own specific TM, so you can now go hunting ruins to complete your move dex!
|
||||
- The Prehistoric Underwater Fissure and Prehistoric Submerged Impact fossil structures now use the biome tag `#cobblemon:is_temperate_ocean`.
|
||||
- The lush shipwreck cove's phantom mob spawner has been replaced with breezes.
|
||||
- Shipwreck coves now generate slightly more frequently.
|
||||
- Added equipment loot tables for shipwreck cove enemies.
|
||||
- Maps from abandoned fishing boats leading to shipwreck coves now will skip explored chunks, allowing the player to find more shipwreck coves more easily.
|
||||
- All shipwreck coves' spawners have been adjusted to give compatible mobs enchanted iron or diamond armour and weapons while in its ominous state. The armour given to the mobs will also use the automaton trim. We upped the difficulty because it was too easy now that your Pokémon can fight for you.
|
||||
- One TM of the elemental hyper beams has been added as guaranteed loot to the main treasure chest in every shipwreck cove. (Magma Cove gets Blast Burn, Lush Cove gets Frenzy Plant, and Submerged Cove gets Hydro Cannon.)
|
||||
- The following items can now be obtained by brushing the following Pokémon:
|
||||
- Pink Wool - Wigglytuff
|
||||
- White Wool - Swablu, Altaria
|
||||
@@ -279,129 +268,147 @@
|
||||
- The following items can now be obtained by evolving the following Pokémon into any of their evolutions:
|
||||
- Turtle Scute - Squirtle, Wartortle, Turtwig, Grotle, Tirtouga, Chewtle
|
||||
- Shed Shell - Metapod, Kakuna, Ekans, Paras, Venonat, Krabby, Scyther, Kabuto, Dratini, Dragonair, Ledyba, Spinarak, Yanma, Pineco, Dunsparce, GLigar, Pupitar, Treecko, Grovyle, Silcoon, Cascoon, Surskit, Nincada, Trapinch, Vibrava, Corphish, Anorith, Bagon, Shelgon, Kricketot, Burmy, Combee, Skorupi, Swadloon, Whirlipede, Dwebble, Scraggy, Karrablast, Joltik, Larvesta, Spewpa, Clauncher, Helioptile, Charjabug, Crabrawler, Cutiefly, Dewpider, Salandit, Wimpod, Poipole, Sobble, Drizzile, Dottler, Silicobra, Toxel, Sizzlipede, Snom, Tarountula, Nymble, Rellor
|
||||
- Saccharine Leaves now drop Tart, Sweet, or Syrupy Apples, depending on their honey coating stage, instead of vanilla Apples
|
||||
- Fixed the height of the Tumblestone Bud items when held in hand, placed on head, viewed in a GUI, and placed in an Item Frame
|
||||
- Refactored all advancements, removing several deemed unnecessary. Due to this refactor, all previously obtained advancements will be reset besides the root (for picking a starter Pokémon). We are sorry for the inconvience, but it makes the tab cleaner and simplifies future advancements.
|
||||
- Restructured Botany Pots integration folder structure
|
||||
- Decrease the default pastured mon wander radius to 32.
|
||||
- Factor in the weight of Pokémon when calculating pushing forces between hitboxes.
|
||||
- Remade the Starter Selection Screen with new assets
|
||||
- Refactored berry trees to be less impactful on TPS (more performant)
|
||||
- Changed the bait effects of the following items: (Vanilla) Sweet & Glow Berries, Golden & Enchanted Golden Apples (Cobblemon) Custap, Eggant, Hopo & Micle Berries, Sweet Hearts
|
||||
- Wild Pokémon now reliably have at least one offensive move if they can have offensive moves at that level.
|
||||
- Data Monitor can accept Disks (TMs, Music Disks, Upgrade, Dubious Disk, etc.) to change what's being displayed on the screen
|
||||
- Rider positioning is now client-driven (Remove poseOffsets and offset per seat/pose) in favour of sending real-time passenger position.
|
||||
- Cleaned up seat data. Removed all now unused fields from seats in all species files. Also made locator seat names explicit in the species files (however, this doesn't break the legacy format)
|
||||
- Marks can now provide aspects.
|
||||
- Added new shiny and Alpha chance configs
|
||||
- Apricorns now make a new sound when harvested
|
||||
- Lowered the volume of harvesting berries
|
||||
- Added alternate versions of the basic PC Wallpapers based on the original design of Cobblemon's PC, before public release
|
||||
- Saccharine Leaves now drop Tart, Sweet, or Syrupy Apples, depending on their honey coating stage, instead of vanilla Apples.
|
||||
- Fixed the height of the Tumblestone Bud items when held in hand, placed on head, viewed in a GUI, and placed in an Item Frame.
|
||||
- Refactored all advancements, removing several deemed unnecessary. Due to this cleanup, all previously obtained advancements will be reset besides the root (for picking a starter Pokémon). This sucks, and we're sorry. We had to do this eventually so better now than later.
|
||||
- Forces between colliding hitboxes now factors in the weight of Pokémon.
|
||||
- Improved berry tree performance on singleplayer and servers.
|
||||
- Updated stat increase and decrease particle effects with the addition of alpha boost particles.
|
||||
- Improved the performance of pasture blocks on singleplayer and servers.
|
||||
- Changed the bait effects of the following items: (Vanilla) Sweet & Glow Berries, Golden & Enchanted Golden Apples (Cobblemon) Custap, Eggant, Hopo & Micle Berries, Sweet Hearts.
|
||||
- Wild Pokémon now reliably have at least one offensive move if they can have offensive moves at that level. No more free lunches with Pokémon that can't even hurt you.
|
||||
- Data Monitor can accept Disks (TMs, Music Disks, Upgrade, Dubious Disk, etc.) to change what's being displayed on the screen.
|
||||
- The party overlay's experience-gained animation now displays the amount of EXP the Pokémon gained.
|
||||
- Pressing the inventory key now closes the Pokémon interact wheel GUI.
|
||||
- Updated the sound for harvesting Apricorns.
|
||||
- Lowered the volume of harvesting berries.
|
||||
- Improved compatibility with various mods
|
||||
- Farmer's Delight's cutting board can now be used to strip Apricorn and Saccharine's logs, or salvage their planks from various blocks. It can also separate their boats from chests
|
||||
- Farmer's Delight's cutting board can be used to get two white dye from Pep-Up Flowers and two magenta dye from Medicinal Leeks
|
||||
- Farmer's Delight's cutting board can separate Tumblestone Blocks back into Tumblestones
|
||||
- Farmer's Delight's cutting board can salvage Type Gems from their Gem Blocks
|
||||
- Farmer's Delight's Onions, Tomatoes, and Cabbages can be used to cook Open-Faced Sandwiches. Nature's Spirit's Olives also can be used
|
||||
- Farmer's Delight's cutting board can be used on Hearty Grains to obtain rice and straw, similarly to Farmer's Delight's Rice Panicles
|
||||
- Farmer's Delight's Apple Pies and Apple Ciders can now be made using Applin Apples, alongside the Vanilla counterpart
|
||||
- Amendments allows for cooking Leek and Potato Stew in a Cauldron
|
||||
- Any mods that utilise Moonlight's Soft Fluid system can store Leek and Potato Stew, Medicinal Brew, Antidote, Awakening, Burn Heal, Ice Heal, Paralyze Heal, Full Heal, Potion, Super Potion, Hyper Potion, Max Potion, Full Restore, Ability Capsules, Moomoo Milk, and Berry Juice in liquid form (such as Suplementaries' Jar or Goblet, or Cauldrons while using Amendments)
|
||||
- Supplementaries' Hourglass can now use Bright Powder, Quick Powder, Metal Powder, Heal Powder, Silver Powder, and Remedy
|
||||
- Farmer's Delight's cutting board can now be used to strip Apricorn and Saccharine's logs, or salvage their planks from various blocks. It can also separate their boats from chests.
|
||||
- Farmer's Delight's cutting board can be used to get two white dye from Pep-Up Flowers and two magenta dye from Medicinal Leeks.
|
||||
- Farmer's Delight's cutting board can separate Tumblestone Blocks back into Tumblestones.
|
||||
- Farmer's Delight's cutting board can salvage Type Gems from their Gem Blocks.
|
||||
- Farmer's Delight's Onions, Tomatoes, and Cabbages can be used to cook Open-Faced Sandwiches. Nature's Spirit's Olives also can be used.
|
||||
- Farmer's Delight's cutting board can be used on Hearty Grains to obtain rice and straw, similarly to Farmer's Delight's Rice Panicles.
|
||||
- Farmer's Delight's Apple Pies and Apple Ciders can now be made using Applin Apples, alongside the Vanilla counterpart.
|
||||
- Amendments allows for cooking Leek and Potato Stew in a Cauldron.
|
||||
- Any mods that utilise Moonlight's Soft Fluid system can store Leek and Potato Stew, Medicinal Brew, Antidote, Awakening, Burn Heal, Ice Heal, Paralyze Heal, Full Heal, Potion, Super Potion, Hyper Potion, Max Potion, Full Restore, Ability Capsules, Moomoo Milk, and Berry Juice in liquid form (such as Suplementaries' Jar or Goblet, or Cauldrons while using Amendments).
|
||||
- Supplementaries' Hourglass can now use Bright Powder, Quick Powder, Metal Powder, Heal Powder, Silver Powder, and Remedy.
|
||||
- Berry Trees are now compatible with the Planter properly
|
||||
- Saccharine Way Signs (added by Supplementaries automagically) now use a premade texture to prevent odd visual issues
|
||||
- Supplementaries' Jar can now store various Cobblemon cookies, candies, and similar items
|
||||
- Some of Supplementaries' items have been added to the `#cobblemon:held/container_held_items` item tag, including sacks, safes, and lunch baskets
|
||||
- Experience Nuggets can be used in place of Sculk for making the EXP Candies if using Create
|
||||
- Rage Candy Bar has a Create Mixing recipe
|
||||
- All Cobblemon ores can now be crushed in Create's Crushing Wheels
|
||||
- All Gem and Tumblestone Clusters can be crushed for automatic, low return, gems
|
||||
- Hearty Grains can be milled like Farmer's Delight Rice Panicles if both Farmer's Delight and Create are installed
|
||||
- Big Roots and Revival Herbs can be milled to their respective powders
|
||||
- Pep-Up Flowers, Medicinal Leeks, and all 70 berries can be milled in Create's Millstone for additional dye drops
|
||||
- Auspicious Armour and Upgrades can be Haunted using Create's crafting systems
|
||||
- Applin Apples can be used to make Honeyed Apples in Create
|
||||
- Golden Apples can now be crafted using the Applin Apples
|
||||
- Prismarine Crystals and Amethyst Shards can now be used to craft Pokedexes
|
||||
- Updated Pokédex Screens item tag to support tagged variants of Redstone and Glowstone Dust
|
||||
- Sounds for interacting with various Cobblemon blocks now play from the centre of the block, rather than the corner
|
||||
- Saccharine Way Signs (added by Supplementaries automagically) now use a premade texture to prevent odd visual issues.
|
||||
- Supplementaries' Jar can now store various Cobblemon cookies, candies, and similar items.
|
||||
- Some of Supplementaries' items have been added to the `#cobblemon:held/container_held_items` item tag, including sacks, safes, and lunch baskets.
|
||||
- Experience Nuggets can be used in place of Sculk for making the EXP Candies if using Create.
|
||||
- Rage Candy Bar has a Create Mixing recipe.
|
||||
- All Cobblemon ores can now be crushed in Create's Crushing Wheels. All Gem and Tumblestone Clusters can be crushed for automatic, low return, gems.
|
||||
- Hearty Grains can be milled like Farmer's Delight Rice Panicles if both Farmer's Delight and Create are installed.
|
||||
- Big Roots and Revival Herbs can be milled to their respective powders.
|
||||
- Pep-Up Flowers, Medicinal Leeks, and all 70 berries can be milled in Create's Millstone for additional dye drops.
|
||||
- Auspicious Armour and Upgrades can be Haunted using Create's crafting systems.
|
||||
- Applin Apples can be used to make Honeyed Apples in Create.
|
||||
- Sounds for interacting with various Cobblemon blocks now play from the centre of the block, rather than the corner. You probably didn't notice.
|
||||
- Dragonite's mailbag cosmetic can now also be obtained with a chest in the cosmetic slot.
|
||||
- Adjusted the walk speed for Croagunk and Aerodactyl.
|
||||
- The `/pc` command no longer plays PC activation sounds
|
||||
- Pressing the Summary key while either the starter selection or summary screen are open now closes those screens.
|
||||
- Ice type Pokémon are now immune to Packed Snow.
|
||||
- Added cobweb block slowness immunity for spider Pokémon
|
||||
|
||||
### Fixes
|
||||
- Fixed Blitzle's base scale being `1` rather than the intended `0.8`
|
||||
- Fixed Magnezone's emissive layer for the shiny having the wrong name, thus displaying wrongly
|
||||
- Fixed Litleo not blinking
|
||||
- Fixed rare Pokémon being far too likely to spawn multiple times in a single spawn cycle. The dev told me that the exact bug is too complicated to explain.
|
||||
- Fixed Omanyte and Omastar incorrectly using water animations on land.
|
||||
- Fixed Pokédex layout for genderless variations
|
||||
- Fixed odd stacking behaviour with the poke_bait item.
|
||||
- Fixed Pokédex layout for genderless variations.
|
||||
- Fixed odd stacking behaviour with Poké Baits.
|
||||
- Fixed a compatibility issue with World Game Rules which caused some log spam in specific cases.
|
||||
- Fixed improper validation of Pokémon when performing a trade.
|
||||
- Fixed an issue where particle like beam can disappear when you don't see the beginning of the beam, or you look away
|
||||
- Fixed Bedrock particle materials (alpha/opaque/blend/add) sharing one render batch, which caused incorrect culling on mixed batches; each material now batches and draws with its own blend and cull state, and the alpha material renders as a true cutout
|
||||
- Fixed an occasional crash on retrieving revived fossils
|
||||
- Fixed brushing not working on Neoforge
|
||||
- Fixed braking not working for submarines (whoops).
|
||||
- Fixed an issue where particles like beams can disappear when you don't see the beginning of the beam, or you look away.
|
||||
- Fixed Bedrock particle materials sometimes being incorrectly invisible from some sides.
|
||||
- Fixed an occasional crash on retrieving revived fossils.
|
||||
- Fixed brushing not working on Neoforge. Again.
|
||||
- Fixed braking not working for submarine-style mounts (whoops).
|
||||
- Fixed strafing not having the same friction as forward movement (funny whoops).
|
||||
- Fixed submarine's surface-water animations not playing when supposed to.
|
||||
- Fixed submarine camera freaking out when looking up or down on the surface.
|
||||
- Fixed pastured mons despawning and running away.
|
||||
- Fixed Apricorn trees crashing when other mods bonemeal it
|
||||
- Fixed the issue that caused Hover Behaviour rides without a ground style to be rendered useless upon touching the ground on a server.
|
||||
- Removed the "inAir" penalty for block destruction speed when on a hover mount.
|
||||
- Fixed horizontal and vertical collisions with hover mounts so they no longer accumulate or retain momentum
|
||||
- Fixed NeoForge brewing stand unexpectedly crashing users when shift clicking items within its menu
|
||||
- Fixed NPCs switching Pokémon very often during battles
|
||||
- Fixed Campfire pot causing crashes under certain circumstances
|
||||
- Fixed Type Gems not being consumed upon use
|
||||
- Fixed Ancient Pokéball's to their respective modifiers
|
||||
- Fixed a Server warning when recalling Pokémon
|
||||
- Fixed sliding particles incorrectly handling block collision
|
||||
- Fixed Full Heal not curing status conditions in battle
|
||||
- Fixed submarine-style mounts' surface-water animations not playing when supposed to.
|
||||
- Fixed submarine-style mounts' camera freaking out when looking up or down on the surface.
|
||||
- Fixed pastured Pokémon despawning and running away.
|
||||
- Fixed Apricorn trees crashing when other mods bonemeal them.
|
||||
- Fixed the issue that caused hover-style mounts without a ground style to be rendered useless upon touching the ground on a server.
|
||||
- Fixed horizontal and vertical collisions with hover-style mounts so they no longer accumulate or retain momentum.
|
||||
- Fixed NeoForge brewing stand unexpectedly crashing users when shift clicking items within its menu. Well, I suppose all crashes are unexpected. You know what I mean.
|
||||
- Fixed NPCs switching Pokémon very often during battles.
|
||||
- Fixed Campfire Pot causing crashes under certain circumstances.
|
||||
- Fixed Type Gems not being consumed upon use in battles.
|
||||
- Fixed several Ancient Pokéball's not using the correct capture multiplier.
|
||||
- Fixed a server warning that could occur when recalling Pokémon.
|
||||
- Fixed sliding particles incorrectly handling block collision.
|
||||
- Fixed Full Heal not curing status conditions in battle. Literally it's one job.
|
||||
- Fixed a rare issue with battles locking up when you are forced to switch, with the switch menu appearing instantly.
|
||||
- Fixed the combined effects of Pledge moves having broken Showdown message handling and localisation
|
||||
- Fixed rare Pokémon being far too likely to spawn multiple times in a single spawn cycle. The dev told me that the exact bug is too complicated to explain.
|
||||
- Resolved the niche issue where Structures would spawn in an incorrect location, creating very funky world gen.
|
||||
- Fixed the combined effects of Pledge moves having broken Showdown message handling and localisation.
|
||||
- Fixed a very niche issue where structures would spawn in an incorrect location, creating very funky world gen.
|
||||
- Fixed Galarian Ponyta missing its cry.
|
||||
- Fixed various log warnings caused by redundant files and sound events.
|
||||
- Traded Pokémon will now retain the original friendship level when traded back to its OT
|
||||
- Clusters now display correctly on maps
|
||||
- Fixed removing mulch from berry trees with a shovel not working.
|
||||
- Fixed collecting honey from Saccharine Leaf blocks deleting Honey Bottles when the inventory was full
|
||||
- Fixed Stripped Saccharine Wood recipe being missing
|
||||
- Fixed CancelableSoundInstance causing lag by attempting to create sounds every tick when out of range of hearing
|
||||
- Fixed Stat Reducing Aprijuice not being possible to apply on a max out Pokémon, and the possibility of going into negatives
|
||||
- Fixed Exploit where you could take out the bait or drop your Pokérod with bait to avoid consuming bait, now the bobber will just disappear if you do so
|
||||
- Fixed Apricorn and Saccharine boats incorrectly using chest boat models
|
||||
- Fixed wild and trainer battle AI refusing to select moves with the `adjacentAlly` target type, even when it's their only option
|
||||
- Fixed gilded chests being more accessible than intended
|
||||
- Fixed fished up Pokémon not being added as "seen" to the Pokedex
|
||||
- Fixed surprised Gimmighoul encounters not being added as "seen" to the Pokedex
|
||||
- Traded Pokémon will now retain the original friendship level when traded back to its OT.
|
||||
- Tumblestone Clusters now display correctly on maps.
|
||||
- Fixed removing mulch from berry trees with a shovel not working. That was meant to be a thing.
|
||||
- Fixed collecting honey from Saccharine Leaf blocks deleting Honey Bottles when the inventory was full.
|
||||
- Fixed Stripped Saccharine Wood recipe being... not there.
|
||||
- Fixed some performance issues with a kind of sound event causing lag by attempting to create sounds every tick when out of range of hearing.
|
||||
- Fixed stat-reducing Aprijuice not being possible to apply on a maxed out Pokémon. Also fixed the possibility of going into negatives.
|
||||
- Fixed exploit where you could take out the bait or drop your Pokérod with bait to avoid consuming bait, now the bobber will just disappear if you do so.
|
||||
- Fixed Apricorn and Saccharine boats incorrectly using chest boat models.
|
||||
- Fixed wild and trainer battle AI refusing to select moves with the `adjacentAlly` target type, even when it's their only option.
|
||||
- Fixed gilded chests being more accessible than intended.
|
||||
- Fixed fished up Pokémon not being added as "seen" to the Pokédex.
|
||||
- Fixed surprised Gimmighoul encounters not being added as "seen" to the Pokédex.
|
||||
- Fixed a crash involving berry trees that have been world edited.
|
||||
- Fixed visual desync in multiplayer for players mounting Pokémon outside other players' loaded chunks
|
||||
- Fixed visual desync in multiplayer for players mounting Pokémon outside other players' loaded chunks.
|
||||
- Fixed Pokémon entities leveled by rare candy not getting stronger as Minecraft entities unless recalled.
|
||||
- Fixed a freeze during game load that occurred when multiple mods tried to load Cobblemon API classes at the same time.
|
||||
- Fixed random tick crashes from berry trees
|
||||
- Lowered the volume of Blitzle and Zebstrika's cry
|
||||
- Regional Foods will now prioritise being eaten instead of used for healing Pokémon, shift clicking will use it as healing
|
||||
- Resolved Z-Fighting on Pokédex Models
|
||||
- Restored Ninjask's ability to do barrel rolls
|
||||
- Lowered the volume of Blitzle and Zebstrika's cry (shut up!).
|
||||
- Regional Foods will now prioritise being eaten instead of used for healing Pokémon - shift clicking will use it as healing.
|
||||
- Resolved z-fighting (texture flickering) on Pokédex Models.
|
||||
- Restored Ninjask's ability to do barrel rolls.
|
||||
- Fixed Raichu (male) and Alolan Raichu (both genders) not displaying the correct Partner Cap when Pewter Crunchies are in the cosmetic slot.
|
||||
- Fixed a crash caused by adding enchanted items to the Resurrection Machine
|
||||
- Fixed a crash caused by adding enchanted items to the Resurrection Machine.
|
||||
- Fixed a crash that could occur when starting a PvN battle with only fainted Pokémon.
|
||||
- Fixed the Remember Riding Camera config not being respected when dismounting and resolved the incompatibility with the Auto Third Person mod
|
||||
- Fixed Full Heal block not dropping Full Heals
|
||||
- Fixed status cure items not returning an empty bottle when used
|
||||
- Fixed Panpour consuming its held item when evolving with a Water Stone
|
||||
- Fixed Smoked Tail Curry returning a Wooden Bowl when consumed despite it not being included in the recipe
|
||||
- Fixed `/giveallpokemon` not respecting the min and max parameters
|
||||
- Fixed the choose starter toast not disappearing when capturing a Pokémon instead of opening the starter selection screen
|
||||
- Fixed an issue where certain Sinister Tea seasonings were only applying as instant effects and would not apply over time
|
||||
- Long config option labels now scroll instead of overflowing
|
||||
- Fixed the Remember Riding Camera config not being respected when dismounting and resolved the incompatibility with the Auto Third Person mod.
|
||||
- Fixed Full Heal block not dropping Full Heals. Lmao.
|
||||
- Fixed status cure items not returning an empty bottle when used.
|
||||
- Fixed Panpour consuming its held item when evolving with a Water Stone.
|
||||
- Fixed Smoked Tail Curry returning a Wooden Bowl when consumed despite it not being included in the recipe. Free bowls!
|
||||
- Fixed `/giveallpokemon` not respecting the min and max arguments.
|
||||
- Fixed the choose starter toast not disappearing when capturing a Pokémon instead of opening the starter selection screen.
|
||||
- Fixed an issue where certain Sinister Tea seasonings were only applying as instant effects and would not apply over time.
|
||||
- Long config option labels now scroll instead of overflowing in the configuration menu.
|
||||
- Fixed some z-fighting and clipping on Dewott and Hisui-Bias Dewott.
|
||||
- Eggant Berries can now be composted properly on NeoForge.
|
||||
- Composting chances are now the same on NeoForge as on Fabric.
|
||||
- Fixed problem where furnaces which had smelted Revival Herbs into Heal Powder in older versions would glitch out on trying to get the experience out of the block.
|
||||
- Fixed the Battle AI not recognizing Surging Strikes as a multistrike move.
|
||||
- Fixed Tentacool not using its swim animation when on water surface.
|
||||
- Fixed Eevee using its left shoulder pose when in battle.
|
||||
- Fixed Magikarp and Gyarados Jump Pattern resourcepacks replacing shiny textures of addons targeting Magikarp or Gyarados.
|
||||
- Fixed Combee's pollinated texture overwriting the shiny and female textures.
|
||||
- Fixed a colour mistake with Dracovish's shiny.
|
||||
- Fixed Togedemaru's back spikes z-fighting.
|
||||
- Fixed Sliggoo (+ Hisuian) evolving in the Nether and End where it can't actually rain.
|
||||
- Corrected the scales, hitbox sizes, and eye heights for Ariados, Cetoddle, Durant, Galvantula, Klink, Lanturn, Lumineon, Mantine, Mantyke, Mudbray, Numel, Staravia, and Torkoal.
|
||||
- Fixed Torkoal's walk speed not matching its animation. He will no longer move faster than Bunnelby and Buneary. This tortoise would've won.
|
||||
- Fixed Lanturn T-posing due to missing ground walk and sleep animations.
|
||||
- Fixed Oshawott and Dewott using their sleep animation in unintended scenarios.
|
||||
- Fixed Dudunsparce and Maushold always having the same form instead of having the 1 in 100 chance of being different.
|
||||
- Fixed bird mounts rapidly switching between their flying and gliding animations when flying at low speed.
|
||||
- Fixed some battles being startable with fainted Pokémon in the initial sendout.
|
||||
- Fixed random gender selection for forms with strict gender divides (such as Meowstic and Oinkologne) never choosing female (that's sexist).
|
||||
- Fixed the "Press R to battle" prompt not disappearing after you finish your first battle, at least until you relogged.
|
||||
- Fixed the composter block being listed as "composer" in the cosmetic items species feature
|
||||
- Fixed Castform's forms being tagged as introduced in generation 4 instead of 3.
|
||||
- Fixed Blitzle's base scale being `1` rather than the intended `0.8`.
|
||||
- Fixed Magnezone's emissive layer for the shiny having the wrong name, thus displaying wrongly.
|
||||
- Fixed Litleo not blinking.
|
||||
|
||||
### Developer
|
||||
- Added `PokeSnackSpawnerFactory` which allows influence registration on PokeSnack encounters
|
||||
- Added `FishingSpawnerFactory` which allows influence registration on fishing encounters
|
||||
- Added `BattleFleeAttemptEvent` fired from `PokemonBattle.checkFleeAttempt`, allowing developers to intercept and control flee attempts
|
||||
- Added `PokeSnackSpawnerFactory` which allows influence registration on PokeSnack encounters.
|
||||
- Added `FishingSpawnerFactory` which allows influence registration on fishing encounters.
|
||||
- Added `BattleFleeAttemptEvent` fired from `PokemonBattle.checkFleeAttempt`, allowing developers to intercept and control flee attempts.
|
||||
- Tweaked the spawning selector interface to take a bucket function rather than a bucket directly.
|
||||
- Added a new `cobblemon:height_range` processor type to allow developers to restrict structure-spawning ranges.
|
||||
- Separated all the functions of MoLangFunctions.kt into their own files.
|
||||
@@ -409,33 +416,36 @@
|
||||
- Removed "SpawnBucket" class in favour of just storing maps of bucket names to weights.
|
||||
- Fixed nicknames not being applied to Pokémon spawned from `spawn_pool_world` files.
|
||||
- Added support for `profilePokedexScale`, `profilePokedexTranslation`, `profileSummaryScale`, and `profileSummaryTranslation` in poser files for finer control over profile displays.
|
||||
- Fixed riding camera offsets defined on Pokémon forms not being applied
|
||||
- Fixed riding camera offsets defined on Pokémon forms not being applied.
|
||||
- Marks can now provide aspects.
|
||||
|
||||
### Molang & Datapacks
|
||||
- Added `moveset_builders` datapack folder for different styles of movesets.
|
||||
- Added `party_pools` datapack folder for defining groups of Pokémon for complex NPC party definitions.
|
||||
- Added `party_compositions` datapack folder for arranging parties on NPCs that rely on party pools.
|
||||
- Added `composed_pool` NPC party provider type which combines a party pool with a party composition to create more complex NPC parties.
|
||||
- Added basic chatter NPC Behaviour
|
||||
- Added `q.item.is_enchanted()`
|
||||
- Added `q.item.has_enchantment(minecraft:sharpness, 3)`
|
||||
- Added `has_chosen_starter` & `get_starter_uuid` as available Molang functions
|
||||
- Added `has_tm_move_unlocked`, `unlock_tm_move`, & `lock_tm_move` as available Molang functions for Players
|
||||
- Added `marks`, `has_mark`, & `remove_marks` as available Molang functions for Pokémon
|
||||
- Added basic chatter NPC Behaviour.
|
||||
- Added `q.item.is_enchanted()`.
|
||||
- Added `q.item.has_enchantment(minecraft:sharpness, 3)`.
|
||||
- Added `has_chosen_starter` and `get_starter_uuid` as available Molang functions.
|
||||
- Added `has_tm_move_unlocked`, `unlock_tm_move`, and `lock_tm_move` as available Molang functions for Players.
|
||||
- Added `marks`, `has_mark`, and `remove_marks` as available Molang functions for Pokémon.
|
||||
- Added Data Component support for species drops, eg `"components": {"minecraft:custom_model_data": 123}`
|
||||
- Added the new `sortOrder` field to mark entries, (defaults to 0 if not specified) which controls the order in which marks are rendered on the HUD, with higher numbers being rendered on top of lower numbers
|
||||
- Added optional `order` field to starter categories. It will allow explicitly sorting categories in the starter selection screen
|
||||
- SpeciesAdditions append vs override now matches wiki documentation
|
||||
- Added `weighted_choice` as a new feature type. It requires setting weights for each choice and allows developers to simplify the process of assigning random aspect choice based on marble chance
|
||||
- Added `q.world.spawn_loot_table_items(loot_table_id, x, y, z)` which spawns the items from the loot table at the position. (Use type: "minecraft:chest" for the loot table.)
|
||||
- Added the new `sortOrder` field to mark entries, (defaults to 0 if not specified) which controls the order in which marks are rendered on the HUD, with higher numbers being rendered on top of lower numbers.
|
||||
- Added optional `order` field to starter categories. It will allow explicitly sorting categories in the starter selection screen.
|
||||
- SpeciesAdditions append vs override now matches the wiki documentation.
|
||||
- Added `weighted_choice` as a new feature type. It requires setting weights for each choice and allows developers to simplify the process of assigning random aspect choice based on marble chance.
|
||||
- Added `q.world.spawn_loot_table_items(loot_table_id, x, y, z)` which spawns the items from the loot table at the position. Use type: `minecraft:chest` for the loot table.
|
||||
- Added `q.pokemon.entity` to access the entity of Pokémon.
|
||||
- Flamethrower and Seismic Toss had their action effect JSON cleaned up
|
||||
- Ride sounds can now be set as exclusive to passengers
|
||||
- Ride sounds no longer play when submerged unless specified with a new setting
|
||||
- Flamethrower and Seismic Toss had their action effect JSON cleaned up.
|
||||
- Ride sounds can now be set as exclusive to passengers.
|
||||
- Ride sounds no longer play when submerged unless specified with a new setting.
|
||||
- NPC Trainers can now call a `command` animation when issuing a command in battle.
|
||||
- Added a q.failed function to move action effects.
|
||||
- Herd spawned Pokémon have their levels controlled differently. The `levelRange` property now acts as a clamp instead of a filter, with a new `herdLevelRange` property to do the filter behaviour.
|
||||
- `q.sound` now accepts three parameters (sound event, volume and pitch) instead of just the sound event and pitch.
|
||||
- Herd spawned Pokémon have their levels controlled differently. The `levelRange` property now acts as a pre-offset clamp instead of a filter, with a new `herdLevelRange` property to do the filter behaviour.
|
||||
- `q.sound` now accepts three parameters (sound event, volume, and pitch) instead of just the sound event and pitch.
|
||||
- Added a new layer property that makes a layer scroll in a direction. "scrolling": {"speedU": 0.1, "speedV": 0.1}
|
||||
- Cleaned up seat data. Removed all now unused fields from seats in all species files. Also made locator seat names explicit in the species files (however, this doesn't break the legacy format)
|
||||
|
||||
### Particles
|
||||
|
||||
@@ -502,8 +512,8 @@
|
||||
|
||||
#### Miscellaneous Particles
|
||||
|
||||
+ Added Wild Might particles for Alpha Pokémon
|
||||
+ Updated stat increase and decrease particles
|
||||
- Added Wild Might particles for Alpha Pokémon.
|
||||
- Updated stat increase and decrease particles.
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
@@ -515,4 +525,5 @@
|
||||
- Brazilian Portuguese
|
||||
- Simplified Chinese
|
||||
- Traditional Chinese
|
||||
- Korean
|
||||
- Korean
|
||||
- Russian
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.duck;
|
||||
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Duck that facilitates getting a level key for a given level.
|
||||
*
|
||||
* @author dualspiral
|
||||
* @since August 30th, 2026
|
||||
*/
|
||||
public interface MinecraftServerDuck {
|
||||
Optional<ResourceKey<Level>> cobblemon$getLevelKey(Level level);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.duck;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
/**
|
||||
* Duck that facilitates getting a level key that we store on the level.
|
||||
*
|
||||
* @author dualspiral
|
||||
* @since August 30th, 2026
|
||||
*/
|
||||
public interface ServerLevelDuck {
|
||||
ResourceLocation cobblemon$getLevelResourceLocation();
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||
import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
@Mixin(ClientPacketListener.class)
|
||||
public class ClientPacketListenerMixin {
|
||||
|
||||
@Shadow private ClientLevel level;
|
||||
|
||||
@Inject(method = "handleSetEntityPassengersPacket", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/world/entity/Entity;hasIndirectPassenger(Lnet/minecraft/world/entity/Entity;)Z", shift = At.Shift.BEFORE), cancellable = true)
|
||||
private void cobblemon$handlePokemonPassengers(ClientboundSetPassengersPacket packet, CallbackInfo ci) {
|
||||
Entity entity = this.level.getEntity(packet.getVehicle());
|
||||
if (entity instanceof PokemonEntity pokemon) {
|
||||
var passengers = new ArrayList<Entity>();
|
||||
for (int passenger : packet.getPassengers()) {
|
||||
passengers.add(this.level.getEntity(passenger));
|
||||
}
|
||||
pokemon.getOccupiedSeats().values().stream()
|
||||
.filter(x -> !passengers.contains(x))
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(Entity::stopRiding);
|
||||
|
||||
// Mount passengers not yet in the map
|
||||
var currentPassengers = new ArrayList<>(pokemon.getOccupiedSeats().values());
|
||||
passengers.stream()
|
||||
.filter(x -> !currentPassengers.contains(x))
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(x -> x.startRiding(pokemon, true));
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.mixin.accessor.SinglePoolElementAccessor;
|
||||
import com.cobblemon.mod.common.world.structureprocessors.HeightRangeStructureProcessor;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||
import net.minecraft.world.level.levelgen.structure.pools.*;
|
||||
import net.minecraft.world.level.levelgen.structure.pools.alias.PoolAliasLookup;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.LiquidSettings;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessor;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorList;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Mixin(JigsawPlacement.class)
|
||||
public class JigsawPlacementMixin {
|
||||
|
||||
@Inject(
|
||||
method = "addPieces(Lnet/minecraft/world/level/levelgen/structure/Structure$GenerationContext;Lnet/minecraft/core/Holder;Ljava/util/Optional;ILnet/minecraft/core/BlockPos;ZLjava/util/Optional;ILnet/minecraft/world/level/levelgen/structure/pools/alias/PoolAliasLookup;Lnet/minecraft/world/level/levelgen/structure/pools/DimensionPadding;Lnet/minecraft/world/level/levelgen/structure/templatesystem/LiquidSettings;)Ljava/util/Optional;",
|
||||
at = @At("RETURN"),
|
||||
cancellable = true
|
||||
)
|
||||
private static void onAddPieces(
|
||||
Structure.GenerationContext context,
|
||||
Holder<StructureTemplatePool> startPool,
|
||||
Optional<ResourceLocation> startJigsawName,
|
||||
int maxDepth,
|
||||
BlockPos pos,
|
||||
boolean useExpansionHack,
|
||||
Optional<Heightmap.Types> projectStartToHeightmap,
|
||||
int maxDistanceFromCenter,
|
||||
PoolAliasLookup aliasLookup,
|
||||
DimensionPadding dimensionPadding,
|
||||
LiquidSettings liquidSettings,
|
||||
CallbackInfoReturnable<Optional<Structure.GenerationStub>> cir
|
||||
) {
|
||||
Optional<Structure.GenerationStub> result = cir.getReturnValue();
|
||||
if (result.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
BlockPos spawnPos = result.get().position();
|
||||
boolean canPlace = cobblemon$canAnyStartElementPlace(context, startPool, spawnPos);
|
||||
|
||||
if (canPlace) {
|
||||
return;
|
||||
}
|
||||
|
||||
cir.setReturnValue(Optional.empty());
|
||||
}
|
||||
|
||||
@Unique
|
||||
private static boolean cobblemon$canAnyStartElementPlace(
|
||||
Structure.GenerationContext generationContext,
|
||||
Holder<StructureTemplatePool> startPool,
|
||||
BlockPos startPos
|
||||
) {
|
||||
for (StructurePoolElement element : startPool.value().templates) {
|
||||
Optional<HeightRangeStructureProcessor> heightRangeProcessor = cobblemon$getHeightRangeProcessor(element);
|
||||
|
||||
if (heightRangeProcessor.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
HeightRangeStructureProcessor processor = heightRangeProcessor.get();
|
||||
boolean valid = processor.isValidPlacement(
|
||||
generationContext.chunkGenerator(),
|
||||
generationContext.heightAccessor(),
|
||||
generationContext.randomState(),
|
||||
startPos
|
||||
);
|
||||
|
||||
if (valid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Unique
|
||||
private static Optional<HeightRangeStructureProcessor> cobblemon$getHeightRangeProcessor(StructurePoolElement element) {
|
||||
if (!(element instanceof SinglePoolElement)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
StructureProcessorList processorList = ((SinglePoolElementAccessor) element).getProcessors().value();
|
||||
for (StructureProcessor processor : processorList.list()) {
|
||||
if (processor instanceof HeightRangeStructureProcessor heightRangeStructureProcessor) {
|
||||
return Optional.of(heightRangeStructureProcessor);
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.duck.MinecraftServerDuck;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@Mixin(MinecraftServer.class)
|
||||
public class MinecraftServerMixin implements MinecraftServerDuck {
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private Map<ResourceKey<Level>, ServerLevel> levels;
|
||||
|
||||
@Override
|
||||
public Optional<ResourceKey<Level>> cobblemon$getLevelKey(final Level level) {
|
||||
return this.levels.entrySet()
|
||||
.stream()
|
||||
// Reference equality is intended here, the level we're handed is the same one as in the
|
||||
// map so we don't need to check value semantics.
|
||||
.filter(entry -> entry.getValue() == level)
|
||||
.map(Map.Entry::getKey)
|
||||
.findFirst();
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@@ -114,15 +115,13 @@ public abstract class ServerEntityMixin {
|
||||
if (currentPassengers.equals(cobblemon$lastSeatPassengers)) return;
|
||||
cobblemon$lastSeatPassengers = List.copyOf(currentPassengers);
|
||||
|
||||
var assignments = new LinkedHashMap<String, Integer>();
|
||||
pokemon.getOccupiedSeats().forEach((seat, passenger) -> {
|
||||
if (seat.getLocator() == null) return;
|
||||
if (passenger == null) return;
|
||||
cobblemon$broadcast(new ClientboundSeatAssignmentPacket(
|
||||
passenger.getId(),
|
||||
pokemon.getId(),
|
||||
seat.getLocator()
|
||||
));
|
||||
assignments.put(seat.getLocator(), passenger.getId());
|
||||
});
|
||||
cobblemon$broadcast(new ClientboundSeatAssignmentPacket(pokemon.getId(), assignments));
|
||||
}
|
||||
|
||||
private void cobblemon$broadcast(NetworkPacket<?> packet) {
|
||||
|
||||
@@ -8,22 +8,69 @@
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.duck.MinecraftServerDuck;
|
||||
import com.cobblemon.mod.common.duck.ServerLevelDuck;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.profiling.ProfilerFiller;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
import net.minecraft.world.level.storage.WritableLevelData;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
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.CallbackInfoReturnable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
|
||||
@Mixin(ServerLevel.class)
|
||||
public abstract class ServerLevelMixin {
|
||||
public abstract class ServerLevelMixin extends Level implements ServerLevelDuck {
|
||||
|
||||
// Ignored by Mixin, fulfils Java contract
|
||||
protected ServerLevelMixin(
|
||||
WritableLevelData levelData,
|
||||
ResourceKey<Level> dimension,
|
||||
RegistryAccess registryAccess,
|
||||
Holder<DimensionType> dimensionTypeRegistration,
|
||||
Supplier<ProfilerFiller> profiler,
|
||||
boolean isClientSide,
|
||||
boolean isDebug,
|
||||
long biomeZoomSeed,
|
||||
int maxChainedNeighborUpdates
|
||||
) {
|
||||
super(levelData, dimension, registryAccess, dimensionTypeRegistration, profiler, isClientSide, isDebug, biomeZoomSeed, maxChainedNeighborUpdates);
|
||||
}
|
||||
|
||||
@Shadow
|
||||
public abstract MinecraftServer shadow$getServer();
|
||||
|
||||
/**
|
||||
* Cached to speed up level world key checks every tick.
|
||||
*/
|
||||
private ResourceLocation cobblemon$levelResourceLocation;
|
||||
|
||||
@Override
|
||||
public ResourceLocation cobblemon$getLevelResourceLocation() {
|
||||
if (this.cobblemon$levelResourceLocation == null) {
|
||||
this.cobblemon$levelResourceLocation = ((MinecraftServerDuck) this.shadow$getServer())
|
||||
.cobblemon$getLevelKey(this)
|
||||
.map(ResourceKey::location)
|
||||
.orElse(null);
|
||||
}
|
||||
return this.cobblemon$levelResourceLocation;
|
||||
}
|
||||
|
||||
@Inject(method = "findLightningRod", at = @At(value = "RETURN"), cancellable = true)
|
||||
private void cobblemon$findLightningRod(BlockPos blockPos, CallbackInfoReturnable<Optional<BlockPos>> ci) {
|
||||
|
||||
@@ -15,15 +15,18 @@ 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.duck.ServerLevelDuck;
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity;
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules;
|
||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
@@ -33,9 +36,13 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ServerPlayer.class)
|
||||
public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
|
||||
|
||||
@Shadow
|
||||
public abstract ServerLevel serverLevel();
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
public MinecraftServer server;
|
||||
@Unique
|
||||
public PlayerSpawner cobblemon$spawner;
|
||||
|
||||
@@ -55,12 +62,9 @@ public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
|
||||
|
||||
@Inject(method = "tick", at = @At("TAIL"))
|
||||
private void cobblemon$tickSpawner(CallbackInfo ci) {
|
||||
if (!Cobblemon.config.getEnableSpawning()) {
|
||||
return;
|
||||
} else if (!serverLevel().getGameRules().getBoolean(CobblemonGameRules.DO_POKEMON_SPAWNING)) {
|
||||
return;
|
||||
if (cobblemon$canSpawn()) {
|
||||
getPlayerSpawner().tick();
|
||||
}
|
||||
getPlayerSpawner().tick();
|
||||
}
|
||||
|
||||
@Inject(method = "rideTick", at = @At("HEAD"))
|
||||
@@ -121,4 +125,21 @@ public abstract class ServerPlayerMixin implements PlayerSpawnerAccessor {
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether we should spawn Cobblemon entities here.
|
||||
*
|
||||
* @return true if we can spawn cobblemon in the current level,
|
||||
* false otherwise
|
||||
*/
|
||||
@SuppressWarnings("resource")
|
||||
@Unique
|
||||
private boolean cobblemon$canSpawn() {
|
||||
return Cobblemon.config.getEnableSpawning() &&
|
||||
this.serverLevel().getGameRules().getBoolean(CobblemonGameRules.DO_POKEMON_SPAWNING) &&
|
||||
// intentionally last as this is a more expensive check, even with all the caching
|
||||
!Cobblemon.config.getWorldSpawningBlocklist().contains(
|
||||
((ServerLevelDuck) this.serverLevel()).cobblemon$getLevelResourceLocation()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin;
|
||||
|
||||
import com.cobblemon.mod.common.mixin.accessor.SinglePoolElementAccessor;
|
||||
import com.cobblemon.mod.common.world.structureprocessors.HeightRangeStructureProcessor;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.LevelHeightAccessor;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.biome.BiomeSource;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
import net.minecraft.world.level.levelgen.RandomState;
|
||||
import net.minecraft.world.level.levelgen.structure.PoolElementStructurePiece;
|
||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||
import net.minecraft.world.level.levelgen.structure.StructurePiece;
|
||||
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||
import net.minecraft.world.level.levelgen.structure.pools.SinglePoolElement;
|
||||
import net.minecraft.world.level.levelgen.structure.pools.StructurePoolElement;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessor;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorList;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@Mixin(Structure.class)
|
||||
public abstract class StructureMixin {
|
||||
|
||||
/**
|
||||
* Discards a structure start when any of its pieces carries a {@link HeightRangeStructureProcessor}
|
||||
* whose range the piece does not fit in.
|
||||
* Crab Note: We have to make this has to happen here rather than in the processor itself. Terrain adaptation and {@code /locate}
|
||||
* both read the start, so by the time processors run the terrain has already been generated and the
|
||||
* structure is already on the map which previously were left behdind when we were trying to make some structures not generate via processor. Now
|
||||
* Returning {@link StructureStart#INVALID_START} keeps the start from ever existing, which makes sure that weird generation isn't left behind.
|
||||
*/
|
||||
@Inject(
|
||||
method = "generate",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/levelgen/structure/StructureStart;isValid()Z"),
|
||||
cancellable = true
|
||||
)
|
||||
private void cobblemon$rejectStartsOutsideHeightRange(
|
||||
RegistryAccess registryAccess, ChunkGenerator chunkGenerator, BiomeSource biomeSource,
|
||||
RandomState randomState, StructureTemplateManager structureTemplateManager, long seed,
|
||||
ChunkPos chunkPos, int references, LevelHeightAccessor heightAccessor,
|
||||
Predicate<Holder<Biome>> validBiome,
|
||||
CallbackInfoReturnable<StructureStart> cir,
|
||||
@Local StructureStart structureStart
|
||||
) {
|
||||
for (StructurePiece piece : structureStart.getPieces()) {
|
||||
if (!(piece instanceof PoolElementStructurePiece poolPiece)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Optional<HeightRangeStructureProcessor> heightRangeProcessor = cobblemon$getHeightRangeProcessor(poolPiece.getElement());
|
||||
if (heightRangeProcessor.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean valid = heightRangeProcessor.get().isValidPlacement(
|
||||
chunkGenerator,
|
||||
heightAccessor,
|
||||
randomState,
|
||||
piece.getBoundingBox()
|
||||
);
|
||||
|
||||
if (!valid) {
|
||||
cir.setReturnValue(StructureStart.INVALID_START);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
private static Optional<HeightRangeStructureProcessor> cobblemon$getHeightRangeProcessor(StructurePoolElement element) {
|
||||
if (!(element instanceof SinglePoolElement)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
StructureProcessorList processorList = ((SinglePoolElementAccessor) element).getProcessors().value();
|
||||
for (StructureProcessor processor : processorList.list()) {
|
||||
if (processor instanceof HeightRangeStructureProcessor heightRangeStructureProcessor) {
|
||||
return Optional.of(heightRangeStructureProcessor);
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -20,7 +20,7 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
//This is a yucky hack but better than what we were doing before
|
||||
// There appears to be a data driven way to do this now, however I am not sure how it works since there is no wiki or anything so yolo
|
||||
@Mixin(BlockVariantSets.class)
|
||||
public abstract class AdornRegisterInvoker {
|
||||
@Final
|
||||
|
||||
@@ -133,7 +133,7 @@ open class PokemonBattle(
|
||||
set(value) { field = value.coerceAtMost(Int.MAX_VALUE) } // go outside
|
||||
|
||||
/** The current duration of the battle in seconds. */
|
||||
val time: Int get() = ticks % 20
|
||||
val time: Int get() = ticks / 20
|
||||
|
||||
var dispatchResult = GO
|
||||
val dispatches = ConcurrentLinkedDeque<BattleDispatch>()
|
||||
|
||||
@@ -65,7 +65,7 @@ class HabitatSpawn {
|
||||
/** The maximum light level that the Pokémon can spawn in. */
|
||||
var maxLight: Int? = null
|
||||
|
||||
open fun writeToNBT(nbt: CompoundTag) {
|
||||
fun writeToNBT(nbt: CompoundTag) {
|
||||
nbt.putString(DataKeys.HABITAT_POOL_SPAWN_SPECIES, species.resourceIdentifier.toString())
|
||||
nbt.putString(DataKeys.HABITAT_POOL_SPAWN_POSITION_TYPE, spawnablePositionType)
|
||||
nbt.putFloat(DataKeys.HABITAT_POOL_SPAWN_WEIGHT, weight)
|
||||
@@ -78,7 +78,7 @@ class HabitatSpawn {
|
||||
nbt.putString(DataKeys.HABITAT_POOL_SPAWN_BUCKET, bucket)
|
||||
}
|
||||
|
||||
open fun readFromNBT(nbt: CompoundTag) {
|
||||
fun readFromNBT(nbt: CompoundTag) {
|
||||
species = PokemonSpecies.getByIdentifier(nbt.getString(DataKeys.HABITAT_POOL_SPAWN_SPECIES).asIdentifierDefaultingNamespace())!!
|
||||
spawnablePositionType = nbt.getString(DataKeys.HABITAT_POOL_SPAWN_POSITION_TYPE)
|
||||
weight = nbt.getFloat(DataKeys.HABITAT_POOL_SPAWN_WEIGHT)
|
||||
@@ -91,7 +91,7 @@ class HabitatSpawn {
|
||||
bucket = if (nbt.contains(DataKeys.HABITAT_POOL_SPAWN_BUCKET)) nbt.getString(DataKeys.HABITAT_POOL_SPAWN_BUCKET) else "common"
|
||||
}
|
||||
|
||||
open fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeResourceLocation(species.resourceIdentifier)
|
||||
buffer.writeUtf(spawnablePositionType)
|
||||
buffer.writeFloat(weight)
|
||||
@@ -104,7 +104,7 @@ class HabitatSpawn {
|
||||
buffer.writeUtf(bucket)
|
||||
}
|
||||
|
||||
open fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
species = PokemonSpecies.getByIdentifier(buffer.readResourceLocation())!!
|
||||
spawnablePositionType = buffer.readUtf()
|
||||
weight = buffer.readFloat()
|
||||
@@ -118,7 +118,7 @@ class HabitatSpawn {
|
||||
}
|
||||
|
||||
/** Creates the [PokemonSpawnDetail] that will be used in the spawner. This is done per habitat block. */
|
||||
open fun createSpawnDetail(habitatBlockEntity: HabitatBlockEntity): PokemonSpawnDetail? {
|
||||
fun createSpawnDetail(habitatBlockEntity: HabitatBlockEntity): PokemonSpawnDetail? {
|
||||
val spawnDetail = PokemonSpawnDetail()
|
||||
|
||||
// If the habitat block specifies a level range, it restricts how and if this spawn exists
|
||||
|
||||
@@ -109,8 +109,10 @@ open class Learnset {
|
||||
evolutionMoves
|
||||
}
|
||||
|
||||
// We only sync level up moves atm
|
||||
// Syncs level up, TM, and egg moves.
|
||||
fun shouldSynchronize(other: Learnset) = other.levelUpMoves != this.levelUpMoves
|
||||
|| other.tmMoves != this.tmMoves
|
||||
|| other.eggMoves != this.eggMoves
|
||||
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) {
|
||||
this.levelUpMoves.clear()
|
||||
@@ -122,6 +124,8 @@ open class Learnset {
|
||||
}
|
||||
levelUpMoves[level] = moves
|
||||
}
|
||||
decodeMoveList(buffer, this.tmMoves)
|
||||
decodeMoveList(buffer, this.eggMoves)
|
||||
}
|
||||
|
||||
fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
@@ -133,5 +137,21 @@ open class Learnset {
|
||||
buffer.writeInt(move.num)
|
||||
}
|
||||
}
|
||||
encodeMoveList(buffer, this.tmMoves)
|
||||
encodeMoveList(buffer, this.eggMoves)
|
||||
}
|
||||
|
||||
private fun decodeMoveList(buffer: RegistryFriendlyByteBuf, list: MutableList<MoveTemplate>) {
|
||||
list.clear()
|
||||
repeat(times = buffer.readSizedInt(IntSize.U_SHORT)) {
|
||||
Moves.getByNumericalId(buffer.readInt())?.let(list::add)
|
||||
}
|
||||
}
|
||||
|
||||
private fun encodeMoveList(buffer: RegistryFriendlyByteBuf, list: List<MoveTemplate>) {
|
||||
buffer.writeSizedInt(IntSize.U_SHORT, list.size)
|
||||
for (move in list) {
|
||||
buffer.writeInt(move.num)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+24
-20
@@ -40,6 +40,10 @@ import kotlin.math.*
|
||||
class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
companion object {
|
||||
val KEY = cobblemonResource("air/bird")
|
||||
|
||||
private const val FLY_POSE_SPEED = 0.1
|
||||
private const val GLIDE_ENTRY_SPEED = 0.19
|
||||
private const val GLIDE_EXIT_SPEED = 0.13
|
||||
}
|
||||
|
||||
override val key: ResourceLocation = KEY
|
||||
@@ -49,7 +53,7 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
}
|
||||
|
||||
val poseProvider = PoseProvider<BirdSettings, BirdState>(PoseType.HOVER)
|
||||
.with(PoseOption(PoseType.FLY) { _, state, _ -> state.rideVelocity.get().z > 0.2 })
|
||||
.with(PoseOption(PoseType.FLY) { _, state, _ -> state.rideVelocity.get().z > FLY_POSE_SPEED })
|
||||
|
||||
val globalBird: BirdSettings
|
||||
get() = CobblemonRideSettings.bird
|
||||
@@ -192,21 +196,23 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
}
|
||||
|
||||
// speed up and slow down based on input
|
||||
if (driver.zza != 0.0f && state.stamina.get() > 0.0 && newVelocity.length() < glideTopSpeed) {
|
||||
//make sure it can't exceed top speed
|
||||
val forwardInput = when {
|
||||
state.stamina.get() == 0.0f -> 0.0
|
||||
driver.zza > 0 && newVelocity.z > topSpeed -> 0.0
|
||||
driver.zza < 0 && newVelocity.z < (-topSpeed / 3.0) -> 0.0
|
||||
else -> driver.zza.sign
|
||||
}
|
||||
|
||||
newVelocity = Vec3(
|
||||
newVelocity.x,
|
||||
newVelocity.y,
|
||||
(newVelocity.z + (accel * forwardInput.toDouble())))
|
||||
|
||||
if (driver.zza != 0.0f && state.stamina.get() > 0.0) {
|
||||
activeInput = true
|
||||
|
||||
if (newVelocity.length() < glideTopSpeed) {
|
||||
//make sure it can't exceed top speed
|
||||
val forwardInput = when {
|
||||
state.stamina.get() == 0.0f -> 0.0
|
||||
driver.zza > 0 && newVelocity.z > topSpeed -> 0.0
|
||||
driver.zza < 0 && newVelocity.z < (-topSpeed / 3.0) -> 0.0
|
||||
else -> driver.zza.sign
|
||||
}
|
||||
|
||||
newVelocity = Vec3(
|
||||
newVelocity.x,
|
||||
newVelocity.y,
|
||||
(newVelocity.z + (accel * forwardInput.toDouble())))
|
||||
}
|
||||
}
|
||||
|
||||
val controller = (vehicle as? OrientationControllable)?.orientationController
|
||||
@@ -264,11 +270,9 @@ class BirdBehaviour : RidingBehaviour<BirdSettings, BirdState> {
|
||||
|
||||
//Check if the ride should be gliding
|
||||
if (driver.isLocalPlayer) {
|
||||
if ((activeInput && state.stamina.get() > 0.0) || state.rideVelocity.get().z < 0.2) {
|
||||
state.gliding.set(false)
|
||||
} else {
|
||||
state.gliding.set(true)
|
||||
}
|
||||
val powered = activeInput && state.stamina.get() > 0.0
|
||||
val requiredSpeed = if (state.gliding.get()) GLIDE_EXIT_SPEED else GLIDE_ENTRY_SPEED
|
||||
state.gliding.set(!powered && newVelocity.z >= requiredSpeed)
|
||||
}
|
||||
|
||||
//air resistance
|
||||
|
||||
+1
-1
@@ -193,7 +193,7 @@ class HorseBehaviour : RidingBehaviour<HorseSettings, HorseState> {
|
||||
val newStam = if (state.sprinting.get()) {
|
||||
max(0.0f,stam - stamDrainRate)
|
||||
} else {
|
||||
min(1.0f,stam + stamDrainRate * 4)
|
||||
min(1.0f,stam + stamDrainRate * 8) // Need to change this to probably be in seconds eventually? idk something that isn't this magic number.
|
||||
}
|
||||
|
||||
state.stamina.set(newStam.coerceIn(0F, 1F))
|
||||
|
||||
+1
-1
@@ -147,7 +147,7 @@ class DolphinBehaviour : RidingBehaviour<DolphinSettings, DolphinState> {
|
||||
val stamDrainRate = (1.0f / boostTime).toFloat()
|
||||
|
||||
val newStam = if (state.boosting.get()) max(0.0f,stam - stamDrainRate)
|
||||
else (stam + stamDrainRate).coerceIn(0F, 1F)
|
||||
else (stam + stamDrainRate * 2).coerceIn(0F, 1F)
|
||||
|
||||
state.stamina.set(newStam)
|
||||
}
|
||||
|
||||
+5
-1
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition
|
||||
import com.cobblemon.mod.common.api.spawning.MoonPhaseRange
|
||||
import com.cobblemon.mod.common.api.spawning.TimeRange
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
import com.cobblemon.mod.common.block.entity.PokeSnackBlockEntity
|
||||
import com.cobblemon.mod.common.util.Merger
|
||||
import com.cobblemon.mod.common.util.math.orMax
|
||||
import com.cobblemon.mod.common.util.math.orMin
|
||||
@@ -59,6 +60,7 @@ abstract class SpawningCondition<T : SpawnablePosition> {
|
||||
var structures: MutableList<Either<ResourceLocation, TagKey<Structure>>>? = null
|
||||
var isSlimeChunk: Boolean? = null
|
||||
var markers: MutableList<String>? = null
|
||||
var isPokeSnack: Boolean? = null
|
||||
|
||||
@Transient
|
||||
var appendages = mutableListOf<AppendageCondition>()
|
||||
@@ -75,7 +77,9 @@ abstract class SpawningCondition<T : SpawnablePosition> {
|
||||
}
|
||||
|
||||
protected open fun fits(spawnablePosition: T): Boolean {
|
||||
if (spawnablePosition.position.x < minX.orMin() || spawnablePosition.position.x > maxX.orMax()) {
|
||||
if (isPokeSnack != null && (spawnablePosition.spawner is PokeSnackBlockEntity.Spawner != isPokeSnack!!)) {
|
||||
return false
|
||||
} else if (spawnablePosition.position.x < minX.orMin() || spawnablePosition.position.x > maxX.orMax()) {
|
||||
return false
|
||||
} else if (spawnablePosition.position.y < minY.orMin() || spawnablePosition.position.y > maxY.orMax()) {
|
||||
return false
|
||||
|
||||
+1
@@ -32,6 +32,7 @@ import com.cobblemon.mod.common.api.spawning.selection.SpawnSelectionData
|
||||
class EmptySpawnDetail : SpawnDetail() {
|
||||
companion object {
|
||||
val TYPE = "empty"
|
||||
val EMPTY = EmptySpawnDetail()
|
||||
}
|
||||
|
||||
override val type: String = TYPE
|
||||
|
||||
+42
-24
@@ -11,14 +11,19 @@ package com.cobblemon.mod.common.api.spawning.detail
|
||||
import com.cobblemon.mod.common.Cobblemon.LOGGER
|
||||
import com.cobblemon.mod.common.api.drop.DropTable
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.api.spawning.position.AreaSpawnablePosition
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
import com.cobblemon.mod.common.api.spawning.selection.SpawnSelectionData
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import com.cobblemon.mod.common.util.weightedSelection
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.util.Mth.clamp
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import kotlin.math.ceil
|
||||
|
||||
/**
|
||||
* A spawn detail that spawns a herd of Pokémon. This relies on the same [PokemonSpawnAction]s as
|
||||
@@ -36,7 +41,6 @@ import net.minecraft.world.item.Items
|
||||
class PokemonHerdSpawnDetail : SpawnDetail() {
|
||||
companion object {
|
||||
val TYPE = "pokemon-herd"
|
||||
const val HERD_LEADER = "leader"
|
||||
}
|
||||
|
||||
override val type: String = TYPE
|
||||
@@ -50,14 +54,14 @@ class PokemonHerdSpawnDetail : SpawnDetail() {
|
||||
get() = "${id}__LEVEL"
|
||||
|
||||
class Herdable {
|
||||
var pokemon: PokemonProperties = PokemonProperties()
|
||||
var pokemon = PokemonProperties()
|
||||
val levelRange: IntRange? = null
|
||||
var levelRangeOffset: IntRange? = null
|
||||
val herdLevelRange: IntRange? = null
|
||||
var dropTable: DropTable? = null
|
||||
var isLeader: Boolean = false
|
||||
var isFollower: Boolean = true
|
||||
var weight: Float = 1F
|
||||
var isLeader = false
|
||||
var isFollower = true
|
||||
var weight = 1F
|
||||
var maxTimes = 10
|
||||
var heldItem: ResourceLocation? = null
|
||||
}
|
||||
@@ -69,22 +73,23 @@ class PokemonHerdSpawnDetail : SpawnDetail() {
|
||||
selectionData: SpawnSelectionData
|
||||
) {
|
||||
selectionData.removeSpawnDetails { it != this }
|
||||
selectionData.guaranteedBucket = bucket
|
||||
selectionData.removeSpawnablePositions { _, pos -> pos.distanceTo(spawnablePosition) < minDistanceBetweenSpawns }
|
||||
|
||||
val herdSpawnCount = selectionData.spawnActions.count { it.detail == this } + 1
|
||||
val lacksPossibleLeader = lacksPossibleLeader(selectionData)
|
||||
|
||||
if (herdSpawnCount >= maxHerdSize || getValidHerdMembers(selectionData).isEmpty()) {
|
||||
if (herdSpawnCount >= maxHerdSize || getValidHerdMembersForRole(selectionData, useLeaderRole = lacksPossibleLeader).isEmpty()) {
|
||||
// We can't spawn any more in the herd so remove this spawn from the selection pool.
|
||||
selectionData.removeSpawnDetails { it == this }
|
||||
}
|
||||
}
|
||||
|
||||
fun lacksPossibleLeader(selectionData: SpawnSelectionData): Boolean {
|
||||
val level = getOrSetHerdLevel(selectionData)
|
||||
val herdable = getValidHerdMembers(selectionData)
|
||||
val herdCounts = getHerdMemberCounts(selectionData)
|
||||
|
||||
val leaderIsPossible = herdable.any { it.herdLevelRange?.contains(level) != false && it.isLeader }
|
||||
val leaderIsPossible = herdable.any { it.isLeader }
|
||||
val leaderIsSelected = herdCounts.any { it.key?.isLeader == true && it.value > 0 }
|
||||
return leaderIsPossible && !leaderIsSelected
|
||||
}
|
||||
@@ -93,25 +98,42 @@ class PokemonHerdSpawnDetail : SpawnDetail() {
|
||||
return (selectionData.context[herdLevelKey] as? Int) ?: run {
|
||||
val level = levelRange.random()
|
||||
selectionData.context[herdLevelKey] = level
|
||||
return level
|
||||
level
|
||||
}
|
||||
}
|
||||
|
||||
private fun getValidHerdMembersForRole(selectionData: SpawnSelectionData, useLeaderRole: Boolean): List<Herdable> {
|
||||
return getValidHerdMembers(selectionData).filter { (useLeaderRole && it.isLeader) || (!useLeaderRole && it.isFollower) }
|
||||
}
|
||||
|
||||
override fun createSpawnAction(
|
||||
spawnablePosition: SpawnablePosition,
|
||||
bucket: String,
|
||||
selectionData: SpawnSelectionData
|
||||
): PokemonSpawnAction {
|
||||
val validHerdMembers = getValidHerdMembers(selectionData)
|
||||
var searchedForLeader = false
|
||||
val herdable = if (lacksPossibleLeader(selectionData)) {
|
||||
searchedForLeader = true
|
||||
validHerdMembers.filter { it.isLeader }
|
||||
} else {
|
||||
validHerdMembers.filter { it.isFollower }
|
||||
}.weightedSelection { it.weight } ?: herdablePokemon[0]
|
||||
): SpawnAction<*> {
|
||||
val herdable = getValidHerdMembersForRole(
|
||||
selectionData = selectionData,
|
||||
useLeaderRole = lacksPossibleLeader(selectionData)
|
||||
).weightedSelection { it.weight } ?: herdablePokemon[0]
|
||||
|
||||
var level = selectionData.context[herdLevelKey] as? Int ?: 1
|
||||
|
||||
// Attempt to do more detailed anti-wall-spawn logic. Herd members could spawn in walls because
|
||||
// we've just been assuming they're 1 block wide (or at least, all in the herd have the same size).
|
||||
// Some pokemon are not that though.
|
||||
if (spawnablePosition is AreaSpawnablePosition) {
|
||||
val species = herdable.pokemon.species?.let { PokemonSpecies.getByIdentifier(it.asIdentifierDefaultingNamespace()) }
|
||||
if (species != null) {
|
||||
val height = ceil(species.hitbox.height * species.baseScale).toInt()
|
||||
val width = ceil(species.hitbox.width * species.baseScale).toInt()
|
||||
if (!spawnablePosition.hasSpace(width, height)) {
|
||||
return EmptySpawnAction(spawnablePosition, bucket, EmptySpawnDetail.EMPTY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
level = herdable.levelRange?.let { clamp(level, it.first, it.last) } ?: level
|
||||
|
||||
val level = selectionData.context[herdLevelKey] as? Int ?: 1
|
||||
val levelRange = herdable.levelRangeOffset?.let { offset ->
|
||||
val min = level + offset.first
|
||||
val max = level + offset.last
|
||||
@@ -136,11 +158,7 @@ class PokemonHerdSpawnDetail : SpawnDetail() {
|
||||
drops = herdable.dropTable,
|
||||
heldItem = heldItem,
|
||||
levelRange = levelRange
|
||||
).also {
|
||||
if (herdable.isLeader && searchedForLeader) {
|
||||
it.labels += HERD_LEADER
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun getHerdMemberCounts(selectionData: SpawnSelectionData): Map<Herdable?, Int> {
|
||||
|
||||
+27
-22
@@ -53,34 +53,39 @@ open class AreaSpawnablePosition(
|
||||
*/
|
||||
open fun isSafeSpace(world: ServerLevel, pos: BlockPos, state: BlockState): Boolean = !state.isSolid
|
||||
|
||||
fun hasSpace(width: Int, height: Int): Boolean {
|
||||
val sizeX = width.takeIf { it > 0 } ?: 1
|
||||
val sizeY = height.takeIf { it > 0 } ?: 1
|
||||
|
||||
val minX = floor(position.x + 0.5 - (sizeX - 1) / 2F).toInt() - 1
|
||||
val maxX = ceil(position.x + 0.5 + (sizeX + 1) / 2F).toInt() + 1
|
||||
|
||||
val maxY = ceil(position.y + (sizeY + 1) / 2F).toInt() + 1
|
||||
|
||||
val minZ = floor(position.z + 0.5 - (sizeX - 1) / 2F).toInt() - 1
|
||||
val maxZ = ceil(position.z + 0.5 + (sizeX + 1) / 2F).toInt() + 1
|
||||
|
||||
val mutable = BlockPos.MutableBlockPos()
|
||||
for (x in minX until maxX) {
|
||||
for (y in (position.y + 1)..maxY) {
|
||||
for (z in minZ until maxZ) {
|
||||
val state = zone.getBlockState(mutable.set(x, y, z))
|
||||
if (!isSafeSpace(world, mutable, state)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun postFilter(detail: SpawnDetail): Boolean {
|
||||
if (!super.postFilter(detail)) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (detail.width > 1 || detail.height > 1) {
|
||||
val sizeX = detail.width.takeIf { it > 0 } ?: 1
|
||||
val sizeY = detail.height.takeIf { it > 0 } ?: 1
|
||||
|
||||
val minX = floor(position.x + 0.5 - (sizeX - 1) / 2F).toInt() - 1
|
||||
val maxX = ceil(position.x + 0.5 + (sizeX + 1) / 2F).toInt() + 1
|
||||
|
||||
val maxY = ceil(position.y + (sizeY + 1) / 2F).toInt() + 1
|
||||
|
||||
val minZ = floor(position.z + 0.5 - (sizeX - 1) / 2F).toInt() - 1
|
||||
val maxZ = ceil(position.z + 0.5 + (sizeX + 1) / 2F).toInt() + 1
|
||||
|
||||
val mutable = BlockPos.MutableBlockPos()
|
||||
for (x in minX until maxX) {
|
||||
for (y in (position.y + 1)..maxY) {
|
||||
for (z in minZ until maxZ) {
|
||||
val state = zone.getBlockState(mutable.set(x, y, z))
|
||||
if (!isSafeSpace(world, mutable, state)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return hasSpace(detail.width, detail.height)
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
+3
-3
@@ -28,7 +28,7 @@ import java.io.InputStreamReader
|
||||
* @since July 8th, 2022
|
||||
*/
|
||||
class BestSpawnerConfig {
|
||||
val version = 0
|
||||
val version = 2
|
||||
/** Whether an external config will be replaced by an internal one once [version] is higher on the internal. */
|
||||
val replaceWithNewVersion = true
|
||||
@SerializedName("spawnablePositionTypeWeights", alternate = ["contextWeights"])
|
||||
@@ -40,11 +40,11 @@ class BestSpawnerConfig {
|
||||
)
|
||||
|
||||
val worldBuckets = mutableMapOf(
|
||||
"common" to 94F,
|
||||
"common" to 94.05F,
|
||||
"uncommon" to 5F,
|
||||
"rare" to 0.5F,
|
||||
"ultra-rare" to 0.2F,
|
||||
"boss" to 0.3F,
|
||||
"boss" to 0.25F,
|
||||
)
|
||||
|
||||
val fishingBuckets = mutableMapOf(
|
||||
|
||||
@@ -89,6 +89,7 @@ open class FlatSelector : SpawningSelector<FlatSelector.SpawnablePositionSelecti
|
||||
val spawnablePositions: List<SpawnablePosition>,
|
||||
val selectingSpawnInformation: MutableMap<String, SpawnablePositionBucketSelectionData>,
|
||||
): SpawnSelectionData {
|
||||
override var guaranteedBucket: String? = null
|
||||
override val spawnActions = mutableListOf<SpawnAction<*>>()
|
||||
override val context = mutableMapOf<String, Any>()
|
||||
|
||||
|
||||
+1
@@ -101,6 +101,7 @@ open class FlatSpawnablePositionWeightedSelector : SpawningSelector<FlatSpawnabl
|
||||
val spawner: Spawner,
|
||||
val spawnablePositions: List<SpawnablePosition>
|
||||
) : SpawnSelectionData {
|
||||
override var guaranteedBucket: String? = null
|
||||
override val spawnActions = mutableListOf<SpawnAction<*>>()
|
||||
override val context = mutableMapOf<String, Any>()
|
||||
|
||||
|
||||
+2
@@ -21,6 +21,7 @@ import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
* @since April 21st, 2025
|
||||
*/
|
||||
interface SpawnSelectionData {
|
||||
var guaranteedBucket: String?
|
||||
val context: MutableMap<String, Any>
|
||||
val spawnActions: MutableList<SpawnAction<*>>
|
||||
fun removeSpawnDetails(shouldRemove: (SpawnDetail) -> Boolean)
|
||||
@@ -28,6 +29,7 @@ interface SpawnSelectionData {
|
||||
|
||||
companion object {
|
||||
val EMPTY = object : SpawnSelectionData {
|
||||
override var guaranteedBucket: String? = null
|
||||
override val context: MutableMap<String, Any> = mutableMapOf()
|
||||
override val spawnActions: MutableList<SpawnAction<*>> = mutableListOf()
|
||||
override fun removeSpawnDetails(shouldRemove: (SpawnDetail) -> Boolean) {}
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ interface SpawningSelector<T : SpawnSelectionData> {
|
||||
val spawnActions = selectionData.spawnActions
|
||||
|
||||
while (spawnActions.size < maxSpawns) {
|
||||
val bucket = bucketSelector()
|
||||
val bucket = selectionData.guaranteedBucket ?: bucketSelector()
|
||||
val spawnAction = selectSpawnAction(
|
||||
spawner = spawner,
|
||||
bucket = bucket,
|
||||
|
||||
+3
-2
@@ -17,6 +17,7 @@ import com.cobblemon.mod.common.api.spawning.influence.BucketNormalizingInfluenc
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawnBaitInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.rules.SpawnRule
|
||||
import com.cobblemon.mod.common.block.entity.PokeSnackBlockEntity
|
||||
import com.cobblemon.mod.common.util.mutableLazy
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
@@ -66,10 +67,10 @@ object PokeSnackSpawnerFactory {
|
||||
},
|
||||
)
|
||||
|
||||
fun create(ctx: Context): FixedAreaSpawner {
|
||||
fun create(ctx: Context): PokeSnackBlockEntity.Spawner {
|
||||
val influences = influenceBuilders.mapNotNull { it(ctx) }
|
||||
|
||||
return FixedAreaSpawner(
|
||||
return PokeSnackBlockEntity.Spawner(
|
||||
name = ctx.name,
|
||||
spawnPool = spawnPool,
|
||||
buckets = Cobblemon.bestSpawner.config.pokeSnackBuckets,
|
||||
|
||||
@@ -46,6 +46,7 @@ open class BottomlessStore(override val uuid: UUID) : PokemonStore<BottomlessPos
|
||||
pokemon.forEachIndexed { index, pokemon ->
|
||||
pokemon.storeCoordinates.set(StoreCoordinates(this, BottomlessPosition(index)))
|
||||
}
|
||||
rebuildPokemonByUuid()
|
||||
}
|
||||
|
||||
override fun saveToNBT(nbt: CompoundTag, registryAccess: RegistryAccess): CompoundTag {
|
||||
|
||||
@@ -53,7 +53,7 @@ abstract class PokemonStore<T : StorePosition> : Iterable<Pokemon> {
|
||||
* Runs initialization logic for this store, knowing that it has just been constructed in a [PokemonStoreFactory].
|
||||
*
|
||||
* The minimum of what this function should do is iterate over all the Pokémon in this store and set their store
|
||||
* coordinates.
|
||||
* coordinates. Built-in stores then rebuild the UUID index via [rebuildPokemonByUuid].
|
||||
*
|
||||
* If this does not get called, or it does not do its job properly, serious de-sync issues may follow.
|
||||
*/
|
||||
@@ -99,6 +99,7 @@ abstract class PokemonStore<T : StorePosition> : Iterable<Pokemon> {
|
||||
|
||||
setAtPosition(position, pokemon)
|
||||
pokemon.storeCoordinates.set(StoreCoordinates(this, position))
|
||||
pokemonByUuid[pokemon.uuid] = pokemon
|
||||
}
|
||||
|
||||
/** Swaps the Pokémon at the specified positions. If one of the spaces is empty, it will simply move the not-null one to that space. */
|
||||
@@ -147,10 +148,26 @@ abstract class PokemonStore<T : StorePosition> : Iterable<Pokemon> {
|
||||
pokemon.recall()
|
||||
pokemon.storeCoordinates.set(null)
|
||||
setAtPosition(currentPosition.position, null)
|
||||
pokemonByUuid.remove(pokemon.uuid)
|
||||
return true
|
||||
}
|
||||
|
||||
operator fun get(uuid: UUID) = find { it.uuid.equals(uuid) }
|
||||
/** In-memory UUID index. Not serialized; rebuilt by [rebuildPokemonByUuid]. */
|
||||
private val pokemonByUuid = hashMapOf<UUID, Pokemon>()
|
||||
|
||||
/** Gets the [Pokemon] with this UUID, or null if it is not in this store. */
|
||||
operator fun get(uuid: UUID): Pokemon? = pokemonByUuid[uuid]
|
||||
|
||||
/**
|
||||
* Rebuilds the UUID index from the store's current contents.
|
||||
*
|
||||
* Call after load or any structural mutation that does not go through [set] / [remove], such as
|
||||
* filling slots directly from NBT/JSON or shrinking a PC.
|
||||
*/
|
||||
protected fun rebuildPokemonByUuid() {
|
||||
pokemonByUuid.clear()
|
||||
forEach { pokemonByUuid[it.uuid] = it }
|
||||
}
|
||||
|
||||
open fun handleInvalidSpeciesNBT(nbt: CompoundTag) {
|
||||
Cobblemon.LOGGER.error("Failed to read unknown species: ${nbt.getString(DataKeys.POKEMON_SPECIES_IDENTIFIER)}")
|
||||
|
||||
@@ -138,6 +138,7 @@ open class PartyStore(override val uuid: UUID) : PokemonStore<PartyPosition>() {
|
||||
val pokemon = get(slot) ?: continue
|
||||
pokemon.storeCoordinates.set(StoreCoordinates(this, PartyPosition(slot)))
|
||||
}
|
||||
rebuildPokemonByUuid()
|
||||
}
|
||||
|
||||
override fun onPokemonChanged(pokemon: Pokemon) {
|
||||
@@ -279,7 +280,7 @@ open class PartyStore(override val uuid: UUID) : PokemonStore<PartyPosition>() {
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
return result.sortedBy { it.health <= 0 }
|
||||
}
|
||||
fun clearParty() {
|
||||
forEach {
|
||||
|
||||
@@ -105,6 +105,7 @@ open class PCStore(
|
||||
override fun initialize() {
|
||||
boxes.forEach { it.initialize() }
|
||||
backupStore.initialize()
|
||||
rebuildPokemonByUuid()
|
||||
}
|
||||
|
||||
fun relocateEvictedBoxPokemon(pokemon: Pokemon) {
|
||||
@@ -135,6 +136,7 @@ open class PCStore(
|
||||
|
||||
tryRestoreBackedUpPokemon()
|
||||
}
|
||||
rebuildPokemonByUuid()
|
||||
pcChangeObservable.emit(Unit)
|
||||
}
|
||||
|
||||
@@ -142,6 +144,7 @@ open class PCStore(
|
||||
this.lockedSize = lockNewSize
|
||||
boxes.removeAll(boxList)
|
||||
boxList.flatMap { it.asIterable() }.forEach(overflowHandler)
|
||||
rebuildPokemonByUuid()
|
||||
pcChangeObservable.emit(Unit)
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +66,8 @@ object CobblemonBiomeTags {
|
||||
val IS_WARM_OCEAN = create("is_warm_ocean")
|
||||
@JvmField
|
||||
val IS_DEEP_DARK = create("is_deep_dark")
|
||||
@JvmField
|
||||
val IS_MOUNTAIN = create("is_mountain")
|
||||
|
||||
// Has Block tags
|
||||
@JvmField
|
||||
|
||||
+1
-1
@@ -166,7 +166,7 @@ object AIUtility {
|
||||
"geargrind" to Pair(2, 2),
|
||||
"twinbeam" to Pair(2, 2),
|
||||
"twineedle" to Pair(2, 2),
|
||||
"suringstrikes" to Pair(3, 3),
|
||||
"surgingstrikes" to Pair(3, 3),
|
||||
"tripledive" to Pair(3, 3),
|
||||
"watershuriken" to Pair(3, 3),
|
||||
|
||||
|
||||
+2
-1
@@ -39,7 +39,6 @@ class FaintInstruction(battle: PokemonBattle, val message: BattleMessage) : Inte
|
||||
battle.dispatchFuture {
|
||||
val (pnx, _) = message.pnxAndUuid(0) ?: return@dispatchFuture CompletableFuture.completedFuture(Unit)
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchFuture CompletableFuture.completedFuture(Unit)
|
||||
battle.sendUpdate(BattleFaintPacket(pnx))
|
||||
val actor = pokemon.actor
|
||||
pokemon.effectedPokemon.currentHealth = 0
|
||||
val preamble = if (actor is EntityBackedBattleActor<*>) {
|
||||
@@ -50,6 +49,8 @@ class FaintInstruction(battle: PokemonBattle, val message: BattleMessage) : Inte
|
||||
val context = ShowdownInterpreter.getContextFromFaint(faintingPokemon, battle)
|
||||
|
||||
preamble.thenAccept {
|
||||
// Sent after the faint/recall animation so clients don't learn about the KO early
|
||||
battle.sendUpdate(BattleFaintPacket(pnx))
|
||||
faintingPokemon.effectedPokemon.currentHealth = 0
|
||||
faintingPokemon.faintedAt = battle.faintCounter++
|
||||
faintingPokemon.sendUpdate()
|
||||
|
||||
+23
-10
@@ -17,15 +17,8 @@ import com.cobblemon.mod.common.api.events.cooking.PokeSnackSpawnPokemonEvent
|
||||
import com.cobblemon.mod.common.api.fishing.SpawnBait
|
||||
import com.cobblemon.mod.common.api.fishing.SpawnBait.Effect
|
||||
import com.cobblemon.mod.common.api.fishing.SpawnBaitEffects
|
||||
import com.cobblemon.mod.common.api.spawning.CobblemonSpawnPools
|
||||
import com.cobblemon.mod.common.api.spawning.SpawnCause
|
||||
import com.cobblemon.mod.common.api.spawning.detail.EntitySpawnResult
|
||||
import com.cobblemon.mod.common.api.spawning.detail.PokemonHerdSpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnAction
|
||||
import com.cobblemon.mod.common.api.spawning.detail.SpawnDetail
|
||||
import com.cobblemon.mod.common.api.spawning.influence.BucketMultiplyingInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.BucketNormalizingInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawnBaitInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.detail.*
|
||||
import com.cobblemon.mod.common.api.spawning.influence.SpawningInfluence
|
||||
import com.cobblemon.mod.common.api.spawning.position.SpawnablePosition
|
||||
import com.cobblemon.mod.common.api.spawning.spawner.FixedAreaSpawner
|
||||
@@ -37,7 +30,6 @@ import com.cobblemon.mod.common.item.components.FoodColourComponent
|
||||
import com.cobblemon.mod.common.item.components.IngredientComponent
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.PokeSnackBlockParticlesPacket
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
import java.util.UUID
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.HolderLookup
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
@@ -51,6 +43,7 @@ import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import java.util.*
|
||||
|
||||
open class PokeSnackBlockEntity(pos: BlockPos, state: BlockState) :
|
||||
BlockEntity(CobblemonBlockEntities.POKE_SNACK, pos, state), TintBlockEntity,
|
||||
@@ -63,9 +56,29 @@ open class PokeSnackBlockEntity(pos: BlockPos, state: BlockState) :
|
||||
const val POKE_SNACK_CRUMBED_ASPECT = "poke_snack_crumbed"
|
||||
}
|
||||
|
||||
class Spawner(
|
||||
name: String,
|
||||
spawnPool: SpawnPool,
|
||||
buckets: Map<String, Float>,
|
||||
world: ServerLevel,
|
||||
position: BlockPos,
|
||||
horizontalRadius: Int,
|
||||
verticalRadius: Int,
|
||||
maxPokemonPerChunk: Float
|
||||
) : FixedAreaSpawner(
|
||||
name = name,
|
||||
spawnPool = spawnPool,
|
||||
buckets = buckets,
|
||||
world = world,
|
||||
position = position,
|
||||
horizontalRadius = horizontalRadius,
|
||||
verticalRadius = verticalRadius,
|
||||
maxPokemonPerChunk = maxPokemonPerChunk
|
||||
)
|
||||
|
||||
override var tint: Int? = null
|
||||
|
||||
val spawner: FixedAreaSpawner by lazy {
|
||||
val spawner: Spawner by lazy {
|
||||
val server = level as ServerLevel
|
||||
|
||||
val baitEffects = getBaitEffects()
|
||||
|
||||
@@ -278,7 +278,7 @@ class HabitatBlockEntity(pos: BlockPos, state: BlockState) :
|
||||
override fun injectSpawns(bucket: String, spawnablePosition: SpawnablePosition): List<SpawnDetail>? {
|
||||
val spawningStyle = spawningStyle
|
||||
return if (spawningStyle is NaturalHabitatSpawning) {
|
||||
spawnDetails.filter { it.spawnablePositionType.clazz == spawnablePosition::class.java && it.isSatisfiedBy(spawnablePosition) }
|
||||
spawnDetails.filter { it.bucket == bucket && it.spawnablePositionType.clazz == spawnablePosition::class.java && it.isSatisfiedBy(spawnablePosition) }
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
+5
-6
@@ -470,7 +470,7 @@ class PokemonClientDelegate : PosableState(), PokemonSideDelegate {
|
||||
val random = currentEntity.level().random
|
||||
when (particleData) {
|
||||
is ParticleData.SnowstormParticle -> {
|
||||
val locators = particleData.locatorResolver(locatorStates).ifEmpty { listOf("root") }.filter(::isLocatorVisible)
|
||||
val locators = particleData.locatorResolver(locatorStates).filter(::isLocatorVisible)
|
||||
if (particleData.chance > random.nextDouble()) {
|
||||
locators.forEach { locator ->
|
||||
repeat(particleData.amount) {
|
||||
@@ -518,15 +518,14 @@ class PokemonClientDelegate : PosableState(), PokemonSideDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
fun getSeatLocator(passenger: Entity): String {
|
||||
val seat = this.getEntity().occupiedSeats.entries
|
||||
fun getSeatLocator(passenger: Entity): String? {
|
||||
return this.getEntity().occupiedSeats.entries
|
||||
.firstOrNull { it.value == passenger }?.key
|
||||
?: throw IllegalArgumentException("Entity is not currently riding a seat")
|
||||
return seat.locator
|
||||
?.locator
|
||||
}
|
||||
|
||||
override fun positionRider(passenger: Entity, positionUpdater: MoveFunction) {
|
||||
val locatorName = getSeatLocator(passenger)
|
||||
val locatorName = getSeatLocator(passenger) ?: return
|
||||
val locator = this.locatorStates[locatorName] ?: return
|
||||
|
||||
val locatorOffset = locator.matrix.getTranslation(Vector3f())
|
||||
|
||||
+55
-29
@@ -66,12 +66,14 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
|
||||
private val platformShadow = cobblemonResource("textures/gui/pokedex/platform_shadow.png")
|
||||
private val typeSpacerResource = cobblemonResource("textures/gui/starterselection/type_spacer_single.png")
|
||||
private val ballResource = cobblemonResource("textures/item/poke_balls/poke_ball.png")
|
||||
|
||||
private val unknownResource = cobblemonResource("textures/gui/pokedex/platform_unknown.png")
|
||||
}
|
||||
|
||||
var currentSelection = 0
|
||||
lateinit var currentCategory: RenderableStarterCategory
|
||||
private lateinit var modelWidget: ModelWidget
|
||||
private lateinit var currentPokemon: RenderablePokemon
|
||||
private var currentPokemon: RenderablePokemon? = null
|
||||
|
||||
var ticksElapsed = 0
|
||||
var currentBallBackgroundFrame = 0
|
||||
@@ -98,9 +100,9 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
|
||||
}
|
||||
|
||||
currentCategory = categories.first()
|
||||
currentPokemon = currentCategory.pokemon[currentSelection]
|
||||
currentPokemon = currentCategory.pokemon[0]
|
||||
|
||||
with(currentPokemon) {
|
||||
with(currentPokemon!!) {
|
||||
modelWidget = ModelWidget(
|
||||
pX = x + 6, pY = y + 17,
|
||||
pWidth = 118, pHeight = 100,
|
||||
@@ -188,7 +190,7 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
|
||||
width = 113,
|
||||
height = 32
|
||||
)
|
||||
val typePlatform = getPlatformResource(currentPokemon.form.primaryType)
|
||||
val typePlatform = currentPokemon?.let { getPlatformResource(it.form.primaryType) }
|
||||
if (typePlatform != null) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
@@ -209,6 +211,18 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
|
||||
scale = 0.5F
|
||||
)
|
||||
|
||||
if (currentPokemon == null) { // Model widget won't render
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = unknownResource,
|
||||
x = (x + 36) / 0.15f,
|
||||
y = (y + 36) / 0.15f,
|
||||
width = 390,
|
||||
height = 444,
|
||||
scale = 0.15f
|
||||
)
|
||||
}
|
||||
|
||||
//Base
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
@@ -220,23 +234,25 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
|
||||
)
|
||||
|
||||
//Type Icon
|
||||
TypeIcon(
|
||||
x = x + 65,
|
||||
y = y + 120,
|
||||
type = currentPokemon.form.primaryType,
|
||||
secondaryType = currentPokemon.form.secondaryType,
|
||||
centeredX = true
|
||||
).render(context)
|
||||
if (currentPokemon != null) {
|
||||
TypeIcon(
|
||||
x = x + 65,
|
||||
y = y + 120,
|
||||
type = currentPokemon!!.form.primaryType,
|
||||
secondaryType = currentPokemon!!.form.secondaryType,
|
||||
centeredX = true
|
||||
).render(context)
|
||||
|
||||
if (currentPokemon.form.secondaryType == null) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = typeSpacerResource,
|
||||
x = x + 47,
|
||||
y = y + 123,
|
||||
width = 36,
|
||||
height = 12
|
||||
)
|
||||
if (currentPokemon!!.form.secondaryType == null) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = typeSpacerResource,
|
||||
x = x + 47,
|
||||
y = y + 123,
|
||||
width = 36,
|
||||
height = 12
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
//Name
|
||||
@@ -253,7 +269,7 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
|
||||
drawScaledText(
|
||||
context = context,
|
||||
font = CobblemonResources.DEFAULT_LARGE,
|
||||
text = currentPokemon.species.translatedName.bold(),
|
||||
text = currentPokemon?.species?.translatedName?.bold() ?: lang("ui.starter.random").bold(),
|
||||
x = x + 14,
|
||||
y = y + 2,
|
||||
shadow = true
|
||||
@@ -261,11 +277,13 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
|
||||
|
||||
// Pokédex Number
|
||||
// Add preceding zeroes if Pokédex number is less than 4 digits
|
||||
var dexNo = currentPokemon.species.nationalPokedexNumber.toString()
|
||||
while (dexNo.length < 4) {
|
||||
dexNo = "0$dexNo"
|
||||
}
|
||||
dexNo = "#$dexNo"
|
||||
var dexNo = currentPokemon?.species?.nationalPokedexNumber?.toString()
|
||||
if (dexNo != null) {
|
||||
while (dexNo!!.length < 4) {
|
||||
dexNo = "0$dexNo"
|
||||
}
|
||||
dexNo = "#$dexNo"
|
||||
} else dexNo = "#????"
|
||||
|
||||
drawScaledText(
|
||||
context = context,
|
||||
@@ -290,10 +308,12 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
|
||||
//Description Text
|
||||
val smallTextScale = 0.5F
|
||||
|
||||
val textEntry = currentPokemon?.form?.pokedex?.first()?.asTranslated() ?: lang("ui.starter.random_description")
|
||||
|
||||
matrices.pushPose()
|
||||
matrices.scale(smallTextScale, smallTextScale, 1F)
|
||||
MultiLineLabelK.create(
|
||||
component = currentPokemon.form.pokedex.first().asTranslated(),
|
||||
component = textEntry,
|
||||
width = 114 / smallTextScale,
|
||||
maxLines = 5
|
||||
).renderLeftAligned(
|
||||
@@ -320,8 +340,14 @@ class StarterSelectionScreen(private val categories: List<RenderableStarterCateg
|
||||
fun selectPokemon(category: RenderableStarterCategory, slot: Int) {
|
||||
currentCategory = category
|
||||
currentSelection = slot
|
||||
currentPokemon = currentCategory.pokemon[currentSelection].also {
|
||||
modelWidget.pokemon = it
|
||||
if (currentSelection < currentCategory.pokemon.size) {
|
||||
currentPokemon = currentCategory.pokemon[currentSelection].also {
|
||||
modelWidget.pokemon = it
|
||||
}
|
||||
modelWidget.shouldRender = true
|
||||
} else {
|
||||
currentPokemon = null
|
||||
modelWidget.shouldRender = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+33
-17
@@ -52,6 +52,8 @@ class CategoryList(
|
||||
private val buttonResource = cobblemonResource("textures/gui/starterselection/starter_selection.png")
|
||||
private val buttonActiveResource = cobblemonResource("textures/gui/starterselection/starter_selection_active.png")
|
||||
|
||||
private val unknownResource = cobblemonResource("textures/gui/pokedex/platform_unknown.png")
|
||||
|
||||
const val MARGIN = 4
|
||||
const val HEADER_HEIGHT = 7
|
||||
const val BUTTON_SEPERATION = 3
|
||||
@@ -84,7 +86,8 @@ class CategoryList(
|
||||
mouseY: Int,
|
||||
partialTick: Float
|
||||
) {
|
||||
val rows = (category.pokemon.size - 1) / 3 + 1
|
||||
val itemSize = category.pokemon.size + if (category.randomStarter) 1 else 0
|
||||
val rows = (itemSize - 1) / 3 + 1
|
||||
val matrices = guiGraphics.pose()
|
||||
//Header
|
||||
blitk(
|
||||
@@ -152,7 +155,7 @@ class CategoryList(
|
||||
)
|
||||
|
||||
//Buttons
|
||||
for (index in 0..<category.pokemon.size) {
|
||||
for (index in 0..<itemSize) {
|
||||
val row = index / 3
|
||||
val column = index % 3
|
||||
|
||||
@@ -173,21 +176,33 @@ class CategoryList(
|
||||
vOffset = if (hovered) CONTAINER_BUTTON_SIZE else 0
|
||||
)
|
||||
|
||||
matrices.pushPose()
|
||||
matrices.translate(startX + (CONTAINER_BUTTON_SIZE / 2.0), startY.toDouble() - 6, 0.0)
|
||||
matrices.scale(3.5F, 3.5F, 1F)
|
||||
if (index == category.pokemon.size) {
|
||||
blitk(
|
||||
matrixStack = matrices,
|
||||
texture = unknownResource,
|
||||
x = (startX + 4.5F) / 0.04f,
|
||||
y = (startY + 3.5F) / 0.04f,
|
||||
width = 390,
|
||||
height = 444,
|
||||
scale = 0.04f
|
||||
)
|
||||
} else {
|
||||
matrices.pushPose()
|
||||
matrices.translate(startX + (CONTAINER_BUTTON_SIZE / 2.0), startY.toDouble() - 6, 0.0)
|
||||
matrices.scale(3.5F, 3.5F, 1F)
|
||||
|
||||
val state = FloatingState()
|
||||
state.currentAspects = category.pokemon[index].aspects
|
||||
drawProfilePokemon(
|
||||
species = category.pokemon[index].species.resourceIdentifier,
|
||||
matrixStack = matrices,
|
||||
rotation = Quaternionf().fromEulerXYZDegrees(Vector3f(13F, 35F, 0F)),
|
||||
state = state,
|
||||
scale = 4.5F,
|
||||
partialTicks = 0F
|
||||
)
|
||||
matrices.popPose()
|
||||
val state = FloatingState()
|
||||
state.currentAspects = category.pokemon[index].aspects
|
||||
drawProfilePokemon(
|
||||
species = category.pokemon[index].species.resourceIdentifier,
|
||||
matrixStack = matrices,
|
||||
rotation = Quaternionf().fromEulerXYZDegrees(Vector3f(13F, 35F, 0F)),
|
||||
state = state,
|
||||
scale = 4.5F,
|
||||
partialTicks = 0F
|
||||
)
|
||||
matrices.popPose()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +218,8 @@ class CategoryList(
|
||||
}
|
||||
|
||||
private fun getButtonHovered(x: Int, y: Int, mouseX: Double, mouseY: Double): Int {
|
||||
for (index in 0..<category.pokemon.size) {
|
||||
val itemSize = category.pokemon.size + if (category.randomStarter) 1 else 0
|
||||
for (index in 0..<itemSize) {
|
||||
val row = index / 3
|
||||
val column = index % 3
|
||||
|
||||
|
||||
+3
-2
@@ -36,7 +36,6 @@ class ModelWidget(
|
||||
): SoundlessWidget(pX, pY, pWidth, pHeight, Component.literal("Summary - ModelWidget")) {
|
||||
|
||||
companion object {
|
||||
var render = true
|
||||
const val MAX_SECONDS_LOOKING = 6L
|
||||
}
|
||||
|
||||
@@ -59,8 +58,10 @@ class ModelWidget(
|
||||
var currentYawAndPitch: Pair<Float, Float> = Pair(0f, 0f)
|
||||
val rotationVector = Vector3f(13F, rotationY, 0F)
|
||||
|
||||
var shouldRender = true
|
||||
|
||||
override fun renderWidget(context: GuiGraphics, pMouseX: Int, pMouseY: Int, partialTicks: Float) {
|
||||
if (!render) {
|
||||
if (!shouldRender) {
|
||||
return
|
||||
}
|
||||
isHovered = pMouseX >= x && pMouseY >= y && pMouseX < x + width && pMouseY < y + height
|
||||
|
||||
+13
@@ -1267,6 +1267,19 @@ class TMMachineScreen(containerMenu: TMMachineMenu, val inventory: Inventory, ti
|
||||
Minecraft.getInstance().soundManager.play(SimpleSoundInstance.forUI(soundEvent, 1.0F))
|
||||
}
|
||||
|
||||
override fun hasClickedOutside(
|
||||
mouseX: Double,
|
||||
mouseY: Double,
|
||||
guiLeft: Int,
|
||||
guiTop: Int,
|
||||
mouseButton: Int
|
||||
): Boolean {
|
||||
partySlotList.forEach {
|
||||
if (it.pokemon != null && it.isMouseOver(mouseX, mouseY)) return false
|
||||
}
|
||||
return super.hasClickedOutside(mouseX, mouseY, guiLeft, guiTop, mouseButton)
|
||||
}
|
||||
|
||||
class MoveDescriptionWidget(pX: Int, pY: Int, width: Int, height: Int) : ScrollingWidget<MoveDescriptionWidget.TextSlot>(
|
||||
left = pX,
|
||||
top = pY - height,
|
||||
|
||||
+3
-2
@@ -27,12 +27,13 @@ object SetActiveTMPacketHandler : ServerNetworkPacketHandler<SetActiveTMPacket>
|
||||
|
||||
menu.tmMachineEntity?.let { blockEntity ->
|
||||
blockEntity.activeMove = packet.tm?.moveName?.name ?: ""
|
||||
blockEntity.setChanged()
|
||||
player.level().sendBlockUpdated(blockEntity.blockPos, blockEntity.blockState, blockEntity.blockState, Block.UPDATE_CLIENTS)
|
||||
|
||||
blockEntity.burnActive = false
|
||||
blockEntity.burnProgress = 0
|
||||
|
||||
blockEntity.setChanged()
|
||||
player.level().sendBlockUpdated(blockEntity.blockPos, blockEntity.blockState, blockEntity.blockState, Block.UPDATE_CLIENTS)
|
||||
|
||||
player.level().players().forEach { thePlayer -> //Update all players with matching menu/blockentity
|
||||
val tmmMenu = thePlayer.containerMenu as? TMMachineMenu ?: return@forEach
|
||||
if (tmmMenu.tmMachineEntity == blockEntity) {
|
||||
|
||||
+2
@@ -29,6 +29,8 @@ object SetTMMachineContainerDataPacketHandler : ServerNetworkPacketHandler<SetTM
|
||||
menu.containerData?.set(TMMachineBlockEntity.BURN_PROGRESS_INDEX, 0)
|
||||
}
|
||||
|
||||
menu.tmMachineEntity?.setChanged()
|
||||
|
||||
menu.broadcastChanges()
|
||||
}
|
||||
}
|
||||
|
||||
+7
-14
@@ -16,22 +16,15 @@ import net.minecraft.client.Minecraft
|
||||
object ClientboundSeatAssignmentPacketHandler : ClientNetworkPacketHandler<ClientboundSeatAssignmentPacket> {
|
||||
override fun handle(packet: ClientboundSeatAssignmentPacket, client: Minecraft) {
|
||||
val vehicle = client.level?.getEntity(packet.vehicleEntityId) as? PokemonEntity ?: return
|
||||
val passenger = client.level?.getEntity(packet.passengerEntityId) ?: return
|
||||
val seat = vehicle.form.riding.seats.firstOrNull { it.locator == packet.seatLocator } ?: return
|
||||
|
||||
// If the passenger was already seated somewhere else then move seats for them if needed.
|
||||
// It could also be that the client assigned the wrong seat. The server has authority in seating so
|
||||
// replace in that case too.
|
||||
val currentSeat = vehicle.occupiedSeats.entries.firstOrNull { it.value == passenger }
|
||||
if (currentSeat != null) {
|
||||
if (currentSeat.key == seat) return
|
||||
vehicle.occupiedSeats.remove(currentSeat.key)
|
||||
val assignments = packet.seatAssignments.mapNotNull { (locator, entityId) ->
|
||||
val seat = vehicle.form.riding.seats.firstOrNull { it.locator == locator } ?: return@mapNotNull null
|
||||
val passenger = client.level?.getEntity(entityId) ?: return@mapNotNull null
|
||||
seat to passenger
|
||||
}
|
||||
|
||||
vehicle.occupiedSeats[seat] = passenger
|
||||
|
||||
if (!vehicle.hasPassenger(passenger)) {
|
||||
passenger.startRiding(vehicle, true)
|
||||
vehicle.occupiedSeats.clear()
|
||||
assignments.forEach { (seat, passenger) ->
|
||||
vehicle.occupiedSeats[seat] = passenger
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -75,7 +75,7 @@ object MountedCameraRenderer {
|
||||
val state = FloatingState().also { it.currentAspects = vehicle.pokemon.aspects }
|
||||
val model = getPoser(vehicle.pokemon.species.resourceIdentifier, state)
|
||||
|
||||
val locatorName = delegate.getSeatLocator(driver)
|
||||
val locatorName = delegate.getSeatLocator(driver) ?: return null
|
||||
val locator = delegate.locatorStates[locatorName] ?: return null
|
||||
|
||||
// Get additional offset from poser and add to the eyeHeight offset
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ object MountedLivingEntityRenderer {
|
||||
if (entity.vehicle !is Rideable) return
|
||||
val matrix = stack.last().pose()
|
||||
val delegate = pokemon.delegate as PokemonClientDelegate
|
||||
val locator = delegate.locatorStates[delegate.getSeatLocator(entity)]
|
||||
val locator = delegate.getSeatLocator(entity)?.let { delegate.locatorStates[it] }
|
||||
|
||||
//Positions entity
|
||||
if (locator != null) {
|
||||
|
||||
-69
@@ -1,69 +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.gen1
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.QuadrupedFrame
|
||||
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 RattataAlolanModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame, QuadrupedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("rattata")
|
||||
override val foreLeftLeg= getPart("leg_front_left")
|
||||
override val foreRightLeg = getPart("leg_front_right")
|
||||
override val hindLeftLeg = getPart("leg_back_left")
|
||||
override val hindRightLeg = getPart("leg_back_right")
|
||||
override val head = getPart("head")
|
||||
|
||||
override var portraitScale = 2.2F
|
||||
override var portraitTranslation = Vec3(-0.2, -1.4, 0.0)
|
||||
|
||||
override var profileScale = 1.1F
|
||||
override var profileTranslation = Vec3(0.0, 0.1, 0.0)
|
||||
|
||||
lateinit var sleep: Pose
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
// override val cryAnimation = CryProvider { bedrockStateful("rattata", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("rattata", "blink")}
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
animations = arrayOf(bedrock("rattata", "sleep"))
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = setOf(PoseType.NONE, PoseType.PROFILE, PoseType.STAND, PoseType.FLOAT, PoseType.PORTRAIT, PoseType.SHOULDER_LEFT, PoseType.SHOULDER_RIGHT),
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("rattata", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseType = PoseType.WALK,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("rattata", "ground_walk")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getFaintAnimation(state: PosableState) = bedrockStateful("rattata", "faint")
|
||||
}
|
||||
-71
@@ -1,71 +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.gen1
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.QuadrupedFrame
|
||||
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 RattataModel(root: ModelPart) : PokemonPosableModel(root), HeadedFrame, QuadrupedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("rattata")
|
||||
override val foreLeftLeg= getPart("leg_front_left")
|
||||
override val foreRightLeg = getPart("leg_front_right")
|
||||
override val hindLeftLeg = getPart("leg_back_left")
|
||||
override val hindRightLeg = getPart("leg_back_right")
|
||||
override val head = getPart("head")
|
||||
|
||||
override var portraitScale = 2.2F
|
||||
override var portraitTranslation = Vec3(-0.2, -1.4, 0.0)
|
||||
|
||||
override var profileScale = 1.1F
|
||||
override var profileTranslation = Vec3(0.0, 0.1, 0.0)
|
||||
|
||||
lateinit var sleep: Pose
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
// override val cryAnimation = CryProvider { bedrockStateful("rattata", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
animations = arrayOf(bedrock("rattata", "sleep"))
|
||||
)
|
||||
|
||||
val blink = quirk { bedrockStateful("rattata", "blink")}
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = setOf(PoseType.NONE, PoseType.PROFILE, PoseType.STAND, PoseType.FLOAT, PoseType.PORTRAIT, PoseType.SHOULDER_LEFT, PoseType.SHOULDER_RIGHT),
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("rattata", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseType = PoseType.WALK,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("rattata", "ground_walk")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getFaintAnimation(state: PosableState) = bedrockStateful("rattata", "faint")
|
||||
}
|
||||
+3
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
|
||||
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 com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.isBattling
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
@@ -33,6 +34,8 @@ class DusclopsModel (root: ModelPart) : PokemonPosableModel(root) {
|
||||
lateinit var battleidle: Pose
|
||||
|
||||
override fun registerPoses() {
|
||||
animations["cry"] = "q.bedrock_stateful('squirtle', 'cry')".asExpressionLike()
|
||||
|
||||
val blink = quirk { bedrockStateful("dusclops", "blink") }
|
||||
|
||||
sleep = registerPose(
|
||||
|
||||
+2
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.PosableState
|
||||
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 com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.isBattling
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
@@ -33,6 +34,7 @@ class DuskullModel (root: ModelPart) : PokemonPosableModel(root) {
|
||||
lateinit var battleidle: Pose
|
||||
|
||||
override fun registerPoses() {
|
||||
animations["cry"] = "q.bedrock_stateful('duskull', 'cry')".asExpressionLike()
|
||||
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
|
||||
-81
@@ -1,81 +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.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 com.cobblemon.mod.common.util.isBattling
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class DarumakaModel (root: ModelPart) : PokemonPosableModel(root) {
|
||||
override val rootPart = root.registerChildWithAllChildren("darumaka")
|
||||
|
||||
override var portraitScale = 1.96F
|
||||
override var portraitTranslation = Vec3(-0.18, -0.84, 0.0)
|
||||
|
||||
override var profileScale = 0.76F
|
||||
override var profileTranslation = Vec3(0.0, 0.57, 0.0)
|
||||
|
||||
lateinit var standing: CobblemonPose
|
||||
lateinit var walk: CobblemonPose
|
||||
lateinit var sleep: CobblemonPose
|
||||
lateinit var battleidle: CobblemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("darumaka", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("darumaka", "blink") }
|
||||
val quirk = quirk(secondsBetweenOccurrences = 15F to 100F) { bedrockStateful("darumaka", "quirk") }
|
||||
val quirk2 = quirk(secondsBetweenOccurrences = 20F to 360F) { bedrockStateful("darumaka","quirk2")}
|
||||
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
animations = arrayOf(bedrock("darumaka", "sleep"))
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
|
||||
quirks = arrayOf(blink, quirk, quirk2),
|
||||
condition = { !it.isBattling },
|
||||
animations = arrayOf(
|
||||
bedrock("darumaka", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
battleidle = registerPose(
|
||||
poseName = "battle_idle",
|
||||
poseTypes = PoseType.STATIONARY_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink, quirk),
|
||||
condition = { it.isBattling },
|
||||
animations = arrayOf(
|
||||
bedrock("darumaka", "battle_idle")
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseTypes = PoseType.MOVING_POSES,
|
||||
quirks = arrayOf(blink, quirk),
|
||||
animations = arrayOf(
|
||||
bedrock("darumaka", "ground_walk")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PosableState<PokemonEntity>
|
||||
// ) = if (state.isPosedIn(standing, walk)) bedrockStateful("darumaka", "faint") else null
|
||||
}
|
||||
-118
@@ -1,118 +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.createTransformation
|
||||
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.CobblemonPose
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.isBattling
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class DewottHisuiBiasModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BimanualFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("dewott_hisui_bias")
|
||||
override val head = getPart("head")
|
||||
override val rightArm = getPart("arm_right")
|
||||
override val leftArm = getPart("arm_left")
|
||||
override val rightLeg = getPart("leg_right")
|
||||
override val leftLeg = getPart("leg_left")
|
||||
val scalchop_body_right = getPart("scalchop_skirt_right")
|
||||
val scalchop_body_left = getPart("scalchop_skirt_left")
|
||||
val scalchop_right = getPart("scalchop_hand_right")
|
||||
val scalchop_left = getPart("scalchop_hand_left")
|
||||
|
||||
override var portraitScale = 2.0F
|
||||
override var portraitTranslation = Vec3(-0.15, 0.8, 0.0)
|
||||
override var profileScale = 0.7F
|
||||
override var profileTranslation = Vec3(0.0, 0.69, 0.0)
|
||||
|
||||
lateinit var battleidle: CobblemonPose
|
||||
lateinit var sleep: CobblemonPose
|
||||
lateinit var standing: CobblemonPose
|
||||
lateinit var walk: CobblemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("dewott_hisui_bias", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("dewott_hisui_bias", "blink") }
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
transformTicks = 10,
|
||||
condition = { !it.isBattling },
|
||||
transformedParts = arrayOf(
|
||||
scalchop_right.createTransformation().withVisibility(visibility = false),
|
||||
scalchop_left.createTransformation().withVisibility(visibility = false),
|
||||
scalchop_body_right.createTransformation().withVisibility(visibility = true),
|
||||
scalchop_body_left.createTransformation().withVisibility(visibility = true)
|
||||
|
||||
),
|
||||
animations = arrayOf(bedrock("dewott_hisui_bias", "sleep"))
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = setOf(PoseType.NONE, PoseType.STAND, PoseType.PORTRAIT, PoseType.PROFILE),
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { !it.isBattling },
|
||||
transformedParts = arrayOf(
|
||||
scalchop_right.createTransformation().withVisibility(visibility = false),
|
||||
scalchop_left.createTransformation().withVisibility(visibility = false),
|
||||
scalchop_body_right.createTransformation().withVisibility(visibility = true),
|
||||
scalchop_body_left.createTransformation().withVisibility(visibility = true)
|
||||
),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("dewott_hisui_bias", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walking",
|
||||
poseTypes = setOf(PoseType.SWIM, PoseType.WALK),
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { !it.isBattling },
|
||||
transformedParts = arrayOf(
|
||||
scalchop_right.createTransformation().withVisibility(visibility = false),
|
||||
scalchop_left.createTransformation().withVisibility(visibility = false),
|
||||
scalchop_body_right.createTransformation().withVisibility(visibility = true),
|
||||
scalchop_body_left.createTransformation().withVisibility(visibility = true)
|
||||
),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("dewott_hisui_bias", "ground_walk")
|
||||
)
|
||||
)
|
||||
|
||||
battleidle = registerPose(
|
||||
poseName = "battle_idle",
|
||||
poseTypes = PoseType.STATIONARY_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { it.isBattling },
|
||||
transformedParts = arrayOf(
|
||||
scalchop_right.createTransformation().withVisibility(visibility = true),
|
||||
scalchop_left.createTransformation().withVisibility(visibility = true),
|
||||
scalchop_body_right.createTransformation().withVisibility(visibility = false),
|
||||
scalchop_body_left.createTransformation().withVisibility(visibility = false)
|
||||
),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("dewott_hisui_bias", "ground_idle")
|
||||
)
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
-118
@@ -1,118 +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.createTransformation
|
||||
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 com.cobblemon.mod.common.util.isBattling
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class DewottModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BimanualFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("dewott")
|
||||
override val head = getPart("head")
|
||||
override val rightArm = getPart("arm_right")
|
||||
override val leftArm = getPart("arm_left")
|
||||
override val rightLeg = getPart("leg_right")
|
||||
override val leftLeg = getPart("leg_left")
|
||||
val scalchop_body_right = getPart("scalchop_skirt_right")
|
||||
val scalchop_body_left = getPart("scalchop_skirt_left")
|
||||
val scalchop_right = getPart("scalchop_hand_right")
|
||||
val scalchop_left = getPart("scalchop_hand_left")
|
||||
|
||||
override var portraitScale = 2.0F
|
||||
override var portraitTranslation = Vec3(-0.15, 0.8, 0.0)
|
||||
override var profileScale = 0.7F
|
||||
override var profileTranslation = Vec3(0.0, 0.69, 0.0)
|
||||
|
||||
lateinit var battleidle: Pose
|
||||
lateinit var sleep: Pose
|
||||
lateinit var standing: Pose
|
||||
lateinit var walk: Pose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("dewott", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("dewott", "blink") }
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
transformTicks = 10,
|
||||
condition = { !it.isBattling },
|
||||
transformedParts = arrayOf(
|
||||
scalchop_right.createTransformation().withVisibility(visibility = false),
|
||||
scalchop_left.createTransformation().withVisibility(visibility = false),
|
||||
scalchop_body_right.createTransformation().withVisibility(visibility = true),
|
||||
scalchop_body_left.createTransformation().withVisibility(visibility = true)
|
||||
|
||||
),
|
||||
animations = arrayOf(bedrock("dewott", "sleep"))
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = setOf(PoseType.NONE, PoseType.STAND, PoseType.PORTRAIT, PoseType.PROFILE),
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { !it.isBattling },
|
||||
transformedParts = arrayOf(
|
||||
scalchop_right.createTransformation().withVisibility(visibility = false),
|
||||
scalchop_left.createTransformation().withVisibility(visibility = false),
|
||||
scalchop_body_right.createTransformation().withVisibility(visibility = true),
|
||||
scalchop_body_left.createTransformation().withVisibility(visibility = true)
|
||||
),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("dewott", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walking",
|
||||
poseTypes = setOf(PoseType.SWIM, PoseType.WALK),
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { !it.isBattling },
|
||||
transformedParts = arrayOf(
|
||||
scalchop_right.createTransformation().withVisibility(visibility = false),
|
||||
scalchop_left.createTransformation().withVisibility(visibility = false),
|
||||
scalchop_body_right.createTransformation().withVisibility(visibility = true),
|
||||
scalchop_body_left.createTransformation().withVisibility(visibility = true)
|
||||
),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("dewott", "ground_walk")
|
||||
)
|
||||
)
|
||||
|
||||
battleidle = registerPose(
|
||||
poseName = "battle_idle",
|
||||
poseTypes = PoseType.STATIONARY_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { it.isBattling },
|
||||
transformedParts = arrayOf(
|
||||
scalchop_right.createTransformation().withVisibility(visibility = true),
|
||||
scalchop_left.createTransformation().withVisibility(visibility = true),
|
||||
scalchop_body_right.createTransformation().withVisibility(visibility = false),
|
||||
scalchop_body_left.createTransformation().withVisibility(visibility = false)
|
||||
),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("dewott", "ground_idle")
|
||||
)
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
-112
@@ -1,112 +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.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BimanualSwingAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedWalkAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.createTransformation
|
||||
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.pose.CobblemonPose
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.ModelPartTransformation
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.isBattling
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class OshawottHisuiBiasModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BimanualFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("oshawott_hisui_bias")
|
||||
override val head = getPart("head")
|
||||
override val rightArm = getPart("arm_right")
|
||||
override val leftArm = getPart("arm_left")
|
||||
override val rightLeg = getPart("leg_right")
|
||||
override val leftLeg = getPart("leg_left")
|
||||
val scalchop = getPart("scalchop_hand")
|
||||
val scalchopbody = getPart("scalchop_torso")
|
||||
|
||||
override var portraitScale = 2.0F
|
||||
override var portraitTranslation = Vec3(-0.2, -0.15, 0.0)
|
||||
override var profileScale = 0.7F
|
||||
override var profileTranslation = Vec3(0.0, 0.69, 0.0)
|
||||
|
||||
lateinit var battleidle: CobblemonPose
|
||||
lateinit var sleep: CobblemonPose
|
||||
lateinit var standing: CobblemonPose
|
||||
lateinit var walk: CobblemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("oshawott_hisui_bias", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("oshawott_hisui_bias", "blink") }
|
||||
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
transformTicks = 10,
|
||||
transformedParts = arrayOf(
|
||||
scalchop.createTransformation().withVisibility(visibility = false),
|
||||
scalchopbody.createTransformation().withVisibility(visibility = true),
|
||||
rootPart.createTransformation().addPosition(ModelPartTransformation.Y_AXIS, -7)
|
||||
),
|
||||
animations = arrayOf(bedrock("oshawott_hisui_bias", "sleep"))
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = setOf(PoseType.NONE, PoseType.STAND, PoseType.PORTRAIT, PoseType.PROFILE),
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { !it.isBattling },
|
||||
transformedParts = arrayOf(
|
||||
scalchop.createTransformation().withVisibility(visibility = false),
|
||||
scalchopbody.createTransformation().withVisibility(visibility = true)
|
||||
),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("oshawott_hisui_bias", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walking",
|
||||
poseTypes = setOf(PoseType.SWIM, PoseType.WALK),
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { !it.isBattling },
|
||||
transformedParts = arrayOf(
|
||||
scalchop.createTransformation().withVisibility(visibility = false),
|
||||
scalchopbody.createTransformation().withVisibility(visibility = true)
|
||||
),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("oshawott_hisui_bias", "ground_idle"),
|
||||
BipedWalkAnimation(this, periodMultiplier = 0.6F, amplitudeMultiplier = 0.9F),
|
||||
BimanualSwingAnimation(this, swingPeriodMultiplier = 0.6F, amplitudeMultiplier = 0.9F)
|
||||
)
|
||||
)
|
||||
|
||||
battleidle = registerPose(
|
||||
poseName = "battle_idle",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.FLOAT,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { it.isBattling },
|
||||
transformedParts = arrayOf(
|
||||
scalchop.createTransformation().withVisibility(visibility = true),
|
||||
scalchopbody.createTransformation().withVisibility(visibility = false)
|
||||
),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("oshawott_hisui_bias", "ground_idle")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
-112
@@ -1,112 +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.pokemon.PokemonPosableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BimanualSwingAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedWalkAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.createTransformation
|
||||
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.pose.CobblemonPose
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.ModelPartTransformation
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.isBattling
|
||||
import net.minecraft.client.model.geom.ModelPart
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
class OshawottModel (root: ModelPart) : PokemonPosableModel(root), HeadedFrame, BipedFrame, BimanualFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("oshawott")
|
||||
override val head = getPart("head")
|
||||
override val rightArm = getPart("arm_right")
|
||||
override val leftArm = getPart("arm_left")
|
||||
override val rightLeg = getPart("leg_right")
|
||||
override val leftLeg = getPart("leg_left")
|
||||
val scalchop = getPart("scalchop_hand")
|
||||
val scalchopbody = getPart("scalchop_torso")
|
||||
|
||||
override var portraitScale = 2.0F
|
||||
override var portraitTranslation = Vec3(-0.2, -0.15, 0.0)
|
||||
override var profileScale = 0.7F
|
||||
override var profileTranslation = Vec3(0.0, 0.69, 0.0)
|
||||
|
||||
lateinit var battleidle: CobblemonPose
|
||||
lateinit var sleep: CobblemonPose
|
||||
lateinit var standing: CobblemonPose
|
||||
lateinit var walk: CobblemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { bedrockStateful("oshawott", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("oshawott", "blink") }
|
||||
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
transformTicks = 10,
|
||||
transformedParts = arrayOf(
|
||||
scalchop.createTransformation().withVisibility(visibility = false),
|
||||
scalchopbody.createTransformation().withVisibility(visibility = true),
|
||||
rootPart.createTransformation().addPosition(ModelPartTransformation.Y_AXIS, -7)
|
||||
),
|
||||
animations = arrayOf(bedrock("oshawott", "sleep"))
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = setOf(PoseType.NONE, PoseType.STAND, PoseType.PORTRAIT, PoseType.PROFILE),
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { !it.isBattling },
|
||||
transformedParts = arrayOf(
|
||||
scalchop.createTransformation().withVisibility(visibility = false),
|
||||
scalchopbody.createTransformation().withVisibility(visibility = true)
|
||||
),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("oshawott", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walking",
|
||||
poseTypes = setOf(PoseType.SWIM, PoseType.WALK),
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { !it.isBattling },
|
||||
transformedParts = arrayOf(
|
||||
scalchop.createTransformation().withVisibility(visibility = false),
|
||||
scalchopbody.createTransformation().withVisibility(visibility = true)
|
||||
),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("oshawott", "ground_idle"),
|
||||
BipedWalkAnimation(this, periodMultiplier = 0.6F, amplitudeMultiplier = 0.9F),
|
||||
BimanualSwingAnimation(this, swingPeriodMultiplier = 0.6F, amplitudeMultiplier = 0.9F)
|
||||
)
|
||||
)
|
||||
|
||||
battleidle = registerPose(
|
||||
poseName = "battle_idle",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.FLOAT,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { it.isBattling },
|
||||
transformedParts = arrayOf(
|
||||
scalchop.createTransformation().withVisibility(visibility = true),
|
||||
scalchopbody.createTransformation().withVisibility(visibility = false)
|
||||
),
|
||||
animations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("oshawott", "ground_idle")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
-7
@@ -225,9 +225,7 @@ object VaryingModelRepository {
|
||||
inbuilt("butterfree", ::ButterfreeModel)
|
||||
inbuilt("weedle", ::WeedleModel)
|
||||
inbuilt("beedrill", ::BeedrillModel)
|
||||
inbuilt("rattata", ::RattataModel)
|
||||
inbuilt("raticate", ::RaticateModel)
|
||||
inbuilt("rattata_alolan", ::RattataAlolanModel)
|
||||
inbuilt("raticate_alolan", ::RaticateAlolanModel)
|
||||
inbuilt("krabby", ::KrabbyModel)
|
||||
inbuilt("paras", ::ParasModel)
|
||||
@@ -358,8 +356,6 @@ object VaryingModelRepository {
|
||||
inbuilt("grookey", ::GrookeyModel)
|
||||
inbuilt("thwackey", ::ThwackeyModel)
|
||||
inbuilt("rillaboom", ::RillaboomModel)
|
||||
inbuilt("oshawott", ::OshawottModel)
|
||||
inbuilt("dewott", ::DewottModel)
|
||||
inbuilt("samurott", ::SamurottModel)
|
||||
inbuilt("snivy", ::SnivyModel)
|
||||
inbuilt("servine", ::ServineModel)
|
||||
@@ -521,7 +517,6 @@ object VaryingModelRepository {
|
||||
inbuilt("lilligant", ::LilligantModel)
|
||||
inbuilt("petilil_hisui_bias", ::PetililHisuiBiasModel)
|
||||
inbuilt("lilligant_hisuian", ::LilligantHisuianModel)
|
||||
inbuilt("darumaka", ::DarumakaModel)
|
||||
inbuilt("cufant", ::CufantModel)
|
||||
inbuilt("copperajah", ::CopperajahModel)
|
||||
inbuilt("budew", ::BudewModel)
|
||||
@@ -553,8 +548,6 @@ object VaryingModelRepository {
|
||||
inbuilt("morgrem", ::MorgremModel)
|
||||
inbuilt("grimmsnarl", ::GrimmsnarlModel)
|
||||
inbuilt("klefki", ::KlefkiModel)
|
||||
inbuilt("oshawott_hisui_bias", ::OshawottHisuiBiasModel)
|
||||
inbuilt("dewott_hisui_bias", ::DewottHisuiBiasModel)
|
||||
inbuilt("samurott_hisuian", ::SamurottHisuianModel)
|
||||
inbuilt("cyndaquil_hisui_bias", ::CyndaquilHisuiBiasModel)
|
||||
inbuilt("quilava_hisui_bias", ::QuilavaHisuiBiasModel)
|
||||
|
||||
+3
-2
@@ -48,11 +48,12 @@ fun updateEyeTrail(
|
||||
entityPos: Vec3,
|
||||
trailPositions: MutableMap<String, ArrayDeque<Pair<Vec3, Long>>>
|
||||
) {
|
||||
if ("alpha_eyes" !in aspects) {
|
||||
val locators = locatorStates.keys.filter { "eye" in it.lowercase() }
|
||||
if ("alpha_eyes" !in aspects || locators.isEmpty()) {
|
||||
trailPositions.clear()
|
||||
return
|
||||
}
|
||||
for (locatorName in locatorStates.keys.filter { "eye" in it.lowercase() }) {
|
||||
for (locatorName in locators) {
|
||||
val wrapper = locatorStates[locatorName] ?: continue
|
||||
val pos = wrapper.matrix.getTranslation(Vector3f())
|
||||
val worldPos = Vec3(
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.api.text.underline
|
||||
import com.cobblemon.mod.common.api.text.yellow
|
||||
import com.cobblemon.mod.common.command.argument.SpawnBucketArgumentType
|
||||
import com.cobblemon.mod.common.duck.ServerLevelDuck
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.cobblemon.mod.common.util.permission
|
||||
import com.cobblemon.mod.common.util.spawner
|
||||
@@ -54,7 +55,8 @@ object CheckSpawnsCommand {
|
||||
}
|
||||
|
||||
private fun execute(context: CommandContext<CommandSourceStack>, player: ServerPlayer) : Int {
|
||||
if (!config.enableSpawning) {
|
||||
if (!config.enableSpawning ||
|
||||
(player.serverLevel() as ServerLevelDuck).`cobblemon$getLevelResourceLocation`() in config.worldSpawningBlocklist) {
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
@@ -91,6 +91,9 @@ class CobblemonConfig {
|
||||
@CobblemonConfigField(Category.Spawning, lang = "enable_spawning", SERVER)
|
||||
var enableSpawning = true
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "world_spawning_blocklist", SERVER)
|
||||
var worldSpawningBlocklist = mutableSetOf<ResourceLocation>()
|
||||
|
||||
@CobblemonConfigField(Category.Spawning, lang = "minimum_distance_between_entities", SERVER)
|
||||
var minimumDistanceBetweenEntities = 8.0
|
||||
|
||||
|
||||
@@ -16,16 +16,18 @@ data class StarterCategory(
|
||||
val name: String,
|
||||
val order: Int = 0, // fallback for old behavior
|
||||
val displayName: String,
|
||||
val pokemon: List<PokemonProperties>
|
||||
val pokemon: List<PokemonProperties>,
|
||||
val randomStarter: Boolean = false // Decides if includes random starter
|
||||
) {
|
||||
fun asRenderableStarterCategory() = RenderableStarterCategory(name, order, displayName, pokemon.map { it.asRenderablePokemon() })
|
||||
fun asRenderableStarterCategory() = RenderableStarterCategory(name, order, displayName, pokemon.map { it.asRenderablePokemon() }, randomStarter)
|
||||
}
|
||||
|
||||
data class RenderableStarterCategory(
|
||||
val name: String,
|
||||
val order: Int = 0, // fallback for old behavior
|
||||
val displayName: String,
|
||||
val pokemon: List<RenderablePokemon>
|
||||
val pokemon: List<RenderablePokemon>,
|
||||
val randomStarter: Boolean = false
|
||||
) {
|
||||
val displayNameText = displayName.asTranslated()
|
||||
}
|
||||
|
||||
@@ -144,7 +144,8 @@ class StarterConfig {
|
||||
pokemon = mutableListOf(
|
||||
PokemonProperties.parse("Pikachu level=10"),
|
||||
PokemonProperties.parse("Eevee level=10")
|
||||
)
|
||||
),
|
||||
randomStarter = true
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
+1
-1
@@ -368,7 +368,7 @@ class PokemonServerDelegate : PokemonSideDelegate {
|
||||
?: entity.mainHandItem
|
||||
}.copy()
|
||||
/* Hide items tagged as hidden (If the item is in this list, it will not render) */
|
||||
.let { if (it.`is`(CobblemonItemTags.HIDDEN_ITEMS)) ItemStack.EMPTY else it}
|
||||
.let { if (it.`is`(CobblemonItemTags.HIDDEN_ITEMS) || (entity.pokemon.isAlpha && entity.pokemon.isWild())) ItemStack.EMPTY else it}
|
||||
|
||||
entity.entityData.set(PokemonEntity.SHOWN_HELD_ITEM, trackedShownItem)
|
||||
}
|
||||
|
||||
+5
-5
@@ -67,11 +67,11 @@ class AlphaLevelMatchingSensor : Sensor<PokemonEntity>(20) {
|
||||
val strongestPartyLevel = player.party().maxOfOrNull { it.level } ?: return null
|
||||
val minEvolutionLevel = minimumEvolutionLevel(pokemon)
|
||||
return when {
|
||||
strongestPartyLevel < 20 -> strongestPartyLevel + 5
|
||||
strongestPartyLevel in 31..40 -> strongestPartyLevel + 10
|
||||
strongestPartyLevel in 51..65 -> strongestPartyLevel + 15
|
||||
strongestPartyLevel >= 66 -> strongestPartyLevel + 20
|
||||
else -> strongestPartyLevel
|
||||
strongestPartyLevel < 21 -> strongestPartyLevel + 4
|
||||
strongestPartyLevel in 21..30 -> strongestPartyLevel + 8
|
||||
strongestPartyLevel in 31..45 -> strongestPartyLevel + 12
|
||||
strongestPartyLevel in 46..65 -> strongestPartyLevel + 16
|
||||
else -> strongestPartyLevel + 20
|
||||
}.coerceAtMost(100).coerceAtLeast(minEvolutionLevel)
|
||||
}
|
||||
|
||||
|
||||
@@ -133,6 +133,7 @@ object AdvancementHandler : EventHandler {
|
||||
}
|
||||
Cobblemon.playerDataManager.saveSingle(playerData, PlayerInstancedDataStoreTypes.GENERAL)
|
||||
CobblemonCriteria.DEFEAT_POKEMON.trigger(player, CountableContext(advancementData.totalBattleVictoryCount))
|
||||
playerData.sendToPlayer(player)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,6 +151,7 @@ object AdvancementHandler : EventHandler {
|
||||
advancementData.updateTotalPvNBattleVictoryCount()
|
||||
Cobblemon.playerDataManager.saveSingle(playerData, PlayerInstancedDataStoreTypes.GENERAL)
|
||||
CobblemonCriteria.WIN_BATTLE.trigger(player, BattleCountableContext(event.battle, advancementData.totalBattleVictoryCount))
|
||||
playerData.sendToPlayer(player)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.cobblemon.mod.common.CobblemonCallbacks
|
||||
import com.cobblemon.mod.common.api.Priority
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.asMoLangValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.moLangFunctionMap
|
||||
import com.cobblemon.mod.common.platform.events.PlatformEvents
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
|
||||
@@ -23,7 +24,7 @@ object CallbackHandler {
|
||||
fun setup() {
|
||||
CobblemonEvents.STARTER_CHOSEN.subscribe { CobblemonCallbacks.run(cobblemonResource("starter_chosen"), it.getContext(), it.functions) }
|
||||
CobblemonEvents.POKEMON_CAPTURED.subscribe { CobblemonCallbacks.run(cobblemonResource("pokemon_captured"), it.context) }
|
||||
CobblemonEvents.POKEMON_ENTITY_SPAWN.subscribe { CobblemonCallbacks.run(cobblemonResource("pokemon_entity_spawn"), mutableMapOf<String, MoValue>("pokemon_entity" to it.entity.asMoLangValue())) }
|
||||
CobblemonEvents.POKEMON_ENTITY_SPAWN.subscribe { entity -> CobblemonCallbacks.run(cobblemonResource("pokemon_entity_spawn"), mutableMapOf<String, MoValue>("pokemon_entity" to entity.entity.asMoLangValue()), functions = moLangFunctionMap("pokemon" to { entity.entity.pokemon.struct })) }
|
||||
CobblemonEvents.BATTLE_VICTORY.subscribe { CobblemonCallbacks.run(cobblemonResource("battle_victory"), it.context) }
|
||||
CobblemonEvents.POKEDEX_DATA_CHANGED_PRE.subscribe { CobblemonCallbacks.run(cobblemonResource("pokedex_data_changed_pre"), it.getContext(), it.functions) }
|
||||
CobblemonEvents.POKEDEX_DATA_CHANGED_POST.subscribe { CobblemonCallbacks.run(cobblemonResource("pokedex_data_changed_post"), it.getContext()) }
|
||||
|
||||
@@ -8,16 +8,14 @@
|
||||
|
||||
package com.cobblemon.mod.common.integration
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import juuxel.adorn.block.variant.BlockVariant
|
||||
import juuxel.adorn.block.variant.CompatBlockVariantSet
|
||||
import juuxel.adorn.block.variant.BlockVariantSet
|
||||
|
||||
class AdornCompatibility : CompatBlockVariantSet() {
|
||||
class AdornCompatibility: BlockVariantSet {
|
||||
override fun getWoodVariants(): List<BlockVariant?>? {
|
||||
return this.createVariants({ BlockVariant.Wood(it) }, "apricorn", "saccharine")
|
||||
}
|
||||
|
||||
override fun getModId(): String? {
|
||||
return Cobblemon.MODID
|
||||
val result: MutableList<BlockVariant> = mutableListOf()
|
||||
result.add(BlockVariant.Wood("cobblemon/apricorn"))
|
||||
result.add(BlockVariant.Wood("cobblemon/saccharine"))
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -23,23 +23,23 @@ import net.minecraft.network.codec.ByteBufCodecs
|
||||
import net.minecraft.network.codec.StreamCodec
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
||||
data class TMMoveComponent(val move: MoveTemplate) {
|
||||
data class TMMoveComponent(val moveName: String) {
|
||||
companion object {
|
||||
// Codec to serialize/deserialize TMMoveComponent
|
||||
val CODEC: Codec<TMMoveComponent> = RecordCodecBuilder.create { instance ->
|
||||
instance.group(
|
||||
Codec.STRING.fieldOf("move").forGetter { it.move.name } // Serialize the move's name
|
||||
).apply(instance) { moveName -> TMMoveComponent(Moves.getByNameOrDummy(moveName)) }
|
||||
Codec.STRING.fieldOf("move").forGetter { it.moveName } // Serialize the move's name
|
||||
).apply(instance) { moveName -> TMMoveComponent(moveName) }
|
||||
}
|
||||
|
||||
val PACKET_CODEC: StreamCodec<ByteBuf, TMMoveComponent> = ByteBufCodecs.fromCodec(CODEC)
|
||||
|
||||
fun getTMMove(stack: ItemStack): MoveTemplate? {
|
||||
return stack.get(CobblemonItemComponents.TM_MOVE)?.move
|
||||
return stack.get(CobblemonItemComponents.TM_MOVE)?.moveName?.let(Moves::getByNameOrDummy)
|
||||
}
|
||||
|
||||
fun setTMMove(stack: ItemStack, move: MoveTemplate): ItemStack {
|
||||
stack.set(CobblemonItemComponents.TM_MOVE, TMMoveComponent(move))
|
||||
stack.set(CobblemonItemComponents.TM_MOVE, TMMoveComponent(move.name))
|
||||
return stack
|
||||
}
|
||||
|
||||
@@ -58,4 +58,9 @@ data class TMMoveComponent(val move: MoveTemplate) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
constructor(move: TMMoveComponent): this(move.moveName)
|
||||
|
||||
val move: MoveTemplate
|
||||
get() = Moves.getByNameOrDummy(moveName)
|
||||
}
|
||||
|
||||
+5
-6
@@ -13,8 +13,10 @@ import com.cobblemon.mod.common.api.pokeball.PokeBalls
|
||||
import com.cobblemon.mod.common.net.messages.client.pokemon.update.SingleUpdatePacket
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.readMap
|
||||
import com.cobblemon.mod.common.util.readIdentifier
|
||||
import com.cobblemon.mod.common.util.readString
|
||||
import com.cobblemon.mod.common.util.writeMap
|
||||
import com.cobblemon.mod.common.util.writeString
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
|
||||
@@ -25,9 +27,8 @@ import net.minecraft.network.RegistryFriendlyByteBuf
|
||||
* @since March 31st, 2026
|
||||
*/
|
||||
class ClientboundSeatAssignmentPacket(
|
||||
val passengerEntityId: Int,
|
||||
val vehicleEntityId: Int,
|
||||
val seatLocator: String
|
||||
val seatAssignments: Map<String, Int>
|
||||
) : NetworkPacket<ClientboundSeatAssignmentPacket> {
|
||||
override val id = ID
|
||||
|
||||
@@ -35,14 +36,12 @@ class ClientboundSeatAssignmentPacket(
|
||||
val ID = cobblemonResource("seat_assignment")
|
||||
fun decode(buffer: RegistryFriendlyByteBuf) = ClientboundSeatAssignmentPacket(
|
||||
buffer.readInt(),
|
||||
buffer.readInt(),
|
||||
buffer.readString()
|
||||
buffer.readMap({ buffer.readString() }, { buffer.readInt() })
|
||||
)
|
||||
}
|
||||
|
||||
override fun encode(buffer: RegistryFriendlyByteBuf) {
|
||||
buffer.writeInt(passengerEntityId)
|
||||
buffer.writeInt(vehicleEntityId)
|
||||
buffer.writeString(seatLocator)
|
||||
buffer.writeMap(seatAssignments, { _, locator -> buffer.writeString(locator) }, { _, entityId -> buffer.writeInt(entityId) })
|
||||
}
|
||||
}
|
||||
|
||||
+4
-1
@@ -31,6 +31,7 @@ class OpenStarterUIPacket internal constructor(val categories: List<RenderableSt
|
||||
buffer.writeInt(category.order)
|
||||
buffer.writeInt(category.pokemon.size)
|
||||
category.pokemon.forEach { it.saveToBuffer(buffer) }
|
||||
buffer.writeBoolean(category.randomStarter)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,12 +49,14 @@ class OpenStarterUIPacket internal constructor(val categories: List<RenderableSt
|
||||
repeat(numProperties) {
|
||||
renderablePokemon.add(RenderablePokemon.loadFromBuffer(buffer))
|
||||
}
|
||||
val randomStarter = buffer.readBoolean()
|
||||
categories.add(
|
||||
RenderableStarterCategory(
|
||||
name = name,
|
||||
order = order,
|
||||
displayName = displayName,
|
||||
pokemon = renderablePokemon
|
||||
pokemon = renderablePokemon,
|
||||
randomStarter = randomStarter
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1731,12 +1731,22 @@ open class Pokemon : ShowdownIdentifiable {
|
||||
}
|
||||
|
||||
if (reassess) {
|
||||
gender = if (form.maleRatio !in 0F..1F) {
|
||||
Gender.GENDERLESS
|
||||
} else if (form.maleRatio == 1F || Random.nextFloat() <= form.maleRatio) {
|
||||
Gender.MALE
|
||||
val allForms = form.species.forms
|
||||
val isGenderedForms = allForms.any { it.maleRatio == 1F } && allForms.any { it.maleRatio == 0F }
|
||||
gender = if (isGenderedForms) {
|
||||
if (Random.nextBoolean()) {
|
||||
Gender.FEMALE
|
||||
} else {
|
||||
Gender.MALE
|
||||
}
|
||||
} else {
|
||||
Gender.FEMALE
|
||||
if (form.maleRatio !in 0F..1F) {
|
||||
Gender.GENDERLESS
|
||||
} else if (form.maleRatio == 1F || Random.nextFloat() <= form.maleRatio) {
|
||||
Gender.MALE
|
||||
} else {
|
||||
Gender.FEMALE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.advancement.CobblemonCriteria
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.starter.StarterChosenEvent
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonProperties
|
||||
import com.cobblemon.mod.common.api.starter.StarterHandler
|
||||
import com.cobblemon.mod.common.api.storage.player.PlayerInstancedDataStoreTypes
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
@@ -21,6 +22,7 @@ import com.cobblemon.mod.common.net.messages.client.starter.OpenStarterUIPacket
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import com.cobblemon.mod.common.world.gamerules.CobblemonGameRules
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import kotlin.random.Random
|
||||
|
||||
open class CobblemonStarterHandler : StarterHandler {
|
||||
|
||||
@@ -55,11 +57,15 @@ open class CobblemonStarterHandler : StarterHandler {
|
||||
|
||||
val category = getStarterList(player).find { it.name == categoryName } ?: return
|
||||
|
||||
if (index < 0 || index >= category.pokemon.size) {
|
||||
if (index < 0 || index > category.pokemon.size) {
|
||||
return
|
||||
}
|
||||
val properties = if (index == category.pokemon.size) { // means random
|
||||
getStarterList(player).flatMap { it.pokemon }.random()
|
||||
} else {
|
||||
category.pokemon[index]
|
||||
}
|
||||
|
||||
val properties = category.pokemon[index]
|
||||
val pokemon = properties.create(player)
|
||||
|
||||
CobblemonEvents.STARTER_CHOSEN.postThen(StarterChosenEvent(player, properties, pokemon)) {
|
||||
|
||||
+3
@@ -97,6 +97,8 @@ object CobblemonPlacedFeatures {
|
||||
val STRANGE_WARPED_FUNGAL_DWELLINGS = of("habitats/strange_warped_fungal_dwellings")
|
||||
@JvmField
|
||||
val VOLCANIC_PLUMES = of("habitats/volcanic_plumes")
|
||||
@JvmField
|
||||
val ROCKY_OUTCROPS = of("habitats/rocky_outcrops")
|
||||
|
||||
@JvmField
|
||||
val PREHISTORIC_BIRCH_TREE = of("fossils/prehistoric_birch_tree")
|
||||
@@ -208,6 +210,7 @@ object CobblemonPlacedFeatures {
|
||||
Cobblemon.implementation.addFeatureToWorldGen(CRUMBLING_ARCH, GenerationStep.Decoration.UNDERGROUND_DECORATION, BiomeTags.IS_OVERWORLD)
|
||||
Cobblemon.implementation.addFeatureToWorldGen(DEEP_CRYPT, GenerationStep.Decoration.UNDERGROUND_DECORATION, CobblemonBiomeTags.IS_DEEP_DARK)
|
||||
Cobblemon.implementation.addFeatureToWorldGen(ROOTED_ARCH, GenerationStep.Decoration.UNDERGROUND_DECORATION, CobblemonBiomeTags.IS_LUSH)
|
||||
Cobblemon.implementation.addFeatureToWorldGen(ROCKY_OUTCROPS, GenerationStep.Decoration.UNDERGROUND_DECORATION, CobblemonBiomeTags.IS_MOUNTAIN)
|
||||
}
|
||||
|
||||
private fun of(id: String): ResourceKey<PlacedFeature> = ResourceKey.create(Registries.PLACED_FEATURE, cobblemonResource(id))
|
||||
|
||||
+14
-29
@@ -17,33 +17,33 @@ import net.minecraft.world.level.LevelHeightAccessor
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator
|
||||
import net.minecraft.world.level.levelgen.Heightmap
|
||||
import net.minecraft.world.level.levelgen.RandomState
|
||||
import net.minecraft.world.level.levelgen.structure.BoundingBox
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessor
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate
|
||||
|
||||
/**
|
||||
* Restricts the height range a structure piece is allowed to generate in, relative to a [HeightReference].
|
||||
*
|
||||
* The range is enforced while the structure start is still being built,
|
||||
* by `StructureMixin`, which gets rid of the entire start when any piece falls outside of its range. Voiding
|
||||
* blocks here instead would run after terrain adaptation has already deformed the terrain, leaving behind
|
||||
* random pockets of land and the `/locate` command would incorrectly find a structure that was never placed.
|
||||
*/
|
||||
class HeightRangeStructureProcessor(
|
||||
val minOffset: Int,
|
||||
val maxOffset: Int,
|
||||
val reference: HeightReference = HeightReference.SEA_LEVEL
|
||||
) : StructureProcessor() {
|
||||
|
||||
fun isValidPlacement(world: LevelReader, pos: BlockPos): Boolean {
|
||||
val referenceY = reference.getY(world, pos)
|
||||
val minY = referenceY + minOffset
|
||||
val maxY = referenceY + maxOffset
|
||||
return pos.y in minY..maxY
|
||||
}
|
||||
|
||||
fun isValidPlacement(
|
||||
chunkGenerator: ChunkGenerator,
|
||||
heightAccessor: LevelHeightAccessor,
|
||||
randomState: RandomState,
|
||||
pos: BlockPos
|
||||
box: BoundingBox
|
||||
): Boolean {
|
||||
val referenceY = reference.getY(chunkGenerator, heightAccessor, randomState, pos)
|
||||
val minY = referenceY + minOffset
|
||||
val maxY = referenceY + maxOffset
|
||||
return pos.y in minY..maxY
|
||||
val referenceY = reference.getY(chunkGenerator, heightAccessor, randomState, box.center)
|
||||
return box.minY() in (referenceY + minOffset)..(referenceY + maxOffset)
|
||||
}
|
||||
|
||||
override fun processBlock(
|
||||
@@ -53,13 +53,7 @@ class HeightRangeStructureProcessor(
|
||||
originalBlockInfo: StructureTemplate.StructureBlockInfo,
|
||||
currentBlockInfo: StructureTemplate.StructureBlockInfo,
|
||||
data: StructurePlaceSettings
|
||||
): StructureTemplate.StructureBlockInfo? {
|
||||
return if (isValidPlacement(world, pos)) {
|
||||
currentBlockInfo
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
): StructureTemplate.StructureBlockInfo = currentBlockInfo
|
||||
|
||||
override fun getType() = CobblemonProcessorTypes.HEIGHT_RANGE
|
||||
|
||||
@@ -74,15 +68,6 @@ class HeightRangeStructureProcessor(
|
||||
|
||||
fun getSerializedName(): String = id
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
fun getY(world: LevelReader, pos: BlockPos): Int {
|
||||
return if (this == SEA_LEVEL) {
|
||||
world.seaLevel
|
||||
} else {
|
||||
world.getHeight(type ?: Heightmap.Types.WORLD_SURFACE_WG, pos.x, pos.z)
|
||||
}
|
||||
}
|
||||
|
||||
fun getY(
|
||||
chunkGenerator: ChunkGenerator,
|
||||
heightAccessor: LevelHeightAccessor,
|
||||
@@ -113,4 +98,4 @@ class HeightRangeStructureProcessor(
|
||||
).apply(instance, ::HeightRangeStructureProcessor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-1
@@ -390,6 +390,14 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.rattata.cry": {
|
||||
"animation_length": 1,
|
||||
"sound_effects": {
|
||||
"0.0417": {
|
||||
"effect": "pokemon.rattata.cry"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
-8
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"format_version": "1.8.0",
|
||||
"animations": {
|
||||
"animation.rattata.ground_idle": {
|
||||
"animation.rattata_alolan.ground_idle": {
|
||||
"loop": true,
|
||||
"animation_length": 21.375,
|
||||
"bones": {
|
||||
@@ -55,7 +55,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.rattata.ground_walk": {
|
||||
"animation.rattata_alolan.ground_walk": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
@@ -124,7 +124,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.rattata.faint": {
|
||||
"animation.rattata_alolan.faint": {
|
||||
"animation_length": 3,
|
||||
"bones": {
|
||||
"body": {
|
||||
@@ -311,7 +311,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.rattata.mouth_open": {
|
||||
"animation.rattata_alolan.mouth_open": {
|
||||
"animation_length": 1.25,
|
||||
"bones": {
|
||||
"jaw": {
|
||||
@@ -333,7 +333,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.rattata.sleep": {
|
||||
"animation.rattata_alolan.sleep": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"body": {
|
||||
@@ -390,7 +390,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.rattata.blink": {
|
||||
"animation.rattata_alolan.blink": {
|
||||
"animation_length": 0.1667,
|
||||
"bones": {
|
||||
"eyelid_right": {
|
||||
@@ -407,7 +407,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.rattata.blink2": {
|
||||
"animation.rattata_alolan.blink2": {
|
||||
"animation_length": 0.16667,
|
||||
"bones": {
|
||||
"eyelid_right": {
|
||||
@@ -425,6 +425,14 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.rattata_alolan.cry": {
|
||||
"animation_length": 1,
|
||||
"sound_effects": {
|
||||
"0.0417": {
|
||||
"effect": "pokemon.rattata_alolan.cry"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -42,7 +42,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.sandshrew.cry": {
|
||||
"animation.sandshrew_alolan.cry": {
|
||||
"animation_length": 1.2,
|
||||
"sound_effects": {
|
||||
"0.04": {
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.sandslash.cry": {
|
||||
"animation.sandslash_alolan.cry": {
|
||||
"animation_length": 1.2,
|
||||
"sound_effects": {
|
||||
"0.04": {
|
||||
|
||||
+9
-1
@@ -679,6 +679,14 @@
|
||||
"position": [0, -1, 0]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.wigglytuff.cry": {
|
||||
"animation_length": 1.25,
|
||||
"sound_effects": {
|
||||
"0.0417": {
|
||||
"effect": "pokemon.wigglytuff.cry"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -2630,7 +2630,7 @@
|
||||
"0.5": [-7.69971, -17.84044, 12.03862]
|
||||
}
|
||||
},
|
||||
"locator_seat1": {
|
||||
"locator_seat_1": {
|
||||
"rotation": ["-2.5-math.sin(q.anim_time*90*8*2)*7", 0, 0]
|
||||
},
|
||||
"chest_fluff_left": {
|
||||
|
||||
+6
-6
@@ -59,7 +59,7 @@
|
||||
"rotation": [0, 0, 0],
|
||||
"position": [0, "0-math.sin(q.anim_time*90*3/2)*0.2", 0]
|
||||
},
|
||||
"locator_seat1": {
|
||||
"locator_seat_1": {
|
||||
"rotation": ["-15+math.cos(q.anim_time*90*3/2)*1", 0, 0]
|
||||
}
|
||||
}
|
||||
@@ -123,7 +123,7 @@
|
||||
"rotation": [7.5, 0, 0],
|
||||
"position": [0, "0-math.sin(q.anim_time*90*2)*0.2", 0]
|
||||
},
|
||||
"locator_seat1": {
|
||||
"locator_seat_1": {
|
||||
"rotation": ["-37.5+math.cos(q.anim_time*90*2)*1", 0, 0]
|
||||
}
|
||||
}
|
||||
@@ -482,7 +482,7 @@
|
||||
"thorax": {
|
||||
"rotation": [0, "0+math.cos(q.anim_time*90*3-120)*4", "0+math.cos(q.anim_time*90*3-120)*3"]
|
||||
},
|
||||
"locator_seat1": {
|
||||
"locator_seat_1": {
|
||||
"rotation": ["-12.5+math.cos(q.anim_time*90*3*2)*3", "0-math.cos(q.anim_time*90*3-180)*6", "0-math.cos(q.anim_time*90*3)*6"]
|
||||
}
|
||||
}
|
||||
@@ -1532,7 +1532,7 @@
|
||||
"thorax": {
|
||||
"rotation": ["22.5-math.cos(q.anim_time*90*9*2-120)*1/2", "0+math.sin(q.anim_time*90*9-120)*4", "0-math.cos(q.anim_time*90*9-60)*4"]
|
||||
},
|
||||
"locator_seat1": {
|
||||
"locator_seat_1": {
|
||||
"rotation": ["-17.5+math.cos(q.anim_time*90*9*2)*4", "0+math.cos(q.anim_time*90*9-60)*4", 0]
|
||||
}
|
||||
}
|
||||
@@ -1647,7 +1647,7 @@
|
||||
"thorax": {
|
||||
"rotation": ["5-math.sin(q.anim_time*90*20)*2-q.r.velocity_y(2)*15", 0, 0]
|
||||
},
|
||||
"locator_seat1": {
|
||||
"locator_seat_1": {
|
||||
"rotation": ["-7.5+q.r.velocity_y(2)*15", 0, 0]
|
||||
}
|
||||
}
|
||||
@@ -1867,7 +1867,7 @@
|
||||
"thorax": {
|
||||
"rotation": ["-37.5-math.cos(q.anim_time*90*3/2-60)*0.5", "0-math.cos(q.anim_time*90*3/2/2-60)*2", 0]
|
||||
},
|
||||
"locator_seat1": {
|
||||
"locator_seat_1": {
|
||||
"rotation": [-12.5, 0, 0]
|
||||
}
|
||||
}
|
||||
|
||||
+271
@@ -70,6 +70,201 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.lanturn.ground_walk": {
|
||||
"loop": true,
|
||||
"animation_length": 1.33333,
|
||||
"bones": {
|
||||
"torso": {
|
||||
"rotation": ["18.5323-1*math.cos(q.anim_time*90*6+30)*-1", "8*math.cos(q.anim_time*90*3+30)*1", "2*math.cos(q.anim_time*90*3+30)*1"],
|
||||
"position": [0, "-0.1+0.3*math.sin(q.anim_time*90*6+30)*1", 0]
|
||||
},
|
||||
"arm_left": {
|
||||
"rotation": {
|
||||
"0.0": [27.13972, 17.81489, 54.80802],
|
||||
"0.5": [-9.78627, -11.33853, 53.65617],
|
||||
"0.6667": {
|
||||
"pre": [-11.47, -13.08, 42.11],
|
||||
"post": [-11.47, -13.08, 42.11],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.8333": {
|
||||
"post": [-8.23014, -10.8395, 27.91971],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.9583": {
|
||||
"post": [-3.82491, -6.18459, 13.68449],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.125": {
|
||||
"post": [0.38257, 5.03012, 2.61807],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.3333": [27.13972, 17.81489, 54.80802]
|
||||
},
|
||||
"position": {
|
||||
"0.0": [0.6, -0.2, -0.3],
|
||||
"0.25": [-0.56, -0.2, -0.7],
|
||||
"0.5": [-0.63, -0.2, -0.9],
|
||||
"0.6667": [-0.51, -0.2, -0.65],
|
||||
"0.8333": [-0.4, -0.2, -0.4],
|
||||
"1.3333": [0.6, -0.2, -0.3]
|
||||
}
|
||||
},
|
||||
"arm_left2": {
|
||||
"rotation": {
|
||||
"0.0": [0, 0, -51],
|
||||
"0.25": {
|
||||
"pre": [0, 0, -53.5],
|
||||
"post": [0, 0, -53.5],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.5": {
|
||||
"post": [0, 0, -48.55],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.6667": {
|
||||
"post": [0, 0, -31.44],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.9167": {
|
||||
"post": [0, 0, 6.71],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.0417": {
|
||||
"post": [0, 0, 25.7],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.125": {
|
||||
"post": [0, 0, 4.89],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.25": {
|
||||
"post": [0, 0, -48.1],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.3333": [0, 0, -51]
|
||||
}
|
||||
},
|
||||
"arm_right": {
|
||||
"rotation": {
|
||||
"0.0": {
|
||||
"post": [-11.47, 13.08, -42.11],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.1667": {
|
||||
"post": [-8.23014, 10.8395, -27.91971],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.2917": {
|
||||
"post": [-3.82491, 6.18459, -13.68449],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.4583": {
|
||||
"post": [0.38257, -5.03012, -2.61807],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.6667": [27.13972, -17.81489, -54.80802],
|
||||
"1.1667": [-9.78627, 11.33853, -53.65617],
|
||||
"1.3333": [-11.47, 13.08, -42.11]
|
||||
},
|
||||
"position": {
|
||||
"0.0": [0.51, -0.2, -0.65],
|
||||
"0.1667": [0.4, -0.2, -0.4],
|
||||
"0.6667": [-0.6, -0.2, -0.3],
|
||||
"0.9167": [0.56, -0.2, -0.7],
|
||||
"1.1667": [0.63, -0.2, -0.9],
|
||||
"1.3333": [0.51, -0.2, -0.65]
|
||||
}
|
||||
},
|
||||
"arm_right2": {
|
||||
"rotation": {
|
||||
"0.0": {
|
||||
"post": [0, 0, 31.44],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.25": {
|
||||
"post": [0, 0, -6.71],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.375": {
|
||||
"post": [0, 0, -25.7],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.4583": {
|
||||
"post": [0, 0, -4.89],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.5833": {
|
||||
"post": [0, 0, 48.1],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.6667": [0, 0, 51],
|
||||
"0.9167": {
|
||||
"pre": [0, 0, 53.5],
|
||||
"post": [0, 0, 53.5],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.1667": {
|
||||
"post": [0, 0, 48.55],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.3333": {
|
||||
"post": [0, 0, 31.44],
|
||||
"lerp_mode": "catmullrom"
|
||||
}
|
||||
}
|
||||
},
|
||||
"head": {
|
||||
"rotation": ["-13.4677-1*math.cos(q.anim_time*90*6+30)*-1", "8*math.cos(q.anim_time*90*3+40)*-1", 0]
|
||||
},
|
||||
"stem": {
|
||||
"rotation": ["-0.5*math.sin(q.anim_time*90*6-30)*1", "1-5*math.sin(q.anim_time*90*3-150)*1", "1*math.sin(q.anim_time*90*6-10)*1"]
|
||||
},
|
||||
"stem2": {
|
||||
"rotation": ["50-0.5*math.sin(q.anim_time*90*6-40)*1", 0, 0]
|
||||
},
|
||||
"stem3": {
|
||||
"rotation": ["35-0.5*math.sin(q.anim_time*90*6-80)*1", 0, 0]
|
||||
},
|
||||
"stem4": {
|
||||
"rotation": ["30-1*math.sin(q.anim_time*90*6-100)*1", 0, 0]
|
||||
},
|
||||
"stem5": {
|
||||
"rotation": ["30-0.5*math.sin(q.anim_time*90*6-90)*1", 0, 0]
|
||||
},
|
||||
"stem6": {
|
||||
"rotation": ["30-3*math.sin(q.anim_time*90*6-150)*1", 0, 0]
|
||||
},
|
||||
"stem7": {
|
||||
"rotation": ["-65.75+5*math.sin(q.anim_time*90*6-50)*1", 0, 0],
|
||||
"position": [0, -0.9, 0]
|
||||
},
|
||||
"stem8": {
|
||||
"rotation": ["-30.75+1*math.sin(q.anim_time*90*6-70)*1", 0, 0]
|
||||
},
|
||||
"stem9": {
|
||||
"rotation": ["-25+1*math.sin(q.anim_time*90*6-100)*1", 0, 0]
|
||||
},
|
||||
"stem10": {
|
||||
"rotation": ["-22.5+5*math.sin(q.anim_time*90*6-120)*1", 0, 0]
|
||||
},
|
||||
"tail": {
|
||||
"rotation": [-20, "5*math.cos(q.anim_time*90*3+50)*-1", 0]
|
||||
},
|
||||
"tail2": {
|
||||
"rotation": [7.5, "5*math.cos(q.anim_time*90*3+70)*-1", 0]
|
||||
},
|
||||
"tail3": {
|
||||
"rotation": [7.5, "5*math.cos(q.anim_time*90*3+90)*-1", 0]
|
||||
},
|
||||
"tail4": {
|
||||
"rotation": [10, "7*math.cos(q.anim_time*90*3+120)*-1", 0]
|
||||
},
|
||||
"body": {
|
||||
"rotation": [0, "8*math.cos(q.anim_time*90*3)*1", 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.lanturn.ground_battle_idle": {
|
||||
"loop": true,
|
||||
"animation_length": 2.66667,
|
||||
@@ -1163,6 +1358,82 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.lanturn.sleep": {
|
||||
"loop": true,
|
||||
"bones": {
|
||||
"torso": {
|
||||
"rotation": ["20+0.5*math.sin(q.anim_time*90*1+170)*1", 0, 0],
|
||||
"position": [0, "-0.3+0.2*math.sin(q.anim_time*90*1-20)*1", 0]
|
||||
},
|
||||
"arm_left": {
|
||||
"rotation": [0, "-0.5-0.5*math.sin(q.anim_time*90*1-20)*1", 58.5],
|
||||
"position": [0, "0.2-0.2*math.sin(q.anim_time*90*1-20)*1", 0]
|
||||
},
|
||||
"arm_left2": {
|
||||
"rotation": [0, 0, -58]
|
||||
},
|
||||
"arm_right": {
|
||||
"rotation": [0, "0.5-0.5*math.sin(q.anim_time*90*1-20)*-1", -58.5],
|
||||
"position": [0, "0.2-0.2*math.sin(q.anim_time*90*1-20)*1", 0]
|
||||
},
|
||||
"arm_right2": {
|
||||
"rotation": [0, 0, 58]
|
||||
},
|
||||
"head": {
|
||||
"rotation": ["1-1*math.sin(q.anim_time*90*1+130)*1.5", 0, 0],
|
||||
"position": [0, 0, -0.6]
|
||||
},
|
||||
"eyelid_left": {
|
||||
"position": [0.1, 0, 0]
|
||||
},
|
||||
"eyelid_right": {
|
||||
"position": [-0.1, 0, 0]
|
||||
},
|
||||
"stem": {
|
||||
"rotation": ["-3*math.sin(q.anim_time*90*1-30)*1", "1-1*math.sin(q.anim_time*90*1-90)*-1", "1*math.sin(q.anim_time*90*1-10)*1"]
|
||||
},
|
||||
"stem2": {
|
||||
"rotation": ["50-0.25*math.sin(q.anim_time*90*1-40)*1", 0, 0]
|
||||
},
|
||||
"stem3": {
|
||||
"rotation": ["35-1*math.sin(q.anim_time*90*1-80)*1", 0, 0]
|
||||
},
|
||||
"stem4": {
|
||||
"rotation": ["30-1*math.sin(q.anim_time*90*1-90)*1", 0, 0]
|
||||
},
|
||||
"stem5": {
|
||||
"rotation": ["30-1*math.sin(q.anim_time*90*1-90)*1", 0, 0]
|
||||
},
|
||||
"stem6": {
|
||||
"rotation": ["30-1*math.sin(q.anim_time*90*1-90)*1", 0, 0]
|
||||
},
|
||||
"stem7": {
|
||||
"rotation": ["-72.5+3*math.sin(q.anim_time*90*1-30)*1", 0, 0],
|
||||
"position": [0, -0.9, 0]
|
||||
},
|
||||
"stem8": {
|
||||
"rotation": ["-27.5+2*math.sin(q.anim_time*90*1-10)*1", 0, 0]
|
||||
},
|
||||
"stem9": {
|
||||
"rotation": ["-25+1*math.sin(q.anim_time*90*1-15)*1", 0, 0]
|
||||
},
|
||||
"stem10": {
|
||||
"rotation": ["-22.5+2*math.sin(q.anim_time*90*1-30)*1", 0, 0]
|
||||
},
|
||||
"tail": {
|
||||
"rotation": [-20, "0+1*math.sin(q.anim_time*90*1-30)*1", 0]
|
||||
},
|
||||
"tail2": {
|
||||
"rotation": [2.5, "0+1*math.sin(q.anim_time*90*1-50)*1", 0]
|
||||
},
|
||||
"tail3": {
|
||||
"rotation": [15, "1*math.sin(q.anim_time*90*1-60)*1", 0]
|
||||
},
|
||||
"tail4": {
|
||||
"rotation": [5, "0+2*math.sin(q.anim_time*90*1-120)*1", 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.lanturn.cry": {
|
||||
"animation_length": 1.5,
|
||||
"bones": {
|
||||
|
||||
+9
-1
@@ -47,6 +47,14 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.unown.cry": {
|
||||
"animation_length": 1.25,
|
||||
"sound_effects": {
|
||||
"0.0417": {
|
||||
"effect": "pokemon.unown.cry"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+207
-1
@@ -334,6 +334,212 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.tyranitar.cry": {
|
||||
"animation_length": 1.2,
|
||||
"bones": {
|
||||
"arm_left": {
|
||||
"rotation": {
|
||||
"0.0": {
|
||||
"post": [0, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.2083": {
|
||||
"post": [-0.22492, 7.46745, 10.26621],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.625": {
|
||||
"post": [-0.22492, 7.46745, 10.26621],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.9167": {
|
||||
"post": [0.1236, -2.46953, -2.31291],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.0833": {
|
||||
"post": [0, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
}
|
||||
}
|
||||
},
|
||||
"arm_left2": {
|
||||
"rotation": {
|
||||
"0.0": {
|
||||
"post": [0, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.2083": {
|
||||
"post": [-0.22492, 7.46745, 10.26621],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.625": {
|
||||
"post": [-0.22492, 7.46745, 10.26621],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.1667": {
|
||||
"post": [0.1236, -2.46953, -2.31291],
|
||||
"lerp_mode": "catmullrom"
|
||||
}
|
||||
}
|
||||
},
|
||||
"arm_right": {
|
||||
"rotation": {
|
||||
"0.0": {
|
||||
"post": [0, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.2083": {
|
||||
"post": [-0.22492, -7.46745, -10.26621],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.625": {
|
||||
"post": [-0.22492, -7.46745, -10.26621],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.9167": {
|
||||
"post": [0.1236, 2.46953, 2.31291],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.0833": {
|
||||
"post": [0, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
}
|
||||
}
|
||||
},
|
||||
"arm_right2": {
|
||||
"rotation": {
|
||||
"0.0": {
|
||||
"post": [0, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.2083": {
|
||||
"post": [-0.22492, -7.46745, -10.26621],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.625": {
|
||||
"post": [-0.22492, -7.46745, -10.26621],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.1667": {
|
||||
"post": [0.1236, 2.46953, 2.31291],
|
||||
"lerp_mode": "catmullrom"
|
||||
}
|
||||
}
|
||||
},
|
||||
"chest2": {
|
||||
"rotation": {
|
||||
"0.0": {
|
||||
"post": [0, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.25": {
|
||||
"post": [-7.5, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.7917": {
|
||||
"post": [-7.5, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.1667": {
|
||||
"post": [0, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
}
|
||||
}
|
||||
},
|
||||
"neck": {
|
||||
"rotation": {
|
||||
"0.0": {
|
||||
"post": [0, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.25": {
|
||||
"post": [-2.5, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.7917": {
|
||||
"post": [-2.5, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.1667": {
|
||||
"post": [0, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
}
|
||||
}
|
||||
},
|
||||
"neck2": {
|
||||
"rotation": {
|
||||
"0.0": {
|
||||
"post": [0, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.2083": {
|
||||
"post": [-25, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.7917": {
|
||||
"post": [-18.92, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.1667": {
|
||||
"post": [0, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
}
|
||||
}
|
||||
},
|
||||
"head_rotation": {
|
||||
"rotation": {
|
||||
"0.0": {
|
||||
"post": [0, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.25": {
|
||||
"post": [-12.39638, -1.61888, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.5833": {
|
||||
"post": [-1.47437, 0.12898, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.7917": {
|
||||
"post": [-12.5, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.1667": {
|
||||
"post": [0, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
}
|
||||
}
|
||||
},
|
||||
"jaw_closed": {
|
||||
"rotation": {
|
||||
"0.0": {
|
||||
"post": [0, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.25": {
|
||||
"post": [50, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.6667": {
|
||||
"post": [39.6, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"0.7917": {
|
||||
"post": [60, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
},
|
||||
"1.1667": {
|
||||
"post": [0, 0, 0],
|
||||
"lerp_mode": "catmullrom"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sound_effects": {
|
||||
"0.0417": {
|
||||
"effect": "pokemon.tyranitar.cry"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-1
@@ -461,6 +461,14 @@
|
||||
"position": [0.1, 0, 0]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.mawile.cry": {
|
||||
"animation_length": 1.5,
|
||||
"sound_effects": {
|
||||
"0.0417": {
|
||||
"effect": "pokemon.mawile.cry"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
-2
@@ -64,14 +64,20 @@
|
||||
"position": {
|
||||
"0.0": [0.1, 0, -0.1],
|
||||
"0.125": [0.1, 0, -0.1],
|
||||
"0.1667": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]}
|
||||
"0.1667": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_right": {
|
||||
"position": {
|
||||
"0.0": [-0.1, 0, -0.1],
|
||||
"0.125": [-0.1, 0, -0.1],
|
||||
"0.1667": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
|
||||
"0.1667": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,6 +109,11 @@
|
||||
"1.5": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"sound_effects": {
|
||||
"0.0833": {
|
||||
"effect": "pokemon.electrike.cry"
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.electrike.item_hold": {
|
||||
|
||||
+17
-3
@@ -83,21 +83,30 @@
|
||||
"position": {
|
||||
"0.0": [0.1, 0, 0.1],
|
||||
"0.125": [0.1, 0, 0.1],
|
||||
"0.1667": {"pre": [0.1, 0, 0.1], "post": [0, 0, 0]}
|
||||
"0.1667": {
|
||||
"pre": [0.1, 0, 0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_right": {
|
||||
"position": {
|
||||
"0.0": [-0.1, 0, -0.1],
|
||||
"0.125": [-0.1, 0, -0.1],
|
||||
"0.1667": {"pre": [-0.1, 0, -0.1], "post": [0, 0, 0]}
|
||||
"0.1667": {
|
||||
"pre": [-0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"eyelid_left": {
|
||||
"position": {
|
||||
"0.0": [0.1, 0, -0.1],
|
||||
"0.125": [0.1, 0, -0.1],
|
||||
"0.1667": {"pre": [0.1, 0, -0.1], "post": [0, 0, 0]}
|
||||
"0.1667": {
|
||||
"pre": [0.1, 0, -0.1],
|
||||
"post": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -129,6 +138,11 @@
|
||||
"1.5": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
},
|
||||
"sound_effects": {
|
||||
"0.0833": {
|
||||
"effect": "pokemon.manectric.cry"
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.manectric.item_hold": {
|
||||
|
||||
+9
-1
@@ -523,6 +523,14 @@
|
||||
"position": [0, 0, -0.1]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.zangoose.cry": {
|
||||
"animation_length": 1.5,
|
||||
"sound_effects": {
|
||||
"0.0417": {
|
||||
"effect": "pokemon.zangoose.cry"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-1
@@ -408,6 +408,14 @@
|
||||
"position": [-0.1, 0, -0.1]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.seviper.cry": {
|
||||
"animation_length": 1.5,
|
||||
"sound_effects": {
|
||||
"0.0417": {
|
||||
"effect": "pokemon.seviper.cry"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -95,6 +95,14 @@
|
||||
"position": [0, 0, -0.1]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.shuppet.cry": {
|
||||
"animation_length": 1.5,
|
||||
"sound_effects": {
|
||||
"0.0417": {
|
||||
"effect": "pokemon.shuppet.cry"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-1
@@ -404,6 +404,14 @@
|
||||
"rotation": [1.49371, 3.63717, -24.68117]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.banette.cry": {
|
||||
"animation_length": 1.5,
|
||||
"sound_effects": {
|
||||
"0.0417": {
|
||||
"effect": "pokemon.banette.cry"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -442,6 +442,14 @@
|
||||
"scale": ["1-math.sin(q.anim_time*90*1+45)*0.01", "1-math.sin(q.anim_time*90*1+225)*0.005", 1]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.duskull.cry": {
|
||||
"animation_length": 1.2,
|
||||
"sound_effects": {
|
||||
"0.04": {
|
||||
"effect": "pokemon.duskull.cry"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -1551,6 +1551,14 @@
|
||||
"rotation": [0, 0, 67.5]
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.dusclops.cry": {
|
||||
"animation_length": 1.2,
|
||||
"sound_effects": {
|
||||
"0.04": {
|
||||
"effect": "pokemon.dusclops.cry"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-1
@@ -237,6 +237,14 @@
|
||||
"position": [0, 0, -0.1]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.cherubi.cry": {
|
||||
"animation_length": 1.5,
|
||||
"sound_effects": {
|
||||
"0.0417": {
|
||||
"effect": "pokemon.cherubi.cry"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-1
@@ -259,6 +259,14 @@
|
||||
"position": [0, 0, -0.1]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.cherrim_overcast.cry": {
|
||||
"animation_length": 1.5,
|
||||
"sound_effects": {
|
||||
"0.0417": {
|
||||
"effect": "pokemon.cherrim.cry"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-1
@@ -370,6 +370,14 @@
|
||||
"position": [0, 0, -0.1]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.cherrim_sunshine.cry": {
|
||||
"animation_length": 1.5,
|
||||
"sound_effects": {
|
||||
"0.0417": {
|
||||
"effect": "pokemon.cherrim_sunshine.cry"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
-5
@@ -50,10 +50,12 @@
|
||||
"rotation": ["-15+Math.cos((query.anim_time-0.4) * 90 * 2) * 2", 0, 0]
|
||||
},
|
||||
"thigh_right": {
|
||||
"rotation": [0, 22.5, 0]
|
||||
"rotation": [0, 22.5, 0],
|
||||
"position": [0, 0, 0.1]
|
||||
},
|
||||
"thigh_left": {
|
||||
"rotation": [0, -7.5, 0]
|
||||
"rotation": [0, -7.5, 0],
|
||||
"position": [0, 0, -0.25]
|
||||
},
|
||||
"scalchop_hand_right": {
|
||||
"position": [2.5, -0.55, 0]
|
||||
@@ -178,6 +180,12 @@
|
||||
"1.25": [-7.5, 0, 0],
|
||||
"1.5": [7.5, 0, 0]
|
||||
}
|
||||
},
|
||||
"skirt_right": {
|
||||
"rotation": [0, 0, 5]
|
||||
},
|
||||
"skirt_left": {
|
||||
"rotation": [0, 0, -5]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -272,7 +280,5 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"geckolib_format_version": 2
|
||||
}
|
||||
}
|
||||
+9
-1
@@ -128,6 +128,14 @@
|
||||
"position": [0, 0, -0.1]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"animation.audino.cry": {
|
||||
"animation_length": 1.5,
|
||||
"sound_effects": {
|
||||
"0.0417": {
|
||||
"effect": "pokemon.audino.cry"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -814,7 +814,7 @@
|
||||
}
|
||||
},
|
||||
"sound_effects": {
|
||||
"0.0": {
|
||||
"0.0417": {
|
||||
"effect": "pokemon.darumaka.cry"
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -178,7 +178,7 @@
|
||||
},
|
||||
"sound_effects": {
|
||||
"0.125": {
|
||||
"effect": "joltik_cry"
|
||||
"effect": "pokemon.joltik.cry"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
+1
-1
@@ -3257,7 +3257,7 @@
|
||||
}
|
||||
},
|
||||
"sound_effects": {
|
||||
"0.5": {
|
||||
"0.04": {
|
||||
"effect": "pokemon.axew.cry"
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user