forked from mirrors/cobblemon
Compare commits
348
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a0f389c6b | ||
|
|
df8f078d13 | ||
|
|
309b223da9 | ||
|
|
75f688fa30 | ||
|
|
d7fadd58ed | ||
|
|
996c7189b6 | ||
|
|
e1d5f07aed | ||
|
|
6afe77ef0c | ||
|
|
bf54f28b58 | ||
|
|
aac10e967f | ||
|
|
0cd9da80d7 | ||
|
|
d33f1150d2 | ||
|
|
216ed85da1 | ||
|
|
4b70b20ab7 | ||
|
|
125e193b81 | ||
|
|
1ebd249351 | ||
|
|
74727cda48 | ||
|
|
6a8a2489d1 | ||
|
|
3524931596 | ||
|
|
43d9347c9c | ||
|
|
60303504cd | ||
|
|
63db0066d3 | ||
|
|
6e0270ac80 | ||
|
|
333e1fe9ae | ||
|
|
c0c8c103f4 | ||
|
|
a414784cca | ||
|
|
b4b01ef0b6 | ||
|
|
04f725d72e | ||
|
|
0257f591de | ||
|
|
dfeeed8796 | ||
|
|
0e304a81e8 | ||
|
|
03acc21af1 | ||
|
|
2233e6903b | ||
|
|
ac281faa3b | ||
|
|
6891272516 | ||
|
|
eba784071a | ||
|
|
a4435af9c0 | ||
|
|
4b0b0f813e | ||
|
|
c32da0825c | ||
|
|
803703b6a6 | ||
|
|
668914275e | ||
|
|
af90ff6733 | ||
|
|
c657c2ea68 | ||
|
|
2f567830d4 | ||
|
|
569f3c624e | ||
|
|
f30be418f9 | ||
|
|
2c50dc2d0c | ||
|
|
dde2e9f52a | ||
|
|
50a21d91e8 | ||
|
|
58f3de13fa | ||
|
|
8d67a3a909 | ||
|
|
ad4cb8a290 | ||
|
|
d9e5de5f97 | ||
|
|
e4a47af06d | ||
|
|
cc741c0478 | ||
|
|
6887887d6b | ||
|
|
cf1100a20e | ||
|
|
ebc7b97e4f | ||
|
|
d65ce9222a | ||
|
|
706221aead | ||
|
|
26bfca893b | ||
|
|
5f65f3c20c | ||
|
|
1e5239da10 | ||
|
|
7d8ec3470b | ||
|
|
389d2a0adc | ||
|
|
7fa0022095 | ||
|
|
9fde7a7618 | ||
|
|
6c1f7ddd70 | ||
|
|
241b83cec9 | ||
|
|
f0feb81a16 | ||
|
|
00f4052b75 | ||
|
|
407c24b7c5 | ||
|
|
c8904c3e38 | ||
|
|
6bfc711129 | ||
|
|
3d914f47ee | ||
|
|
61891d8fe4 | ||
|
|
1b66ee8ce3 | ||
|
|
5e6091c782 | ||
|
|
5a2e5479e0 | ||
|
|
fc03682140 | ||
|
|
07fbffaa71 | ||
|
|
5e2f5dadb4 | ||
|
|
fc682d1cd1 | ||
|
|
7759c91f3b | ||
|
|
c13654f60c | ||
|
|
289e9df52b | ||
|
|
5dca5a1579 | ||
|
|
3ebad9dc9d | ||
|
|
c93fa02616 | ||
|
|
4e1b82917b | ||
|
|
3b1d257241 | ||
|
|
0b8f916648 | ||
|
|
5897fff954 | ||
|
|
2fd2137d78 | ||
|
|
42c4d6625e | ||
|
|
b0381d1685 | ||
|
|
5ad7d5406a | ||
|
|
3b00043b13 | ||
|
|
2b403df6ef | ||
|
|
f0d5622bab | ||
|
|
ec28ca0c45 | ||
|
|
0d68eedc74 | ||
|
|
6ec008ee83 | ||
|
|
c969e1731b | ||
|
|
bb77c6d4a9 | ||
|
|
5dfc90c0bd | ||
|
|
26a72fe6a9 | ||
|
|
4bb9547822 | ||
|
|
ffe88d75b5 | ||
|
|
d8980fabbe | ||
|
|
7598413e93 | ||
|
|
b0cc4714fc | ||
|
|
5aa3f34880 | ||
|
|
21363405fc | ||
|
|
340be0b2a1 | ||
|
|
933e29b134 | ||
|
|
41b27e5d75 | ||
|
|
e80bf0e331 | ||
|
|
f4d2226ec2 | ||
|
|
0fc5d5e9d7 | ||
|
|
972c0f6430 | ||
|
|
86db95a7dc | ||
|
|
be95b79e4d | ||
|
|
683aa354ed | ||
|
|
aa19ff2c95 | ||
|
|
7d5e790f75 | ||
|
|
5753443ab2 | ||
|
|
c6b7186032 | ||
|
|
32f3be2687 | ||
|
|
9012d78806 | ||
|
|
fffdfb7654 | ||
|
|
76f17c9760 | ||
|
|
b314733f0b | ||
|
|
d5aa07fe91 | ||
|
|
3b0d2cd980 | ||
|
|
27bedc2d2c | ||
|
|
86744c23a5 | ||
|
|
f5a3c93039 | ||
|
|
00dc501df7 | ||
|
|
8d1a64136f | ||
|
|
39fee0bcea | ||
|
|
1162689172 | ||
|
|
bc550dd32c | ||
|
|
b295644070 | ||
|
|
21df0085e2 | ||
|
|
3009af8c42 | ||
|
|
bfd34eb621 | ||
|
|
2dc2c96176 | ||
|
|
df4db17cfd | ||
|
|
08c4f4a0ff | ||
|
|
c4a1704a8b | ||
|
|
45bec488f1 | ||
|
|
9287374504 | ||
|
|
90c5180712 | ||
|
|
51af37b37a | ||
|
|
f2a36cd74a | ||
|
|
158aa05f24 | ||
|
|
8924d0fe0f | ||
|
|
d510eaa462 | ||
|
|
8b63057d9d | ||
|
|
d572b3c505 | ||
|
|
8edc60224a | ||
|
|
a634c4f046 | ||
|
|
7139d4708b | ||
|
|
50e99736a3 | ||
|
|
68c4acf0eb | ||
|
|
5b5e7109f5 | ||
|
|
837aa5acf5 | ||
|
|
37596523db | ||
|
|
eb80c20dbf | ||
|
|
7ab3951613 | ||
|
|
e6d51c4d56 | ||
|
|
3813ec3c92 | ||
|
|
b9364304ca | ||
|
|
9be212d2b8 | ||
|
|
2559257b3a | ||
|
|
8236c6fb11 | ||
|
|
2041d43db4 | ||
|
|
a1687e8304 | ||
|
|
94d92b6fc0 | ||
|
|
3aa95b9339 | ||
|
|
4e97f70801 | ||
|
|
404ca565f5 | ||
|
|
93db0e1cda | ||
|
|
4a4d292228 | ||
|
|
0fef9eec3d | ||
|
|
5f3dc395ec | ||
|
|
1bf9d36dbd | ||
|
|
b19c5ed125 | ||
|
|
e3cca0d9cf | ||
|
|
1aa55f8199 | ||
|
|
4c16b2ce2e | ||
|
|
969d6ac7fc | ||
|
|
920e314444 | ||
|
|
3e4fdc0f22 | ||
|
|
209ac71e06 | ||
|
|
ecfc77f311 | ||
|
|
e64de3aa7d | ||
|
|
46bb9e1aec | ||
|
|
9792ff3392 | ||
|
|
fd7b82dbe3 | ||
|
|
7ef48402fb | ||
|
|
81ac6f3b44 | ||
|
|
347e10d7e4 | ||
|
|
32270b6176 | ||
|
|
a0a26a98b5 | ||
|
|
85836f19b2 | ||
|
|
9f251b7070 | ||
|
|
86ddb6d743 | ||
|
|
9c8a00bbdc | ||
|
|
04abf2bd25 | ||
|
|
e6553655a6 | ||
|
|
5f33d16a75 | ||
|
|
468f84862e | ||
|
|
e863c6d094 | ||
|
|
5b2d542fca | ||
|
|
95db34c55e | ||
|
|
15da48c5c0 | ||
|
|
ead62763c1 | ||
|
|
247c475c2d | ||
|
|
44aab4f0e7 | ||
|
|
94edae591c | ||
|
|
c83f045b4d | ||
|
|
b5d7786ff7 | ||
|
|
9283794e26 | ||
|
|
55580fb564 | ||
|
|
472c9be634 | ||
|
|
a247344ae4 | ||
|
|
1fd0a9775c | ||
|
|
9d9495f1f9 | ||
|
|
88e301d7c8 | ||
|
|
b0e16a7f26 | ||
|
|
54b5b3cbbc | ||
|
|
7850bc5263 | ||
|
|
8ce5a927b9 | ||
|
|
24c34af8bf | ||
|
|
7402426656 | ||
|
|
c658e496cc | ||
|
|
f3300806a3 | ||
|
|
8fee4de49b | ||
|
|
5b951ef511 | ||
|
|
6e0850331a | ||
|
|
79b1771e7e | ||
|
|
c9b2c44083 | ||
|
|
c370076337 | ||
|
|
978d9e76a1 | ||
|
|
a0b263e392 | ||
|
|
d05ae4d535 | ||
|
|
3cebfb38ef | ||
|
|
d69f1f17b6 | ||
|
|
3ba89472fa | ||
|
|
573608b6fc | ||
|
|
f092584f83 | ||
|
|
a76146f8e9 | ||
|
|
548daa84e4 | ||
|
|
7f1dd4546b | ||
|
|
a129c361df | ||
|
|
5d5508a71e | ||
|
|
5e5684d9fd | ||
|
|
a1623c04b7 | ||
|
|
a070dc56bd | ||
|
|
79f9e0f0f2 | ||
|
|
8500eb58ef | ||
|
|
97e51eb7b5 | ||
|
|
ba75dcdf31 | ||
|
|
9bf8c0e3ec | ||
|
|
0c62c247ec | ||
|
|
c70e8872ce | ||
|
|
ce323ddfbf | ||
|
|
ffe7978560 | ||
|
|
a58632752a | ||
|
|
1e067cb7e4 | ||
|
|
0b93481dbf | ||
|
|
dda004a66c | ||
|
|
2f464f82b1 | ||
|
|
9648a91f4a | ||
|
|
e0c4bf7fb2 | ||
|
|
ed919f63f0 | ||
|
|
239acc0623 | ||
|
|
e835b833b3 | ||
|
|
8f1127be46 | ||
|
|
26a8bf1ca5 | ||
|
|
28c0e17a48 | ||
|
|
d3da8c99a8 | ||
|
|
d106deb7f6 | ||
|
|
f1d1e87e47 | ||
|
|
2d9d6e172c | ||
|
|
3c03b0e210 | ||
|
|
724c674992 | ||
|
|
99eb317a87 | ||
|
|
43a2c2f55d | ||
|
|
4db9a35f2b | ||
|
|
31136435fe | ||
|
|
bdeb83c62c | ||
|
|
15bf726421 | ||
|
|
8228ac517b | ||
|
|
c7ae41bf7b | ||
|
|
7f1889db7b | ||
|
|
1653be5fa8 | ||
|
|
548c18bea4 | ||
|
|
b0497065f4 | ||
|
|
dfc1a39f58 | ||
|
|
d9203bef2a | ||
|
|
9a92e074a2 | ||
|
|
44b195f0a6 | ||
|
|
7c21e6feb5 | ||
|
|
3b653b745e | ||
|
|
5e24799295 | ||
|
|
a7243102d5 | ||
|
|
de6a84a75b | ||
|
|
f246d90e4c | ||
|
|
df22cc5b3e | ||
|
|
3fbe2102a0 | ||
|
|
be3c35eb43 | ||
|
|
21b667f5d8 | ||
|
|
eb88a43769 | ||
|
|
c41a6766ef | ||
|
|
842de0e92c | ||
|
|
04b516765d | ||
|
|
3faad69484 | ||
|
|
74e2f8429c | ||
|
|
10219fbf38 | ||
|
|
cf68ccc29e | ||
|
|
f78847f917 | ||
|
|
2bf0fd625b | ||
|
|
65e3052e69 | ||
|
|
be7192ae2c | ||
|
|
1c921a372b | ||
|
|
d03541ff6f | ||
|
|
0d7aff0349 | ||
|
|
c904888c6a | ||
|
|
b4508bf87e | ||
|
|
dcb4f52cdb | ||
|
|
1e9b390f38 | ||
|
|
7edd47f995 | ||
|
|
dd220c5c85 | ||
|
|
bea84a37d4 | ||
|
|
ac30da3c15 | ||
|
|
3861835d47 | ||
|
|
d62fb5c4c7 | ||
|
|
ca9dde92cd | ||
|
|
6ba264ddcb | ||
|
|
ab6c088ddf | ||
|
|
18105a8b3f | ||
|
|
acb5984a9e | ||
|
|
0a3ba8d4fa | ||
|
|
15259f0a95 | ||
|
|
9f66c053e1 |
@@ -21,6 +21,8 @@ build
|
||||
# other
|
||||
eclipse
|
||||
run
|
||||
runClient
|
||||
runServer
|
||||
|
||||
# Files from Forge MDK
|
||||
forge*changelog.txt
|
||||
@@ -34,6 +36,7 @@ common/src/main/resources/assets/cobblemon/showdown
|
||||
*/generated/resources/*
|
||||
/fabric/src/generated/resources/cobblemon-common.accesswidener
|
||||
/.ignored/
|
||||
common/.fabric
|
||||
|
||||
# MacOS
|
||||
.DS_Store
|
||||
+257
-75
@@ -1,44 +1,151 @@
|
||||
# Changelog
|
||||
## [1.5.0](#1-5-0)
|
||||
|
||||
## [1.5.2 (May 27th, 2024)](#1-5-2)
|
||||
### Fixes
|
||||
- Fixed Wooloo and Dubwool dyeing making your game start dying. Only if you do it on a server.
|
||||
- Fixed Gimmighoul causing PCs and parties to look glitched out, also only in a server.
|
||||
- Fixed players being able to dye other people's sheep Pokémon.
|
||||
|
||||
## [1.5.1 (May 27th, 2024)](#1-5-1)
|
||||
|
||||
### Additions
|
||||
- Added over (number here) ruin structures, where you can find Pokémon-themed Armor Trims and Pottery Sherds, Tumblestones, and more.
|
||||
- Added (number here) fossil structures, where you can brush Suspicious Sand/Gravel for Fossils.
|
||||
- Added the Data Monitor, Fossil Compartment, and Restoration Tank. Placed in the correct formation, you can use these to create a Restoration Machine where you can bring fossils back to life.
|
||||
- Added 3 variants of Tumblestones, which can be planted near Lava or Magma to grow harvestable Tumblestone Clusters.
|
||||
- Added unique send out particles for Cherish, Dream, Beast, and Ancient Origin balls.
|
||||
- Made Wooloo and Dubwool dye-able like sheep. So cute!
|
||||
- Added stat up and down particles.
|
||||
- Most status effects now have particles! These include: Paralysis, Poison, Sleep, Confusion, Infatuation.
|
||||
#### Move Particle Effects
|
||||
- Confusion
|
||||
- Cotton Guard
|
||||
- Growl
|
||||
- Ice Punch
|
||||
- Fire Punch
|
||||
- Thunder Punch
|
||||
- Minimize
|
||||
- Quick Attack
|
||||
- Protect
|
||||
- Swords Dance
|
||||
- Sand Attack
|
||||
- Poison Powder
|
||||
- Sleep Powder
|
||||
- Stun Spore
|
||||
- Powder
|
||||
- Rage Powder
|
||||
- Spore
|
||||
- Thunder Wave
|
||||
|
||||
### Changes
|
||||
- Sounds for Relic Coin Sacks have been correctly renamed. Relic Coin Pouches received new sounds for breaking and placing.
|
||||
- Readjusted Petilil portraits so they fit a bit better.
|
||||
- Improved handling of Pokémon taken from the Restoration Tank block to be a bit more stable.
|
||||
- Made Mulch cheaper to craft.
|
||||
|
||||
### Fixes
|
||||
- Fixed a bug in which adding organic material to the restoration tank via right click was adding the full count of the stack currently in hand - but only taking 1 of the item.
|
||||
- Fixed a niche issue where some properties of entities were not initialized correctly, causing Pokémon that appeared to be level 1 until you battle them.
|
||||
- Fixed Fossilized Drake being missing from the Fossils item tag.
|
||||
- Fixed Gilded Chest block entity not being cleared on block break, creating spooky ghost blocks. Old ones can be fixed by placing something like a furnace where it was, then breaking the furnace.
|
||||
- Fixed sherd brokenness on Forge.
|
||||
- Fixed Supplementaries incompatibility.
|
||||
- Fixed Fossil Compartment crash with Jade / WAILA forks.
|
||||
- Fixed pasture block PC lookups when the player is offline.
|
||||
- Fixed an untranslated battle message that occurs when using a move that just ran out of PP (e.g. Fire Blast that just got spited mid-turn).
|
||||
- Fixed held items being eaten even when the held item evolutions are already unlocked.
|
||||
- Fixed Hisuian Decidueye not being Grass/Fighting.
|
||||
- Fixed both Decidueye forms learning both Triple Arrows and Spirit Shackle.
|
||||
- Fixed Pineco being unable to evolve into Shulker Forretress.
|
||||
- Fixed Kabutops T-posing when underwater. It doesn't have proper swimming animations yet, though.
|
||||
- Fixed Pidgey's missing walk animation.
|
||||
- Fixed Cyndaquil's hidden flames clipping if it was swimming.
|
||||
- Fixed Chimecho and Chingling being unable to spawn near bells. They are meant to!
|
||||
- Fixed Tyrantrum and Wailord Party Overlay models peeking through the chat box. It was kinda funny though.
|
||||
- Fixed hitbox sizes for Seedot, Nuzleaf, and Shiftry.
|
||||
- Fixed Budew and Lechonk sliding if they walked for too long.
|
||||
- Fixed Shedinja T-posing in battle.
|
||||
- Fixed recoil evolution condition not working, making things like Basculegion unobtainable.
|
||||
- Fixed issue where poser debug tools didn't work on JSON posers.
|
||||
- Fixed issue where gilded chests don't close when going far away.
|
||||
- Fixed issue where the restoration tank's renderer was reading old data, making it appear wrong.
|
||||
- Fixed issue where the lights on the restoration tank would not animate if it was facing east. Very specific.
|
||||
- Fixed client crash with the fossil machine when updating block state on a chunk that is unloaded in the client. I don't understand this but the devs are sure that all of those are real words.
|
||||
- Fixed Restoration Tank crash with Create upon the tank block's destruction.
|
||||
- Fixed Restoration Tank over consuming items when interacting with Create blocks.
|
||||
- Fixed addons that add very many moves to a learn-set causing disappearing Pokémon (visually) issues on servers.
|
||||
- Fixed Hyper Cutter and Big Pecks incorrectly stating that it prevented accuracy from being lowered in battle.
|
||||
- Fixed missing messages for Rough Skin and Iron Barbs in battle.
|
||||
- Fixed a bug where sometimes Pokémon sendouts wouldn't create an entity, or the entity would spawn at 0 0 0 which is not a good place for a Pokémon to be. Or any of us, really.
|
||||
- Fixed issue in which a locked gilded chest would animate to the open state when the client fails to open it, such as when it is locked.
|
||||
- Fixed a bug where aspects of a form would not be properly reflected on form changes (eg. Normal -> Hisui).
|
||||
- Fixed generic battle effect sounds not sounding the way they were intended to.
|
||||
- Fixed particle effects often not having access to some specific entity functions from MoLang.
|
||||
- Fixed particles sometimes lasting a single tick too long, causing (very quick) visual glitches.
|
||||
- Fixed particle rotations being inverted.
|
||||
- Fixed particle events not spawning at the instigating particle's location.
|
||||
- Fixed a bunch of spam during world generation.
|
||||
- Fixed a bug in which throwing a Poké Ball at a player owned Pokémon with the ability Illusion would reveal its true species. Hilarious meta strategy.
|
||||
- Fixed root-part animations not working for JSON posed Pokémon. You didn't notice this but if we didn't fix this in this update then if you use Quick Attack a lot you'd have seen a whole lot of [this](https://cdn.discordapp.com/attachments/1076993968803434627/1242660506783715369/Minecraft__1.20.1_-_Singleplayer_2024-05-21_22-08-17.mp4?ex=66549408&is=66534288&hm=ff95ee293eb15634fd63e6546534ea279540a1c892605e8d561593ca2c5600c5&) which is damn funny but very unintended.
|
||||
|
||||
### Developer
|
||||
- Changed SpawnAction#complete to return a nullable generic R (the spawn action result) instead of a boolean. Provides more information this way.
|
||||
- Added an event that fires when a fossil is revived, with or without a player.
|
||||
- Added IVS and EVS property extractors.
|
||||
- Fixed PCStore#resize not allowing PC boxes size reduction.
|
||||
|
||||
### Data Pack & Resource Pack Creators
|
||||
- Added support for MoLang conditions for quirks and poses.
|
||||
- Changed the AttackDefenceRatio requirement to StatCompare and StatEqual. There is some backwards compatibility for AttackDefenceRatio, though.
|
||||
- Changed "dimensions" spawn condition to check with dimension IDs instead of effects, so custom dimension IDs can be used.
|
||||
- Added parametric motion and rotation support to particle effects.
|
||||
- Added entity_scale as a molang var for particles (likely only applicable to Pokemon)
|
||||
- Added support for primary quirk animations using the following format:
|
||||
```JSON
|
||||
{
|
||||
"quirks": [
|
||||
"q.bedrock_primary_quirk('<pokemon>', '<animation>', <minSeconds>, <maxSeconds>, <loopTimes>, '<excludedLabels>', q.curve('<waveFunction>'))"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Localization
|
||||
- Updated translations for:
|
||||
- Simplified and Traditional Chinese.
|
||||
- Spanish.
|
||||
|
||||
## [1.5.0 - The Ruins and Revival Update (May 12th, 2024)](#1-5-0)
|
||||
#### "You're telling me that Mojang has added archaeology to the game? Hmm... that gives me an idea."
|
||||
|
||||
### Additions
|
||||
- Added 17 ruin structures, where you can find Pokémon-themed Armor Trims and Pottery Sherds, Tumblestones, and more.
|
||||
- Added 23 fossil structures, where you can brush Suspicious Sand/Gravel for [Fossils](https://wiki.cobblemon.com/index.php/Fossil). You can add [custom fossils using datapacks](https://wiki.cobblemon.com/index.php/Fossils_File).
|
||||
- Added the Data Monitor, Fossil Compartment, and Restoration Tank blocks. Placed in the correct formation, you can use these to create a [Restoration Machine](https://wiki.cobblemon.com/index.php/Resurrection_Machine) where you can bring fossils back to life. Use organic material to fill the tank first!
|
||||
- Added 3 variants of [Tumblestone](https://wiki.cobblemon.com/index.php/Tumblestone), which can be planted near Lava or Magma to grow harvestable Tumblestone Clusters.
|
||||
- Added Tumblestone Blocks, a storage block crafted from 9 Tumblestones.
|
||||
- Added Ancient Poké Balls, which are aesthetic variants crafted from Tumblestones.
|
||||
- Added the Ancient Feather, Wing, and Jet Balls, which fly further than regular Poké Balls.
|
||||
- Added the Ancient Heavy, Leaden, and Gigaton Balls, which are heavier and don't fly as far as regular Poké Balls. These will receive more functionality in a future update.
|
||||
- Added Original Trainer functionality. To edit the OT through commands, you must specify originaltrainertype=<Player/NPC>, and originaltrainer=<Username or UUID/NPC Name>
|
||||
- Added visual effects for many Poké Balls when sending out or capturing Pokémon.
|
||||
- Added a new send-out ball toss animation that showcases the ball used for the Pokémon.
|
||||
- Added simple move animations for Pokémon in battle with a proof of concept (Flamethrower) for more complicated animations. More and more specific animations will come in future updates.
|
||||
- Added Original Trainer to the summary menu. To edit the OT through commands, you must specify originaltrainertype=<Player/NPC>, and originaltrainer=<Username or UUID/NPC Name>
|
||||
- Added support for planting Apricorn trees, berries, and mints in [Botany Pots](https://modrinth.com/mod/botany-pots)
|
||||
- Added the hidden "True Vivillionaire" advancement.
|
||||
- The "Poké Ball" Vivillon variant is now obtainable by evolving a Spewpa after obtaining the "Aspiring Vivillionaire" advancement.
|
||||
- Added dynamic lighting support for any Species or Forms when using [LambDynamicLights](https://modrinth.com/mod/lambdynamiclights) or [Dynamic Lights Reforged](https://www.curseforge.com/minecraft/mc-mods/dynamiclights-reforged), at this time we don't ship with any defaults for this feature but addon creators can make use of this feature.
|
||||
- Added a Display Case block! Use it to display your archaeological findings, or other items.
|
||||
- Added 6 Pokémon-themed Pottery Sherds, obtained from ruin structures.
|
||||
- Added the [Display Case](https://wiki.cobblemon.com/index.php/Display_Case) block. Use it to display your archaeological findings, Poké Balls, or other items.
|
||||
- Added 6 Pokémon-themed Pottery Sherds, obtained from ruin structures. Sherds... sh-erds. Weird word.
|
||||
- Added a Pokémon-themed armor trim, obtained from ruin structures.
|
||||
- You can now find Nether Fire Stone Ore in, surprisingly, the Nether.
|
||||
- You'll also find Terracotta Sun Stone Ore in Badlands biomes.
|
||||
- Added effects for many Poké Balls when sending out Pokémon or capturing.
|
||||
- Added a new send-out ball toss animation that showcases the ball used for the Pokémon.
|
||||
- Added simple move animations for Pokémon in battle with a proof of concept for more complicated animations.
|
||||
- Added Nether Fire Stone Ore to, surprisingly, the Nether.
|
||||
- Added Terracotta Sun Stone Ore to Badlands biomes.
|
||||
- Added the EV Boosting Feathers.
|
||||
- Added Type Gems.
|
||||
- Added various new tags for searchability and better compatibility.
|
||||
- Added the [Ability Capsule](https://bulbapedia.bulbagarden.net/wiki/Ability_Capsule) and [Patch](https://bulbapedia.bulbagarden.net/wiki/Ability_Patch), these have no acquisition method for now and only work as intended with the traditional ability format of 1 to 2 common abilities and 1 hidden ability.
|
||||
- Added Gilded Chests, available in all Apricorn colors.
|
||||
- Added Relic Coins, Relic Coin Pouches, and Relic Coin Sacks.
|
||||
- Added various new tags for searchability and better compatibility.
|
||||
- Added Type Gems. These items hold no functionality for now. Start collecting though...
|
||||
- Added 6 custom Pottery Sherds, obtained from ruin structures.
|
||||
- Added cries to Meowth, Alolan Meowth, Galaraian Meowth,
|
||||
- Completed the advancement for placing a Tumblestone near Lava or Magma to make it grow.
|
||||
- Added [Gilded Chests](https://wiki.cobblemon.com/index.php/Gilded_Chest), available in all Apricorn colors.
|
||||
- Added Relic Coins, Relic Coin Pouches, and Relic Coin Sacks. Gimmighoul might be interested in these.
|
||||
- Added Type Gems. These will have additional uses later, so you should start collecting them.
|
||||
- Added new held items: Ability Shield, Absorb Bulb, Air Balloon, Binding Band, Blunder Policy, Cell Battery, Covert Cloak, Damp Rock, Eject Button, Eviolite, Expert Belt, Float Stone, Focus Sash, Heat Rock, Icy Rock, Iron Ball, Light Ball, Loaded Dice, Red Card, Shell Bell, Sticky Barb, Smooth Rock, Soothe Bell and Weakness Policy.
|
||||
- Added Hisui starters to the starter selection menu.
|
||||
- Added bubble quirk to Krabby that only play during clear sunset's.
|
||||
- Added Hisui starters to the starter selection menu. They come inside of ancient Poké Balls.
|
||||
- Added a bubble quirk to Krabby that only plays during clear sunsets. It looks familiar...
|
||||
- Added forfeit option to PVP battles.
|
||||
- Added visual changes for entities affected by Illusion, Imposter, or Transform in battle.
|
||||
- Added shoulder mounting for Squirtle, Ralts, Roggenrola, Charcadet, Sizzlipede, Litwick, Cutiefly, Flabebe, Flittle, and Scatterbug
|
||||
- Added species data for Hydrapple, Iron Boulder, Iron Crown, Pecharunt, Raging Bolt, and Terapagos
|
||||
- Added various new tags for search-ability and better mod compatibility.
|
||||
- Added the [Ability Capsule](https://bulbapedia.bulbagarden.net/wiki/Ability_Capsule) and [Patch](https://bulbapedia.bulbagarden.net/wiki/Ability_Patch). These have no way of getting them (for now) and only work as intended with the traditional ability format of 1 to 2 common abilities and 1 hidden ability.
|
||||
|
||||
### Pokémon Added
|
||||
#### Gen 2
|
||||
@@ -162,8 +269,6 @@
|
||||
- Dreepy
|
||||
- Drakloak
|
||||
- Dragapult
|
||||
- Hisuian Sliggoo
|
||||
- Hisuian Goodra
|
||||
- Impidimp
|
||||
- Morgrem
|
||||
- Grimmsnarl
|
||||
@@ -171,10 +276,10 @@
|
||||
#### Gen 9
|
||||
- Gimmighoul
|
||||
- Using Relic Coins, you can increase Gimmighoul's Coin Stash. Upon reaching 999, it can be evolved into Gholdengo.
|
||||
- Additionally, if you give Gimmighoul a Netherite Scrap, you can increase its Netherite Stash. Who knows what might happen if it fills up?
|
||||
- Additionally, if you give Gimmighoul a Netherite Scrap, you can increase its Netherite Stash. But what will that do to when you evolve it?
|
||||
- Gholdengo
|
||||
|
||||
#### Cobblemon Exclusive's
|
||||
#### Cobblemon Exclusives
|
||||
- Hisui Bias Rowlet
|
||||
- Hisui Bias Dartrix
|
||||
- Hisui Bias Cyndaquil
|
||||
@@ -184,79 +289,153 @@
|
||||
- Hisui Bias Goomy
|
||||
- Hisui Bias Petilil
|
||||
|
||||
These are our compromise for having both regular and Hisuian forms of these Pokémon in the game. Hisui Biased variations will evolve into the Hisuian evolutions under most conditions. They are otherwise purely cosmetic differences.
|
||||
|
||||
### Added cries to the following Pokémon
|
||||
- Alolan Raticate
|
||||
- Vulpix, Ninetales
|
||||
- Zubat, Golbat, Crobat
|
||||
- Meowth, Persian
|
||||
- Psyduck, Golduck
|
||||
- Growlithe, Arcanine
|
||||
- Geodude, Graveler, Golem
|
||||
- Doduo, Dodrio
|
||||
- Seel, Dewgong
|
||||
- Muk, Grimer
|
||||
- Krabby, Kingler
|
||||
- Voltorb, Electrode, Hisuian Voltorb, Hisuian Electrode
|
||||
- Tangela, Tangrowth
|
||||
- Snorlax
|
||||
- Cubone, Marowak
|
||||
- Koffing, Weezing
|
||||
- Aerodactyl
|
||||
- Elekid, Electabuzz, Electivire
|
||||
- Omanyte, Omastar
|
||||
- Kabuto, Kabutops
|
||||
- Lapras
|
||||
- Scyther
|
||||
- Hisui Bias Cyndaquil, Hisui Bias Quilava
|
||||
- Igglybuff
|
||||
- Yanma, Yanmega
|
||||
- Gligar, Gliscor
|
||||
- Qwilfish, Hisuian Qwilfish, Overqwil
|
||||
- Sneasel, Hisuian Sneasel, Weavile, Sneasler
|
||||
- Larvitar, Pupitar, Tyranitar
|
||||
- Swinub, Piloswine, Mamoswine
|
||||
- Aron, Lairon, Aggron
|
||||
- Trapinch, Vibrava, Flygon
|
||||
- Cacnea, Cacturne
|
||||
- Barboach, Whiscash
|
||||
- Lileep, Cradily
|
||||
- Anorith, Armaldo
|
||||
- Tropius
|
||||
- Chimecho
|
||||
- Bidoof, Bibarel
|
||||
- Buizel, Floatzel
|
||||
- Gible, Gabite, Garchomp
|
||||
- Hisui Bias Oshawott, Hisui Bias Dewott
|
||||
- Petilil, Lilligant, Hisui Bias Petilil, Hisuian Lilligant
|
||||
- Basculin, Basculegion
|
||||
- Sandile, Krokolok, Krookodile
|
||||
- Darumaka, Darmanitan
|
||||
- Archen, Archeops
|
||||
- Zorua, Zoroark, Hisuian Zorua, Hisuian Zoroark
|
||||
- Tyrunt, Tyrantrum
|
||||
- Amaura Aurorus
|
||||
- Carbink
|
||||
- Goomy, Sliggoo, Goodra, Hisui Bias Goomy, Hisuian Sliggoo, Hisuian Goodra
|
||||
- Klefki
|
||||
- Hisui Bias Rowlet, Hisui Bias Dartrix
|
||||
- Komala
|
||||
- Impidimp, Morgrem, Grimmsnarl
|
||||
- Cufant, Copperajah
|
||||
- Dreepy, Drakloak, Dragapult
|
||||
- Dracozolt, Arctozolt, Dracovish, Arctovish
|
||||
- Lechonk, Oinkologne
|
||||
- Maushold family of three and four
|
||||
|
||||
|
||||
### Changes
|
||||
- Alolan Pikachu and Exeggcute changed to Alola bias.
|
||||
- Alolan Pikachu and Exeggcute changed to Alola Bias.
|
||||
- Pokémon now transition more smoothly between different poses.
|
||||
- Updated models for Mimikyu, Alcremie, Squirtle, Wartortle, Blastoise, Pidgey, Pidgeotto, Pidgeot, Omanyte, Omastar, Growlithe, Arcanine, Nidoran Male, Nidoran Female, Lapras, Swinub, Piloswine, Basculin, Rowlet, Dartrix, Decidueye, Kabuto, Kabutops, Piplup, Prinplup, Elekid, Electabuzz, Cubone, Marowak, Paras, Mawile, Drifloon, Drifblim, Venonat, Venomoth, Yanma, Yanmega, Psyduck, Dusknoir, Diglett, Dugtrio, Natu, Xatu, Oshawott, Samurott, Torchic, Grovyle, Sceptile, Sizzlipede, and Raboot.
|
||||
- Updated models for Mimikyu, Alcremie, Squirtle, Wartortle, Blastoise, Pidgey, Pidgeotto, Pidgeot, Omanyte, Omastar, Growlithe, Arcanine, Nidoran Male, Nidoran Female, Lapras, Swinub, Piloswine, Basculin, Rowlet, Dartrix, Decidueye, Kabuto, Kabutops, Piplup, Prinplup, Elekid, Electabuzz, Cubone, Marowak, Paras, Mawile, Drifloon, Drifblim, Venonat, Venomoth, Yanma, Yanmega, Psyduck, Dusknoir, Diglett, Dugtrio, Natu, Xatu, Oshawott, Samurott, Torchic, Grovyle, Sceptile, Sizzlipede, Mismagius, and Raboot.
|
||||
- Updated animations for Squirtle, Wartortle, Blastoise, Pidgey, Pidgeotto, Diglett, Dugtrio, Magikarp, Dragonite, Omanyte, Omastar, Kabuto, Pinsir, Chinchou, Lanturn, Ralts, Kirlia, Gardevoir, Gallade, Buizel, Garchomp, Pumpkaboo, Falinks, Lechonk, Litwick, Lampent, Chandelure, Carnivine, Galarian Meowth, Galarian Rapidash, Venonat, Venomoth, Phanphy, Donphan, Dratini, Dragonair, Happiny, Chansey, Blissey, Volbeat, Illumise, Numel, Sizzlipede, Centiskorch, Obstagoon, Timburr, Gurdurr, Conkeldurr, Drifloon, and Drifblim.
|
||||
- Resized Drifloon.
|
||||
- Added more held items to the held item tag, and Metal Coat to the held item tab.
|
||||
- Added all ores to the modloader ore tags, and added tags for each ore type to the mod (both blocks and items).
|
||||
- Changed the Destiny Knot to be crafted with a Ghast Tear, rather than a diamond.
|
||||
- You can now punch grown apricorns to harvest them.
|
||||
- Changed the Destiny Knot to be crafted with a Ghast Tear rather than a diamond. We have big plans for the Destiny Knot...
|
||||
- You can now punch grown apricorns to harvest them. We saw so many content creators breaking apricorns with their fists that it was making us die inside.
|
||||
- The "Poké Ball" Vivillon variant is now obtainable by evolving a Spewpa after obtaining the "Aspiring Vivillionaire" advancement.
|
||||
- Renamed the "Vivillionaire" advancement to "Aspiring Vivillionaire"
|
||||
- Removed the Inferno, Forsaken, Poké Ball, and Void patterns from the Aspiring Vivillionaire advancement.
|
||||
- Updated movesets to add Gen 9 DLC moves.
|
||||
- Updated the biome tags for Spewpa's evolutions into the various Vivillon patterns. You should mostly be getting one evolution option at a time now.
|
||||
- Apricorn Sprouts can now be planted directly on Apricorn leaves to create a new Apricorn of the same color.
|
||||
- Added tooltips to interaction GUIs to make it clearer what they do.
|
||||
- Poké Ball recipes now use tags for their center ingredient, rather than specificied Copper Ingot, Iron Ingot, Gold Ingot, and Diamond, allowing for further datapack customisation.
|
||||
- Starter Toast now closes once corresponding button is pressed once.
|
||||
- Moved some items in the vanilla Food & Drinks category.
|
||||
- Poké Ball recipes now use tags for their center ingredient, rather than specifically Copper Ingots, Iron Ingots, Gold Ingots, and Diamonds, allowing for further datapack customisation and mod compatibility.
|
||||
- Starter Toast now closes once the corresponding button is pressed once.
|
||||
- Moved some items into the vanilla Food & Drinks category.
|
||||
- Stacked Cobblemon Potion Bases can now be quick moved into Brewing Stands.
|
||||
- Changed Healer recipe to swap the Max Revive for a Revive.
|
||||
- Upped the rate that Gastly drop Ghast Tears from 2.5% to 5%.
|
||||
- Changed the Healing Machine recipe to swap the Max Revive for a Revive so that it is a bit easier to craft.
|
||||
- Upped the rate that Gastly drop Ghast Tears from 2.5% to 5%, further helping the crafting of a Healing Machine.
|
||||
- Pokémon with a low Blaze Powder drop chance now drop it more frequently in the Nether.
|
||||
- Reorganised a few advancements.
|
||||
- Pokémon entity shadows now scale when the Pokémon is being sent out or recalled.
|
||||
- Remade Torkoal particles, now they only appear when in battle.
|
||||
- Updated shiny icon within summary and PC interfaces.
|
||||
- Improved the shiny icon within summary and PC interfaces.
|
||||
- Changed the Poison Barb sprite so that it doesn't look like a sword when held. It's a Poison Barb, not a Poison Sword. Wait, that gives me an idea.
|
||||
- Moon Stone ore generates more frequently in Taigas and has been added to Magical and Spooky biomes. Ooo... Sorry.
|
||||
- Density, Season, and Nether biome tags have been moved and renamed within the biome tags directory.
|
||||
- Added particles to Lucario when in battle. Lucario is special.
|
||||
- Movesets updated for Blueberry DLC.
|
||||
|
||||
### Fixes
|
||||
- Resized Snorlax
|
||||
- Re-added the recipe for the Iron Vitamin.
|
||||
- Cleaned up empty evolutions declaration in species files (no, I'm not listing all 169 by name).
|
||||
- Fixed Exeggcute not being able to evolve.
|
||||
- Fixed battle lang for Poison Touch Ability
|
||||
- Fixed Cubone not being able to evolve into Alolan Marowak.
|
||||
- Re-added the recipe for the Iron vitamin. Well, technically it's a mineral.
|
||||
- Fixed Exeggcute and Pikachu not being able to evolve.
|
||||
- Fixed evolution priority for Exeggcute and Pikachu regional evolutions. Using a thunder stone on Kantonian Pikachu on the beach will give Alolan Raichu. A second thunder stone would then give Kantonian Raichu.
|
||||
- Fixed battle text for the Poison Touch Ability.
|
||||
- Finally found Sudowoodo and Bonsly. They were missing spawn data. Same with Drifloon and Litwick. Uh... sorry about that.
|
||||
- Fixed Squawkabilly forms not being recognized.
|
||||
- Fixed the bounce animation for Poké Balls being delayed by like, a full second.
|
||||
- Note blocks now play the correct sound on the Apricorn Plank based blocks.
|
||||
- Fixed the bounce animation for Poké Balls being delayed by like, a full second. It's enough to drive you mad.
|
||||
- Note blocks now play the correct sound on the Apricorn Plank-based blocks.
|
||||
- Fixed an issue with transformed parts in posers causing whacky positional issues.
|
||||
- Fixed Poké Balls freezing in an open state if you look away when it's meant to close.
|
||||
- Adds a translation string name to the Empty Pokeball entity.
|
||||
- Fixed very many issues with Bedrock particle effects.
|
||||
- Fixed Arbok patterns not being as specific in spawning as they were intended.
|
||||
- Fixed Poké Balls freezing in an open state if you're looking away at the moment that it's meant to close. This actually fixes some other things but it's hard to explain.
|
||||
- Fixed thrown Poké Balls technically having no name.
|
||||
- Fixed very many issues with Bedrock particle effects. There are probably many more. Life goes on.
|
||||
- Fixed Arbok patterns not being as specific in spawning as they were intended to be.
|
||||
- Fixed Pokémon not avoiding danger at all when pathfinding.
|
||||
- Fixed Pokémon pathing over snow layers and carpets.
|
||||
- Fixed Sobble line not being able to swim or breathe underwater.
|
||||
- Fixed incompatibility with [Just Enough Resources](https://modrinth.com/mod/just-enough-resources-jer).
|
||||
- Fixed incompatibility with [Visual Overhaul](https://modrinth.com/mod/visual-overhaul).
|
||||
- Fixed an issue that allowed Pokemon to spawn on rails.
|
||||
- Fixed the Sobble line not being able to swim or breathe underwater.
|
||||
- Fixed mod incompatibility with [Just Enough Resources](https://modrinth.com/mod/just-enough-resources-jer).
|
||||
- Fixed mod incompatibility with [Visual Overhaul](https://modrinth.com/mod/visual-overhaul).
|
||||
- Fixed an issue that allowed Pokémon to spawn on rails.
|
||||
- Fixed the data set on Pokémon when abilities are given via properties such as in ``/spawnpokemon``.
|
||||
- Fixed sometimes Pokémon losing hidden abilities when evolving, this fix will only take effect to newly created Pokémon.
|
||||
- Fixed capture messages not displaying.
|
||||
- Fixed illusion ability causing the wrong Pokémon to be targeted in battle.
|
||||
- Battles starting with fainted party members no longer cause a softlock on defeat.
|
||||
- Fixed Pokémon sometimes losing hidden abilities when evolving. This fix will only take effect for newly created Pokémon because of technical reasons that were explained to me but which I then forgot.
|
||||
- Fixed capture messages not displaying in battle.
|
||||
- Fixed the Illusion ability causing the wrong Pokémon to be targeted in battle.
|
||||
- Fixed battles started with fainted party members causing a soft-lock on defeat.
|
||||
- Fixed some issues with eyes in the faint animations of Hitmonlee and Phantump
|
||||
- Fixed missing evolution moves, for example Stone Axe for Kleavor.
|
||||
- Cleaned up empty evolutions declaration in species data (And no, I'm not listing all 169. No I don't care what you pay me, I'm not doing it).
|
||||
- Fixed non-consumable held items being consumed or swapped in battle permanently.
|
||||
|
||||
### Developer
|
||||
- Significantly changed the way properties in PokemonEntity work. This could break some plugins (not in a big way, but changes will be needed).
|
||||
- Rebuilt the scheduling API to more clearly force side choices and temporal frames of reference for tasks.
|
||||
- Added dialogue API and data registry.
|
||||
- Significantly changed the way the properties in PokemonEntity work. This could break some plugins (not in a big way, but changes will be needed for some things).
|
||||
- Rebuilt the scheduling API to more clearly force side choices and temporal frames of reference for tasks. The developers say that how it works is cool but I stopped listening.
|
||||
- Added dialogue API and data registry. This is powerful, and there is a full example in the Cobblemon mod you can trigger using /opendialogue \<username\> cobblemon:example. The example JSON is inside the data folder of the mod.
|
||||
- Opened up the ItemDropEntry class to allow for it to be extended.
|
||||
- Added a new "advancement" evolution variant that takes an advancement identifier and succeeds if the player has the advancement.
|
||||
- Made spawning API capable of non-entity spawning
|
||||
- Made PokemonProperties.parse more interoperable with Java.
|
||||
- Made the spawning API capable of non-entity spawning. You can make it 'spawn' commands if you want. Go nuts.
|
||||
- Made PokemonProperties.parse more interoperable with Java. Save yourself and stop using Java.
|
||||
- Added the ``HeldItemEvent``, this comes with 2 implementation ``HeldItemEvent.Pre`` and ``HeldItemEvent.Post``.
|
||||
- API to support dynamic lighting in any mod that implements this feature has been added to all Species & Forms, see LightingData class for details.
|
||||
- Added a Mixin for the BrewingStandScreenHandler to fix the incorrect handling of quickMove in Fabric.
|
||||
- Corrections to the ability implementation have been made that make ``Ability.forced`` function as intended and never reroll an ability for a Pokémon, please check your implementations to ensure the corrected behavior is intended for your use case.
|
||||
- ``Pokemon.ability`` no longer has a public setter, please migrate to using ``Pokemon#updateAbility``, this handles the ability coordinate storage for you when necessary.
|
||||
- ``Pokemon.ability`` no longer has a public setter. Please migrate to using ``Pokemon#updateAbility``, this handles the ability coordinate storage for you when necessary.
|
||||
- ``Ability.forced``, ``Ability.index`` and ``Ability.priority`` have all had their setters internalized, there is no longer any need to manually adjust these migrate to the method mentioned above to handle that process for you.
|
||||
- ``AbilityChanger`` has been added to API alongside some implementations, this is subject to change as the ability capsule and patch currently only expect the traditional behaviour in the Pokémon games of 1 to 2 regular abilities and 1 hidden.
|
||||
- ``Pokemon#rollAbility`` has been added, this rerolls a legal ability for the Pokémon.
|
||||
- `docs/cobblemon-tags` tags and spawn-presets can now be auto-generated from the current tags in the cobblemon mod with the `generateSpawnPresetList.py` and `generateTagList.py` scripts.
|
||||
- ``AbilityChanger`` has been added to API alongside some implementations, this is subject to change as the ability capsule and patch currently only expect the traditional behaviour in the Pokémon games of 1 or 2 regular abilities and 1 hidden ability.
|
||||
- ``Pokemon#rollAbility`` has been added which rerolls for a legal ability for the Pokémon.
|
||||
- `docs/cobblemon-tags` tags and spawn-presets can now be auto-generated from the current tags in the Cobblemon mod with the `generateSpawnPresetList.py` and `generateTagList.py` scripts.
|
||||
- `public_spawns_to_json.py` script has been added to give the powerful spawn.json generator a simplistic UI.
|
||||
- Updated Showdown with Gen 9 DLC.
|
||||
- Updated Showdown with Gen 9 DLC.
|
||||
- Changed mixins to be Java 17 for compatibility level instead of 16, removing a warning from startup logs.
|
||||
|
||||
### Datapack & Resourcepack Creators
|
||||
- The maximum amount of fossils that can fit in the Fossil Analyzer can be adjusted in the config.
|
||||
@@ -426,6 +605,7 @@
|
||||
Thank you so much to all of our community translators that bring the mod to the rest of the world!
|
||||
|
||||
## [1.4.0 - The Friends and Farms Update (October 13th, 2023)](#1-4-0)
|
||||
#### "No, we don't provide the friends."
|
||||
### Additions
|
||||
- Added pasture blocks, used to let your PC Pokémon roam around an area.
|
||||
- Added nicknaming from the summary menu of a Pokémon (click their name).
|
||||
@@ -966,6 +1146,7 @@ Thank you so much to all of our community translators that bring the mod to the
|
||||
- All the translators that contributed are amazing.
|
||||
|
||||
## [1.3.0 - The Foundation Update (March 17th, 2023)](#1-3-0)
|
||||
#### "Now we can start doing the really cool stuff."
|
||||
|
||||
### Dependencies
|
||||
- Upgraded Fabric API dependence to 0.75.1+1.19.2
|
||||
@@ -1115,6 +1296,7 @@ Thank you so much to all of our community translators that bring the mod to the
|
||||
- Thank you to all of the fantastic volunteer translators for taking the time to help with this!
|
||||
|
||||
## [1.2.0 - The Customization Update (January 1st, 2023)](#1-2-0)
|
||||
#### "There are going to be so many fakemon..."
|
||||
### Additions
|
||||
- Added models for Natu and Xatu, Murkrow and Honchkrow, Wailmer and Wailord.
|
||||
- Added new PC interface and it is beautiful.
|
||||
@@ -1228,4 +1410,4 @@ Thank you so much to all of our community translators that bring the mod to the
|
||||
- Added species, ability, and move translations for `ko_ko`, `jp_jp`, `fr_fr`, `es_es`, `it_it`, and `zh_cn`.
|
||||
|
||||
## [1.0.0 (November 12th, 2022)](#1-0-0)
|
||||
- Initial release.
|
||||
- Initial release.
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import ca.stellardrift.build.configurate.ConfigFormats
|
||||
import ca.stellardrift.build.configurate.catalog.PolyglotVersionCatalogExtension
|
||||
|
||||
plugins {
|
||||
id("ca.stellardrift.polyglot-version-catalogs") version "5.0.1"
|
||||
}
|
||||
|
||||
extensions.configure<PolyglotVersionCatalogExtension> {
|
||||
from(ConfigFormats.YAML, file("../gradle/libs.versions.yml"))
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
plugins {
|
||||
id("cobblemon.base-conventions")
|
||||
id("com.github.johnrengelman.shadow")
|
||||
}
|
||||
|
||||
val bundle: Configuration by configurations.creating {
|
||||
isCanBeConsumed = false
|
||||
isCanBeResolved = true
|
||||
}
|
||||
|
||||
tasks {
|
||||
|
||||
jar {
|
||||
archiveBaseName.set("Cobblemon-${project.name}")
|
||||
archiveClassifier.set("dev-slim")
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
archiveClassifier.set("dev-shadow")
|
||||
archiveBaseName.set("Cobblemon-${project.name}")
|
||||
configurations = listOf(bundle)
|
||||
mergeServiceFiles()
|
||||
}
|
||||
|
||||
remapJar {
|
||||
dependsOn(shadowJar)
|
||||
inputFile.set(shadowJar.flatMap { it.archiveFile })
|
||||
archiveBaseName.set("Cobblemon-${project.name}")
|
||||
archiveVersion.set("${rootProject.version}")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
plugins {
|
||||
`java-library`
|
||||
}
|
||||
|
||||
tasks {
|
||||
val collectJars by registering(Copy::class) {
|
||||
val tasks = subprojects.filter { it.path != ":common" }.map { it.tasks.named("remapJar") }
|
||||
dependsOn(tasks)
|
||||
|
||||
from(tasks)
|
||||
into(buildDir.resolve("libs"))
|
||||
}
|
||||
|
||||
assemble {
|
||||
dependsOn(collectJars)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType<Test> {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
+2
-3
@@ -1,13 +1,12 @@
|
||||
plugins {
|
||||
base
|
||||
id("cobblemon.root-conventions")
|
||||
id ("net.nemerosa.versioning") version "2.8.2"
|
||||
}
|
||||
|
||||
group = "com.cobblemon.mod"
|
||||
version = "${project.property("mod_version")}+${project.property("mc_version")}"
|
||||
|
||||
val isSnapshot = project.property("snapshot")?.equals("true") ?: false
|
||||
if (isSnapshot) {
|
||||
version = "$version-${versioning.info.branch}-${versioning.info.build}"
|
||||
val fixedBranchName = versioning.info.branch.substringAfter("/")
|
||||
version = "$version-${fixedBranchName}-${versioning.info.build}"
|
||||
}
|
||||
|
||||
+18
-24
@@ -1,5 +1,5 @@
|
||||
import extensions.isSnapshot
|
||||
import extensions.version
|
||||
import utilities.isSnapshot
|
||||
import utilities.version
|
||||
import java.time.OffsetDateTime
|
||||
import java.time.ZoneOffset
|
||||
import java.time.format.DateTimeFormatter
|
||||
@@ -20,7 +20,7 @@ plugins {
|
||||
|
||||
id("net.kyori.blossom")
|
||||
id("org.jetbrains.gradle.plugin.idea-ext")
|
||||
id ("net.nemerosa.versioning") version "2.8.2"
|
||||
id("net.nemerosa.versioning") version "2.8.2"
|
||||
}
|
||||
|
||||
architectury {
|
||||
@@ -34,31 +34,26 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.stdlib)
|
||||
implementation(libs.reflect)
|
||||
|
||||
modImplementation(libs.fabricLoader)
|
||||
//Flywheel has no common dep so just pick one and don't use any platform specific code in common
|
||||
// modCompileOnly(libs.flywheelFabric)
|
||||
implementation(libs.bundles.kotlin)
|
||||
modImplementation(libs.fabric.loader)
|
||||
modApi(libs.molang)
|
||||
compileOnlyApi(libs.jeiApi)
|
||||
modCompileOnly(libs.adornFabric)
|
||||
modCompileOnly(libs.lambDynamicLights) { isTransitive = false }
|
||||
|
||||
// For Showdown
|
||||
// Integrations
|
||||
compileOnlyApi(libs.jei.api)
|
||||
modCompileOnly(libs.bundles.fabric.integrations.compileOnly) {
|
||||
isTransitive = false
|
||||
}
|
||||
// Flywheel has no common dep so just pick one and don't use any platform specific code in common
|
||||
// modCompileOnly(libs.flywheelFabric)
|
||||
|
||||
// Showdown
|
||||
modCompileOnly(libs.graal)
|
||||
|
||||
//shadowCommon group: 'commons-io', name: 'commons-io', version: '2.6'
|
||||
// Data Storage
|
||||
modCompileOnly(libs.bundles.mongo)
|
||||
|
||||
// For datastore
|
||||
modCompileOnly(libs.mongoDriverCore)
|
||||
modCompileOnly(libs.mongoDriverSync)
|
||||
|
||||
testImplementation(libs.fabricJunit)
|
||||
testImplementation(libs.junitParams)
|
||||
testImplementation(libs.mockito)
|
||||
testImplementation(libs.mockk)
|
||||
testImplementation(libs.classgraph)
|
||||
// Unit Testing
|
||||
testImplementation(libs.bundles.unitTesting)
|
||||
}
|
||||
|
||||
tasks.withType<Test> {
|
||||
@@ -94,7 +89,6 @@ sourceSets {
|
||||
property("gitCommit", versioning.info.commit)
|
||||
property("branch", versioning.info.branch)
|
||||
System.getProperty("buildNumber")?.let { property("buildNumber", it) }
|
||||
property("timestamp", OffsetDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ofPattern("MM/dd/yyyy hh:mm:ss")) + " UTC")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ public final class CrashReportMixin {
|
||||
cobblemon.add("Is Snapshot", CobblemonBuildDetails.SNAPSHOT);
|
||||
cobblemon.add("Git Commit", CobblemonBuildDetails.INSTANCE.smallCommitHash() + " (" + "https://gitlab.com/cable-mc/cobblemon/-/commit/" + CobblemonBuildDetails.GIT_COMMIT + ")");
|
||||
cobblemon.add("Branch", CobblemonBuildDetails.BRANCH);
|
||||
cobblemon.add("Timestamp", CobblemonBuildDetails.TIMESTAMP);
|
||||
|
||||
cobblemon.addStackTrace(builder);
|
||||
builder.append("\n\n");
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.mixin.invoker;
|
||||
|
||||
import com.cobblemon.mod.common.integration.adorn.AdornCompatibility;
|
||||
import java.util.List;
|
||||
import juuxel.adorn.block.variant.BlockVariantSet;
|
||||
import juuxel.adorn.block.variant.BlockVariantSets;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
//This is a yucky hack but better than what we were doing before
|
||||
@Mixin(BlockVariantSets.class)
|
||||
public abstract class AdornRegisterInvoker {
|
||||
@Final
|
||||
@Shadow(remap = false)
|
||||
private static List<BlockVariantSet> variantSets;
|
||||
|
||||
@Inject(method = "register()V", at = @At("HEAD"), remap = false)
|
||||
void register(CallbackInfo ci) {
|
||||
variantSets.add(AdornCompatibility.INSTANCE);
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,6 @@ object CobblemonBuildDetails {
|
||||
|
||||
const val GIT_COMMIT = "{{ gitCommit | default("Not Specified") }}"
|
||||
const val BRANCH = "{{ branch | default("Not Specified") }}"
|
||||
const val TIMESTAMP = "{{ timestamp }}"
|
||||
|
||||
fun smallCommitHash(): String {
|
||||
return this.GIT_COMMIT.substring(0, 7)
|
||||
|
||||
@@ -102,7 +102,6 @@ import com.cobblemon.mod.common.pokemon.properties.HiddenAbilityPropertyType
|
||||
import com.cobblemon.mod.common.pokemon.properties.UncatchableProperty
|
||||
import com.cobblemon.mod.common.pokemon.properties.tags.PokemonFlagProperty
|
||||
import com.cobblemon.mod.common.pokemon.stat.CobblemonStatProvider
|
||||
import com.cobblemon.mod.common.sherds.CobblemonSherds
|
||||
import com.cobblemon.mod.common.starter.CobblemonStarterHandler
|
||||
import com.cobblemon.mod.common.trade.TradeManager
|
||||
import com.cobblemon.mod.common.util.DataKeys
|
||||
@@ -141,8 +140,8 @@ import kotlin.reflect.jvm.javaField
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
object Cobblemon {
|
||||
const val MODID = "cobblemon"
|
||||
const val VERSION = "1.4.0"
|
||||
const val MODID = CobblemonBuildDetails.MOD_ID
|
||||
const val VERSION = CobblemonBuildDetails.VERSION
|
||||
const val CONFIG_PATH = "config/$MODID/main.json"
|
||||
val LOGGER: Logger = LogManager.getLogger()
|
||||
|
||||
@@ -179,7 +178,6 @@ object Cobblemon {
|
||||
if(CobblemonBuildDetails.SNAPSHOT) {
|
||||
this.LOGGER.info(" - Git Commit: ${smallCommitHash()} (https://gitlab.com/cable-mc/cobblemon/-/commit/${CobblemonBuildDetails.GIT_COMMIT})")
|
||||
this.LOGGER.info(" - Branch: ${CobblemonBuildDetails.BRANCH}")
|
||||
this.LOGGER.info(" - Timestamp: ${CobblemonBuildDetails.TIMESTAMP}")
|
||||
}
|
||||
|
||||
implementation.registerPermissionValidator()
|
||||
@@ -236,7 +234,7 @@ object Cobblemon {
|
||||
val player = event.player
|
||||
val block = player.world.getBlockState(event.pos).block
|
||||
player.party().forEach { pokemon ->
|
||||
pokemon.evolutions
|
||||
pokemon.lockedEvolutions
|
||||
.filterIsInstance<BlockClickEvolution>()
|
||||
.forEach { evolution ->
|
||||
evolution.attemptEvolution(pokemon, BlockClickEvolution.BlockInteractionContext(block, player.world))
|
||||
@@ -417,7 +415,6 @@ object Cobblemon {
|
||||
).ifSuccessful { it.mute = true }
|
||||
}
|
||||
|
||||
CobblemonSherds.registerSherds()
|
||||
}
|
||||
|
||||
fun getLevel(dimension: RegistryKey<World>): World? {
|
||||
|
||||
@@ -234,7 +234,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
"relic_coin_pouch",
|
||||
CoinPouchBlock(
|
||||
AbstractBlock.Settings.create()
|
||||
.sounds(CobblemonSounds.COIN_POUCH_SOUNDS)
|
||||
.sounds(CobblemonSounds.RELIC_COIN_POUCH_SOUNDS)
|
||||
.pistonBehavior(PistonBehavior.DESTROY)
|
||||
.strength(0.4f)
|
||||
.nonOpaque(), true
|
||||
@@ -245,7 +245,7 @@ object CobblemonBlocks : PlatformRegistry<Registry<Block>, RegistryKey<Registry<
|
||||
"relic_coin_sack",
|
||||
CoinPouchBlock(
|
||||
AbstractBlock.Settings.create()
|
||||
.sounds(CobblemonSounds.COIN_POUCH_SOUNDS)
|
||||
.sounds(CobblemonSounds.RELIC_COIN_SACK_SOUNDS)
|
||||
.pistonBehavior(PistonBehavior.DESTROY)
|
||||
.strength(0.4f), false
|
||||
))
|
||||
|
||||
@@ -48,6 +48,7 @@ object CobblemonCommands {
|
||||
PokemonRestartCommand.register(dispatcher)
|
||||
BedrockParticleCommand.register(dispatcher)
|
||||
OpenDialogueCommand.register(dispatcher)
|
||||
ChallengeCommand.register(dispatcher)
|
||||
|
||||
// Possibly lock down registration if and only if under dev environment or running in an environment
|
||||
// with a certain system environment variable set
|
||||
|
||||
@@ -667,8 +667,8 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
val CHOICE_SPECS = heldItem("choice_specs")
|
||||
@JvmField
|
||||
val CLEANSE_TAG = heldItem("cleanse_tag")
|
||||
@JvmField
|
||||
val CLEAR_AMULET = heldItem("clear_amulet")
|
||||
// @JvmField
|
||||
// val CLEAR_AMULET = heldItem("clear_amulet")
|
||||
@JvmField
|
||||
val COVERT_CLOAK = heldItem("covert_cloak")
|
||||
@JvmField
|
||||
@@ -697,16 +697,16 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
val FOCUS_BAND = heldItem("focus_band")
|
||||
@JvmField
|
||||
val FOCUS_SASH = heldItem("focus_sash")
|
||||
@JvmField
|
||||
val GRIP_CLAW = heldItem("grip_claw")
|
||||
// @JvmField
|
||||
// val GRIP_CLAW = heldItem("grip_claw")
|
||||
@JvmField
|
||||
val HARD_STONE = heldItem("hard_stone")
|
||||
@JvmField
|
||||
val HEAVY_DUTY_BOOTS = heldItem("heavy_duty_boots")
|
||||
@JvmField
|
||||
val IRON_BALL = heldItem("iron_ball")
|
||||
@JvmField
|
||||
val LAGGING_TAIL = heldItem("lagging_tail")
|
||||
// @JvmField
|
||||
// val LAGGING_TAIL = heldItem("lagging_tail")
|
||||
@JvmField
|
||||
val LEFTOVERS = heldItem("leftovers")
|
||||
@JvmField
|
||||
@@ -719,12 +719,12 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
val LOADED_DICE = heldItem("loaded_dice")
|
||||
@JvmField
|
||||
val LUCKY_EGG = heldItem("lucky_egg")
|
||||
@JvmField
|
||||
val LUMINOUS_MOSS = heldItem("luminous_moss")
|
||||
// @JvmField
|
||||
// val LUMINOUS_MOSS = heldItem("luminous_moss")
|
||||
@JvmField
|
||||
val MAGNET = heldItem("magnet")
|
||||
@JvmField
|
||||
val METRONOME = heldItem("metronome")
|
||||
// @JvmField
|
||||
// val METRONOME = heldItem("metronome")
|
||||
@JvmField
|
||||
val MIRACLE_SEED = heldItem("miracle_seed")
|
||||
@JvmField
|
||||
@@ -747,10 +747,10 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
val POWER_LENS = heldItem("power_lens")
|
||||
@JvmField
|
||||
val POWER_WEIGHT = heldItem("power_weight")
|
||||
@JvmField
|
||||
val PROTECTIVE_PADS = heldItem("protective_pads")
|
||||
@JvmField
|
||||
val PUNCHING_GLOVE = heldItem("punching_glove")
|
||||
// @JvmField
|
||||
// val PROTECTIVE_PADS = heldItem("protective_pads")
|
||||
// @JvmField
|
||||
// val PUNCHING_GLOVE = heldItem("punching_glove")
|
||||
@JvmField
|
||||
val QUICK_CLAW = heldItem("quick_claw")
|
||||
@JvmField
|
||||
@@ -759,16 +759,16 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
val RING_TARGET = heldItem("ring_target")
|
||||
@JvmField
|
||||
val ROCKY_HELMET = heldItem("rocky_helmet")
|
||||
@JvmField
|
||||
val ROOM_SERVICE = heldItem("room_service")
|
||||
// @JvmField
|
||||
// val ROOM_SERVICE = heldItem("room_service")
|
||||
@JvmField
|
||||
val SAFETY_GOGGLES = heldItem("safety_goggles")
|
||||
@JvmField
|
||||
val SCOPE_LENS = heldItem("scope_lens")
|
||||
// @JvmField
|
||||
// val SCOPE_LENS = heldItem("scope_lens")
|
||||
@JvmField
|
||||
val SHARP_BEAK = heldItem("sharp_beak")
|
||||
@JvmField
|
||||
val SHED_SHELL = heldItem("shed_shell")
|
||||
// @JvmField
|
||||
// val SHED_SHELL = heldItem("shed_shell")
|
||||
@JvmField
|
||||
val SHELL_BELL = heldItem("shell_bell")
|
||||
@JvmField
|
||||
@@ -785,24 +785,24 @@ object CobblemonItems : PlatformRegistry<Registry<Item>, RegistryKey<Registry<It
|
||||
val SOOTHE_BELL = heldItem("soothe_bell")
|
||||
@JvmField
|
||||
val STICKY_BARB = heldItem("sticky_barb")
|
||||
@JvmField
|
||||
val TERRAIN_EXTENDER = heldItem("terrain_extender")
|
||||
@JvmField
|
||||
val THROAT_SPRAY = heldItem("throat_spray")
|
||||
// @JvmField
|
||||
// val TERRAIN_EXTENDER = heldItem("terrain_extender")
|
||||
// @JvmField
|
||||
// val THROAT_SPRAY = heldItem("throat_spray")
|
||||
@JvmField
|
||||
val TOXIC_ORB = heldItem("toxic_orb")
|
||||
@JvmField
|
||||
val TWISTED_SPOON = heldItem("twisted_spoon")
|
||||
@JvmField
|
||||
val UTILITY_UMBRELLA = heldItem("utility_umbrella")
|
||||
// @JvmField
|
||||
// val UTILITY_UMBRELLA = heldItem("utility_umbrella")
|
||||
@JvmField
|
||||
val WEAKNESS_POLICY = heldItem("weakness_policy")
|
||||
@JvmField
|
||||
val WIDE_LENS = heldItem("wide_lens")
|
||||
// @JvmField
|
||||
// val WIDE_LENS = heldItem("wide_lens")
|
||||
@JvmField
|
||||
val WISE_GLASSES = heldItem("wise_glasses")
|
||||
@JvmField
|
||||
val ZOOM_LENS = heldItem("zoom_lens")
|
||||
// @JvmField
|
||||
// val ZOOM_LENS = heldItem("zoom_lens")
|
||||
@JvmField
|
||||
val MENTAL_HERB = compostableHeldItem("mental_herb", null, 1F)
|
||||
@JvmField
|
||||
|
||||
@@ -235,6 +235,7 @@ object CobblemonNetwork : NetworkManager {
|
||||
this.createClientBound(TradeableUpdatePacket.ID, TradeableUpdatePacket::decode, PokemonUpdatePacketHandler())
|
||||
this.createClientBound(SpeciesFeatureUpdatePacket.ID, SpeciesFeatureUpdatePacket::decode, PokemonUpdatePacketHandler())
|
||||
this.createClientBound(OriginalTrainerUpdatePacket.ID, OriginalTrainerUpdatePacket::decode, PokemonUpdatePacketHandler())
|
||||
this.createClientBound(FormUpdatePacket.ID, FormUpdatePacket::decode, PokemonUpdatePacketHandler())
|
||||
|
||||
// Evolution start
|
||||
this.createClientBound(AddEvolutionPacket.ID, AddEvolutionPacket::decode, PokemonUpdatePacketHandler())
|
||||
|
||||
@@ -122,13 +122,18 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
||||
val FOSSIL_MACHINE_UNPROTECTED = this.create("fossil_machine.unprotected")
|
||||
|
||||
@JvmField
|
||||
val COIN_POUCH_BREAK = this.create("coin_pouch.break")
|
||||
val RELIC_COIN_SACK_BREAK = this.create("relic_coin_sack.break")
|
||||
@JvmField
|
||||
val COIN_POUCH_HIT = this.create("coin_pouch.hit")
|
||||
val RELIC_COIN_SACK_HIT = this.create("relic_coin_sack.hit")
|
||||
@JvmField
|
||||
val COIN_POUCH_STEP = this.create("coin_pouch.step")
|
||||
val RELIC_COIN_SACK_STEP = this.create("relic_coin_sack.step")
|
||||
@JvmField
|
||||
val COIN_POUCH_PLACE = this.create("coin_pouch.place")
|
||||
val RELIC_COIN_SACK_PLACE = this.create("relic_coin_sack.place")
|
||||
@JvmField
|
||||
val RELIC_COIN_POUCH_BREAK = this.create("relic_coin_pouch.break")
|
||||
@JvmField
|
||||
val RELIC_COIN_POUCH_PLACE = this.create("relic_coin_pouch.place")
|
||||
|
||||
@JvmField
|
||||
val TUMBLESTONE_BREAK = this.create("tumblestone.break")
|
||||
@JvmField
|
||||
@@ -189,13 +194,22 @@ object CobblemonSounds : PlatformRegistry<Registry<SoundEvent>, RegistryKey<Regi
|
||||
val GILDED_CHEST_PLACE = this.create("gilded_chest.place")
|
||||
|
||||
@JvmField
|
||||
val COIN_POUCH_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
COIN_POUCH_BREAK,
|
||||
COIN_POUCH_STEP,
|
||||
COIN_POUCH_PLACE,
|
||||
COIN_POUCH_HIT,
|
||||
COIN_POUCH_STEP
|
||||
val RELIC_COIN_SACK_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
RELIC_COIN_SACK_BREAK,
|
||||
RELIC_COIN_SACK_STEP,
|
||||
RELIC_COIN_SACK_PLACE,
|
||||
RELIC_COIN_SACK_HIT,
|
||||
RELIC_COIN_SACK_STEP
|
||||
)
|
||||
@JvmField
|
||||
val RELIC_COIN_POUCH_SOUNDS = BlockSoundGroup(1f, 1f,
|
||||
RELIC_COIN_POUCH_BREAK,
|
||||
RELIC_COIN_SACK_STEP,
|
||||
RELIC_COIN_POUCH_PLACE,
|
||||
RELIC_COIN_SACK_HIT,
|
||||
RELIC_COIN_SACK_STEP
|
||||
)
|
||||
|
||||
@JvmField
|
||||
val IMPACT_NORMAL = this.create("impact.normal")
|
||||
@JvmField
|
||||
|
||||
+1
-1
@@ -170,7 +170,7 @@ class BattleMessage(rawMessage: String) {
|
||||
*/
|
||||
fun pnxAndUuid(index: Int): Pair<String, String>? {
|
||||
val argument = this.argumentAt(index)?.takeIf { it.length >= 2 }?.split(":")?.takeIf { it.size == 2 } ?: return null
|
||||
val pnx = argument[0].takeIf { it.matches(PNX_MATCHER) } ?: return null
|
||||
val pnx = argument[0].takeIf { it.matches(PNX_MATCHER) || it.matches(PN_MATCHER) } ?: return null
|
||||
val uuid = argument[1].trim()
|
||||
return pnx to uuid
|
||||
}
|
||||
|
||||
@@ -226,7 +226,7 @@ open class PokemonBattle(
|
||||
val facedFainted = opponentPokemon.facedOpponents.contains(faintedPokemon)
|
||||
val pokemon = opponentPokemon.effectedPokemon
|
||||
if (facedFainted) {
|
||||
pokemon.evolutions.forEach { evolution ->
|
||||
pokemon.lockedEvolutions.forEach { evolution ->
|
||||
evolution.requirements.filterIsInstance<DefeatRequirement>().forEach { defeatRequirement ->
|
||||
if (defeatRequirement.target.matches(faintedPokemon.effectedPokemon)) {
|
||||
val progress = pokemon.evolutionProxy.current().progressFirstOrCreate({ it is DefeatEvolutionProgress && it.currentProgress().target == defeatRequirement.target }) { DefeatEvolutionProgress() }
|
||||
|
||||
@@ -78,6 +78,8 @@ object CobblemonEvents {
|
||||
val POKE_BALL_CAPTURE_CALCULATED = EventObservable<PokeBallCaptureCalculatedEvent>()
|
||||
@JvmField
|
||||
val POKEMON_CAPTURED = EventObservable<PokemonCapturedEvent>()
|
||||
@JvmField
|
||||
val FOSSIL_REVIVED = EventObservable<FossilRevivedEvent>()
|
||||
// @JvmField
|
||||
// val EGG_HATCH = EventObservable<HatchEggEvent>()
|
||||
@JvmField
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.api.events.pokemon
|
||||
|
||||
import com.cobblemon.mod.common.pokemon.Pokemon
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
|
||||
data class FossilRevivedEvent (
|
||||
val pokemon: Pokemon,
|
||||
val player: ServerPlayerEntity?
|
||||
)
|
||||
+4
-2
@@ -10,9 +10,7 @@ package com.cobblemon.mod.common.api.moves.animations
|
||||
|
||||
import com.bedrockk.molang.Expression
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.struct.VariableStruct
|
||||
import com.cobblemon.mod.common.api.moves.animations.keyframes.ActionEffectKeyframe
|
||||
import com.cobblemon.mod.common.api.scheduling.ScheduledTask
|
||||
import com.cobblemon.mod.common.util.asExpression
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import java.util.concurrent.CompletableFuture
|
||||
@@ -43,6 +41,9 @@ class ActionEffectTimeline(
|
||||
// .toList copy because I'm paranoid about iterators being trying to share between identical effects playing
|
||||
chainKeyframes(context, timeline.toList().iterator(), finalFuture)
|
||||
finalFuture
|
||||
}.exceptionallyCompose {
|
||||
it.printStackTrace()
|
||||
CompletableFuture.completedFuture(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +56,7 @@ class ActionEffectTimeline(
|
||||
keyframe.play(context)
|
||||
.thenRun { context.currentKeyframes.remove(keyframe) }
|
||||
.thenApply { chainKeyframes(context, iterator, finalFuture) }
|
||||
.exceptionally { finalFuture.completeExceptionally(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -8,7 +8,6 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.moves.animations.keyframes
|
||||
|
||||
import com.cobblemon.mod.common.CobblemonNetwork.sendPacket
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.EntityProvider
|
||||
@@ -40,7 +39,7 @@ class EntityParticlesActionEffectKeyframe : ConditionalActionEffectKeyframe(), E
|
||||
.flatMap { prov -> prov.entities.filter { test(context, it, isUser = prov is UsersProvider) } }
|
||||
|
||||
val effectIdentifier = try {
|
||||
effect?.asExpressionLike()?.resolveString(context.runtime)
|
||||
effect?.asExpressionLike()?.resolveString(context.runtime)?.takeIf { it != "0.0" } ?: effect
|
||||
} catch (e: Exception) {
|
||||
effect
|
||||
}?.asIdentifierDefaultingNamespace() ?: return skip()
|
||||
|
||||
@@ -60,13 +60,14 @@ abstract class MultiblockBlock(properties: Settings) : BlockWithEntity(propertie
|
||||
}
|
||||
|
||||
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity?) {
|
||||
super.onBreak(world, pos, state, player)
|
||||
if (!world.isClient) {
|
||||
val entity = world.getBlockEntity(pos)
|
||||
if (entity is MultiblockEntity && entity.multiblockStructure != null) {
|
||||
entity.multiblockStructure!!.onBreak(world, pos, state, player)
|
||||
}
|
||||
entity?.markRemoved()
|
||||
}
|
||||
super.onBreak(world, pos, state, player)
|
||||
}
|
||||
|
||||
override fun createBlockEntity(pos: BlockPos, state: BlockState): BlockEntity? {
|
||||
@@ -78,6 +79,7 @@ abstract class MultiblockBlock(properties: Settings) : BlockWithEntity(propertie
|
||||
return BlockRenderType.MODEL
|
||||
}
|
||||
|
||||
//This is done so a block picked with NBT doesnt absolutely DESTROY multiblocks
|
||||
override fun getPickStack(world: BlockView, pos: BlockPos, state: BlockState): ItemStack {
|
||||
val blockEntity = world.getBlockEntity(pos) as? MultiblockEntity ?: return ItemStack.EMPTY
|
||||
return if (blockEntity.multiblockStructure == null) super.getPickStack(world, pos, state) else ItemStack.EMPTY
|
||||
|
||||
+4
@@ -47,6 +47,10 @@ fun interface PokemonPropertyExtractor {
|
||||
val NICKNAME = add { pokemon, properties -> properties.nickname = pokemon.nickname }
|
||||
@JvmField
|
||||
val STATUS = add { pokemon, properties -> properties.status = pokemon.status?.status?.showdownName }
|
||||
@JvmField
|
||||
val IVS = add { pokemon, properties -> properties.ivs = pokemon.ivs }
|
||||
@JvmField
|
||||
val EVS = add { pokemon, properties -> properties.evs = pokemon.evs }
|
||||
|
||||
@JvmField
|
||||
val ILLUSION = mutableListOf(SPECIES, FORM, ASPECTS, GENDER, NICKNAME, SHINY)
|
||||
|
||||
@@ -153,7 +153,7 @@ interface Evolution : EvolutionLike {
|
||||
pokemon.getOwnerPlayer()?.sendMessage(lang("experience.learned_move", pokemon.getDisplayName(), move.displayName))
|
||||
}
|
||||
// we want to instantly tick for example you might only evolve your Bulbasaur at level 34 so Venusaur should be immediately available
|
||||
pokemon.evolutions.filterIsInstance<PassiveEvolution>().forEach { evolution -> evolution.attemptEvolution(pokemon) }
|
||||
pokemon.lockedEvolutions.filterIsInstance<PassiveEvolution>().forEach { evolution -> evolution.attemptEvolution(pokemon) }
|
||||
pokemon.getOwnerPlayer()?.playSound(CobblemonSounds.EVOLVING, SoundCategory.NEUTRAL, 1F, 1F)
|
||||
CobblemonEvents.EVOLUTION_COMPLETE.post(EvolutionCompleteEvent(pokemon, this))
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ open class Learnset : ClientDataSynchronizer<Learnset> {
|
||||
repeat(times = buffer.readSizedInt(IntSize.U_BYTE)) {
|
||||
val level = buffer.readSizedInt(IntSize.U_SHORT)
|
||||
val moves = mutableListOf<MoveTemplate>()
|
||||
repeat(times = buffer.readSizedInt(IntSize.U_BYTE)) {
|
||||
repeat(times = buffer.readSizedInt(IntSize.U_SHORT)) {
|
||||
Moves.getByNumericalId(buffer.readInt())?.let(moves::add)
|
||||
}
|
||||
levelUpMoves[level] = moves
|
||||
@@ -112,7 +112,7 @@ open class Learnset : ClientDataSynchronizer<Learnset> {
|
||||
buffer.writeSizedInt(IntSize.U_BYTE, levelUpMoves.size)
|
||||
for ((level, moves) in levelUpMoves) {
|
||||
buffer.writeSizedInt(IntSize.U_SHORT, level)
|
||||
buffer.writeSizedInt(IntSize.U_BYTE, moves.size)
|
||||
buffer.writeSizedInt(IntSize.U_SHORT, moves.size)
|
||||
for (move in moves) {
|
||||
buffer.writeInt(move.num)
|
||||
}
|
||||
|
||||
@@ -51,8 +51,8 @@ enum class Stats(override val identifier: Identifier, override val displayName:
|
||||
|
||||
/** Gets the [Stat] from the respective Showdown id. */
|
||||
fun getStat(statKey: String) = when(statKey) {
|
||||
"atk" -> ATTACK
|
||||
"def" -> DEFENCE
|
||||
"atk", "Attack" -> ATTACK // Hyper Cutter states the full stat name "Attack"
|
||||
"def", "Defense" -> DEFENCE // Big Pecks states the full stat name "Defense"
|
||||
"spa" -> SPECIAL_ATTACK
|
||||
"spd" -> SPECIAL_DEFENCE
|
||||
"spe" -> SPEED
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
|
||||
package com.cobblemon.mod.common.api.pokemon.status
|
||||
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectTimeline
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
@@ -20,4 +23,6 @@ open class Status(
|
||||
val showdownName: String = "",
|
||||
val applyMessage: String,
|
||||
val removeMessage: String
|
||||
)
|
||||
) {
|
||||
fun getActionEffect() = ActionEffects.actionEffects[name]
|
||||
}
|
||||
@@ -9,21 +9,29 @@
|
||||
package com.cobblemon.mod.common.api.pokemon.status
|
||||
|
||||
import com.cobblemon.mod.common.pokemon.status.PersistentStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.BurnStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.FrozenStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.ParalysisStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonBadlyStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.PoisonStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.SleepStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.VolatileStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.BurnStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.FrozenStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.ParalysisStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonBadlyStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.SleepStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.nonpersistent.ConfuseStatus
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.nonpersistent.AttractStatus
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* Main API point for Statuses
|
||||
* Get or register Statuses
|
||||
*
|
||||
* NOTE: May seem weird to have so many things called volatile statuses but the package is called nonpersistent.
|
||||
* Its because volatile is a reserved keyword in Java. Cant use it in a package name
|
||||
*
|
||||
* @author Deltric
|
||||
*/
|
||||
object Statuses {
|
||||
private val persistentStatuses = mutableListOf<Status>()
|
||||
private val volatileStatuses = mutableListOf<Status>()
|
||||
private val allStatuses = mutableListOf<Status>()
|
||||
|
||||
val POISON = registerStatus(PoisonStatus())
|
||||
@@ -32,13 +40,23 @@ object Statuses {
|
||||
val SLEEP = registerStatus(SleepStatus())
|
||||
val FROZEN = registerStatus(FrozenStatus())
|
||||
val BURN = registerStatus(BurnStatus())
|
||||
val ATTRACT = registerStatus(AttractStatus())
|
||||
val CONFUSE = registerStatus(ConfuseStatus())
|
||||
|
||||
|
||||
|
||||
fun <T: Status> registerStatus(status: T) : T {
|
||||
if (status is PersistentStatus) {
|
||||
persistentStatuses.add(status)
|
||||
}
|
||||
else if (status is VolatileStatus) {
|
||||
volatileStatuses.add(status)
|
||||
}
|
||||
allStatuses.add(status)
|
||||
return status
|
||||
}
|
||||
|
||||
fun getStatus(name: Identifier) = allStatuses.find { status -> status.name == name }
|
||||
fun getStatus(showdownName: String) = allStatuses.find { it.showdownName == showdownName }
|
||||
fun getPersistentStatuses() = allStatuses.filterIsInstance<PersistentStatus>()
|
||||
fun getPersistentStatuses() = persistentStatuses
|
||||
}
|
||||
@@ -123,10 +123,8 @@ class RotateYCameraMode : ParticleCameraMode {
|
||||
viewDirection: Vec3d
|
||||
): Quaternionf {
|
||||
val i = if (angle == 0F) 0F else MathHelper.lerp(deltaTicks, prevAngle, angle)
|
||||
|
||||
val q2 = RotationAxis.POSITIVE_Y.rotationDegrees(/*180 - */cameraYaw)
|
||||
val q2 = RotationAxis.POSITIVE_Y.rotationDegrees(-cameraYaw)
|
||||
q2.hamiltonProduct(RotationAxis.POSITIVE_Z.rotationDegrees(i))
|
||||
|
||||
return q2
|
||||
}
|
||||
|
||||
@@ -191,9 +189,10 @@ class LookAtY : ParticleCameraMode {
|
||||
cameraPitch: Float,
|
||||
viewDirection: Vec3d
|
||||
): Quaternionf {
|
||||
val rotation = Quaternionf(0F, 0F, 0F, 1F)
|
||||
rotation.hamiltonProduct(RotationAxis.POSITIVE_Y.rotationDegrees(-cameraYaw))
|
||||
return rotation
|
||||
val i = if (angle == 0F) 0F else MathHelper.lerp(deltaTicks, prevAngle, angle)
|
||||
val q2 = RotationAxis.POSITIVE_Y.rotationDegrees(-cameraYaw)
|
||||
q2.hamiltonProduct(RotationAxis.POSITIVE_Z.rotationDegrees(i))
|
||||
return q2
|
||||
}
|
||||
|
||||
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
||||
|
||||
@@ -79,15 +79,15 @@ class ParticleEvent(
|
||||
particleEffect?.let { effect ->
|
||||
val bedrockParticleEffect = BedrockParticleEffectRepository.getEffect(effect.effect) ?: return@let
|
||||
val rootMatrix = when (effect.type) {
|
||||
EventParticleEffect.EventParticleType.EMITTER -> MatrixWrapper().updatePosition(storm.matrixWrapper.getOrigin())
|
||||
EventParticleEffect.EventParticleType.EMITTER_BOUND -> storm.matrixWrapper
|
||||
EventParticleEffect.EventParticleType.EMITTER,// -> MatrixWrapper().updatePosition(storm.matrixWrapper.getOrigin())
|
||||
EventParticleEffect.EventParticleType.EMITTER_BOUND,// -> storm.matrixWrapper
|
||||
EventParticleEffect.EventParticleType.PARTICLE,
|
||||
EventParticleEffect.EventParticleType.PARTICLE_WITH_VELOCITY -> (particle?.let { Vec3d(it.getX(), it.getY(), it.getZ()) } ?: Vec3d(storm.getX(), storm.getY(), storm.getZ())).let { MatrixWrapper().updatePosition(it) }
|
||||
}
|
||||
|
||||
val sourceVelocity = when (effect.type) {
|
||||
EventParticleEffect.EventParticleType.EMITTER -> storm.sourceVelocity().let { { it } }
|
||||
EventParticleEffect.EventParticleType.EMITTER_BOUND -> storm.sourceVelocity
|
||||
EventParticleEffect.EventParticleType.EMITTER,// -> storm.sourceVelocity().let { { it } }
|
||||
EventParticleEffect.EventParticleType.EMITTER_BOUND,// -> storm.sourceVelocity
|
||||
EventParticleEffect.EventParticleType.PARTICLE -> { { Vec3d.ZERO } }
|
||||
EventParticleEffect.EventParticleType.PARTICLE_WITH_VELOCITY -> (particle?.let { Vec3d(it.getVelocityX(), it.getVelocityY(), it.getVelocityZ()) } ?: Vec3d.ZERO).let { { it } }
|
||||
}
|
||||
|
||||
@@ -15,10 +15,12 @@ import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.codec.CodecMapped
|
||||
import com.cobblemon.mod.common.api.data.ArbitrarilyMappedSerializableCompanion
|
||||
import com.cobblemon.mod.common.client.particle.ParticleStorm
|
||||
import com.cobblemon.mod.common.client.render.SnowstormParticle
|
||||
import com.cobblemon.mod.common.util.codec.EXPRESSION_CODEC
|
||||
import com.cobblemon.mod.common.util.getString
|
||||
import com.cobblemon.mod.common.util.math.geometry.transformDirection
|
||||
import com.cobblemon.mod.common.util.resolveDouble
|
||||
import com.cobblemon.mod.common.util.resolveVec3d
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.DynamicOps
|
||||
import com.mojang.serialization.codecs.PrimitiveCodec
|
||||
@@ -35,20 +37,79 @@ interface ParticleMotion : CodecMapped {
|
||||
init {
|
||||
registerSubtype(ParticleMotionType.DYNAMIC, DynamicParticleMotion::class.java, DynamicParticleMotion.CODEC)
|
||||
registerSubtype(ParticleMotionType.STATIC, StaticParticleMotion::class.java, StaticParticleMotion.CODEC)
|
||||
registerSubtype(ParticleMotionType.PARAMETRIC, ParametricParticleMotion::class.java, ParametricParticleMotion.CODEC)
|
||||
}
|
||||
}
|
||||
|
||||
val type: ParticleMotionType
|
||||
fun getInitialVelocity(runtime: MoLangRuntime, storm: ParticleStorm, particlePos: Vec3d, emitterPos: Vec3d): Vec3d
|
||||
fun getAcceleration(runtime: MoLangRuntime, velocity: Vec3d): Vec3d
|
||||
fun getVelocity(runtime: MoLangRuntime, particle: SnowstormParticle, velocity: Vec3d): Vec3d
|
||||
fun getParticleDirection(runtime: MoLangRuntime, storm: ParticleStorm, velocity: Vec3d, minSpeed: Float): Vec3d
|
||||
}
|
||||
|
||||
enum class ParticleMotionType {
|
||||
DYNAMIC,
|
||||
PARAMETRIC, // TODO figure out how that even works
|
||||
PARAMETRIC,
|
||||
STATIC
|
||||
}
|
||||
|
||||
class ParametricParticleMotion(
|
||||
var offset: Triple<Expression, Expression, Expression> = Triple(
|
||||
NumberExpression(0.0),
|
||||
NumberExpression(0.0),
|
||||
NumberExpression(0.0)
|
||||
),
|
||||
var direction: Triple<Expression, Expression, Expression> = Triple(
|
||||
NumberExpression(0.0),
|
||||
NumberExpression(0.0),
|
||||
NumberExpression(0.0)
|
||||
)
|
||||
) : ParticleMotion {
|
||||
companion object {
|
||||
val CODEC: Codec<ParametricParticleMotion> = RecordCodecBuilder.create { instance ->
|
||||
instance.group(
|
||||
PrimitiveCodec.STRING.fieldOf("type").forGetter { it.type.name },
|
||||
EXPRESSION_CODEC.listOf().fieldOf("offset").forGetter { listOf(it.offset.first, it.offset.second, it.offset.third) },
|
||||
EXPRESSION_CODEC.listOf().fieldOf("direction").forGetter { listOf(it.direction.first, it.direction.second, it.direction.third) }
|
||||
).apply(instance) { _, offset, direction -> ParametricParticleMotion(Triple(offset[0], offset[1], offset[2]), Triple(direction[0], direction[1], direction[2])) }
|
||||
}
|
||||
}
|
||||
|
||||
override val type = ParticleMotionType.PARAMETRIC
|
||||
|
||||
override fun getInitialVelocity(runtime: MoLangRuntime, storm: ParticleStorm, particlePos: Vec3d, emitterPos: Vec3d) = Vec3d.ZERO
|
||||
override fun getVelocity(runtime: MoLangRuntime, particle: SnowstormParticle, velocity: Vec3d): Vec3d {
|
||||
val stormPosition = Vec3d(particle.storm.getX(), particle.storm.getY(), particle.storm.getZ())
|
||||
val offset = runtime.resolveVec3d(this.offset)
|
||||
val particlePosition = Vec3d(particle.getX(), particle.getY(), particle.getZ())
|
||||
val desiredPosition = stormPosition.add(offset)
|
||||
return desiredPosition.subtract(particlePosition)
|
||||
}
|
||||
|
||||
override fun getParticleDirection(runtime: MoLangRuntime, storm: ParticleStorm, velocity: Vec3d, minSpeed: Float) = runtime.resolveVec3d(direction).normalize()
|
||||
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
||||
override fun readFromBuffer(buffer: PacketByteBuf) {
|
||||
offset = Triple(
|
||||
MoLang.createParser(buffer.readString()).parseExpression(),
|
||||
MoLang.createParser(buffer.readString()).parseExpression(),
|
||||
MoLang.createParser(buffer.readString()).parseExpression()
|
||||
)
|
||||
direction = Triple(
|
||||
MoLang.createParser(buffer.readString()).parseExpression(),
|
||||
MoLang.createParser(buffer.readString()).parseExpression(),
|
||||
MoLang.createParser(buffer.readString()).parseExpression()
|
||||
)
|
||||
}
|
||||
override fun writeToBuffer(buffer: PacketByteBuf) {
|
||||
buffer.writeString(offset.first.getString())
|
||||
buffer.writeString(offset.second.getString())
|
||||
buffer.writeString(offset.third.getString())
|
||||
buffer.writeString(direction.first.getString())
|
||||
buffer.writeString(direction.second.getString())
|
||||
buffer.writeString(direction.third.getString())
|
||||
}
|
||||
}
|
||||
|
||||
class DynamicParticleMotion(
|
||||
var direction: ParticleMotionDirection = InwardsMotionDirection(),
|
||||
var speed: Expression = NumberExpression(0.0),
|
||||
@@ -79,14 +140,23 @@ class DynamicParticleMotion(
|
||||
return direction.getDirectionVector(runtime, storm, emitterPos, particlePos).normalize().multiply(runtime.resolveDouble(speed))
|
||||
}
|
||||
|
||||
override fun getAcceleration(runtime: MoLangRuntime, velocity: Vec3d): Vec3d {
|
||||
return Vec3d(
|
||||
override fun getVelocity(runtime: MoLangRuntime, particle: SnowstormParticle, velocity: Vec3d): Vec3d {
|
||||
val acceleration = Vec3d(
|
||||
runtime.resolveDouble(acceleration.first),
|
||||
runtime.resolveDouble(acceleration.second),
|
||||
runtime.resolveDouble(acceleration.third)
|
||||
).subtract(velocity.multiply(runtime.resolveDouble(drag)))
|
||||
)
|
||||
.subtract(velocity.multiply(20 * runtime.resolveDouble(drag)))
|
||||
.multiply(1 / 20.0).multiply(1 / 20.0) // blocks per second per second -> blocks per tick per tick
|
||||
|
||||
return Vec3d(
|
||||
velocity.x + acceleration.x,
|
||||
velocity.y + acceleration.y,
|
||||
velocity.z + acceleration.z
|
||||
)
|
||||
}
|
||||
|
||||
override fun getParticleDirection(runtime: MoLangRuntime, storm: ParticleStorm, velocity: Vec3d, minSpeed: Float) = velocity.normalize()
|
||||
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
||||
|
||||
override fun readFromBuffer(buffer: PacketByteBuf) {
|
||||
@@ -234,7 +304,8 @@ class StaticParticleMotion : ParticleMotion {
|
||||
override val type = ParticleMotionType.STATIC
|
||||
|
||||
override fun getInitialVelocity(runtime: MoLangRuntime, storm: ParticleStorm, particlePos: Vec3d, emitterPos: Vec3d) = Vec3d.ZERO
|
||||
override fun getAcceleration(runtime: MoLangRuntime, velocity: Vec3d) = Vec3d.ZERO
|
||||
override fun getVelocity(runtime: MoLangRuntime, particle: SnowstormParticle, velocity: Vec3d) = velocity
|
||||
override fun getParticleDirection(runtime: MoLangRuntime, storm: ParticleStorm, velocity: Vec3d, minSpeed: Float) = velocity.normalize()
|
||||
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
||||
override fun readFromBuffer(buffer: PacketByteBuf) {}
|
||||
override fun writeToBuffer(buffer: PacketByteBuf) {}
|
||||
|
||||
@@ -32,6 +32,7 @@ interface ParticleRotation : CodecMapped {
|
||||
) {
|
||||
init {
|
||||
registerSubtype(ParticleRotationType.DYNAMIC, DynamicParticleRotation::class.java, DynamicParticleRotation.CODEC)
|
||||
registerSubtype(ParticleRotationType.PARAMETRIC, ParametricParticleRotation::class.java, ParametricParticleRotation.CODEC)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +40,34 @@ interface ParticleRotation : CodecMapped {
|
||||
|
||||
fun getInitialRotation(runtime: MoLangRuntime): Double
|
||||
fun getInitialAngularVelocity(runtime: MoLangRuntime): Double
|
||||
fun getAngularAcceleration(runtime: MoLangRuntime, angularVelocity: Double): Double
|
||||
fun getAngularVelocity(runtime: MoLangRuntime, angle: Double, angularVelocity: Double): Double
|
||||
}
|
||||
|
||||
class ParametricParticleRotation(var expression: Expression = NumberExpression(0.0)): ParticleRotation {
|
||||
companion object {
|
||||
val CODEC: Codec<ParametricParticleRotation> = RecordCodecBuilder.create { instance ->
|
||||
instance.group(
|
||||
PrimitiveCodec.STRING.fieldOf("type").forGetter { it.type.name },
|
||||
EXPRESSION_CODEC.fieldOf("expression").forGetter { it.expression }
|
||||
).apply(instance) { _, expression ->
|
||||
ParametricParticleRotation(expression)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val type = ParticleRotationType.PARAMETRIC
|
||||
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
||||
override fun getInitialRotation(runtime: MoLangRuntime) = runtime.resolveDouble(expression)
|
||||
override fun getInitialAngularVelocity(runtime: MoLangRuntime) = 0.0
|
||||
override fun getAngularVelocity(runtime: MoLangRuntime, angle: Double, angularVelocity: Double) = runtime.resolveDouble(expression) - angle
|
||||
|
||||
override fun readFromBuffer(buffer: PacketByteBuf) {
|
||||
expression = MoLang.createParser(buffer.readString()).parseExpression()
|
||||
}
|
||||
|
||||
override fun writeToBuffer(buffer: PacketByteBuf) {
|
||||
buffer.writeString(expression.getString())
|
||||
}
|
||||
}
|
||||
|
||||
class DynamicParticleRotation(
|
||||
@@ -65,16 +93,16 @@ class DynamicParticleRotation(
|
||||
override val type = ParticleRotationType.DYNAMIC
|
||||
override fun <T> encode(ops: DynamicOps<T>) = CODEC.encodeStart(ops, this)
|
||||
override fun getInitialRotation(runtime: MoLangRuntime) = runtime.resolveDouble(startRotation)
|
||||
override fun getInitialAngularVelocity(runtime: MoLangRuntime) = runtime.resolveDouble(speed)
|
||||
override fun getAngularAcceleration(runtime: MoLangRuntime, angularVelocity: Double): Double {
|
||||
override fun getInitialAngularVelocity(runtime: MoLangRuntime) = runtime.resolveDouble(speed) / 20
|
||||
override fun getAngularVelocity(runtime: MoLangRuntime, angle: Double, angularVelocity: Double): Double {
|
||||
val acceleration = runtime.resolveDouble(acceleration)
|
||||
val nextVelocity = angularVelocity + acceleration
|
||||
val nextVelocity = angularVelocity * 20 + acceleration
|
||||
val drag = nextVelocity * runtime.resolveDouble(drag)
|
||||
return if (abs(drag) > abs(nextVelocity)) {
|
||||
return angularVelocity + (if (abs(drag) > abs(nextVelocity)) {
|
||||
0.0
|
||||
} else {
|
||||
nextVelocity - drag - angularVelocity
|
||||
}
|
||||
nextVelocity - drag - angularVelocity * 20
|
||||
})
|
||||
}
|
||||
|
||||
override fun readFromBuffer(buffer: PacketByteBuf) {
|
||||
|
||||
@@ -35,11 +35,13 @@ class TimeRange : IntRanges {
|
||||
"night" to TimeRange(12542..23459),
|
||||
"noon" to TimeRange(5000..6999),
|
||||
"midnight" to TimeRange(17000..18999),
|
||||
"dawn" to TimeRange(22300..23999, 0..166),
|
||||
"dawn" to TimeRange(22300..23999, 0..999),
|
||||
"dusk" to TimeRange(11834..13701),
|
||||
"twilight" to TimeRange(11834..13701, 22300..23999, 0..166),
|
||||
"morning" to TimeRange(0..4999),
|
||||
"afternoon" to TimeRange(7000..12039)
|
||||
"morning" to TimeRange(23000..23999, 0..4999),
|
||||
"afternoon" to TimeRange(7000..12999),
|
||||
"predawn" to TimeRange(19000..22999),
|
||||
"evening" to TimeRange(13000..16999)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ abstract class SpawningCondition<T : SpawningContext> {
|
||||
return false
|
||||
} else if (ctx.position.z < minZ.orMin() || ctx.position.z > maxZ.orMax()) {
|
||||
return false
|
||||
} else if (dimensions != null && dimensions!!.isNotEmpty() && ctx.world.dimension.effects !in dimensions!!) {
|
||||
} else if (dimensions != null && dimensions!!.isNotEmpty() && ctx.world.dimensionKey.value !in dimensions!!) {
|
||||
return false
|
||||
} else if (moonPhase != null && ctx.moonPhase !in moonPhase!!) {
|
||||
return false
|
||||
|
||||
+2
-2
@@ -30,8 +30,8 @@ import net.minecraft.server.world.ServerWorld
|
||||
*/
|
||||
interface SpawningContextCalculator<I : SpawningContextInput, O : SpawningContext> {
|
||||
companion object {
|
||||
val isAirCondition: (BlockState) -> Boolean = { it.isAir || (!it.isSolid && !it.isLiquid) }
|
||||
val isSolidCondition: (BlockState) -> Boolean = { it.isSolid && !it.isIn(BlockTags.LEAVES) }
|
||||
val isAirCondition: (BlockState) -> Boolean = { it.isAir || (!it.isSolid && !it.fluidState.isIn(FluidTags.WATER)) }
|
||||
val isSolidCondition: (BlockState) -> Boolean = { it.isSolid }
|
||||
val isWaterCondition: (BlockState) -> Boolean = { it.fluidState.isIn(FluidTags.WATER) && it.fluidState.isStill }
|
||||
val isLavaCondition: (BlockState) -> Boolean = { it.fluidState.isIn(FluidTags.LAVA) && it.fluidState.isStill }
|
||||
|
||||
|
||||
@@ -34,15 +34,19 @@ abstract class SpawnAction<R>(
|
||||
/**
|
||||
* Runs the spawn action and processes any non-null result.
|
||||
*/
|
||||
open fun complete(): Boolean {
|
||||
open fun complete(): R? {
|
||||
if (future.isDone) {
|
||||
return null
|
||||
}
|
||||
|
||||
ctx.influences.forEach { it.affectAction(this) }
|
||||
val result = run()
|
||||
return if (result != null) {
|
||||
if (result != null) {
|
||||
future.complete(result)
|
||||
true
|
||||
} else {
|
||||
future.completeExceptionally(Exception("Nothing was spawned."))
|
||||
false
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ abstract class SpawnDetailPreset {
|
||||
var weightMultipliers: MutableList<WeightMultiplier>? = null
|
||||
var weight: Float? = null
|
||||
var percentage: Float? = null
|
||||
var mergeMode = MergeMode.KEEP
|
||||
var mergeMode = MergeMode.INSERT
|
||||
|
||||
open fun apply(spawnDetail: SpawnDetail) {
|
||||
bucket?.let { spawnDetail.bucket = it }
|
||||
|
||||
+1
-1
@@ -124,7 +124,7 @@ open class PlayerPartyStore(
|
||||
}
|
||||
|
||||
// Passive evolutions
|
||||
pokemon.evolutions.filterIsInstance<PassiveEvolution>().forEach { it.attemptEvolution(pokemon) }
|
||||
pokemon.lockedEvolutions.filterIsInstance<PassiveEvolution>().forEach { it.attemptEvolution(pokemon) }
|
||||
val removeList = mutableListOf<Evolution>()
|
||||
pokemon.evolutionProxy.server().forEach {
|
||||
if (!it.test(pokemon) && it is LevelUpEvolution && !it.permanent)
|
||||
|
||||
@@ -99,7 +99,7 @@ open class PCStore(
|
||||
this.lockedSize = lockNewSize
|
||||
if (boxes.size > newSize) {
|
||||
// reduce
|
||||
val slicedBoxes = boxes.slice(boxes.size until newSize)
|
||||
val slicedBoxes = boxes.slice(newSize until boxes.size)
|
||||
boxes.removeAll(slicedBoxes)
|
||||
slicedBoxes.flatMap { it.asIterable() }.forEach(overflowHandler)
|
||||
} else {
|
||||
|
||||
@@ -71,7 +71,6 @@ object BattleBuilder {
|
||||
player1Actor.battleTheme = player2.getBattleTheme()
|
||||
player2Actor.battleTheme = player1.getBattleTheme()
|
||||
}
|
||||
errors
|
||||
} else {
|
||||
errors
|
||||
}
|
||||
@@ -140,7 +139,6 @@ object BattleBuilder {
|
||||
}
|
||||
playerActor.battleTheme = pokemonEntity.getBattleTheme()
|
||||
}
|
||||
errors
|
||||
} else {
|
||||
errors
|
||||
}
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Cobblemon Contributors
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package com.cobblemon.mod.common.battles.dispatch
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import net.minecraft.util.Identifier
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* An [InterpreterInstruction] that triggers an [ActionEffectTimeline]
|
||||
* I think it might be better to have this as an abstract class so we can default the fields
|
||||
*
|
||||
* @author Apion
|
||||
* @since May 19, 2024
|
||||
*/
|
||||
interface ActionEffectInstruction : InterpreterInstruction {
|
||||
var future: CompletableFuture<*>
|
||||
var holds: MutableSet<String>
|
||||
//To expose via molang, so action effects can do different stuff in different instructions
|
||||
//e.g. "x is confused" vs "x hit itself in confusion"
|
||||
val id: Identifier
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
preActionEffect(battle)
|
||||
val runtime = MoLangRuntime()
|
||||
battle.addQueryFunctions(runtime.environment.getQueryStruct())
|
||||
runtime.environment.getQueryStruct().addStandardFunctions()
|
||||
addMolangQueries(runtime)
|
||||
runActionEffect(battle, runtime)
|
||||
postActionEffect(battle)
|
||||
}
|
||||
|
||||
fun preActionEffect(battle: PokemonBattle)
|
||||
fun runActionEffect(battle: PokemonBattle, runtime: MoLangRuntime)
|
||||
fun postActionEffect(battle: PokemonBattle)
|
||||
|
||||
fun addMolangQueries(runtime: MoLangRuntime) {
|
||||
runtime.environment.getQueryStruct()
|
||||
.addFunction("instruction_id") { StringValue(id.toString()) }
|
||||
}
|
||||
|
||||
}
|
||||
+52
-6
@@ -8,16 +8,28 @@
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.ActionEffectInstruction
|
||||
import com.cobblemon.mod.common.battles.dispatch.CauserInstruction
|
||||
import com.cobblemon.mod.common.battles.dispatch.GO
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
|
||||
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* Format: |-activate|POKEMON|EFFECT
|
||||
@@ -28,19 +40,52 @@ import net.minecraft.text.Text
|
||||
* @author Hunter
|
||||
* @since September 25th, 2022
|
||||
*/
|
||||
class ActivateInstruction(val instructionSet: InstructionSet, val message: BattleMessage) : InterpreterInstruction, CauserInstruction {
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
class ActivateInstruction(val instructionSet: InstructionSet, val message: BattleMessage) : ActionEffectInstruction, CauserInstruction {
|
||||
override var future: CompletableFuture<*> = CompletableFuture.completedFuture(Unit)
|
||||
override var holds = mutableSetOf<String>()
|
||||
override val id = cobblemonResource("activate")
|
||||
|
||||
override fun preActionEffect(battle: PokemonBattle) {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return
|
||||
val effect = message.effectAt(1) ?: return
|
||||
val extraEffect = message.effectAt(2)?.typelessData ?: Text.literal("UNKNOWN")
|
||||
ShowdownInterpreter.broadcastOptionalAbility(battle, effect, pokemon)
|
||||
|
||||
battle.dispatch{
|
||||
val pokemonName = pokemon.getName()
|
||||
val sourceName = message.battlePokemonFromOptional(battle)?.getName() ?: Text.literal("UNKNOWN")
|
||||
ShowdownInterpreter.lastCauser[battle.battleId] = message
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
GO
|
||||
}
|
||||
}
|
||||
|
||||
override fun runActionEffect(battle: PokemonBattle, runtime: MoLangRuntime) {
|
||||
battle.dispatch {
|
||||
val effect = message.effectAt(1) ?: return@dispatch GO
|
||||
val status = Statuses.getStatus(effect.id)
|
||||
val actionEffect = status?.getActionEffect() ?: return@dispatch GO
|
||||
val providers = mutableListOf<Any>(battle)
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatch GO
|
||||
if (!SwitchInstruction.isVirtual) {
|
||||
pokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
|
||||
}
|
||||
val context = ActionEffectContext(
|
||||
actionEffect = actionEffect,
|
||||
runtime = runtime,
|
||||
providers = providers
|
||||
)
|
||||
this.future = actionEffect.run(context)
|
||||
holds = context.holds // Reference so future things can check on this action effect's holds
|
||||
future.thenApply { holds.clear() }
|
||||
return@dispatch GO
|
||||
}
|
||||
}
|
||||
|
||||
override fun postActionEffect(battle: PokemonBattle) {
|
||||
battle.dispatch {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatch GO
|
||||
val extraEffect = message.effectAt(2)?.typelessData ?: Text.literal("UNKNOWN")
|
||||
val effect = message.effectAt(1) ?: return@dispatch GO
|
||||
val pokemonName = pokemon.getName()
|
||||
val sourceName = message.battlePokemonFromOptional(battle)?.getName() ?: Text.literal("UNKNOWN")
|
||||
val lang = when (effect.id) {
|
||||
// Includes a 3rd argument being the magnitude level as a number
|
||||
"magnitude" -> battleLang("activate.magnitude", message.argumentAt(2)?.toIntOrNull() ?: 1)
|
||||
@@ -59,7 +104,8 @@ class ActivateInstruction(val instructionSet: InstructionSet, val message: Battl
|
||||
else -> battleLang("activate.${effect.id}", pokemonName, sourceName, extraEffect)
|
||||
}
|
||||
battle.broadcastChatMessage(lang)
|
||||
WaitDispatch(1F)
|
||||
//We check holds here so the chat msg + particle effect happen more concurrently, instead of sequentially
|
||||
UntilDispatch { "effects" !in holds}
|
||||
}
|
||||
}
|
||||
}
|
||||
+47
-3
@@ -8,14 +8,25 @@
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleContext
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffects
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.stats.Stats
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.dispatch.ActionEffectInstruction
|
||||
import com.cobblemon.mod.common.battles.dispatch.GO
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import net.minecraft.util.Identifier
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* Format: |-boost|POKEMON|STAT|AMOUNT or |-unboost|POKEMON|STAT|AMOUNT
|
||||
@@ -25,9 +36,35 @@ import com.cobblemon.mod.common.util.battleLang
|
||||
* @author Hiroku
|
||||
* @since August 20th, 2022
|
||||
*/
|
||||
class BoostInstruction(val instructionSet: InstructionSet, val message: BattleMessage, val remainingLines: Iterator<BattleMessage>, val isBoost: Boolean = true): InterpreterInstruction {
|
||||
class BoostInstruction(val instructionSet: InstructionSet, val message: BattleMessage, val remainingLines: Iterator<BattleMessage>, val isBoost: Boolean = true): ActionEffectInstruction {
|
||||
override var future: CompletableFuture<*> = CompletableFuture.completedFuture(Unit)
|
||||
override var holds = mutableSetOf<String>()
|
||||
override val id = cobblemonResource("boost")
|
||||
override fun preActionEffect(battle: PokemonBattle) {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
}
|
||||
|
||||
override fun runActionEffect(battle: PokemonBattle, runtime: MoLangRuntime) {
|
||||
battle.dispatch {
|
||||
val actionEffect = if (isBoost) BOOST_EFFECT else UNBOOST_EFFECT
|
||||
val providers = mutableListOf<Any>(battle)
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatch GO
|
||||
if (!SwitchInstruction.isVirtual) {
|
||||
pokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
|
||||
}
|
||||
val context = ActionEffectContext(
|
||||
actionEffect = actionEffect,
|
||||
runtime = runtime,
|
||||
providers = providers
|
||||
)
|
||||
this.future = actionEffect.run(context)
|
||||
holds = context.holds // Reference so future things can check on this action effect's holds
|
||||
future.thenApply { holds.clear() }
|
||||
return@dispatch GO
|
||||
}
|
||||
}
|
||||
|
||||
override fun postActionEffect(battle: PokemonBattle) {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return
|
||||
val statKey = message.argumentAt(1) ?: return
|
||||
val stages = message.argumentAt(2)?.toInt() ?: return
|
||||
@@ -35,7 +72,7 @@ class BoostInstruction(val instructionSet: InstructionSet, val message: BattleMe
|
||||
val severity = Stats.getSeverity(stages)
|
||||
val rootKey = if (isBoost) "boost" else "unboost"
|
||||
|
||||
battle.dispatchWaiting(1.5F) {
|
||||
battle.dispatch {
|
||||
val lang = when {
|
||||
message.hasOptionalArgument("zeffect") -> battleLang("$rootKey.$severity.zeffect", pokemon.getName(), stat)
|
||||
else -> battleLang("$rootKey.$severity", pokemon.getName(), stat)
|
||||
@@ -47,6 +84,13 @@ class BoostInstruction(val instructionSet: InstructionSet, val message: BattleMe
|
||||
// TODO: replace with context that tracks detailed information such as # of stages
|
||||
repeat(stages) { pokemon.contextManager.add(context) }
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
return@dispatch UntilDispatch { "effects" !in holds }
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val BOOST_EFFECT = ActionEffects.actionEffects[cobblemonResource("boost")]!!
|
||||
val UNBOOST_EFFECT = ActionEffects.actionEffects[cobblemonResource("unboost")]!!
|
||||
}
|
||||
|
||||
}
|
||||
+53
-6
@@ -8,14 +8,27 @@
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.TargetsProvider
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.battles.dispatch.ActionEffectInstruction
|
||||
import com.cobblemon.mod.common.battles.dispatch.GO
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
|
||||
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import net.minecraft.util.Identifier
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
* Formats: |cant|POKEMON|REASON and |cant|POKEMON|REASON|MOVE
|
||||
@@ -24,12 +37,42 @@ import com.cobblemon.mod.common.util.lang
|
||||
* @author Deltric
|
||||
* @since January 22nd, 2022
|
||||
*/
|
||||
class CantInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
class CantInstruction(val message: BattleMessage): ActionEffectInstruction {
|
||||
override var future: CompletableFuture<*> = CompletableFuture.completedFuture(Unit)
|
||||
override var holds = mutableSetOf<String>()
|
||||
override val id = cobblemonResource("cant")
|
||||
override fun preActionEffect(battle: PokemonBattle) {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
battle.dispatchWaiting {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatchWaiting
|
||||
val effectID = message.effectAt(1)?.id ?: return@dispatchWaiting
|
||||
}
|
||||
|
||||
override fun runActionEffect(battle: PokemonBattle, runtime: MoLangRuntime) {
|
||||
battle.dispatch {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatch GO
|
||||
val effectID = message.effectAt(1)?.id ?: return@dispatch GO
|
||||
val name = pokemon.getName()
|
||||
val status = Statuses.getStatus(effectID)
|
||||
val actionEffect = status?.getActionEffect() ?: return@dispatch GO
|
||||
val providers = mutableListOf<Any>(battle)
|
||||
if (!SwitchInstruction.isVirtual) {
|
||||
pokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
|
||||
}
|
||||
|
||||
val context = ActionEffectContext(
|
||||
actionEffect = actionEffect,
|
||||
runtime = runtime,
|
||||
providers = providers
|
||||
)
|
||||
this.future = actionEffect.run(context)
|
||||
holds = context.holds // Reference so future things can check on this action effect's holds
|
||||
future.thenApply { holds.clear() }
|
||||
GO
|
||||
}
|
||||
}
|
||||
|
||||
override fun postActionEffect(battle: PokemonBattle) {
|
||||
battle.dispatch {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return@dispatch GO
|
||||
val effectID = message.effectAt(1)?.id ?: return@dispatch GO
|
||||
val name = pokemon.getName()
|
||||
// Move may be null as it's not always given
|
||||
val moveName = message.moveAt(2)?.displayName ?: run { "(Unrecognized: ${message.argumentAt(2)})".text() }
|
||||
@@ -38,7 +81,7 @@ class CantInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
// TODO: in the games they use a generic image because there is a popup of the ability and the sprite of the mon, it may be good to have a similar system here
|
||||
"armortail", "damp", "dazzling", "queenlymajesty" -> battleLang("cant.generic", name, moveName)
|
||||
"par", "slp", "frz" -> {
|
||||
val status = Statuses.getStatus(effectID)?.name?.path ?: return@dispatchWaiting
|
||||
val status = Statuses.getStatus(effectID)?.name?.path ?: return@dispatch GO
|
||||
lang("status.$status.is", name)
|
||||
}
|
||||
else -> battleLang("cant.$effectID", name, moveName)
|
||||
@@ -46,6 +89,10 @@ class CantInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
battle.broadcastChatMessage(lang.red())
|
||||
battle.minorBattleActions[pokemon.uuid] = message
|
||||
UntilDispatch { "effects" !in holds }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+78
-25
@@ -8,15 +8,21 @@
|
||||
|
||||
package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.battles.model.actor.BattleActor
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.moves.animations.ActionEffectContext
|
||||
import com.cobblemon.mod.common.api.moves.animations.UsersProvider
|
||||
import com.cobblemon.mod.common.api.pokemon.status.Statuses
|
||||
import com.cobblemon.mod.common.api.text.red
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.ShowdownInterpreter.lastCauser
|
||||
import com.cobblemon.mod.common.battles.dispatch.ActionEffectInstruction
|
||||
import com.cobblemon.mod.common.battles.dispatch.GO
|
||||
import com.cobblemon.mod.common.battles.dispatch.InstructionSet
|
||||
import com.cobblemon.mod.common.battles.dispatch.InterpreterInstruction
|
||||
import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
|
||||
import com.cobblemon.mod.common.battles.dispatch.WaitDispatch
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
@@ -25,11 +31,13 @@ import com.cobblemon.mod.common.net.messages.client.battle.BattleHealthChangePac
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.RunPosableMoLangPacket
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.DamageTakenEvolutionProgress
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.RecoilEvolutionProgress
|
||||
import com.cobblemon.mod.common.pokemon.status.statuses.persistent.PoisonStatus
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import com.cobblemon.mod.common.util.lang
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import kotlin.math.roundToInt
|
||||
import net.minecraft.text.Text
|
||||
import net.minecraft.util.Identifier
|
||||
|
||||
/**
|
||||
* Format: |-damage|POKEMON|HP STATUS
|
||||
@@ -43,46 +51,90 @@ class DamageInstruction(
|
||||
val actor: BattleActor,
|
||||
val publicMessage: BattleMessage,
|
||||
val privateMessage: BattleMessage
|
||||
) : InterpreterInstruction {
|
||||
var future = CompletableFuture.completedFuture(Unit)
|
||||
) : ActionEffectInstruction {
|
||||
val expectedTarget = publicMessage.battlePokemon(0, actor.battle)
|
||||
override var future: CompletableFuture<*> = CompletableFuture.completedFuture(Unit)
|
||||
override var holds = mutableSetOf<String>()
|
||||
override val id = cobblemonResource("damage")
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
override fun preActionEffect(battle: PokemonBattle) {
|
||||
val battlePokemon = publicMessage.battlePokemon(0, actor.battle) ?: return
|
||||
val recoiling = privateMessage.optionalArgument("from")?.equals("recoil", true) == true
|
||||
val lastCauser = instructionSet.getMostRecentCauser(comparedTo = this)
|
||||
if (recoiling) {
|
||||
battlePokemon.effectedPokemon.let { pokemon ->
|
||||
if (RecoilEvolutionProgress.supports(pokemon)) {
|
||||
val newPercentage = privateMessage.argumentAt(1)?.split("/")?.getOrNull(0)?.toIntOrNull() ?: 0
|
||||
val newHealth = (pokemon.hp * (newPercentage / 100.0)).roundToInt()
|
||||
val difference = pokemon.currentHealth - newHealth
|
||||
if (difference > 0) {
|
||||
val progress = pokemon.evolutionProxy.current().progressFirstOrCreate({ it is RecoilEvolutionProgress }) { RecoilEvolutionProgress() }
|
||||
progress.updateProgress(RecoilEvolutionProgress.Progress(progress.currentProgress().recoil + difference))
|
||||
}
|
||||
doRecoilEvoChecks(battlePokemon)
|
||||
if (lastCauser is MoveInstruction) {
|
||||
battle.dispatch {
|
||||
//Is the recoil hold currently used anywhere?
|
||||
UntilDispatch { "recoil" !in lastCauser.holds }
|
||||
}
|
||||
}
|
||||
}
|
||||
val newHealth = privateMessage.argumentAt(1)?.split(" ")?.get(0) ?: return
|
||||
val effect = privateMessage.effect()
|
||||
val source = privateMessage.battlePokemonFromOptional(battle)
|
||||
var causedFaint = newHealth == "0"
|
||||
source?.let { ShowdownInterpreter.broadcastOptionalAbility(battle, effect, it) }
|
||||
}
|
||||
|
||||
battle.dispatch {
|
||||
if (lastCauser is MoveInstruction && recoiling) {
|
||||
UntilDispatch { "recoil" !in lastCauser.holds }
|
||||
} else {
|
||||
GO
|
||||
private fun doRecoilEvoChecks(battlePokemon: BattlePokemon) {
|
||||
battlePokemon.effectedPokemon.let { pokemon ->
|
||||
if (RecoilEvolutionProgress.supports(pokemon)) {
|
||||
val healthStr = privateMessage.argumentAt(1) ?: throw UnsupportedOperationException(
|
||||
"Cant get recoil string"
|
||||
)
|
||||
val newHealth =
|
||||
"([0-9]+).*".toRegex().find(healthStr)?.groups?.get(1)?.value?.toIntOrNull()
|
||||
?: throw UnsupportedOperationException("Cant get recoil string")
|
||||
val difference = pokemon.currentHealth - newHealth
|
||||
if (difference > 0) {
|
||||
val progress = pokemon.evolutionProxy.current()
|
||||
.progressFirstOrCreate({ it is RecoilEvolutionProgress }) { RecoilEvolutionProgress() }
|
||||
progress.updateProgress(RecoilEvolutionProgress.Progress(progress.currentProgress().recoil + difference))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
source?.let { ShowdownInterpreter.broadcastOptionalAbility(battle, effect, it) }
|
||||
override fun runActionEffect(battle: PokemonBattle, runtime: MoLangRuntime) {
|
||||
val effect = privateMessage.effect()
|
||||
val battlePokemon = publicMessage.battlePokemon(0, actor.battle) ?: return
|
||||
var status = effect?.id?.let { Statuses.getStatus(it) }
|
||||
battle.dispatch {
|
||||
val pokemon = privateMessage.battlePokemon(0, battle) ?: return@dispatch GO
|
||||
//Showdown doesnt tell us on damage if its poison or toxic so we gotta consult the entity
|
||||
if (status is PoisonStatus) {
|
||||
status = pokemon.effectedPokemon.status?.status ?: status
|
||||
}
|
||||
val actionEffect = status?.getActionEffect() ?: return@dispatch GO
|
||||
val providers = mutableListOf<Any>(battle)
|
||||
if (!SwitchInstruction.isVirtual) {
|
||||
battlePokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
|
||||
}
|
||||
|
||||
val context = ActionEffectContext(
|
||||
actionEffect = actionEffect,
|
||||
runtime = runtime,
|
||||
providers = providers
|
||||
)
|
||||
this.future = actionEffect.run(context)
|
||||
holds = context.holds // Reference so future things can check on this action effect's holds
|
||||
future.thenApply { holds.clear() }
|
||||
return@dispatch GO
|
||||
}
|
||||
}
|
||||
|
||||
override fun postActionEffect(battle: PokemonBattle) {
|
||||
val newHealth = privateMessage.argumentAt(1)?.split(" ")?.get(0) ?: return
|
||||
val battlePokemon = publicMessage.battlePokemon(0, actor.battle) ?: return
|
||||
var causedFaint = newHealth == "0"
|
||||
val effect = privateMessage.effect()
|
||||
val source = privateMessage.battlePokemonFromOptional(battle)
|
||||
val lastCauser = instructionSet.getMostRecentCauser(comparedTo = this)
|
||||
battle.dispatch {
|
||||
val pokemonName = battlePokemon.getName()
|
||||
val pokemonEntity = battlePokemon.entity
|
||||
if (!causedFaint && pokemonEntity != null) {
|
||||
//Play recoil animation if the pokemon recoiling isnt dead
|
||||
if (!causedFaint && pokemonEntity != null && !SwitchInstruction.isVirtual) {
|
||||
val pkt = PlayPoseableAnimationPacket(pokemonEntity.id, setOf("recoil"), emptySet())
|
||||
pkt.sendToPlayersAround(
|
||||
x = pokemonEntity.x,
|
||||
@@ -92,8 +144,8 @@ class DamageInstruction(
|
||||
distance = 50.0
|
||||
)
|
||||
}
|
||||
|
||||
if (pokemonEntity != null) {
|
||||
//Play hit particle
|
||||
if (pokemonEntity != null && !SwitchInstruction.isVirtual) {
|
||||
RunPosableMoLangPacket(pokemonEntity.id, setOf("q.particle('cobblemon:hit', 'target')")).sendToPlayersAround(
|
||||
x = pokemonEntity.x,
|
||||
y = pokemonEntity.y,
|
||||
@@ -157,8 +209,9 @@ class DamageInstruction(
|
||||
} else if (causedFaint) {
|
||||
GO
|
||||
} else {
|
||||
WaitDispatch(1F)
|
||||
UntilDispatch {"effects" !in holds}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -47,7 +47,7 @@ class DragInstruction(val instructionSet: InstructionSet, val battleActor: Battl
|
||||
val entity = if (battleActor is EntityBackedBattleActor<*>) battleActor.entity else null
|
||||
setOf(
|
||||
BattleDispatch {
|
||||
if (entity != null) {
|
||||
if (entity != null && !SwitchInstruction.isVirtual) {
|
||||
SwitchInstruction.createEntitySwitch(battle, battleActor, entity, pnx, activePokemon, pokemon, illusion, imposter)
|
||||
} else {
|
||||
SwitchInstruction.createNonEntitySwitch(battle, battleActor, pnx, activePokemon, pokemon, illusion)
|
||||
|
||||
+3
-1
@@ -38,7 +38,9 @@ class EndItemInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
battle.minorBattleActions[battlePokemon.uuid] = message
|
||||
battlePokemon.contextManager.remove(itemEffect.id, BattleContext.Type.ITEM)
|
||||
if (message.hasOptionalArgument("eat")) {
|
||||
battlePokemon.entity?.playSound(CobblemonSounds.BERRY_EAT, 1F, 1F)
|
||||
if (!SwitchInstruction.isVirtual) {
|
||||
battlePokemon.entity?.playSound(CobblemonSounds.BERRY_EAT, 1F, 1F)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -27,12 +27,12 @@ class FieldStartInstruction(val message: BattleMessage): InterpreterInstruction
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val effect = message.effectAt(0) ?: return
|
||||
val user = message.battlePokemonFromOptional(battle)
|
||||
user?.let { ShowdownInterpreter.broadcastOptionalAbility(battle, effect, user) }
|
||||
val source = message.battlePokemonFromOptional(battle)
|
||||
source?.let { ShowdownInterpreter.broadcastOptionalAbility(battle, message.effect(), source) }
|
||||
|
||||
battle.dispatchWaiting(1.5F) {
|
||||
// Note persistent is a CAP ability only we can ignore the flag
|
||||
val lang = battleLang("fieldstart.${effect.id}", user?.getName() ?: Text.literal("UNKNOWN"))
|
||||
val lang = battleLang("fieldstart.${effect.id}", source?.getName() ?: Text.literal("UNKNOWN"))
|
||||
battle.broadcastChatMessage(lang)
|
||||
|
||||
val type = BattleContext.Type.valueOf(effect.rawData.substringAfterLast(" ").uppercase())
|
||||
|
||||
+4
-1
@@ -10,10 +10,10 @@ package com.cobblemon.mod.common.battles.interpreter.instructions
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.BattleMessage
|
||||
import com.cobblemon.mod.common.api.battles.interpreter.Effect
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunction
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addStandardFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.moves.Moves
|
||||
@@ -29,6 +29,7 @@ import com.cobblemon.mod.common.battles.dispatch.UntilDispatch
|
||||
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon
|
||||
import com.cobblemon.mod.common.pokemon.evolution.progress.UseMoveEvolutionProgress
|
||||
import com.cobblemon.mod.common.util.battleLang
|
||||
import com.cobblemon.mod.common.util.cobblemonResource
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
/**
|
||||
@@ -85,6 +86,7 @@ class MoveInstruction(
|
||||
battle.majorBattleActions[userPokemon.uuid] = message
|
||||
|
||||
val providers = mutableListOf<Any>(battle)
|
||||
if (SwitchInstruction.isVirtual) return@dispatch GO
|
||||
userPokemon.effectedPokemon.entity?.let { UsersProvider(it) }?.let(providers::add)
|
||||
targetPokemon?.effectedPokemon?.entity?.let { TargetsProvider(it) }?.let(providers::add)
|
||||
val runtime = MoLangRuntime().also {
|
||||
@@ -121,6 +123,7 @@ class MoveInstruction(
|
||||
}
|
||||
|
||||
runtime.environment.getQueryStruct().addFunction("move") { move.struct }
|
||||
runtime.environment.getQueryStruct().addFunction("instruction_id") { StringValue(cobblemonResource("move").toString()) }
|
||||
|
||||
this.future = actionEffect.run(context)
|
||||
holds = context.holds // Reference so future things can check on this action effect's holds
|
||||
|
||||
+4
-2
@@ -32,8 +32,10 @@ class ReplaceInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
val pokemon = message.battlePokemon(0, battle) ?: return
|
||||
|
||||
battle.dispatchGo {
|
||||
val entity = pokemon.entity
|
||||
entity?.let { it.effects.mockEffect?.end(it) }
|
||||
if (!SwitchInstruction.isVirtual) {
|
||||
val entity = pokemon.entity
|
||||
entity?.let { it.effects.mockEffect?.end(it) }
|
||||
}
|
||||
|
||||
battle.sendSidedUpdate(
|
||||
source = actor,
|
||||
|
||||
+4
-2
@@ -48,7 +48,7 @@ class SwitchInstruction(val instructionSet: InstructionSet, val battleActor: Bat
|
||||
activePokemon.battlePokemon = pokemon
|
||||
activePokemon.illusion = illusion
|
||||
val pokemonEntity = pokemon.entity
|
||||
if (pokemonEntity == null && entity != null) {
|
||||
if (pokemonEntity == null && entity != null && !isVirtual) {
|
||||
val targetPos = battleActor.getSide().getOppositeSide().actors.filterIsInstance<EntityBackedBattleActor<*>>().firstOrNull()?.entity?.pos?.let { pos ->
|
||||
val offset = pos.subtract(entity.pos)
|
||||
val idealPos = entity.pos.add(offset.multiply(0.33))
|
||||
@@ -87,7 +87,7 @@ class SwitchInstruction(val instructionSet: InstructionSet, val battleActor: Bat
|
||||
|
||||
setOf(
|
||||
BattleDispatch {
|
||||
if (entity != null) {
|
||||
if (entity != null && !isVirtual) {
|
||||
createEntitySwitch(battle, actor, entity, pnx, activePokemon, pokemon, illusion, imposter)
|
||||
} else {
|
||||
createNonEntitySwitch(battle, actor, pnx, activePokemon, pokemon, illusion)
|
||||
@@ -99,6 +99,8 @@ class SwitchInstruction(val instructionSet: InstructionSet, val battleActor: Bat
|
||||
}
|
||||
|
||||
companion object{
|
||||
val isVirtual = true
|
||||
|
||||
fun createEntitySwitch(
|
||||
battle: PokemonBattle,
|
||||
actor: BattleActor,
|
||||
|
||||
+11
-7
@@ -40,22 +40,26 @@ class TransformInstruction(val battle: PokemonBattle, val message: BattleMessage
|
||||
ShowdownInterpreter.broadcastOptionalAbility(battle, effect, pokemon)
|
||||
|
||||
battle.dispatch {
|
||||
if (SwitchInstruction.isVirtual) return@dispatch GO
|
||||
val entity = pokemon.entity ?: return@dispatch GO
|
||||
val future = TransformEffect(targetPokemon.effectedPokemon, battle.started).start(entity)
|
||||
UntilDispatch { future?.isDone != false }
|
||||
}
|
||||
|
||||
battle.dispatchWaiting {
|
||||
val mock = pokemon.entity?.effects?.mockEffect?.mock
|
||||
val pokemonName = pokemon.getName()
|
||||
val targetPokemonName = targetPokemon.getName()
|
||||
|
||||
mock?.let {
|
||||
battle.sendSidedUpdate(
|
||||
source = actor,
|
||||
allyPacket = BattleTransformPokemonPacket(pnx, pokemon, it, true),
|
||||
opponentPacket = BattleTransformPokemonPacket(pnx, pokemon, it, false)
|
||||
)
|
||||
if (!SwitchInstruction.isVirtual) {
|
||||
val mock = pokemon.entity?.effects?.mockEffect?.mock
|
||||
|
||||
mock?.let {
|
||||
battle.sendSidedUpdate(
|
||||
source = actor,
|
||||
allyPacket = BattleTransformPokemonPacket(pnx, pokemon, it, true),
|
||||
opponentPacket = BattleTransformPokemonPacket(pnx, pokemon, it, false)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val lang = battleLang("transform", pokemonName, targetPokemonName)
|
||||
|
||||
+2
-2
@@ -30,8 +30,8 @@ class WeatherInstruction(val message: BattleMessage): InterpreterInstruction {
|
||||
|
||||
override fun invoke(battle: PokemonBattle) {
|
||||
val weather = message.effectAt(0)?.id ?: return
|
||||
val user = message.battlePokemonFromOptional(battle) ?: return
|
||||
ShowdownInterpreter.broadcastOptionalAbility(battle, message.effect(), user)
|
||||
val source = message.battlePokemonFromOptional(battle)
|
||||
source?.let { ShowdownInterpreter.broadcastOptionalAbility(battle, message.effect(), source) }
|
||||
|
||||
battle.dispatchWaiting(1.5F) {
|
||||
val lang = when {
|
||||
|
||||
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.battles.runner
|
||||
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.battles.runner.graal.GraalShowdownService
|
||||
import com.cobblemon.mod.common.battles.runner.socket.SocketShowdownService
|
||||
import com.google.gson.JsonArray
|
||||
import java.util.UUID
|
||||
|
||||
@@ -36,6 +37,6 @@ interface ShowdownService {
|
||||
|
||||
|
||||
companion object {
|
||||
val service: ShowdownService by lazy { GraalShowdownService() }
|
||||
val service: ShowdownService by lazy { SocketShowdownService() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
-2
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.battles.runner.socket
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonImplementation
|
||||
import com.cobblemon.mod.common.api.battles.model.PokemonBattle
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies
|
||||
import com.cobblemon.mod.common.battles.BagItems
|
||||
@@ -16,9 +17,11 @@ import com.cobblemon.mod.common.battles.ShowdownInterpreter
|
||||
import com.cobblemon.mod.common.battles.runner.ShowdownService
|
||||
import com.cobblemon.mod.common.pokemon.FormData
|
||||
import com.cobblemon.mod.common.pokemon.Species
|
||||
import com.cobblemon.mod.common.util.server
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonArray
|
||||
import java.io.BufferedReader
|
||||
import java.io.File
|
||||
import java.io.InputStreamReader
|
||||
import java.io.OutputStreamWriter
|
||||
import java.net.InetAddress
|
||||
@@ -83,7 +86,9 @@ class SocketShowdownService(val host: String = "localhost", val port: Int = 1846
|
||||
|
||||
private fun readMessage(): String {
|
||||
val payloadSize = read(reader, 8).toInt()
|
||||
println("Reading payload of size: $payloadSize")
|
||||
val payload = read(reader, payloadSize)
|
||||
println("Response: $payload")
|
||||
return payload
|
||||
}
|
||||
|
||||
@@ -113,7 +118,18 @@ class SocketShowdownService(val host: String = "localhost", val port: Int = 1846
|
||||
writer.write(">getCobbledMoves\n")
|
||||
writer.flush()
|
||||
val response = readMessage()
|
||||
return gson.fromJson(response, JsonArray::class.java)
|
||||
try {
|
||||
return gson.fromJson(response, JsonArray::class.java)
|
||||
}
|
||||
catch (e: Exception) {
|
||||
println("Error, JSON logged to logs/showdown.log")
|
||||
File("./showdown.log").writer().use {
|
||||
server()?.getFile("./logs/showdown.log")?.writer().use { writer ->
|
||||
writer?.write(response)
|
||||
}
|
||||
}
|
||||
}
|
||||
return JsonArray()
|
||||
}
|
||||
|
||||
override fun getItemIds(): JsonArray {
|
||||
@@ -166,4 +182,4 @@ class SocketShowdownService(val host: String = "localhost", val port: Int = 1846
|
||||
acknowledge()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import net.minecraft.entity.LivingEntity
|
||||
import net.minecraft.entity.ai.pathing.NavigationType
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.inventory.SidedInventory
|
||||
import net.minecraft.inventory.SimpleInventory
|
||||
import net.minecraft.item.ItemPlacementContext
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
@@ -38,6 +39,7 @@ import net.minecraft.util.shape.VoxelShapes
|
||||
import net.minecraft.world.BlockView
|
||||
import net.minecraft.world.World
|
||||
import net.minecraft.world.WorldAccess
|
||||
import net.minecraft.world.WorldEvents
|
||||
import net.minecraft.world.WorldView
|
||||
|
||||
|
||||
@@ -72,10 +74,12 @@ class RestorationTankBlock(properties: Settings) : MultiblockBlock(properties),
|
||||
|
||||
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity?) {
|
||||
super.onBreak(world, pos, state, player)
|
||||
val otherPart = world.getBlockState(getPositionOfOtherPart(state, pos))
|
||||
if (otherPart.block is RestorationTankBlock) {
|
||||
world.setBlockState(getPositionOfOtherPart(state, pos), Blocks.AIR.defaultState, 35)
|
||||
world.syncWorldEvent(player, 2001, getPositionOfOtherPart(state, pos), getRawIdFromState(otherPart))
|
||||
if (!world.isClient) {
|
||||
val otherPart = world.getBlockState(getPositionOfOtherPart(state, pos))
|
||||
if (otherPart.block is RestorationTankBlock) {
|
||||
world.setBlockState(getPositionOfOtherPart(state, pos), Blocks.AIR.defaultState, Block.NOTIFY_ALL)
|
||||
world.syncWorldEvent(player, WorldEvents.BLOCK_BROKEN, getPositionOfOtherPart(state, pos), getRawIdFromState(otherPart))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,9 +91,9 @@ class RestorationTankBlock(properties: Settings) : MultiblockBlock(properties),
|
||||
itemStack: ItemStack?
|
||||
) {
|
||||
//Place the full block before we call to super to validate the multiblock
|
||||
world.setBlockState(pos.up(), state.with(PART, TankPart.TOP) as BlockState, 3)
|
||||
world.setBlockState(pos.up(), state.with(PART, TankPart.TOP) as BlockState, Block.NOTIFY_ALL)
|
||||
world.updateNeighbors(pos, Blocks.AIR)
|
||||
state.updateNeighbors(world, pos, 3)
|
||||
state.updateNeighbors(world, pos, Block.NOTIFY_ALL)
|
||||
super.onPlaced(world, pos, state, placer, itemStack)
|
||||
}
|
||||
|
||||
@@ -100,7 +104,7 @@ class RestorationTankBlock(properties: Settings) : MultiblockBlock(properties),
|
||||
val tankBottomPos = pos.down()
|
||||
val tankBottomState = world.getBlockState(tankBottomPos)
|
||||
if(tankBottomState.block.equals(CobblemonBlocks.RESTORATION_TANK.asBlock()) && tankBottomState.get(PART) == TankPart.BOTTOM) {
|
||||
return super.onUse(tankBottomState, world, tankBottomPos, player, hand, hit)
|
||||
return onUse(tankBottomState, world, tankBottomPos, player, hand, hit)
|
||||
}
|
||||
}
|
||||
return super.onUse(state, world, pos, player, hand, hit)
|
||||
@@ -206,9 +210,8 @@ class RestorationTankBlock(properties: Settings) : MultiblockBlock(properties),
|
||||
): SidedInventory {
|
||||
val tankEntity =
|
||||
(if (state.get(PART) == TankPart.TOP) world.getBlockEntity(pos.down())
|
||||
else world.getBlockEntity(pos)) as RestorationTankBlockEntity
|
||||
|
||||
return tankEntity.inv
|
||||
else world.getBlockEntity(pos))
|
||||
return if(tankEntity != null && tankEntity is RestorationTankBlockEntity) tankEntity.inv else DummyInventory()
|
||||
}
|
||||
|
||||
enum class TankPart(private val label: String) : StringIdentifiable {
|
||||
@@ -226,5 +229,18 @@ class RestorationTankBlock(properties: Settings) : MultiblockBlock(properties),
|
||||
val PART = EnumProperty.of("part", TankPart::class.java)
|
||||
val TRIGGERED = Properties.TRIGGERED
|
||||
val ON = BooleanProperty.of("on")
|
||||
class DummyInventory : SimpleInventory(0), SidedInventory {
|
||||
override fun getAvailableSlots(side: Direction): IntArray {
|
||||
return IntArray(0)
|
||||
}
|
||||
|
||||
override fun canInsert(slot: Int, stack: ItemStack, dir: Direction?): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
override fun canExtract(slot: Int, stack: ItemStack, dir: Direction): Boolean {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import net.minecraft.item.ItemPlacementContext
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.screen.ScreenHandler
|
||||
import net.minecraft.server.network.ServerPlayerEntity
|
||||
import net.minecraft.server.world.ServerWorld
|
||||
import net.minecraft.sound.SoundCategory
|
||||
import net.minecraft.state.StateManager
|
||||
import net.minecraft.state.property.BooleanProperty
|
||||
@@ -37,6 +38,7 @@ import net.minecraft.util.*
|
||||
import net.minecraft.util.hit.BlockHitResult
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.util.math.Direction
|
||||
import net.minecraft.util.math.random.Random
|
||||
import net.minecraft.util.shape.VoxelShape
|
||||
import net.minecraft.util.shape.VoxelShapes
|
||||
import net.minecraft.world.BlockView
|
||||
@@ -125,11 +127,13 @@ class GildedChestBlock(settings: Settings, val type: Type = Type.RED) : BlockWit
|
||||
fun isFake() = (type == Type.FAKE)
|
||||
|
||||
override fun onBreak(world: World, pos: BlockPos, state: BlockState, player: PlayerEntity) {
|
||||
if (isFake()) {
|
||||
if (player is ServerPlayerEntity) {
|
||||
if (!world.isClient) {
|
||||
if (isFake() && (player is ServerPlayerEntity)) {
|
||||
spawnPokemon(world, pos, state, player)
|
||||
}
|
||||
world.setBlockState(pos, if (state.fluidState.isOf(Fluids.WATER)) Blocks.WATER.defaultState else Blocks.AIR.defaultState)
|
||||
val bEntity = world.getBlockEntity(pos) as? GildedChestBlockEntity
|
||||
bEntity?.markRemoved()
|
||||
} else super.onBreak(world, pos, state, player)
|
||||
}
|
||||
|
||||
@@ -183,10 +187,6 @@ class GildedChestBlock(settings: Settings, val type: Type = Type.RED) : BlockWit
|
||||
if (!player.world.isClient) {
|
||||
PiglinBrain.onGuardedBlockInteracted(player, true)
|
||||
}
|
||||
val state = entity.poseableState
|
||||
state.currentModel?.let {
|
||||
it.moveToPose(null, state, it.getPose("OPEN")!!)
|
||||
}
|
||||
return ActionResult.SUCCESS
|
||||
}
|
||||
|
||||
@@ -197,9 +197,11 @@ class GildedChestBlock(settings: Settings, val type: Type = Type.RED) : BlockWit
|
||||
newState: BlockState,
|
||||
moved: Boolean
|
||||
) {
|
||||
if (!state.isOf(newState.block)) {
|
||||
val chest = world.getBlockEntity(pos) as GildedChestBlockEntity
|
||||
ItemScatterer.spawn(world, pos, chest.inventoryContents)
|
||||
if (!state.isOf(newState.block) && !world.isClient) {
|
||||
val chest = world.getBlockEntity(pos) as? GildedChestBlockEntity
|
||||
chest?.let {
|
||||
ItemScatterer.spawn(world, pos, chest.inventoryContents)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,4 +263,14 @@ class GildedChestBlock(settings: Settings, val type: Type = Type.RED) : BlockWit
|
||||
}
|
||||
}
|
||||
|
||||
override fun scheduledTick(
|
||||
state: BlockState?,
|
||||
world: ServerWorld?,
|
||||
pos: BlockPos?,
|
||||
random: Random?
|
||||
) {
|
||||
val blockEntity = world?.getBlockEntity(pos) as? GildedChestBlockEntity ?: return
|
||||
blockEntity.onScheduledTick()
|
||||
}
|
||||
|
||||
}
|
||||
+21
-6
@@ -29,11 +29,17 @@ class FossilAnalyzerBlockEntity(
|
||||
|
||||
class FossilAnalyzerInventory(val analyzerEntity: FossilAnalyzerBlockEntity) : SidedInventory {
|
||||
override fun clear() {
|
||||
TODO("Not yet implemented")
|
||||
if(analyzerEntity.multiblockStructure != null && analyzerEntity.multiblockStructure is FossilMultiblockStructure) {
|
||||
val fossilMultiblockStructure = analyzerEntity.multiblockStructure as FossilMultiblockStructure
|
||||
fossilMultiblockStructure.fossilInventory.clear()
|
||||
}
|
||||
}
|
||||
|
||||
override fun size(): Int {
|
||||
TODO("Not yet implemented")
|
||||
if (analyzerEntity.multiblockStructure != null) {
|
||||
return 3
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun isEmpty(): Boolean {
|
||||
@@ -41,11 +47,18 @@ class FossilAnalyzerBlockEntity(
|
||||
}
|
||||
|
||||
override fun getStack(slot: Int): ItemStack {
|
||||
if (analyzerEntity.multiblockStructure != null && analyzerEntity.multiblockStructure is FossilMultiblockStructure) {
|
||||
val fossilMultiblockStructure = analyzerEntity.multiblockStructure as FossilMultiblockStructure
|
||||
if (fossilMultiblockStructure.fossilInventory.size > slot) {
|
||||
return fossilMultiblockStructure.fossilInventory[slot]
|
||||
}
|
||||
}
|
||||
return ItemStack.EMPTY
|
||||
}
|
||||
|
||||
//Unimplemented since no extract
|
||||
override fun removeStack(slot: Int, amount: Int): ItemStack {
|
||||
return ItemStack.EMPTY
|
||||
return removeStack(slot)
|
||||
}
|
||||
|
||||
override fun removeStack(slot: Int): ItemStack {
|
||||
@@ -53,7 +66,7 @@ class FossilAnalyzerBlockEntity(
|
||||
}
|
||||
|
||||
override fun setStack(slot: Int, stack: ItemStack) {
|
||||
if (analyzerEntity.multiblockStructure != null) {
|
||||
if (analyzerEntity.multiblockStructure != null && analyzerEntity.multiblockStructure is FossilMultiblockStructure) {
|
||||
val struct = analyzerEntity.multiblockStructure as FossilMultiblockStructure
|
||||
analyzerEntity.world?.let {
|
||||
struct.insertFossil(stack, it)
|
||||
@@ -72,7 +85,10 @@ class FossilAnalyzerBlockEntity(
|
||||
}
|
||||
|
||||
override fun getAvailableSlots(side: Direction?): IntArray {
|
||||
return IntArray(1)
|
||||
if(analyzerEntity.multiblockStructure != null && analyzerEntity.multiblockStructure is FossilMultiblockStructure) {
|
||||
return intArrayOf(0,1,2)
|
||||
}
|
||||
return IntArray(0)
|
||||
}
|
||||
|
||||
override fun canInsert(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
|
||||
@@ -89,6 +105,5 @@ class FossilAnalyzerBlockEntity(
|
||||
override fun canExtract(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+2
-6
@@ -38,18 +38,14 @@ open class FossilMultiblockEntity(
|
||||
}
|
||||
}
|
||||
get() {
|
||||
return if (field != null) {
|
||||
field
|
||||
} else if (masterBlockPos != null && masterBlockPos != pos) {
|
||||
if(masterBlockPos != null && masterBlockPos != pos) {
|
||||
val chunkPos = ChunkPos(masterBlockPos)
|
||||
if (world?.chunkManager?.isChunkLoaded(chunkPos.x, chunkPos.z) == true) {
|
||||
val entity: FossilMultiblockEntity? = world?.getBlockEntity(masterBlockPos) as FossilMultiblockEntity?
|
||||
field = entity?.multiblockStructure
|
||||
}
|
||||
field
|
||||
} else {
|
||||
null
|
||||
}
|
||||
return field
|
||||
}
|
||||
|
||||
override fun markRemoved() {
|
||||
|
||||
+9
-6
@@ -20,6 +20,7 @@ import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.entity.player.PlayerInventory
|
||||
import net.minecraft.inventory.DoubleInventory
|
||||
import net.minecraft.inventory.Inventories
|
||||
import net.minecraft.inventory.Inventory
|
||||
import net.minecraft.inventory.SidedInventory
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
@@ -58,9 +59,7 @@ class GildedChestBlockEntity(pos: BlockPos, state: BlockState, val type: Type =
|
||||
override fun isPlayerViewing(player: PlayerEntity): Boolean {
|
||||
if (player.currentScreenHandler is GenericContainerScreenHandler) {
|
||||
val inventory = (player.currentScreenHandler as GenericContainerScreenHandler).inventory
|
||||
return inventory === this@GildedChestBlockEntity || inventory is DoubleInventory && inventory.isPart(
|
||||
this@GildedChestBlockEntity
|
||||
)
|
||||
return inventory === this@GildedChestBlockEntity
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -86,7 +85,7 @@ class GildedChestBlockEntity(pos: BlockPos, state: BlockState, val type: Type =
|
||||
}
|
||||
|
||||
override fun getAvailableSlots(side: Direction): IntArray {
|
||||
return if (type == Type.FAKE) IntArray(0) else IntArray(NUM_SLOTS)
|
||||
return if (type == Type.FAKE) IntArray(0) else IntArray(NUM_SLOTS) { it }
|
||||
}
|
||||
|
||||
override fun canInsert(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
|
||||
@@ -99,8 +98,6 @@ class GildedChestBlockEntity(pos: BlockPos, state: BlockState, val type: Type =
|
||||
return dir == Direction.DOWN
|
||||
}
|
||||
|
||||
override fun canPlayerUse(player: PlayerEntity) = !player.isSpectator
|
||||
|
||||
override fun getInvStackList(): DefaultedList<ItemStack> = inventoryContents
|
||||
|
||||
override fun setInvStackList(list: DefaultedList<ItemStack>) {
|
||||
@@ -164,4 +161,10 @@ class GildedChestBlockEntity(pos: BlockPos, state: BlockState, val type: Type =
|
||||
Inventories.readNbt(nbt, inventoryContents)
|
||||
}
|
||||
}
|
||||
|
||||
fun onScheduledTick() {
|
||||
if (!this.removed) {
|
||||
stateManager.updateViewerCount(this.getWorld(), this.getPos(), this.cachedState)
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -36,8 +36,8 @@ import net.minecraft.util.math.BlockPos
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate", "unused")
|
||||
class HealingMachineBlockEntity(
|
||||
val blockPos: BlockPos,
|
||||
val blockState: BlockState
|
||||
blockPos: BlockPos,
|
||||
blockState: BlockState
|
||||
) : BlockEntity(CobblemonBlockEntities.HEALING_MACHINE, blockPos, blockState) {
|
||||
var currentUser: UUID? = null
|
||||
private set
|
||||
@@ -114,7 +114,7 @@ class HealingMachineBlockEntity(
|
||||
this.setUser(player.uuid)
|
||||
alreadyHealing.add(player.uuid)
|
||||
updateBlockChargeLevel(HealingMachineBlock.MAX_CHARGE_LEVEL + 1)
|
||||
if (world != null && !world!!.isClient) world!!.playSoundServer(position = blockPos.toVec3d(), sound = CobblemonSounds.HEALING_MACHINE_ACTIVE, volume = 1F, pitch = 1F)
|
||||
if (world != null && !world!!.isClient) world!!.playSoundServer(position = pos.toVec3d(), sound = CobblemonSounds.HEALING_MACHINE_ACTIVE, volume = 1F, pitch = 1F)
|
||||
}
|
||||
|
||||
fun completeHealing() {
|
||||
@@ -217,10 +217,10 @@ class HealingMachineBlockEntity(
|
||||
else floor((healingCharge / maxCharge) * HealingMachineBlock.MAX_CHARGE_LEVEL).toInt()
|
||||
).coerceIn(0..HealingMachineBlock.MAX_CHARGE_LEVEL + 1)
|
||||
|
||||
val state = world!!.getBlockState(blockPos)
|
||||
val state = world!!.getBlockState(pos)
|
||||
if (state != null && state.block is HealingMachineBlock) {
|
||||
val currentCharge = state.get(HealingMachineBlock.CHARGE_LEVEL).toInt()
|
||||
if (chargeLevel != currentCharge) world!!.setBlockState(blockPos, state.with(HealingMachineBlock.CHARGE_LEVEL, chargeLevel))
|
||||
if (chargeLevel != currentCharge) world!!.setBlockState(pos, state.with(HealingMachineBlock.CHARGE_LEVEL, chargeLevel))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,24 +26,24 @@ import net.minecraft.util.math.Box
|
||||
import net.minecraft.world.World
|
||||
|
||||
class PCBlockEntity(
|
||||
val blockPos: BlockPos,
|
||||
val blockState: BlockState
|
||||
blockPos: BlockPos,
|
||||
blockState: BlockState
|
||||
) : BlockEntity(CobblemonBlockEntities.PC, blockPos, blockState) {
|
||||
|
||||
companion object {
|
||||
internal val TICKER = BlockEntityTicker<PCBlockEntity> { world, _, _, blockEntity ->
|
||||
if (world.isClient) return@BlockEntityTicker
|
||||
|
||||
blockEntity.togglePCOn(blockEntity.getInRangeViewerCount(world, blockEntity.blockPos) > 0)
|
||||
blockEntity.togglePCOn(blockEntity.getInRangeViewerCount(world, blockEntity.pos) > 0)
|
||||
}
|
||||
}
|
||||
|
||||
private fun togglePCOn(on: Boolean) {
|
||||
val pcBlock = blockState.block as PCBlock
|
||||
val pcBlock = cachedState.block as PCBlock
|
||||
|
||||
if (world != null && !world!!.isClient) {
|
||||
val world = world!!
|
||||
val posBottom = pcBlock.getBasePosition(blockState, blockPos)
|
||||
val posBottom = pcBlock.getBasePosition(cachedState, pos)
|
||||
val stateBottom = world.getBlockState(posBottom)
|
||||
|
||||
val posTop = pcBlock.getPositionOfOtherPart(stateBottom, posBottom)
|
||||
@@ -71,7 +71,7 @@ class PCBlockEntity(
|
||||
val pcLink = PCLinkManager.getLink(player.uuid)
|
||||
return pcLink != null
|
||||
&& pcLink is ProximityPCLink
|
||||
&& pcLink.pos == blockPos
|
||||
&& pcLink.pos == pos
|
||||
&& pcLink.world!!.dimension == player.world.dimension
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -48,7 +48,7 @@ import net.minecraft.world.World
|
||||
import java.util.*
|
||||
import kotlin.math.ceil
|
||||
|
||||
class PokemonPastureBlockEntity(pos: BlockPos, val state: BlockState) : BlockEntity(CobblemonBlockEntities.PASTURE, pos, state) {
|
||||
class PokemonPastureBlockEntity(pos: BlockPos, state: BlockState) : BlockEntity(CobblemonBlockEntities.PASTURE, pos, state) {
|
||||
open class Tethering(
|
||||
val minRoamPos: BlockPos,
|
||||
val maxRoamPos: BlockPos,
|
||||
@@ -173,11 +173,11 @@ class PokemonPastureBlockEntity(pos: BlockPos, val state: BlockState) : BlockEnt
|
||||
}
|
||||
|
||||
private fun togglePastureOn(on: Boolean) {
|
||||
val pastureBlock = state.block as PastureBlock
|
||||
val pastureBlock = cachedState.block as PastureBlock
|
||||
|
||||
if (world != null && !world!!.isClient) {
|
||||
val world = world!!
|
||||
val posBottom = pastureBlock.getBasePosition(state, pos)
|
||||
val posBottom = pastureBlock.getBasePosition(cachedState, pos)
|
||||
val stateBottom = world.getBlockState(posBottom)
|
||||
|
||||
val posTop = pastureBlock.getPositionOfOtherPart(stateBottom, posBottom)
|
||||
|
||||
+68
-76
@@ -16,9 +16,10 @@ import net.minecraft.block.BlockState
|
||||
import net.minecraft.entity.player.PlayerEntity
|
||||
import net.minecraft.inventory.Inventories
|
||||
import net.minecraft.inventory.SidedInventory
|
||||
import net.minecraft.item.Item
|
||||
import net.minecraft.inventory.SimpleInventory
|
||||
import net.minecraft.item.ItemStack
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.nbt.NbtList
|
||||
import net.minecraft.registry.Registries
|
||||
import net.minecraft.util.collection.DefaultedList
|
||||
import net.minecraft.util.math.BlockPos
|
||||
@@ -27,88 +28,71 @@ import net.minecraft.util.math.Direction
|
||||
class RestorationTankBlockEntity(
|
||||
pos: BlockPos, state: BlockState,
|
||||
multiblockBuilder: MultiblockStructureBuilder
|
||||
) : FossilMultiblockEntity(pos, state, multiblockBuilder, CobblemonBlockEntities.RESTORATION_TANK) {
|
||||
) : FossilMultiblockEntity(pos, state, multiblockBuilder, CobblemonBlockEntities.RESTORATION_TANK) {
|
||||
val inv = RestorationTankInventory(this)
|
||||
|
||||
override fun writeNbt(nbt: NbtCompound) {
|
||||
super.writeNbt(nbt)
|
||||
Inventories.writeNbt(nbt, inv.items)
|
||||
nbt.put("inventory", inv.toNbtList())
|
||||
}
|
||||
|
||||
override fun readNbt(nbt: NbtCompound) {
|
||||
super.readNbt(nbt)
|
||||
Inventories.readNbt(nbt, inv.items)
|
||||
if (nbt.contains("Items")) {
|
||||
// Old format
|
||||
val items = DefaultedList.ofSize(inv.size(), ItemStack.EMPTY)
|
||||
Inventories.readNbt(nbt, items)
|
||||
RestorationTankInventory(this, *items.toTypedArray())
|
||||
} else if (nbt.contains("inventory")) {
|
||||
// New format
|
||||
inv.readNbtList(nbt.get("inventory") as NbtList)
|
||||
}
|
||||
}
|
||||
|
||||
class RestorationTankInventory(val tankEntity: RestorationTankBlockEntity) : SidedInventory {
|
||||
class RestorationTankInventory(val tankEntity: RestorationTankBlockEntity, vararg items: ItemStack) : SimpleInventory(*items), SidedInventory {
|
||||
|
||||
val items: DefaultedList<ItemStack> = DefaultedList.ofSize(8, ItemStack.EMPTY)
|
||||
constructor(tankEntity: RestorationTankBlockEntity) : this(tankEntity, *Array(8) { ItemStack.EMPTY })
|
||||
|
||||
|
||||
override fun clear() {
|
||||
for (i in items.indices) {
|
||||
items[i] = ItemStack.EMPTY
|
||||
}
|
||||
}
|
||||
|
||||
override fun size(): Int {
|
||||
return 8
|
||||
}
|
||||
|
||||
override fun isEmpty(): Boolean {
|
||||
return items.all { it == ItemStack.EMPTY }
|
||||
}
|
||||
|
||||
override fun getStack(slot: Int): ItemStack {
|
||||
if(slot == -1 || slot >= size()) {
|
||||
return ItemStack.EMPTY
|
||||
}
|
||||
return items[slot]
|
||||
}
|
||||
|
||||
override fun removeStack(slot: Int, amount: Int): ItemStack {
|
||||
if(slot < 0 || slot >= size()) {
|
||||
return ItemStack.EMPTY
|
||||
}
|
||||
val result = items[slot].split(amount)
|
||||
if(items[slot].count == 0) {
|
||||
items[slot] = ItemStack.EMPTY
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override fun removeStack(slot: Int): ItemStack {
|
||||
return removeStack(slot, 1)
|
||||
}
|
||||
|
||||
override fun setStack(slot: Int, stack: ItemStack) {
|
||||
val struct = tankEntity.multiblockStructure as? FossilMultiblockStructure
|
||||
tankEntity.world?.let {
|
||||
struct?.insertOrganicMaterial(stack, it)
|
||||
val returnIdentifier = NaturalMaterials.getReturnItem((stack))
|
||||
if(returnIdentifier != null ) {
|
||||
// Store the return item
|
||||
val returnItem = Registries.ITEM.get(returnIdentifier)
|
||||
storeReturnItem(returnItem, stack.count)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun storeReturnItem(returnItem: Item, count: Int) {
|
||||
val destStack = items.withIndex().firstOrNull {
|
||||
it.value == ItemStack.EMPTY || (it.value.count < it.value.maxCount && it.value.item == returnItem)
|
||||
}
|
||||
if (destStack != null) {
|
||||
if(destStack.value == ItemStack.EMPTY) {
|
||||
items[destStack.index] = ItemStack(returnItem, 1)
|
||||
} else {
|
||||
destStack.value.increment(count)
|
||||
}
|
||||
}
|
||||
override fun getMaxCountPerStack(): Int {
|
||||
return 1
|
||||
}
|
||||
|
||||
override fun markDirty() {
|
||||
super.markDirty()
|
||||
for(i in 0 until size()) { // iterate over inventory, consume items, generate and place return items
|
||||
val itemStack : ItemStack = this.getStack(i)
|
||||
if(!itemStack.isEmpty) {
|
||||
val struct = tankEntity.multiblockStructure as? FossilMultiblockStructure
|
||||
val returnIdentifier = NaturalMaterials.getReturnItem(itemStack)
|
||||
if(tankEntity.world != null) {
|
||||
if(struct?.insertOrganicMaterial(itemStack, tankEntity.world!!) == true) {
|
||||
removeStack(i)
|
||||
if (returnIdentifier != null) {
|
||||
val returnItem = Registries.ITEM.get(returnIdentifier)
|
||||
val returnStack = ItemStack(returnItem, itemStack.count)
|
||||
var done = false
|
||||
for(j in 1 until size()) {
|
||||
// Look for a inventory slot to merge with
|
||||
val existingStack : ItemStack = getStack(j)
|
||||
if (existingStack.isEmpty
|
||||
|| (Registries.ITEM.getId(existingStack.item) == returnIdentifier && existingStack.count + returnStack.count < existingStack.maxCount)) {
|
||||
setStack(j, ItemStack(returnItem, existingStack.count + returnStack.count))
|
||||
done = true
|
||||
}
|
||||
}
|
||||
if (!done) {
|
||||
setStack(i, ItemStack(returnItem, itemStack.count))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tankEntity.world?.let {
|
||||
// tankEntity.world!!.updateListeners(tankEntity.pos, tankEntity.cachedState, tankEntity.cachedState, Block.NOTIFY_ALL)
|
||||
// tankEntity.world!!.updateComparators(tankEntity.pos, tankEntity.world!!.getBlockState(tankEntity.pos).block)
|
||||
tankEntity.markDirty()
|
||||
tankEntity.multiblockStructure?.markDirty(it)
|
||||
}
|
||||
}
|
||||
@@ -118,7 +102,7 @@ class RestorationTankBlockEntity(
|
||||
}
|
||||
|
||||
override fun getAvailableSlots(side: Direction?): IntArray {
|
||||
return if(side == Direction.DOWN) intArrayOf(0,1,2,3,4,5,6,7) else intArrayOf(-1)
|
||||
return if (side == Direction.DOWN) intArrayOf(0,1,2,3,4,5,6,7) else intArrayOf(0)
|
||||
}
|
||||
|
||||
override fun canInsert(slot: Int, stack: ItemStack?, dir: Direction?): Boolean {
|
||||
@@ -127,17 +111,25 @@ class RestorationTankBlockEntity(
|
||||
val structure = tankEntity.multiblockStructure as FossilMultiblockStructure
|
||||
val canUtilize = stack?.let { NaturalMaterials.isNaturalMaterial(it) } == true
|
||||
&& structure.organicMaterialInside < FossilMultiblockStructure.MATERIAL_TO_START
|
||||
&& structure.createdPokemon == null
|
||||
&& !structure.hasCreatedPokemon
|
||||
val returnItem = NaturalMaterials.getReturnItem(stack!!) ?: return canUtilize
|
||||
if(canUtilize) {
|
||||
// See if there's room
|
||||
for (i in items.indices ) {
|
||||
if(items[i] == ItemStack.EMPTY || (items[i].count < items[i].maxCount
|
||||
&& items[i].item == Registries.ITEM.get(returnItem))) {
|
||||
return true
|
||||
val returnStack = ItemStack(Registries.ITEM.get(returnItem), stack.count)
|
||||
if(canUtilize && super.canInsert(returnStack)) {
|
||||
if(returnStack == ItemStack.EMPTY && getStack(0) == ItemStack.EMPTY) {
|
||||
return true
|
||||
}
|
||||
// See if there's room for the return item
|
||||
var emptyCount = 0
|
||||
for(i in 1 until size()) {
|
||||
val existingStack : ItemStack = getStack(i)
|
||||
if(existingStack == ItemStack.EMPTY) {
|
||||
emptyCount += 1
|
||||
if(emptyCount > 1) {
|
||||
// 2 empty slots, safe to insert
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+68
-60
@@ -10,7 +10,8 @@ package com.cobblemon.mod.common.block.multiblock
|
||||
|
||||
import com.cobblemon.mod.common.Cobblemon
|
||||
import com.cobblemon.mod.common.CobblemonSounds
|
||||
import com.cobblemon.mod.common.advancement.CobblemonCriteria
|
||||
import com.cobblemon.mod.common.api.events.CobblemonEvents
|
||||
import com.cobblemon.mod.common.api.events.pokemon.FossilRevivedEvent
|
||||
import com.cobblemon.mod.common.api.fossil.Fossil
|
||||
import com.cobblemon.mod.common.api.fossil.Fossils
|
||||
import com.cobblemon.mod.common.api.fossil.NaturalMaterials
|
||||
@@ -72,7 +73,7 @@ class FossilMultiblockStructure (
|
||||
var organicMaterialInside = 0
|
||||
private set
|
||||
|
||||
var createdPokemon: Pokemon? = null
|
||||
var hasCreatedPokemon: Boolean = false
|
||||
private set
|
||||
var timeRemaining = -1
|
||||
private set
|
||||
@@ -102,8 +103,7 @@ class FossilMultiblockStructure (
|
||||
if (player !is ServerPlayerEntity) {
|
||||
return ActionResult.SUCCESS
|
||||
}
|
||||
if (this.createdPokemon != null) {
|
||||
|
||||
if (this.hasCreatedPokemon) {
|
||||
if (this.fossilOwnerUUID != null && player.uuid != this.fossilOwnerUUID) {
|
||||
var ownerName : String = "UNKNOWN_USER" // TODO: lang agnostic fallback
|
||||
server()?.userCache?.getByUuid(this.fossilOwnerUUID)?.orElse(null)?.name?.let {
|
||||
@@ -114,25 +114,28 @@ class FossilMultiblockStructure (
|
||||
}
|
||||
|
||||
|
||||
|
||||
val ballType = (stack.item as PokeBallItem).pokeBall
|
||||
if (!player.isCreative) {
|
||||
stack?.decrement(1)
|
||||
}
|
||||
|
||||
this.createdPokemon!!.caughtBall = ballType
|
||||
player.party().add(this.createdPokemon!!)
|
||||
this.fossilState.growthState = "Taken"
|
||||
player.playSound(CobblemonSounds.FOSSIL_MACHINE_RETRIEVE_POKEMON, SoundCategory.BLOCKS, 1.0F, 1.0F)
|
||||
CobblemonCriteria.RESURRECT_POKEMON.trigger(player, createdPokemon!!)
|
||||
val pokemon = this.resultingFossil?.result?.create()
|
||||
|
||||
if(pokemon != null) {
|
||||
pokemon.caughtBall = ballType
|
||||
player.party().add(pokemon)
|
||||
this.fossilState.growthState = "Taken"
|
||||
player.playSound(CobblemonSounds.FOSSIL_MACHINE_RETRIEVE_POKEMON, SoundCategory.BLOCKS, 1.0F, 1.0F)
|
||||
CobblemonEvents.FOSSIL_REVIVED.post(FossilRevivedEvent(pokemon, player))
|
||||
}
|
||||
|
||||
// Turn the monitor off
|
||||
val monitorState = world.getBlockState(monitorPos)
|
||||
if(!monitorState.equals(MonitorBlock.MonitorScreen.OFF)) {
|
||||
if(monitorState.contains(MonitorBlock.SCREEN) && !monitorState.equals(MonitorBlock.MonitorScreen.OFF)) {
|
||||
world.setBlockState(monitorPos, monitorState.with(MonitorBlock.SCREEN, MonitorBlock.MonitorScreen.OFF))
|
||||
}
|
||||
|
||||
this.createdPokemon = null
|
||||
this.hasCreatedPokemon = false
|
||||
this.fossilOwnerUUID = null
|
||||
this.protectionTime = -1
|
||||
this.updateFossilType(world)
|
||||
@@ -144,15 +147,14 @@ class FossilMultiblockStructure (
|
||||
|
||||
// Reclaim the last fossil from the machine if their hand is empty
|
||||
if (player.getStackInHand(interactionHand).isEmpty) {
|
||||
if(!this.isRunning() && this.createdPokemon == null) {
|
||||
if(!this.isRunning() && !this.hasCreatedPokemon) {
|
||||
if (fossilInventory.isEmpty()) {
|
||||
return ActionResult.CONSUME
|
||||
}
|
||||
player.setStackInHand(interactionHand, fossilInventory.last())
|
||||
|
||||
// remove last fossil in the fossil machine stack when grabbed out of the machine
|
||||
this.fossilInventory.removeAt(fossilInventory.size - 1)
|
||||
if(!world.isClient) {
|
||||
if(player is ServerPlayerEntity) {
|
||||
player.setStackInHand(interactionHand, fossilInventory.last())
|
||||
// remove last fossil in the fossil machine stack when grabbed out of the machine
|
||||
this.fossilInventory.removeAt(fossilInventory.size - 1)
|
||||
world.playSound(null, analyzerPos, CobblemonSounds.FOSSIL_MACHINE_RETRIEVE_FOSSIL, SoundCategory.BLOCKS)
|
||||
this.updateFossilType(world)
|
||||
this.syncToClient(world)
|
||||
@@ -164,19 +166,17 @@ class FossilMultiblockStructure (
|
||||
|
||||
// Check if the player is holding a fossil and if so insert it into the machine.
|
||||
if (Fossils.isFossilIngredient(stack)) {
|
||||
if(!this.isRunning() && this.createdPokemon == null) {
|
||||
if (!this.isRunning() && !this.hasCreatedPokemon) {
|
||||
if (fossilInventory.size > Cobblemon.config.maxInsertedFossilItems) {
|
||||
return ActionResult.FAIL
|
||||
}
|
||||
|
||||
val copyFossilStack = stack.copyWithCount(1)
|
||||
if (!player.isCreative) {
|
||||
stack?.decrement(1)
|
||||
}
|
||||
|
||||
fossilOwnerUUID = player.uuid
|
||||
fossilInventory.add(copyFossilStack)
|
||||
if(!world.isClient) {
|
||||
if (player is ServerPlayerEntity) {
|
||||
val copyFossilStack = stack.copyWithCount(1)
|
||||
if (!player.isCreative) {
|
||||
stack?.decrement(1)
|
||||
}
|
||||
fossilOwnerUUID = player.uuid
|
||||
fossilInventory.add(copyFossilStack)
|
||||
this.updateFossilType(world)
|
||||
world.playSound(null, analyzerPos, CobblemonSounds.FOSSIL_MACHINE_INSERT_FOSSIL, SoundCategory.BLOCKS)
|
||||
this.syncToClient(world)
|
||||
@@ -188,7 +188,11 @@ class FossilMultiblockStructure (
|
||||
|
||||
// Check if the player is holding a natural material and if so, feed it to the machine.
|
||||
if (NaturalMaterials.isNaturalMaterial(stack)) {
|
||||
if (!this.isRunning() && this.createdPokemon == null && this.organicMaterialInside < MATERIAL_TO_START && insertOrganicMaterial(stack, world)) {
|
||||
if (player is ServerPlayerEntity
|
||||
&& !this.isRunning()
|
||||
&& !this.hasCreatedPokemon
|
||||
&& this.organicMaterialInside < MATERIAL_TO_START
|
||||
&& insertOrganicMaterial(ItemStack(stack.item, 1), world)) {
|
||||
this.lastInteraction = world.time
|
||||
if (!player.isCreative) {
|
||||
val returnItem = NaturalMaterials.getReturnItem(stack)
|
||||
@@ -220,6 +224,7 @@ class FossilMultiblockStructure (
|
||||
entity.setPosition(fixedPosition.toCenterPos().subtract(0.0, 0.5, 0.0))
|
||||
// TODO: Find a correct way to set the new entity's Yaw rotation. (Face away from the machine)
|
||||
if (world.spawnEntity(entity)) {
|
||||
CobblemonEvents.FOSSIL_REVIVED.post(FossilRevivedEvent(pokemon, null))
|
||||
return true
|
||||
} else {
|
||||
Cobblemon.LOGGER.warn("Couldn't spawn resurrected Pokémon for some reason")
|
||||
@@ -271,7 +276,7 @@ class FossilMultiblockStructure (
|
||||
return 0
|
||||
}
|
||||
if(monitorPos == pos) {
|
||||
if(createdPokemon != null) {
|
||||
if(hasCreatedPokemon) {
|
||||
return 15
|
||||
}
|
||||
if(!isRunning()) {
|
||||
@@ -287,13 +292,13 @@ class FossilMultiblockStructure (
|
||||
override fun onTriggerEvent(state: BlockState?, world: ServerWorld?, pos: BlockPos?, random: Random?) {
|
||||
// instantiate the pokemon as a new entity and spawn it at the location of the machine
|
||||
if(this.protectionTime <= 0) {
|
||||
val wildPokemon: Pokemon = this.createdPokemon ?: return
|
||||
val wildPokemon: Pokemon = if (hasCreatedPokemon) resultingFossil?.result?.create() ?: return else return
|
||||
val direction = state?.get(HorizontalFacingBlock.FACING)?.opposite
|
||||
if(pos != null && direction != null && world != null) {
|
||||
val success = this.spawn(world, pos, direction, wildPokemon)
|
||||
if(success) {
|
||||
this.fossilState.growthState = "Taken"
|
||||
this.createdPokemon = null
|
||||
this.hasCreatedPokemon = false
|
||||
this.fossilOwnerUUID = null
|
||||
this.protectionTime = -1
|
||||
world.playSound(null, tankBasePos, CobblemonSounds.FOSSIL_MACHINE_RETRIEVE_POKEMON, SoundCategory.BLOCKS)
|
||||
@@ -310,9 +315,9 @@ class FossilMultiblockStructure (
|
||||
val analyzerEntity = world.getBlockEntity(analyzerPos) as? MultiblockEntity
|
||||
val tankBaseEntity = world.getBlockEntity(tankBasePos) as? MultiblockEntity
|
||||
val tankTopEntity = world.getBlockEntity(tankBasePos.up()) as? MultiblockEntity
|
||||
val state = world.getBlockState(tankBaseEntity?.pos)
|
||||
val direction = state.get(HorizontalFacingBlock.FACING).getOpposite()
|
||||
val wildPokemon: Pokemon? = this.createdPokemon
|
||||
val tankBaseBlockState = world.getBlockState(tankBaseEntity?.pos)
|
||||
val direction = tankBaseBlockState.get(HorizontalFacingBlock.FACING).opposite
|
||||
val wildPokemon: Pokemon? = if(hasCreatedPokemon) resultingFossil?.result?.create() else null
|
||||
|
||||
monitorEntity?.multiblockStructure = null
|
||||
analyzerEntity?.multiblockStructure = null
|
||||
@@ -331,11 +336,9 @@ class FossilMultiblockStructure (
|
||||
}
|
||||
}
|
||||
if(tankBaseEntity is RestorationTankBlockEntity) {
|
||||
tankBaseEntity.inv.items.forEach {
|
||||
val stack = ItemStack(it.item, 1)
|
||||
ItemScatterer.spawn(world, pos.x.toDouble(), pos.y.toDouble(), pos.z.toDouble(), stack)
|
||||
tankBaseEntity.inv.clearToList().forEach {
|
||||
ItemScatterer.spawn(world, pos.x.toDouble(), pos.y.toDouble(), pos.z.toDouble(), it)
|
||||
}
|
||||
tankBaseEntity.inv.clear()
|
||||
}
|
||||
|
||||
|
||||
@@ -374,7 +377,7 @@ class FossilMultiblockStructure (
|
||||
world.playSound(null, tankBasePos, CobblemonSounds.FOSSIL_MACHINE_UNPROTECTED, SoundCategory.BLOCKS)
|
||||
}
|
||||
|
||||
if (this.createdPokemon != null) {
|
||||
if (this.hasCreatedPokemon) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -403,10 +406,7 @@ class FossilMultiblockStructure (
|
||||
if (this.timeRemaining == 0) {
|
||||
world.playSound(null, tankBasePos, CobblemonSounds.FOSSIL_MACHINE_FINISHED, SoundCategory.BLOCKS)
|
||||
fossilInventory.clear()
|
||||
|
||||
this.resultingFossil?.let {
|
||||
this.createdPokemon = it.result.create()
|
||||
}
|
||||
this.hasCreatedPokemon = true
|
||||
if(this.fossilOwnerUUID != null) {
|
||||
protectionTime = PROTECTION_TIME
|
||||
}
|
||||
@@ -477,20 +477,26 @@ class FossilMultiblockStructure (
|
||||
val upperTankPos = tankBasePos.up()
|
||||
val analyzerState = world.getBlockState(analyzerPos)
|
||||
val tankState = world.getBlockState(tankBasePos.up())
|
||||
world.setBlockState(analyzerPos, analyzerState.with(FossilAnalyzerBlock.ON, timeRemaining >= 0))
|
||||
world.setBlockState(upperTankPos, tankState.with(RestorationTankBlock.ON, timeRemaining >= 0))
|
||||
if (analyzerState.contains(FossilAnalyzerBlock.ON)) {
|
||||
world.setBlockState(analyzerPos, analyzerState.with(FossilAnalyzerBlock.ON, timeRemaining >= 0))
|
||||
}
|
||||
if (tankState.contains(RestorationTankBlock.ON)) {
|
||||
world.setBlockState(upperTankPos, tankState.with(RestorationTankBlock.ON, timeRemaining >= 0))
|
||||
}
|
||||
}
|
||||
|
||||
fun updateProgress(world: World) {
|
||||
val screenID = if(protectionTime > 0F ) {
|
||||
MonitorBlock.MonitorScreen.GREEN_PROGRESS_9
|
||||
} else if (timeRemaining <= 0) {
|
||||
MonitorBlock.MonitorScreen.OFF
|
||||
} else {
|
||||
getProgressScreen((TIME_TO_TAKE - timeRemaining) / TIME_PER_STAGE)
|
||||
}
|
||||
val monitorState = world.getBlockState(monitorPos)
|
||||
world.setBlockState(monitorPos, monitorState.with(MonitorBlock.SCREEN, screenID))
|
||||
if (monitorState.contains(MonitorBlock.SCREEN)) {
|
||||
val screenID = if (protectionTime > 0F) {
|
||||
MonitorBlock.MonitorScreen.GREEN_PROGRESS_9
|
||||
} else if (timeRemaining <= 0) {
|
||||
MonitorBlock.MonitorScreen.OFF
|
||||
} else {
|
||||
getProgressScreen((TIME_TO_TAKE - timeRemaining) / TIME_PER_STAGE)
|
||||
}
|
||||
world.setBlockState(monitorPos, monitorState.with(MonitorBlock.SCREEN, screenID))
|
||||
}
|
||||
}
|
||||
|
||||
fun getProgressScreen(progress:Int) : MonitorBlock.MonitorScreen {
|
||||
@@ -533,12 +539,13 @@ class FossilMultiblockStructure (
|
||||
|
||||
//Returns false if material wasnt inserted
|
||||
fun insertOrganicMaterial(stack: ItemStack, world: World): Boolean {
|
||||
val natureValue = NaturalMaterials.getContent(stack)
|
||||
var natureValue = NaturalMaterials.getContent(stack)
|
||||
if (timeRemaining > 0 || this.organicMaterialInside >= MATERIAL_TO_START || natureValue == null) {
|
||||
return false
|
||||
}
|
||||
natureValue *= stack.count
|
||||
|
||||
if (natureValue < 0 && organicMaterialInside == 0) return false
|
||||
if (natureValue <= 0 && organicMaterialInside == 0) return false
|
||||
val oldFillStage = organicMaterialInside * 8 / MATERIAL_TO_START
|
||||
|
||||
// to prevent over/under filling the tank causing a crash
|
||||
@@ -604,9 +611,7 @@ class FossilMultiblockStructure (
|
||||
result.putString(DataKeys.INSERTED_FOSSIL, this.resultingFossil!!.asString())
|
||||
}
|
||||
|
||||
if (this.createdPokemon != null) {
|
||||
result.put(DataKeys.CREATED_POKEMON, createdPokemon!!.saveToNBT(NbtCompound()))
|
||||
}
|
||||
result.putBoolean(DataKeys.HAS_CREATED_POKEMON, hasCreatedPokemon)
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -655,7 +660,10 @@ class FossilMultiblockStructure (
|
||||
}
|
||||
|
||||
if (nbt.contains(DataKeys.CREATED_POKEMON)) {
|
||||
result.createdPokemon = Pokemon.loadFromNBT(nbt.getCompound(DataKeys.CREATED_POKEMON))
|
||||
// migration of instances that saved the created pokeon in the nbt
|
||||
result.hasCreatedPokemon = true
|
||||
} else if (nbt.contains(DataKeys.HAS_CREATED_POKEMON)){
|
||||
result.hasCreatedPokemon = nbt.getBoolean(DataKeys.HAS_CREATED_POKEMON)
|
||||
}
|
||||
result.fillLevel = result.organicMaterialInside * 8 / MATERIAL_TO_START
|
||||
return result
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.bedrockk.molang.runtime.value.MoValue
|
||||
import com.bedrockk.molang.runtime.value.StringValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunctions
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.text.text
|
||||
import com.cobblemon.mod.common.util.asIdentifierDefaultingNamespace
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.sound.PositionedSoundInstance
|
||||
@@ -31,6 +32,13 @@ object ClientMoLangFunctions {
|
||||
MinecraftClient.getInstance().soundManager.play(PositionedSoundInstance.master(soundEvent, pitch))
|
||||
}
|
||||
},
|
||||
"is_time" to java.util.function.Function { params ->
|
||||
val time = (MinecraftClient.getInstance().world?.timeOfDay ?: 0) % 24000
|
||||
val min = params.getInt(0)
|
||||
val max = params.getInt(1)
|
||||
time in min..max
|
||||
},
|
||||
"say" to java.util.function.Function { params -> MinecraftClient.getInstance().player?.sendMessage(params.getString(0).text()) ?: Unit },
|
||||
)
|
||||
|
||||
fun MoLangRuntime.setupClient(): MoLangRuntime {
|
||||
|
||||
@@ -272,6 +272,9 @@ class PokemonClientDelegate : PoseableEntityState<PokemonEntity>(), PokemonSideD
|
||||
},
|
||||
"weight" to java.util.function.Function {
|
||||
return@Function DoubleValue(currentEntity.pokemon.species.weight.toDouble())
|
||||
},
|
||||
"friendship" to java.util.function.Function {
|
||||
return@Function DoubleValue(currentEntity.pokemon.friendship.toDouble())
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
@@ -318,7 +318,6 @@ class PCGUI(
|
||||
centered = true,
|
||||
shadow = true,
|
||||
scale = SCALE,
|
||||
colour = 0x32CBFF,
|
||||
pMouseX = mouseX,
|
||||
pMouseY = mouseY
|
||||
)
|
||||
|
||||
+2
-1
@@ -18,7 +18,8 @@ import net.minecraft.client.MinecraftClient
|
||||
|
||||
object PlayPoseableAnimationHandler : ClientNetworkPacketHandler<PlayPoseableAnimationPacket> {
|
||||
override fun handle(packet: PlayPoseableAnimationPacket, client: MinecraftClient) {
|
||||
val entity = client.world?.getEntityById(packet.entityId) ?: return
|
||||
val world = client.world ?: return
|
||||
val entity = world.getEntityById(packet.entityId) ?: return
|
||||
if (entity is Poseable) {
|
||||
val delegate = entity.delegate
|
||||
if (delegate is PoseableEntityState<*>) {
|
||||
|
||||
+2
-1
@@ -18,7 +18,8 @@ import net.minecraft.client.MinecraftClient
|
||||
|
||||
object RunPosableMoLangHandler : ClientNetworkPacketHandler<RunPosableMoLangPacket> {
|
||||
override fun handle(packet: RunPosableMoLangPacket, client: MinecraftClient) {
|
||||
val entity = client.world?.getEntityById(packet.entityId) ?: return
|
||||
val world = client.world ?: return
|
||||
val entity = world.getEntityById(packet.entityId) ?: return
|
||||
if (entity is Poseable) {
|
||||
val state = entity.delegate as? PoseableEntityState<*> ?: return
|
||||
for (expression in packet.expressions.map { it.asExpression() }) {
|
||||
|
||||
-3
@@ -15,9 +15,6 @@ import com.cobblemon.mod.common.client.render.MatrixWrapper
|
||||
import com.cobblemon.mod.common.net.messages.client.effect.SpawnSnowstormParticlePacket
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.util.math.RotationAxis.NEGATIVE_X
|
||||
import net.minecraft.util.math.RotationAxis.POSITIVE_X
|
||||
import net.minecraft.util.math.RotationAxis.POSITIVE_Y
|
||||
|
||||
object SpawnSnowstormParticleHandler : ClientNetworkPacketHandler<SpawnSnowstormParticlePacket> {
|
||||
override fun handle(packet: SpawnSnowstormParticlePacket, client: MinecraftClient) {
|
||||
|
||||
@@ -10,16 +10,20 @@ package com.cobblemon.mod.common.client.particle
|
||||
|
||||
import com.bedrockk.molang.runtime.MoLangRuntime
|
||||
import com.bedrockk.molang.runtime.value.DoubleValue
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.addFunction
|
||||
import com.cobblemon.mod.common.api.molang.MoLangFunctions.getQueryStruct
|
||||
import com.cobblemon.mod.common.api.pokemon.PokemonSpecies.species
|
||||
import com.cobblemon.mod.common.api.snowstorm.BedrockParticleEffect
|
||||
import com.cobblemon.mod.common.api.snowstorm.ParticleEmitterAction
|
||||
import com.cobblemon.mod.common.client.render.MatrixWrapper
|
||||
import com.cobblemon.mod.common.client.render.SnowstormParticle
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.particle.SnowstormParticleEffect
|
||||
import com.cobblemon.mod.common.util.math.geometry.transformDirection
|
||||
import kotlin.random.Random
|
||||
import net.minecraft.client.MinecraftClient
|
||||
import net.minecraft.client.particle.NoRenderParticle
|
||||
import net.minecraft.client.util.ParticleUtil.spawnParticle
|
||||
import net.minecraft.client.world.ClientWorld
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.util.math.Vec3d
|
||||
@@ -48,12 +52,22 @@ class ParticleStorm(
|
||||
.addFunction("entity_height") { DoubleValue(entity.boundingBox.yLength) }
|
||||
.addFunction("entity_size") { DoubleValue(entity.boundingBox.run { if (xLength > yLength) xLength else yLength }) }
|
||||
.addFunction("entity_radius") { DoubleValue(entity.boundingBox.run { if (xLength > yLength) xLength else yLength } / 2) }
|
||||
.addFunction("entity_scale") {
|
||||
val pokeEntity = entity as? PokemonEntity
|
||||
val pokemon = pokeEntity?.pokemon
|
||||
//Use form data if available, species as fall back
|
||||
val baseScale = pokemon?.form?.baseScale ?: pokemon?.species?.baseScale ?: 1.0F
|
||||
val pokemonScale = pokemon?.scaleModifier ?: 1.0F
|
||||
val entityScale = pokeEntity?.scaleFactor ?: 1.0F
|
||||
DoubleValue(baseScale * pokemonScale * entityScale)
|
||||
}
|
||||
// TODO replace with a generified call to if (entity is MoLangEntity) entity.applyVariables(env) or w/e
|
||||
runtime.environment.setSimpleVariable("entity_width", DoubleValue(entity.boundingBox.xLength))
|
||||
runtime.environment.setSimpleVariable("entity_height", DoubleValue(entity.boundingBox.yLength))
|
||||
val longerDiameter = entity.boundingBox.run { if (xLength > yLength) xLength else yLength }
|
||||
runtime.environment.setSimpleVariable("entity_size", DoubleValue(longerDiameter))
|
||||
runtime.environment.setSimpleVariable("entity_radius", DoubleValue(longerDiameter / 2))
|
||||
runtime.environment.setSimpleVariable("entity_scale", DoubleValue((entity as? PokemonEntity)?.scaleFactor ?: 1.0))
|
||||
}
|
||||
MinecraftClient.getInstance().particleManager.addParticle(this)
|
||||
}
|
||||
|
||||
+17
-15
@@ -118,7 +118,7 @@ class SnowstormParticle(
|
||||
|
||||
init {
|
||||
setVelocity(initialVelocity.x, initialVelocity.y, initialVelocity.z)
|
||||
angle = storm.effect.particle.rotation.getInitialRotation(storm.runtime).toFloat()
|
||||
angle = -storm.effect.particle.rotation.getInitialRotation(storm.runtime).toFloat()
|
||||
prevAngle = angle
|
||||
angularVelocity = storm.effect.particle.rotation.getInitialAngularVelocity(storm.runtime)
|
||||
velocityMultiplier = 1F
|
||||
@@ -243,6 +243,10 @@ class SnowstormParticle(
|
||||
.next()
|
||||
}
|
||||
|
||||
fun runExpirationEvents() {
|
||||
storm.effect.particle.expirationEvents.forEach { it.trigger(storm, this)}
|
||||
}
|
||||
|
||||
override fun tick() {
|
||||
if (storm.effect.space.localPosition) {
|
||||
originPos = storm.matrixWrapper.getOrigin()
|
||||
@@ -250,25 +254,22 @@ class SnowstormParticle(
|
||||
|
||||
applyRandoms()
|
||||
setParticleAgeInRuntime()
|
||||
storm.effect.curves.forEach { it.apply(storm.runtime) }
|
||||
storm.runtime.execute(storm.effect.particle.updateExpressions)
|
||||
angularVelocity += storm.effect.particle.rotation.getAngularAcceleration(storm.runtime, angularVelocity) / 20
|
||||
angularVelocity = storm.effect.particle.rotation.getAngularVelocity(storm.runtime, -angle.toDouble(), angularVelocity) / 20
|
||||
|
||||
if (age > maxAge || storm.runtime.resolveBoolean(storm.effect.particle.killExpression)) {
|
||||
storm.effect.particle.expirationEvents.forEach { it.trigger(storm, this)}
|
||||
if (age >= maxAge || storm.runtime.resolveBoolean(storm.effect.particle.killExpression)) {
|
||||
runExpirationEvents()
|
||||
markDead()
|
||||
return
|
||||
} else {
|
||||
val acceleration = storm.effect.particle.motion.getAcceleration(
|
||||
storm.runtime,
|
||||
Vec3d(velocityX, velocityY, velocityZ).multiply(20.0) // Uses blocks per second, not blocks per tick
|
||||
).multiply(1 / 20.0).multiply(1 / 20.0)
|
||||
|
||||
velocityX += acceleration.x
|
||||
velocityY += acceleration.y
|
||||
velocityZ += acceleration.z
|
||||
|
||||
val velocity = storm.effect.particle.motion.getVelocity(storm.runtime, this, Vec3d(velocityX, velocityY, velocityZ))
|
||||
velocityX = velocity.x
|
||||
velocityY = velocity.y
|
||||
velocityZ = velocity.z
|
||||
prevAngle = angle
|
||||
angle = prevAngle + angularVelocity.toFloat()
|
||||
// Subtract because Bedrock particles are counter-clockwise and Java Edition is clockwise.
|
||||
angle = prevAngle - angularVelocity.toFloat()
|
||||
}
|
||||
|
||||
viewDirection = storm.effect.particle.viewDirection.getDirection(
|
||||
@@ -354,7 +355,7 @@ class SnowstormParticle(
|
||||
// velocityZ = 0.0
|
||||
// }
|
||||
} else {
|
||||
collidesWithWorld = false
|
||||
collidesWithWorld = false
|
||||
if (dx != 0.0 || dy != 0.0 || dz != 0.0) {
|
||||
localX += dx
|
||||
localY += dy
|
||||
@@ -383,6 +384,7 @@ class SnowstormParticle(
|
||||
colliding = false
|
||||
return movement
|
||||
} else if (expiresOnContact) {
|
||||
runExpirationEvents()
|
||||
markDead()
|
||||
return movement
|
||||
}
|
||||
|
||||
+3
-3
@@ -61,17 +61,17 @@ class RestorationTankRenderer(ctx: BlockEntityRendererFactory.Context) : BlockEn
|
||||
matrices.pop()
|
||||
}
|
||||
val fillLevel = struct.fillLevel
|
||||
if (fillLevel == 0 && struct.createdPokemon == null) {
|
||||
if (fillLevel == 0 && !struct.hasCreatedPokemon) {
|
||||
return
|
||||
}
|
||||
|
||||
if (struct.isRunning() or (struct.createdPokemon != null)) renderFetus(entity, tickDelta, matrices, vertexConsumers, light, overlay)
|
||||
if (struct.isRunning() or (struct.hasCreatedPokemon)) renderFetus(entity, tickDelta, matrices, vertexConsumers, light, overlay)
|
||||
|
||||
matrices.push()
|
||||
val transparentBuffer = vertexConsumers.getBuffer(RenderLayer.getTranslucent())
|
||||
|
||||
val fluidModel = if (struct.isRunning()) FLUID_MODELS[8]
|
||||
else if (struct.createdPokemon != null) FLUID_MODELS[7]
|
||||
else if (struct.hasCreatedPokemon) FLUID_MODELS[7]
|
||||
else FLUID_MODELS[fillLevel.coerceAtMost(FLUID_MODELS.size - 1) - 1]
|
||||
fluidModel.getQuads(entity.cachedState, null, entity.world?.random).forEach { quad ->
|
||||
transparentBuffer?.quad(matrices.peek(), quad, 0.75f, 0.75f, 0.75f, light, OverlayTexture.DEFAULT_UV)
|
||||
|
||||
+9
-2
@@ -20,7 +20,10 @@ import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFram
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.quirk.SimpleQuirk
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.normalizeToArray
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.cobblemon.mod.common.util.resolveObject
|
||||
import com.cobblemon.mod.common.util.singularToPluralList
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonPrimitive
|
||||
@@ -34,6 +37,8 @@ class JsonPose<T : Entity>(model: PoseableEntityModel<T>, json: JsonObject) {
|
||||
it.environment.getQueryStruct().addFunctions(model.functions.functions)
|
||||
}
|
||||
|
||||
val condition: ExpressionLike = json.singularToPluralList("condition").get("conditions")?.normalizeToArray()?.map { it.asString }?.asExpressionLike() ?: "true".asExpressionLike()
|
||||
|
||||
val poseName = json.get("poseName")?.asString ?: "pose"
|
||||
val poseTypes = (json.get("poseTypes")?.asJsonArray?.map { name ->
|
||||
PoseType.values().find { it.name.lowercase() == name.asString.lowercase() }
|
||||
@@ -81,8 +86,9 @@ class JsonPose<T : Entity>(model: PoseableEntityModel<T>, json: JsonObject) {
|
||||
}
|
||||
|
||||
json as JsonObject
|
||||
json.singularToPluralList("animation")
|
||||
val animations: (state: PoseableEntityState<T>) -> List<StatefulAnimation<T, *>> = { _ ->
|
||||
(json.get("animations")?.asJsonArray ?: JsonArray()).map { animJson ->
|
||||
(json.get("animations")?.normalizeToArray()?.asJsonArray ?: JsonArray()).map { animJson ->
|
||||
try {
|
||||
val expr = animJson.asString.asExpressionLike()
|
||||
runtime.resolveObject(expr).obj as StatefulAnimation<T, *>
|
||||
@@ -97,10 +103,11 @@ class JsonPose<T : Entity>(model: PoseableEntityModel<T>, json: JsonObject) {
|
||||
val loopTimes = json.get("loopTimes")?.asInt ?: 1
|
||||
val minSeconds = json.get("minSecondsBetweenOccurrences")?.asFloat ?: 8F
|
||||
val maxSeconds = json.get("maxSecondsBetweenOccurrences")?.asFloat ?: 30F
|
||||
val condition = json.get("condition")?.asString?.asExpressionLike() ?: "true".asExpressionLike()
|
||||
|
||||
model.quirkMultiple(
|
||||
secondsBetweenOccurrences = minSeconds to maxSeconds,
|
||||
condition = { true },
|
||||
condition = { it.runtime.resolveBoolean(condition) },
|
||||
loopTimes = 1..loopTimes,
|
||||
animations = animations
|
||||
)
|
||||
|
||||
+29
-3
@@ -11,6 +11,7 @@ package com.cobblemon.mod.common.client.render.models.blockbench
|
||||
import com.cobblemon.mod.common.client.render.MatrixWrapper
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.Bone
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.entity.Entity
|
||||
|
||||
/**
|
||||
* A storage of locator information for a model, attached to its [joint].
|
||||
@@ -68,20 +69,45 @@ class LocatorAccess(
|
||||
* Updates all of the locator states with the position at this current frame.
|
||||
* This is the same logic as ModelPart uses, that's why we reuse ModelPart#rotate.
|
||||
*/
|
||||
fun update(matrixStack: MatrixStack, state: MutableMap<String, MatrixWrapper>) {
|
||||
fun update(matrixStack: MatrixStack, entity: Entity, scale: Float, state: MutableMap<String, MatrixWrapper>, isRoot: Boolean = false) {
|
||||
matrixStack.push()
|
||||
joint.transform(matrixStack)
|
||||
|
||||
if (isRoot) {
|
||||
matrixStack.push()
|
||||
matrixStack.scale(-1F, -1F, 1F)
|
||||
state.getOrPut("root") { MatrixWrapper() }.updateMatrix(matrixStack.peek().positionMatrix)
|
||||
matrixStack.pop()
|
||||
|
||||
// Put in an approximation of the target locator. If the model has one defined,
|
||||
// this will be overridden.
|
||||
matrixStack.push()
|
||||
matrixStack.translate(0.0, -entity.boundingBox.yLength / 2.0 / scale, -entity.width * 0.6 / scale)
|
||||
matrixStack.scale(-1F, -1F, 1F)
|
||||
state.getOrPut("target") { MatrixWrapper() }.updateMatrix(matrixStack.peek().positionMatrix)
|
||||
state.getOrPut("special_attack") { MatrixWrapper() }.updateMatrix(matrixStack.peek().positionMatrix)
|
||||
matrixStack.pop()
|
||||
|
||||
// If we have the entity, put in a "middle" locator for center of mass
|
||||
// this will be overridden.
|
||||
matrixStack.push()
|
||||
matrixStack.translate(0.0, -entity.boundingBox.yLength / 2.0 / scale, 0.0)
|
||||
matrixStack.scale(-1F, -1F, 1F)
|
||||
state.getOrPut("middle") { MatrixWrapper() }.updateMatrix(matrixStack.peek().positionMatrix)
|
||||
matrixStack.pop()
|
||||
|
||||
}
|
||||
|
||||
for ((name, locator) in locators) {
|
||||
matrixStack.push()
|
||||
locator.transform(matrixStack)
|
||||
matrixStack.scale(1F, -1F, 1F)
|
||||
matrixStack.scale(-1F, -1F, 1F)
|
||||
state.getOrPut(name) { MatrixWrapper() }.updateMatrix(matrixStack.peek().positionMatrix)
|
||||
matrixStack.pop()
|
||||
}
|
||||
|
||||
children.forEach {
|
||||
it.update(matrixStack, state)
|
||||
it.update(matrixStack, entity, scale, state, isRoot = false)
|
||||
}
|
||||
|
||||
matrixStack.pop()
|
||||
|
||||
+52
-16
@@ -46,6 +46,7 @@ import com.cobblemon.mod.common.util.asExpressionLike
|
||||
import com.cobblemon.mod.common.util.getDoubleOrNull
|
||||
import com.cobblemon.mod.common.util.getStringOrNull
|
||||
import com.cobblemon.mod.common.util.plus
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import net.minecraft.client.model.ModelPart
|
||||
import net.minecraft.client.render.OverlayTexture
|
||||
import net.minecraft.client.render.RenderLayer
|
||||
@@ -154,6 +155,7 @@ abstract class PoseableEntityModel<T : Entity>(
|
||||
val maxPitch = params.getDoubleOrNull(3) ?: 70F
|
||||
val minPitch = params.getDoubleOrNull(4) ?: -45F
|
||||
val maxYaw = params.getDoubleOrNull(5) ?: 45F
|
||||
val minYaw = params.getDoubleOrNull(6) ?: -45F
|
||||
ObjectValue(
|
||||
SingleBoneLookAnimation<T>(
|
||||
frame = this,
|
||||
@@ -162,7 +164,8 @@ abstract class PoseableEntityModel<T : Entity>(
|
||||
yawMultiplier = yawMultiplier.toFloat(),
|
||||
maxPitch = maxPitch.toFloat(),
|
||||
minPitch = minPitch.toFloat(),
|
||||
maxYaw = maxYaw.toFloat()
|
||||
maxYaw = maxYaw.toFloat(),
|
||||
minYaw = minYaw.toFloat()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -258,6 +261,41 @@ abstract class PoseableEntityModel<T : Entity>(
|
||||
)
|
||||
)
|
||||
}
|
||||
.addFunction("bedrock_primary_quirk") { params ->
|
||||
val animationGroup = params.getString(0)
|
||||
val animationNames = params.get<MoValue>(1)?.let { if (it is ArrayStruct) it.map.values.map { it.asString() } else listOf(it.asString()) } ?: listOf()
|
||||
val minSeconds = params.getDoubleOrNull(2) ?: 8F
|
||||
val maxSeconds = params.getDoubleOrNull(3) ?: 30F
|
||||
val loopTimes = params.getDoubleOrNull(4)?.toInt() ?: 1
|
||||
val excludedLabels = mutableSetOf<String>()
|
||||
var curve: WaveFunction = { t ->
|
||||
if (t < 0.1) {
|
||||
t * 10
|
||||
} else if (t < 0.9) {
|
||||
1F
|
||||
} else {
|
||||
1F
|
||||
}
|
||||
}
|
||||
for (index in 5 until params.params.size) {
|
||||
val param = params.get<MoValue>(index)
|
||||
if (param is ObjectValue<*>) {
|
||||
curve = param.obj as WaveFunction
|
||||
continue
|
||||
}
|
||||
|
||||
val label = params.getString(index) ?: continue
|
||||
excludedLabels.add(label)
|
||||
}
|
||||
ObjectValue(
|
||||
quirk(
|
||||
secondsBetweenOccurrences = minSeconds.toFloat() to maxSeconds.toFloat(),
|
||||
condition = { true },
|
||||
loopTimes = 1..loopTimes,
|
||||
animation = { PrimaryAnimation(bedrockStateful(animationGroup, animationNames.random()), excludedLabels = excludedLabels, curve = curve) }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Transient
|
||||
val runtime = MoLangRuntime().setup().setupClient().also { it.environment.getQueryStruct().addFunctions(functions.functions) }
|
||||
@@ -785,7 +823,6 @@ abstract class PoseableEntityModel<T : Entity>(
|
||||
matrixStack.push()
|
||||
matrixStack.scale(-1F, -1F, 1F)
|
||||
scale = entity.pokemon.form.baseScale * entity.pokemon.scaleModifier * (entity.delegate as PokemonClientDelegate).entityScaleModifier
|
||||
|
||||
matrixStack.scale(scale, scale, scale)
|
||||
} else if (entity is EmptyPokeBallEntity) {
|
||||
matrixStack.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(entity.yaw))
|
||||
@@ -800,27 +837,14 @@ abstract class PoseableEntityModel<T : Entity>(
|
||||
matrixStack.scale(1F, -1F, 1F)
|
||||
}
|
||||
|
||||
matrixStack.push()
|
||||
matrixStack.scale(1F, -1F, 1F)
|
||||
val states = state.locatorStates
|
||||
states.getOrPut("root") { MatrixWrapper() }.updateMatrix(matrixStack.peek().positionMatrix)
|
||||
matrixStack.pop()
|
||||
|
||||
if (isForLivingEntityRenderer) {
|
||||
// Standard living entity offset, only God knows why Mojang did this.
|
||||
matrixStack.translate(0.0, -1.5, 0.0)
|
||||
}
|
||||
|
||||
// If we have the entity, put in an approximation of the target locator. If the model has one defined,
|
||||
// this will be overridden.
|
||||
matrixStack.push()
|
||||
matrixStack.translate(0.0, -entity.boundingBox.yLength / 2.0 / scale + 1.5F, -entity.width * 0.6 / scale)
|
||||
matrixStack.scale(1F, -1F, 1F)
|
||||
states.getOrPut("target") { MatrixWrapper() }.updateMatrix(matrixStack.peek().positionMatrix)
|
||||
states.getOrPut("special_attack") { MatrixWrapper() }.updateMatrix(matrixStack.peek().positionMatrix)
|
||||
matrixStack.pop()
|
||||
|
||||
locatorAccess.update(matrixStack, states)
|
||||
locatorAccess.update(matrixStack, entity, scale, states, isRoot = true)
|
||||
}
|
||||
|
||||
fun ModelPart.translation(
|
||||
@@ -876,6 +900,18 @@ abstract class PoseableEntityModel<T : Entity>(
|
||||
animations = { listOf(animation(it)) }
|
||||
)
|
||||
|
||||
fun quirkMoLangCondition(
|
||||
secondsBetweenOccurrences: Pair<Float, Float> = 8F to 30F,
|
||||
loopTimes: IntRange = 1..1,
|
||||
conditionExpression: ExpressionLike = "true".asExpressionLike(),
|
||||
animation: (state: PoseableEntityState<T>) -> StatefulAnimation<T, *>
|
||||
) = SimpleQuirk<T>(
|
||||
secondsBetweenOccurrences = secondsBetweenOccurrences,
|
||||
loopTimes = loopTimes,
|
||||
condition = { it.runtime.resolveBoolean(conditionExpression) },
|
||||
animations = { listOf(animation(it)) }
|
||||
)
|
||||
|
||||
fun quirkMultiple(
|
||||
secondsBetweenOccurrences: Pair<Float, Float> = 8F to 30F,
|
||||
loopTimes: IntRange = 1..1,
|
||||
|
||||
+2
-1
@@ -78,7 +78,7 @@ abstract class PoseableEntityState<T : Entity> : Schedulable {
|
||||
"anim_time" to java.util.function.Function { return@Function reusableAnimTime.also { it.value = animationSeconds.toDouble() } },
|
||||
"pose_type" to java.util.function.Function { return@Function StringValue((getEntity() as Poseable).getCurrentPoseType().name) },
|
||||
"pose" to java.util.function.Function { _ -> return@Function StringValue(currentPose ?: "") },
|
||||
"say" to java.util.function.Function { params -> MinecraftClient.getInstance().player?.sendMessage(params.getString(0).text()) ?: Unit },
|
||||
"has_entity" to java.util.function.Function { _ -> return@Function DoubleValue(getEntity() != null) },
|
||||
"sound" to java.util.function.Function { params ->
|
||||
val entity = getEntity() ?: return@Function Unit
|
||||
if (params.get<MoValue>(0) !is StringValue) {
|
||||
@@ -135,6 +135,7 @@ abstract class PoseableEntityState<T : Entity> : Schedulable {
|
||||
|
||||
val storm = ParticleStorm(
|
||||
effect = effect,
|
||||
entity = entity,
|
||||
matrixWrapper = matrixWrapper,
|
||||
world = world,
|
||||
runtime = particleRuntime,
|
||||
|
||||
+3
-3
@@ -33,7 +33,7 @@ class SingleBoneLookAnimation<T : Entity>(
|
||||
val pitchMultiplier: Float = 1F,
|
||||
val yawMultiplier: Float = 1F,
|
||||
val maxPitch: Float = 70F,
|
||||
val minPitch: Float = 45F,
|
||||
val minPitch: Float = -45F,
|
||||
val maxYaw: Float = 45F,
|
||||
val minYaw: Float = -45F,
|
||||
) : StatelessAnimation<T, ModelFrame>(frame) {
|
||||
@@ -54,8 +54,8 @@ class SingleBoneLookAnimation<T : Entity>(
|
||||
bone = frame.head,
|
||||
pitchMultiplier = pitchMultiplier ?: if (disableX) 0F else if (invertX) -1F else 1F,
|
||||
yawMultiplier = yawMultiplier ?: if (disableY) 0F else if (invertY) -1F else 1F,
|
||||
maxPitch = maxPitch ?: 45F,
|
||||
minPitch = minPitch ?: -70F,
|
||||
maxPitch = maxPitch ?: 70F,
|
||||
minPitch = minPitch ?: -45F,
|
||||
maxYaw = maxYaw ?: 45F,
|
||||
minYaw = minYaw ?: -45F,
|
||||
)
|
||||
|
||||
+37
-20
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon
|
||||
|
||||
import com.cobblemon.mod.common.api.molang.ExpressionLike
|
||||
import com.cobblemon.mod.common.client.entity.PokemonClientDelegate
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.JsonPose
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.JsonPoseableEntityModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityState
|
||||
@@ -20,6 +21,11 @@ import com.cobblemon.mod.common.client.render.models.blockbench.pose.Pose
|
||||
import com.cobblemon.mod.common.entity.pokemon.PokemonEntity
|
||||
import com.cobblemon.mod.common.util.adapters.ExpressionLikeAdapter
|
||||
import com.cobblemon.mod.common.util.adapters.Vec3dAdapter
|
||||
import com.cobblemon.mod.common.util.isDusk
|
||||
import com.cobblemon.mod.common.util.isStandingOnRedSand
|
||||
import com.cobblemon.mod.common.util.isStandingOnSand
|
||||
import com.cobblemon.mod.common.util.isStandingOnSandOrRedSand
|
||||
import com.cobblemon.mod.common.util.resolveBoolean
|
||||
import com.google.gson.ExclusionStrategy
|
||||
import com.google.gson.FieldAttributes
|
||||
import com.google.gson.GsonBuilder
|
||||
@@ -33,6 +39,7 @@ import com.google.gson.annotations.SerializedName
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import java.lang.reflect.Type
|
||||
import java.util.function.Supplier
|
||||
import net.minecraft.client.model.ModelPart
|
||||
import net.minecraft.util.math.Vec3d
|
||||
|
||||
/**
|
||||
@@ -43,7 +50,8 @@ import net.minecraft.util.math.Vec3d
|
||||
* @author Hiroku
|
||||
* @since August 7th, 2022
|
||||
*/
|
||||
class JsonPokemonPoseableModel(override val rootPart: Bone) : PokemonPoseableModel(), HeadedFrame {
|
||||
class JsonPokemonPoseableModel(rootPart: Bone) : PokemonPoseableModel(), HeadedFrame {
|
||||
override val rootPart = (rootPart as ModelPart).children.entries.first().let { rootPart.registerChildWithAllChildren(it.key) }
|
||||
companion object {
|
||||
val gson = GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
@@ -80,30 +88,12 @@ class JsonPokemonPoseableModel(override val rootPart: Bone) : PokemonPoseableMod
|
||||
|
||||
override val head: Bone by lazy { headJoint?.let { getPart(it) } ?: rootPart }
|
||||
|
||||
|
||||
@SerializedName("portraitScale")
|
||||
private val _portraitScale: Float? = null
|
||||
@SerializedName("portraitTranslation")
|
||||
private val _portraitTranslation: Vec3d? = null
|
||||
|
||||
@SerializedName("profileScale")
|
||||
private val _profileScale: Float? = null
|
||||
@SerializedName("profileTranslation")
|
||||
private val _profileTranslation: Vec3d? = null
|
||||
|
||||
//Some weirdness going on here, vars have to be initialized, gson doesn't like multiple fields with the same name
|
||||
@Transient
|
||||
//Idk, works fine with Blastoise
|
||||
override var portraitScale = 1F
|
||||
get() = _portraitScale ?: 1F
|
||||
@Transient
|
||||
override var portraitTranslation = Vec3d.ZERO
|
||||
get() = _portraitTranslation ?: Vec3d(0.0, 0.0, 0.0)
|
||||
@Transient
|
||||
override var profileScale = 1F
|
||||
get() = _profileScale ?: 1F
|
||||
@Transient
|
||||
override var profileTranslation = Vec3d.ZERO
|
||||
get() = _profileTranslation ?: Vec3d(0.0, 0.0, 0.0)
|
||||
|
||||
|
||||
val faint: Supplier<StatefulAnimation<PokemonEntity, ModelFrame>>? = null
|
||||
@@ -142,6 +132,7 @@ class JsonPokemonPoseableModel(override val rootPart: Bone) : PokemonPoseableMod
|
||||
override fun createInstance(type: Type): JsonPokemonPoseableModel {
|
||||
return JsonPokemonPoseableModel(modelPart!!).also {
|
||||
model = it
|
||||
modelPart as ModelPart
|
||||
it.loadAllNamedChildren(modelPart!!)
|
||||
}
|
||||
}
|
||||
@@ -163,6 +154,32 @@ class JsonPokemonPoseableModel(override val rootPart: Bone) : PokemonPoseableMod
|
||||
if (mustBeTouchingWater != null) {
|
||||
conditionsList.add { mustBeTouchingWater == it.isTouchingWater }
|
||||
}
|
||||
val mustBeTouchingWaterOrRain = json.get("isTouchingWaterOrRain")?.asBoolean
|
||||
if (mustBeTouchingWaterOrRain != null) {
|
||||
conditionsList.add { mustBeTouchingWaterOrRain == it.isTouchingWaterOrRain }
|
||||
}
|
||||
val mustBeSubmergedInWater = json.get("isSubmergedInWater")?.asBoolean
|
||||
if (mustBeSubmergedInWater != null) {
|
||||
conditionsList.add { mustBeSubmergedInWater == it.isSubmergedInWater }
|
||||
}
|
||||
val mustBeStandingOnRedSand = json.get("isStandingOnRedSand")?.asBoolean
|
||||
if (mustBeStandingOnRedSand != null) {
|
||||
conditionsList.add { mustBeStandingOnRedSand == it.isStandingOnRedSand() }
|
||||
}
|
||||
val mustBeStandingOnSand = json.get("isStandingOnSand")?.asBoolean
|
||||
if (mustBeStandingOnSand != null) {
|
||||
conditionsList.add { mustBeStandingOnSand == it.isStandingOnSand() }
|
||||
}
|
||||
val mustBeStandingOnSandOrRedSand = json.get("isStandingOnSandOrRedSand")?.asBoolean
|
||||
if (mustBeStandingOnSandOrRedSand != null) {
|
||||
conditionsList.add { mustBeStandingOnSandOrRedSand == it.isStandingOnSandOrRedSand() }
|
||||
}
|
||||
val mustBeDusk = json.get("isDusk")?.asBoolean
|
||||
if (mustBeDusk != null) {
|
||||
conditionsList.add { mustBeDusk == it.isDusk() }
|
||||
}
|
||||
|
||||
conditionsList.add { (it.delegate as PokemonClientDelegate).runtime.resolveBoolean(pose.condition) }
|
||||
|
||||
val poseCondition: ((PokemonEntity) -> Boolean)? = if (conditionsList.isEmpty()) null else conditionsList.reduce { acc, function -> { acc(it) && function(it) } }
|
||||
|
||||
|
||||
+2
-1
@@ -19,6 +19,7 @@ import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
|
||||
import net.minecraft.client.model.ModelPart
|
||||
import net.minecraft.util.math.Vec3d
|
||||
|
||||
class ArcanineModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, QuadrupedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("arcanine")
|
||||
override val head = getPart("head")
|
||||
@@ -37,7 +38,7 @@ class ArcanineModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Quad
|
||||
lateinit var standing: PokemonPose
|
||||
lateinit var walk: PokemonPose
|
||||
|
||||
//override val cryAnimation = CryProvider { _, _ -> bedrockStateful("arcanine", "cry") }
|
||||
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("arcanine", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("arcanine", "blink") }
|
||||
|
||||
+3
-1
@@ -9,8 +9,8 @@
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.PoseableEntityState
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedWalkAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
@@ -37,6 +37,8 @@ class ChanseyModel(root: ModelPart) : PokemonPoseableModel(), BipedFrame {
|
||||
lateinit var sleep: PokemonPose
|
||||
lateinit var battleIdle: PokemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("chansey", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("chansey", "blink") }
|
||||
|
||||
|
||||
+6
-1
@@ -50,6 +50,11 @@ class DodrioModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
val blink1 = quirk { bedrockStateful("dodrio", "blink1") }
|
||||
val blink2 = quirk { bedrockStateful("dodrio", "blink2") }
|
||||
val blink3 = quirk { bedrockStateful("dodrio", "blink3") }
|
||||
val bite1 = quirk(secondsBetweenOccurrences = 5F to 20F) { bedrockStateful("dodrio", "bite_quirk1") }
|
||||
val bite2 = quirk(secondsBetweenOccurrences = 5F to 20F) { bedrockStateful("dodrio", "bite_quirk2") }
|
||||
val bite3 = quirk(secondsBetweenOccurrences = 5F to 20F) { bedrockStateful("dodrio", "bite_quirk3") }
|
||||
|
||||
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
idleAnimations = arrayOf(bedrock("dodrio", "sleep"))
|
||||
@@ -83,7 +88,7 @@ class DodrioModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
poseName = "battle_idle",
|
||||
poseTypes = PoseType.STATIONARY_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink1, blink2, blink3),
|
||||
quirks = arrayOf(blink1, blink2, blink3, bite1, bite2, bite3),
|
||||
condition = { it.isBattling },
|
||||
idleAnimations = arrayOf(
|
||||
bedrock("dodrio", "battle_idle")
|
||||
|
||||
+4
-4
@@ -37,8 +37,8 @@ class DoduoModel (root: ModelPart) : PokemonPoseableModel() {
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("doduo", "blink1") }
|
||||
val blink2 = quirk { bedrockStateful("doduo", "blink2") }
|
||||
val bite = quirk { bedrockStateful("doduo", "bite_quirk1") }
|
||||
val bite2 = quirk { bedrockStateful("doduo", "bite_quirk2") }
|
||||
val bite = quirk(secondsBetweenOccurrences = 5F to 20F) { bedrockStateful("doduo", "bite_quirk1") }
|
||||
val bite2 = quirk(secondsBetweenOccurrences = 5F to 20F) { bedrockStateful("doduo", "bite_quirk2") }
|
||||
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
@@ -50,7 +50,7 @@ class DoduoModel (root: ModelPart) : PokemonPoseableModel() {
|
||||
poseTypes = STATIONARY_POSES + UI_POSES,
|
||||
transformTicks = 10,
|
||||
condition = { !it.isBattling },
|
||||
quirks = arrayOf(blink, blink2, bite, bite2),
|
||||
quirks = arrayOf(blink, blink2),
|
||||
idleAnimations = arrayOf(
|
||||
bedrock("doduo", "ground_idle")
|
||||
)
|
||||
@@ -60,7 +60,7 @@ class DoduoModel (root: ModelPart) : PokemonPoseableModel() {
|
||||
poseName = "walking",
|
||||
poseTypes = MOVING_POSES,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink, blink2, bite, bite2),
|
||||
quirks = arrayOf(blink, blink2),
|
||||
idleAnimations = arrayOf(
|
||||
bedrock("doduo", "ground_walk")
|
||||
)
|
||||
|
||||
+3
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
@@ -26,6 +27,8 @@ class ElectrodeHisuianModel (root: ModelPart) : PokemonPoseableModel() {
|
||||
lateinit var standing: PokemonPose
|
||||
lateinit var walk: PokemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("electrode_hisuian", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("electrode_hisuian", "blink") }
|
||||
standing = registerPose(
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ class KabutoModel(root: ModelPart) : PokemonPoseableModel() {
|
||||
lateinit var standing: PokemonPose
|
||||
lateinit var walk: PokemonPose
|
||||
|
||||
// override val cryAnimation = CryProvider { _, _ -> bedrockStateful("kabuto", "cry") }
|
||||
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("kabuto", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("kabuto", "blink") }
|
||||
|
||||
+4
-3
@@ -8,13 +8,14 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedWalkAnimation
|
||||
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.PokemonPose
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.STATIONARY_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
|
||||
import net.minecraft.client.model.ModelPart
|
||||
import net.minecraft.util.math.Vec3d
|
||||
@@ -56,7 +57,7 @@ class KabutopsModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Bipe
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = UI_POSES + PoseType.STAND,
|
||||
poseTypes = UI_POSES + STATIONARY_POSES,
|
||||
condition = { !it.isBattling },
|
||||
quirks = arrayOf(blink),
|
||||
idleAnimations = arrayOf(
|
||||
@@ -67,7 +68,7 @@ class KabutopsModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Bipe
|
||||
|
||||
walk = registerPose(
|
||||
poseName = "walk",
|
||||
poseType = PoseType.WALK,
|
||||
poseTypes = MOVING_POSES,
|
||||
quirks = arrayOf(blink),
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ class KrabbyModel(root: ModelPart) : PokemonPoseableModel() {
|
||||
lateinit var standingBubbles: PokemonPose
|
||||
lateinit var standingRain: PokemonPose
|
||||
|
||||
// override val cryAnimation = CryProvider { _, _ -> bedrockStateful("krabby", "cry") }
|
||||
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("krabby", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("krabby", "blink")}
|
||||
|
||||
+3
-3
@@ -41,7 +41,7 @@ class LaprasModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Quadru
|
||||
lateinit var underwaterIdle: PokemonPose
|
||||
lateinit var underwaterMove: PokemonPose
|
||||
|
||||
//override val cryAnimation = CryProvider { _, _ -> bedrockStateful("lapras", "cry") }
|
||||
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("lapras", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("lapras", "blink") }
|
||||
@@ -86,7 +86,7 @@ class LaprasModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Quadru
|
||||
quirks = arrayOf(blink),
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("lapras", "surfacewater_idle")
|
||||
bedrock("lapras", "surfacewater_swim")
|
||||
)
|
||||
)
|
||||
|
||||
@@ -106,7 +106,7 @@ class LaprasModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Quadru
|
||||
quirks = arrayOf(blink),
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("lapras", "surfacewater_idle")
|
||||
bedrock("lapras", "surfacewater_swim")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
+1
-8
@@ -8,21 +8,14 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.WingFlapIdleAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.createTransformation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BiWingedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.HeadedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pose.ModelPartTransformation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.parabolaFunction
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.wavefunction.sineFunction
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.SHOULDER_POSES
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.UI_POSES
|
||||
import com.cobblemon.mod.common.util.math.geometry.toRadians
|
||||
import net.minecraft.client.model.ModelPart
|
||||
import net.minecraft.util.math.Vec3d
|
||||
|
||||
@@ -66,7 +59,7 @@ class PidgeyModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
|
||||
stand = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = SHOULDER_POSES + UI_POSES + PoseType.STANDING_POSES,
|
||||
poseTypes = SHOULDER_POSES + UI_POSES + PoseType.STATIONARY_POSES - PoseType.HOVER,
|
||||
transformTicks = 10,
|
||||
transformedParts = arrayOf(
|
||||
wingClosedLeft.createTransformation().withVisibility(visibility = true),
|
||||
|
||||
-2
@@ -58,7 +58,6 @@ class RattataAlolanModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame,
|
||||
poseTypes = setOf(PoseType.NONE, PoseType.PROFILE, PoseType.STAND, PoseType.FLOAT, PoseType.PORTRAIT, PoseType.SHOULDER_LEFT, PoseType.SHOULDER_RIGHT),
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { !it.dataTracker.get(PokemonEntity.MOVING) },
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("rattata_alolan", "ground_idle")
|
||||
@@ -69,7 +68,6 @@ class RattataAlolanModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame,
|
||||
poseType = PoseType.WALK,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { it.dataTracker.get(PokemonEntity.MOVING) },
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("rattata_alolan", "ground_walk")
|
||||
|
||||
-2
@@ -57,7 +57,6 @@ class RattataModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Quadr
|
||||
poseTypes = setOf(PoseType.NONE, PoseType.PROFILE, PoseType.STAND, PoseType.FLOAT, PoseType.PORTRAIT, PoseType.SHOULDER_LEFT, PoseType.SHOULDER_RIGHT),
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { !it.dataTracker.get(PokemonEntity.MOVING) },
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("rattata", "ground_idle")
|
||||
@@ -68,7 +67,6 @@ class RattataModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Quadr
|
||||
poseType = PoseType.WALK,
|
||||
transformTicks = 10,
|
||||
quirks = arrayOf(blink),
|
||||
condition = { it.dataTracker.get(PokemonEntity.MOVING) },
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("rattata", "ground_walk")
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ class ScytherModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame, Biped
|
||||
lateinit var hover: PokemonPose
|
||||
lateinit var fly: PokemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("voltorb", "cry") }
|
||||
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("scyther", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("scyther", "blink")}
|
||||
|
||||
+3
@@ -9,6 +9,7 @@
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
|
||||
|
||||
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.PokemonPose
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
|
||||
@@ -30,6 +31,8 @@ class SnorlaxModel(root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
lateinit var standing: PokemonPose
|
||||
lateinit var walk: PokemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("snorlax", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
|
||||
+4
@@ -10,6 +10,7 @@ package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedWalkAnimation
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.frame.BipedFrame
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
|
||||
import com.cobblemon.mod.common.entity.PoseType.Companion.MOVING_POSES
|
||||
@@ -33,6 +34,9 @@ class TangelaModel(root: ModelPart) : PokemonPoseableModel(), BipedFrame {
|
||||
lateinit var standing: PokemonPose
|
||||
lateinit var walk: PokemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("tangela", "cry") }
|
||||
// Animating illegally rn. Created a new file for this cry. hope it works
|
||||
|
||||
override fun registerPoses() {
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
|
||||
+3
@@ -8,6 +8,7 @@
|
||||
|
||||
package com.cobblemon.mod.common.client.render.models.blockbench.pokemon.gen1
|
||||
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
@@ -26,6 +27,8 @@ class VoltorbHisuianModel (root: ModelPart) : PokemonPoseableModel() {
|
||||
lateinit var standing: PokemonPose
|
||||
lateinit var walk: PokemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("voltorb_hisuian", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("voltorb_hisuian", "blink") }
|
||||
|
||||
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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.gen2
|
||||
|
||||
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.PokemonPose
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
import net.minecraft.client.model.ModelPart
|
||||
import net.minecraft.util.math.Vec3d
|
||||
|
||||
class CyndaquilHisuiBiasModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
override val rootPart = root.registerChildWithAllChildren("cyndaquil_hisui_bias")
|
||||
override val head = getPart("head")
|
||||
|
||||
override var portraitScale = 1.4F
|
||||
override var portraitTranslation = Vec3d(-0.26, 0.0, 0.0)
|
||||
|
||||
override var profileScale = 0.65F
|
||||
override var profileTranslation = Vec3d(0.0, 0.8, 0.0)
|
||||
|
||||
lateinit var standing: PokemonPose
|
||||
lateinit var walking: PokemonPose
|
||||
lateinit var sleep: PokemonPose
|
||||
lateinit var battleidle: PokemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { entity, _ -> if (entity.isBattling) bedrockStateful("cyndaquil_hisui_bias", "battle_cry") else bedrockStateful("cyndaquil_hisui_bias", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
// val sneeze = quirk { bedrockStateful("cyndaquil_hisui_bias", "sneeze_quirk") }
|
||||
|
||||
sleep = registerPose(
|
||||
poseType = PoseType.SLEEP,
|
||||
idleAnimations = arrayOf(bedrock("cyndaquil_hisui_bias", "sleep"))
|
||||
)
|
||||
|
||||
standing = registerPose(
|
||||
poseName = "standing",
|
||||
poseTypes = PoseType.STATIONARY_POSES + PoseType.UI_POSES,
|
||||
transformTicks = 10,
|
||||
condition = { !it.isBattling },
|
||||
// quirks = arrayOf(sneeze),
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("cyndaquil_hisui_bias", "ground_idle")
|
||||
)
|
||||
)
|
||||
|
||||
walking = registerPose(
|
||||
poseName = "walking",
|
||||
poseTypes = PoseType.MOVING_POSES,
|
||||
transformTicks = 10,
|
||||
// quirks = arrayOf(sneeze),
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
bedrock("cyndaquil_hisui_bias", "ground_walk")
|
||||
)
|
||||
)
|
||||
|
||||
battleidle = registerPose(
|
||||
poseName = "battle_idle",
|
||||
poseTypes = PoseType.STATIONARY_POSES,
|
||||
transformTicks = 10,
|
||||
// quirks = arrayOf(sneeze),
|
||||
condition = { it.isBattling },
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(minPitch = 0F),
|
||||
bedrock("cyndaquil_hisui_bias", "battle_idle")
|
||||
)
|
||||
)
|
||||
}
|
||||
// override fun getFaintAnimation(
|
||||
// pokemonEntity: PokemonEntity,
|
||||
// state: PoseableEntityState<PokemonEntity>
|
||||
// ) = if (state.isPosedIn(standing, walking, battleidle, sleep)) bedrockStateful("cyndaquil_hisui_bias", "faint") else null
|
||||
}
|
||||
+1
-1
@@ -71,7 +71,7 @@ class CyndaquilModel (root: ModelPart) : PokemonPoseableModel(), HeadedFrame {
|
||||
// quirks = arrayOf(sneeze),
|
||||
condition = { it.isBattling },
|
||||
idleAnimations = arrayOf(
|
||||
singleBoneLook(),
|
||||
singleBoneLook(minPitch = 0F),
|
||||
bedrock("cyndaquil", "battle_idle")
|
||||
)
|
||||
)
|
||||
|
||||
+3
@@ -12,6 +12,7 @@ import com.cobblemon.mod.common.client.render.models.blockbench.animation.Bimanu
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.animation.BipedWalkAnimation
|
||||
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.pokemon.CryProvider
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPose
|
||||
import com.cobblemon.mod.common.client.render.models.blockbench.pokemon.PokemonPoseableModel
|
||||
import com.cobblemon.mod.common.entity.PoseType
|
||||
@@ -38,6 +39,8 @@ class ElekidModel(root: ModelPart) : PokemonPoseableModel(), BipedFrame, Bimanua
|
||||
lateinit var walk: PokemonPose
|
||||
lateinit var sleep: PokemonPose
|
||||
|
||||
override val cryAnimation = CryProvider { _, _ -> bedrockStateful("elekid", "cry") }
|
||||
|
||||
override fun registerPoses() {
|
||||
val blink = quirk { bedrockStateful("elekid", "blink") }
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user